protected function _get_lock($session_id)
{
// PHP 7 reuses the SessionHandler object on regeneration,
// so we need to check here if the lock key is for the
// correct session ID.
//すでにロックを取得していればロックキーのttlを伸ばす
if ($this->_lock_key === $this->_key_prefix.$session_id.':lock')
{
return $this->_redis->setTimeout($this->_lock_key, 300);
}
// 30 attempts to obtain a lock, in case another request already has it
$lock_key = $this->_key_prefix.$session_id.':lock';
$attempt = 0;
do
{
//$ttl=-1: 無期限キー $ttl=-2 存在しないキー $ttl > 0 キーのttl
if (($ttl = $this->_redis->ttl($lock_key)) > 0)
{
//他プロセスでキーが作成されていたらループ
sleep(1);
continue;
}
//※ $ttlを取得してからキーをsetするまでに他のプロセスでキーを作成されてしまうことがまれにある
if ($ttl === -2) {
//nxを指定すると、ロックキーが存在すると失敗する(=他のプロセスでロックがかかっている)
$result = $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300));
if ( ! $result)
{
//※のときセッションエラーになってしまう。
log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id);
return FALSE;
}
} else {
$result = $this->_redis->setex($lock_key, 300, time());
if ( ! $result)
{
log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id);
return FALSE;
}
}
$this->_lock_key = $lock_key;
break;
}
while (++$attempt < 30);
if ($attempt === 30)
{
log_message('error', 'Session: Unable to obtain lock for '.$this->_key_prefix.$session_id.' after 30 attempts, aborting.');
return FALSE;
}
elseif ($ttl === -1)
{
log_message('debug', 'Session: Lock for '.$this->_key_prefix.$session_id.' had no TTL, overriding.');
}
$this->_lock = TRUE;log_message('error', 'Session: lock '.$this->_lock_key);
return TRUE;
}