我正在将 memcache 与 CakePHP 一起使用。
我正在运行一个更新内存缓存键的多线程进程。
因此,两个不同的进程最终更新同一个 memcache 键的概率为 10%,这会引发错误。
我正在将 memcache 与 CakePHP 一起使用。
我正在运行一个更新内存缓存键的多线程进程。
因此,两个不同的进程最终更新同一个 memcache 键的概率为 10%,这会引发错误。
您可以在使用如下代码设置之前“锁定”一个键。
此代码假定您拥有 Instrumentation-for-php 库:
http://code.google.com/p/instrumentation-for-php
如果您不想使用它,只需注释掉仪表线
function acquire_mutex_or_wait($key,$memcache = false) {
Instrumentation::get_instance()->increment('memcache_mutex_requests', 1);
if($memcache === false) {
#bring in memcache from global scope
global $memcache;
}
#prepend LOCK:: to the key to designate the new key as a lock for the given key
$key = "LOCK::$key";
#generate a random number for the lock (see below)
$lockval = mt_rand(1,2^31);
#add is SUPPOSED to be atomic, but it isn't really with multiple servers
#to protect against two connections getting the mutex we initialize it
#to a random value and check the value after setting. If we didn't
#really aquire the mutex, the value we get will be different from the
#value we set
$got_lock = $memcache->add($key, $lockval);
if($got_lock) {
$got_lock = $memcache->get($key);
$got_lock = $got_lock === $lockval;
if($got_lock) return true;
}
#the mutex was not acquired. we must wait for it to be released
$sleep_time = .01; #initial sleep time
$sleep_time_increment = .05;
$max_sleep_time=1; #maximum number of seconds to sleep between checking locks
Instrumentation::get_instance()->timer();
Instrumentation::get_instance()->increment('memcache_mutex_waits', 1);
while(1) {
usleep($sleep_time * 1000000);
$sleep_time += $sleep_time_increment;
if($sleep_time > $max_sleep_time) $sleep_time = $max_sleep_time;
$exists = $memcache->get($key);
if(!$exists) break; #mutex has been released
}
Instrumentation::get_instance()->increment('memcache_mutex_wait_time', Instrumentation::get_instance()->timer());
return false;
}
#NOTE - only the connection that acquired a mutex should release it. there is no
#protection to ensure this is the case
function release_mutex($key, $memcache = false) {
if($memcache === false) {
#bring in memcache from global scope
global $memcache;
}
$key = "LOCK::$key";
return($memcache->delete($key));
}