tl;dr;
Это ошибка в коде расширения PHP...
Я копался в коде расширения PHP, который обертывает libmemcached и сам код API libmemcached, но я думаю, что нашел возможную основную причину вашей проблемы...
Если вы посмотрите на реализацию 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
впоследствии после этого не демонстрирует эту проблему или наличие ключа уже существует).
Я предполагаю, что проблема связана с тем, что API libmemcached имеет два разных требования к размеру для параметра 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.
person
Sherif
schedule
05.11.2015