This seems kinda random but basically I have the following member function in my caching class:

public function increment($key, $expires = 0)
{
    // Requires OPT_BINARY_PROTOCOL
    return $this->cache->increment($key, 1, 0, $expires);
}

So then I want to do flood protection like this:

$cache->increment('foo', 10) > 50

90% of the time it works but for some reason sometimes it returns some ridiculously high integer and I can't pinpoint how/why or how to reproduce. Memory issue????

Recommended Answers

All 13 Replies

I'm not sure why this happens, but increment and decrement methods seems to be buggy: the library is still using a deprecated function to retrieve results: memcached_fetch instead of memcached_fetch_result. On github there are few pull request that solves most of the open issues with the increment function, but it seems to be no activity from the authors.

So, you could create your own branch, merge the pull request and recompile the library on your own.

Reference:

So I've made a bit of progress.

Here is my PHP code:

while (true)
{
    echo $cache->increment('never_before_used_key', 5). '<br />';
}

And here is what the result looks like:

140733713842860
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
24921
24922
24923
24924
24925
24926
24927
24928
24929
24930
24931
24932
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

As the page executed [indefinitely], every 5 seconds, the counter would start at 0 again, leaving only the initial value upon loading the page the weird arbitrary number.

Upon refreshing the page while it was still executing (meaning that the key should already exist in the cache because it was touched within the past 5 seconds), here's what I got:

140736194609852
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

This is reproducable behavior for me.

As mentioned, using it as flood protection in a production environment, it works 90% of the time and then every so often gives me this weird input and I can't figure out what it is. Memory address??

When I do:

$cache->set('chat_flood_protection', 0);
while (true)
{
    echo $cache->increment('chat_flood_protection', 5). '<br />';
}

Then my output looks like:

0
0
1
2
3
4
5

Is this by design that you need to warm the cache before using increment????? I was under the impression that was the purpose of passing in the value you want to start at as the third parameter.

My new (working to the best of my knowledge) chat poll flooding function:

public function poll_flooding()
{
    global $cache;

    // TODO: I'm not sure why I'm randomly getting erroneous numbers back from $cache->increment() for first call of the page
    // return ($cache->increment('cache_chat_flood_protection', 5) > 50);

    if ($foo = $cache->get('cache_chat_flood_protection'))
    {
        $cache->set('cache_chat_flood_protection', $foo + 1, 5);
    }
    else
    {
        $foo = 0;
        $cache->set('cache_chat_flood_protection', 1, 5);
    }

    return ($foo > 50);
}

Looking at your first example the increments should be by five, not by one, this is my test:

<?php

$key = 'never_before_used_key';
$cache = new Memcached;
$cache->addServer('127.0.0.1', 11211);
$cache->setOption(Memcached::OPT_BINARY_PROTOCOL, TRUE);
$cache->set($key,0,5);

$limit = 1000;
$i = 0;

while (true)
{
    $current = $cache->get($key);
    echo $cache->increment($key, 5). PHP_EOL;

    $i++;
    if($i > $limit || $key > $current) break;
}

I get this output:

5
10
15
20
25
30
35
40
45
50
55
60
65
70
75
...

What version are you using? Mine is:

STAT version 1.4.13
STAT libevent 2.0.16-stable

You can see that by typing echo stats | nc -v 127.0.0.1 11211 | head

Not sure if this can be useful: https://code.google.com/p/memcached/issues/detail?id=320

Looking at your first example the increments should be by five, not by one, this is my test:

Sorry for the confusion. You can see in the OP that $cache is an object of my Memcached wrapper class. As mentioned, it looks like this:

public function increment($key, $expires = 0)
{
    // Requires OPT_BINARY_PROTOCOL
    return $this->cache->increment($key, 1, 0, $expires);
}

So $cache->increment() is calling the wrapper method. $this->cache is the actual Memcached object.

Sorry for the confusion.

No, because I'm using Memcached::increment(), not Memcache::increment().

http://php.net/manual/en/memcached.increment.php

Memcached::increment() does create an item if it doesn't already exist.

Thanks anyways though!! :)

Unfortunately, as told by the flood of people who said that the chat was just loading a blank page today, my new method of flood protection is massive fail. The reason is because the set() function doesn't work like the increment() function in that it updates the expiration time with each call, while increment does not.

However, I ran into something interesting regarding:

while (true)
{
    echo $cache->increment('chat_flood_protection', 5). '<br />';
}

It turns out that while this gives an erroneous first line, just setting the key name to 'chat' (or anything less than 5 characters, it seems) does not.

Another intersting thing to note, that while (true) seems to be succeptible to this, when I do

for ($i = 1; $i < 10000; $i++)
{
    echo $cache->increment('chat_flood_protection', 5). '<br />';
}

it works just fine!!

It should be noted that in a production environment, $cache->increment() is only being called once per script execution, and the idea is to rate limit the number of script executions happening within a 5 second time frame (aka flood protection lol).

Latest progress:

public function foo()
{
    global $cache;

    $i = 0;
    while (true)
    {
        echo $cache->increment('works_with_key_less_than_9_characters_ONLY', 5). '<br />';
        $i++;
        if ($i > 10000)
        {
            break;
        }
    }

}

$cache variable is a member of this class:

class Dani_cache
{
    private $cache;

    public function __construct()
    {
        global $config;

        $this->cache = new Memcached('daniweb');

        if ($this->cache->isPristine())
        {
            $this->cache->setOptions(array(
                Memcached::OPT_NO_BLOCK => true,
                Memcached::OPT_BUFFER_WRITES => true,
                Memcached::OPT_BINARY_PROTOCOL => true,
                Memcached::OPT_TCP_NODELAY => true,
                Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
                Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
            ));
        }

        if (count($this->cache->getServerList()) == 0)
        {
            // Connect to all memcache servers
            $this->cache->addServers($config['Cache']['memcacheserver']);
        }       
    }

    public function increment($key, $expires = 0)
    {
        // Requires OPT_BINARY_PROTOCOL
        return $this->cache->increment($key, 1, 0, $expires);
    }

}
Member Avatar for LastMitch

Hey Dani,

I havne't been on lately. I like the new design, keep up the good work!

As your for issue you are having. Have you look at this:

http://www.phpfastcache.com/

Maybe that will fix the gibberish data issue

I havne't been on lately. I like the new design, keep up the good work!

Thanks!

http://www.phpfastcache.com/

No, that's just a wrapper class for Memcached and a handful of other caching solutions. Thanks anyways, though!

Member Avatar for LastMitch

No, that's just a wrapper class for Memcached and a handful of other caching solutions. Thanks anyways, though!

OK

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.