I use php memcached to implement token the code is below:
function addTokenKey($token)
{
$allTokens = $this->memcache->get("AllTokens");
if(gettype($allTokens) == "boolean")
{
$array = array();
array_push($array,$token);
$this->memcache->set("AllTokens",$array);
echo "addTokenKey 1.2:".count($array)."<br>";
}
else{
echo "addTokenKey 2.1:".count($allTokens)."<br>";
array_push($allTokens,$token);
$this->memcache->set("AllTokens",$allTokens);
echo "addTokenKey 2.2:".count($allTokens)."<br>";
}
}
I send mulitple request to call this function at the same time
but sometime I get the same result,Ex:
request result
addTokenKey 2.1:5
addTokenKey 2.2:6
another request result
addTokenKey 2.1:5
addTokenKey 2.2:6
How to avoid this case happen? lock or ..?
refer to:https://github.com/zerkalica/Semaphore
I use this library to try to do lock & release,the code is below:
function addTokenKey($token)
{
$adapter = new MemcachedAdapter($this->memcache);
$semaphore = new SemaphoreManager($adapter);
$ttl = 60; // Time in seconds, used, if script dies and release never called.
$handle = $semaphore->acquire('addTokenKey_lock_key', $ttl);
$allTokens = $this->memcache->get("AllTokens");
if($allTokens == false)
{
//array_push($allTokens,$token);
$array = array();
array_push($array,$token);
$this->memcache->set("AllTokens",$array);
echo "addTokenKey 1.2:".count($array)."<br>";
}
else{
echo "addTokenKey 2.1:".count($allTokens)."<br>";
array_push($allTokens,$token);
$result = $this->memcache->set("AllTokens",$allTokens);
echo "addTokenKey 2.2:".count($allTokens)." ".$result."<br>";
}
$semaphore->release($handle);
}
but I always got two error
Fatal error: Uncaught exception 'ErrorException' with message 'Can't acquire lock for millwright_semaphoreaddTokenKey_lock_key' in /xxxxxxx/Server/lib/Semaphore/SemaphoreManager.php on line 50
Fatal error: Uncaught exception 'LogicException' with message 'Call ::acquire('millwright_semaphoremillwright_semaphoreaddTokenKey_lock_key') first' in /xxxxxxx/Server/lib/Semaphore/SemaphoreManager.php on line 65
I already fix this error in SemaphoreManager.php by removing "$this->prefix ." code
but still have miss array count problem.
I modify some code below to try,
I send 100 request,finally allTokens number is only 50,
others will show "Unable to set"
function addTokenKey($token)
{
// initialize lock
$lock = FALSE;
// initialize configurable parameters
$tries = 0;
$max_tries = 1000;
$lock_ttl = 10;
$allTokens = $this->memcache->get("AllTokens");
while($lock === FALSE && $tries < $max_tries ) {
if( $allTokens == false ) {
$allTokens = array();
array_push($allTokens,$token);
$this->memcache->set("AllTokens",$allTokens);
echo "addTokenKey 1.2:".count($allTokens)."<br>";
return;
}
$count = count($allTokens) ;
// add() will return false if someone raced us for this lock
// ALWAYS USE add() FOR CUSTOM LOCKS
$lock = $this->memcache->add("lock_".$count, 1, $lock_ttl);
$tries++;
usleep(100*($tries%($max_tries/10))); // exponential backoff style of sleep
}
if($lock === FALSE && $tries >= $max_tries) {
print("Unable to set");
} else {
echo "addTokenKey 2.1:".count($allTokens)."<br>";
array_push($allTokens,$token);
$this->memcache->set("AllTokens",$allTokens);
echo "addTokenKey 2.2:".count($allTokens)."<br>";
}
}
finally I use memcached getAllKeys function to fix the problem,don't DIY to record allTokens but this function only can use in linux memcached, windows memcache don't support getAllKeys