Я начал использовать increment()
метод PHP Memcached клиента, и с этим переключился на двоичный протокол. По-видимому, increment()
поддерживается только в двоичном протоколе. Иногда я вижу результаты мусора, возвращаемые из увеличенных ключей. Например:
$memcached = new \Memcached();
$memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, TRUE);
…
$this->cache->increment($key,1,1);
…
$this->cache->get($key);
Выход:
"1\u0000ants1 0 1\r\n1\r\n1\r\n25\r"
Учитывая, что ключ не существовал до того, как его сначала увеличили, и начальное значение 1
был дан increment()
вызов, я ожидаю, что возвращаемое значение будет целым числом. Вместо этого возвращаемые строки выглядят как остатки мусора, например ants
часть этой строки не имеет никакого отношения.
Другая (возможно) соответствующая информация:
Это ошибка в коде расширения PHP …
Я копался в коде расширения PHP, в который входит libmemcached, и в самом коде libmemcached API, но я думаю, что нашел возможную причину вашей проблемы …
Если вы посмотрите на PHP Memcached::increment()
реализация вы увидите на линия 1858 г. php_memcached.c
status = memcached_increment_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value);
Проблема здесь в том, что offset
может иметь или не иметь ширину 64 бита. libmemcached API говорит нам, что memcached_increment_with_initial
подпись функции ожидает uint64_t
за offset
тогда как здесь offset
объявлен long
а затем приведен к unsigned int
,
Так что, если бы мы сделали что-то вроде этого …
$memcached = new memcached;
$memcached->addServer('127.0.0.1','11211');
$memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, TRUE);
$memcached->delete('foo'); // remove the key if it already exists
$memcached->increment('foo',1,1);
var_dump($memcached->get('foo'));
Вы бы увидели что-то вроде …
string(22) "8589934592
"
как вывод из этого скрипта. Обратите внимание, это работает только если ключ foo
еще не существует на этом memcached сервере. Также обратите внимание на длину этой строки в 22
персонажи, когда ясно, что это не должно быть где-то рядом с этим.
Если вы посмотрите на шестнадцатеричное представление этой строки ….
var_dump(bin2hex($memcached->get('foo')));
Результат — чистый мусор в конце …
string(44) "38353839393334353932000d0a000000000000000000"
Хранимый объект был явно поврежден между слепками. Таким образом, вы можете получить тот же результат, что и я, или вы можете получить полностью испорченные данные, как вы продемонстрировали выше. Это зависит от того, как приведение повлияло на кусок памяти, сохраняемый в данный момент (что приводит к неопределенному поведению здесь). Также единственной, казалось бы, первопричиной этого является использование начального значения с шагом (используя increment
впоследствии после этого не будет продемонстрирована эта проблема или если ключ уже существует).
Я предполагаю, что проблема этого связана с тем, что у libmemcached API есть два разных требования к размеру offset
параметр между memcached_increment
а также memcached_increment_with_initial
memcached_increment(memcached_st *ptr, const char *key, size_t key_length, uint32_t offset, uint64_t *value)
Бывший берет uint32_t
тогда как позднее uint64_t
и код расширения PHP приводит оба к unsigned int
, что будет эквивалентно uint32_t
довольно много.
Эта дискретность в ширине offset
Параметр, вероятно, является причиной того, что ключ каким-то образом поврежден между вызывающим кодом расширения PHP и кодом API.
Других решений пока нет …