tl; dr;
這是PHP擴展代碼中的錯誤...
我挖成一個包裝libmemcached和libmemcached API代碼本身的PHP擴展的代碼,但我想我已經找到了你的問題可能的根本原因......
如果你看看PHP的Memcached::increment()實現你會看到line 1858 of 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有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的擴展代碼之間的offset參數的兩個不同尺寸要求的事實莖投給unsigned int,這幾乎相當於uint32_t。
offset參數寬度上的這種差異很可能是導致密鑰在調用PHP擴展代碼和API代碼之間以某種方式被破壞的原因。