我已经开始使用PHP Memcached客户端的increment()
方法,并且已经切换到二进制协议。显然,increment()
is only supported on the binary protocol。偶尔,我看到垃圾邮件结果从递增的密钥返回。例如:
$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
部分没有相关性。
其他(可能)相关信息:
答案 0 :(得分:5)
这是PHP扩展代码中的错误......
我深入研究了包含libmemcached和libmemcached API代码本身的PHP扩展代码,但我认为我发现了问题可能的根本原因...
如果你看一下你在line 1858 of php_memcached.c
上看到的PHP Memcached::increment()
实现
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
,然后转换为{{} 1}}。
所以如果我们这样做......
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'));
作为该脚本的输出。 请注意,这只适用于该memcached服务器上尚未存在密钥string(22) "8589934592
"
的情况。还要注意该字符串的长度为foo
个字符,当它显然为{s}时不应该在那附近。
如果你看一下那个字符串的十六进制表示....
22
结果是结尾的垃圾......
var_dump(bin2hex($memcached->get('foo')));
正在存储的对象在演员之间明显被破坏。因此,您可能最终得到与我相同的结果,或者您可能最终得到完全破碎的数据,如上所述。它取决于强制转换如何影响当时存储的内存块(这里将进入未定义的行为)。此外,唯一看似根本原因是使用带有增量的初始值(在此之后使用 string(44) "38353839393334353932000d0a000000000000000000"
未显示该问题或密钥已存在)。
我想这个问题源于这样一个事实:libmemcached API对increment
和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
,而PHP的扩展代码会将其转换为uint64_t
,这几乎等同于unsigned int
。
uint32_t
参数宽度的这种差异可能是导致密钥在调用PHP扩展代码和API代码之间以某种方式被破坏的原因。