From e1a5bb345b1b30ea777348efa9cade21c1f2e2fb Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 4 Mar 2015 13:33:39 +0200 Subject: Fix #3627: Keep timed locks for more than 5 seconds Emulated locks for Redis and Memcached now have a TTL of 300 seconds (the default HTTP request timeout value on many environments) and 30 attemps, each separated by sleep(1), are made by the blocked request to try and obtain a lock if it has been freed. Additionaly, the blocking time for MySQL's locks, which are also timed, is also set to 300 seconds. --- .../Session/drivers/Session_redis_driver.php | 40 +++++++--------------- 1 file changed, 13 insertions(+), 27 deletions(-) (limited to 'system/libraries/Session/drivers/Session_redis_driver.php') diff --git a/system/libraries/Session/drivers/Session_redis_driver.php b/system/libraries/Session/drivers/Session_redis_driver.php index 5fbb5222c..1ce101daf 100644 --- a/system/libraries/Session/drivers/Session_redis_driver.php +++ b/system/libraries/Session/drivers/Session_redis_driver.php @@ -205,7 +205,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle if (isset($this->_lock_key)) { - $this->_redis->setTimeout($this->_lock_key, 5); + $this->_redis->setTimeout($this->_lock_key, 300); if ($this->_fingerprint !== ($fingerprint = md5($session_data))) { if ($this->_redis->set($this->_key_prefix.$session_id, $session_data, $this->_config['expiration'])) @@ -313,40 +313,21 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { if (isset($this->_lock_key)) { - return $this->_redis->setTimeout($this->_lock_key, 5); + 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'; - if (($ttl = $this->_redis->ttl($lock_key)) < 1) - { - if ( ! $this->_redis->setex($lock_key, 5, time())) - { - log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id); - return FALSE; - } - - $this->_lock_key = $lock_key; - - if ($ttl === -1) - { - log_message('debug', 'Session: Lock for '.$this->_key_prefix.$session_id.' had no TTL, overriding.'); - } - - $this->_lock = TRUE; - return TRUE; - } - - // Another process has the lock, we'll try to wait for it to free itself ... $attempt = 0; - while ($attempt++ < 5) + do { - usleep(($ttl * 1000000) - 20000); if (($ttl = $this->_redis->ttl($lock_key)) > 0) { + sleep(1); continue; } - if ( ! $this->_redis->setex($lock_key, 5, time())) + if ( ! $this->_redis->setex($lock_key, 300, time())) { log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id); return FALSE; @@ -355,12 +336,17 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle $this->_lock_key = $lock_key; break; } + while ($attempt++ < 30); - if ($attempt === 5) + if ($attempt === 30) { - log_message('error', 'Session: Unable to obtain lock for '.$this->_key_prefix.$session_id.' after 5 attempts, aborting.'); + 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; return TRUE; -- cgit v1.2.3-24-g4f1b