From 6ec361c6bc647cfeb458f2453ad33aad88a5ca82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= Date: Thu, 24 Oct 2013 09:33:46 +0200 Subject: [PATCH] MDL-42485 add session lock acquire timeout to memcached session driver Credit goes to Eric Merrill, thanks! --- config-dist.php | 2 ++ lib/classes/session/handler.php | 8 +++++++ lib/classes/session/manager.php | 2 +- lib/classes/session/memcached.php | 38 ++++++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/config-dist.php b/config-dist.php index c5bf4bea840..30509734813 100644 --- a/config-dist.php +++ b/config-dist.php @@ -237,6 +237,8 @@ $CFG->admin = 'admin'; // $CFG->session_handler_class = '\core\session\memcached'; // $CFG->session_memcached_save_path = '127.0.0.1:11211'; // $CFG->session_memcached_prefix = 'memc.sess.key.'; +// $CFG->session_memcached_acquire_lock_timeout = 120; +// $CFG->session_memcached_lock_expire = 7200; // Ignored if memcached extension <= 2.1.0 // // Following setting allows you to alter how frequently is timemodified updated in sessions table. // $CFG->session_update_timemodified_frequency = 20; // In seconds. diff --git a/lib/classes/session/handler.php b/lib/classes/session/handler.php index a656175f74d..995784a4e8c 100644 --- a/lib/classes/session/handler.php +++ b/lib/classes/session/handler.php @@ -34,6 +34,14 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ abstract class handler { + /** + * Start the session. + * @return bool success + */ + public function start() { + return session_start(); + } + /** * Init session handler. */ diff --git a/lib/classes/session/manager.php b/lib/classes/session/manager.php index 2b1e7f02007..c5e764ce9d9 100644 --- a/lib/classes/session/manager.php +++ b/lib/classes/session/manager.php @@ -74,7 +74,7 @@ class manager { self::prepare_cookies(); $newsid = empty($_COOKIE[session_name()]); - session_start(); + self::$handler->start(); self::initialise_user_session($newsid); self::check_security(); diff --git a/lib/classes/session/memcached.php b/lib/classes/session/memcached.php index 728153705cb..4e07f3c38cd 100644 --- a/lib/classes/session/memcached.php +++ b/lib/classes/session/memcached.php @@ -40,6 +40,13 @@ class memcached extends handler { protected $servers; /** @var string $prefix session key prefix */ protected $prefix; + /** @var int $acquiretimeout how long to wait for session lock */ + protected $acquiretimeout = 120; + /** + * @var int $lockexpire how long to wait before expiring the lock so that other requests + * may continue execution, ignored if memcached <= 2.1.0. + */ + protected $lockexpire = 7200; /** * Create new instance of handler. @@ -64,6 +71,32 @@ class memcached extends handler { } else { $this->prefix = $CFG->session_memcached_prefix; } + + if (!empty($CFG->session_memcached_acquire_lock_timeout)) { + $this->acquiretimeout = (int)$CFG->session_memcached_acquire_lock_timeout; + } + + if (!empty($CFG->session_memcached_lock_expire)) { + $this->lockexpire = (int)$CFG->session_memcached_lock_expire; + } + } + + /** + * Start the session. + * @return bool success + */ + public function start() { + // NOTE: memcached <= 2.1.0 expires session locks automatically after max_execution_time, + // this leads to major difference compared to other session drivers that timeout + // and stop the second request execution instead. + + $default = ini_get('max_execution_time'); + set_time_limit($this->acquiretimeout); + + $result = parent::start(); + + set_time_limit($default); + return $result; } /** @@ -81,11 +114,14 @@ class memcached extends handler { throw new exception('sessionhandlerproblem', 'error', '', null, '$CFG->session_memcached_save_path must be specified in config.php'); } - // NOTE: we cannot set any lock acquiring timeout here - bad luck. ini_set('session.save_handler', 'memcached'); ini_set('session.save_path', $this->savepath); ini_set('memcached.sess_prefix', $this->prefix); ini_set('memcached.sess_locking', '1'); // Locking is required! + + // Try to configure lock and expire timeouts - ignored if memcached <=2.1.0. + ini_set('memcached.sess_lock_max_wait', $this->acquiretimeout); + ini_set('memcached.sess_lock_expire', $this->lockexpire); } /**