Skip to content

Commit

Permalink
Allow locking to be disabled via config or on the fly. Fixes issue #27
Browse files Browse the repository at this point in the history
  • Loading branch information
colinmollenhour committed Feb 14, 2014
1 parent f51b78f commit 0a03d8c
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Detects inactive waiting processes to prevent false-positives in concurrency throttling.
- Detects crashed processes to prevent session deadlocks (Linux only).
- Gives shorter session lifetimes to bots and crawlers to reduce wasted resources.
- Locking can be disabled entirely using config or `define('CM_REDISSESSION_LOCKING_ENABLED', FALSE);`.
- Requires PHP >= 5.3. Yes, this is a feature. You're welcome. ;)

#### Locking Algorithm Properties: ####
Expand Down Expand Up @@ -60,6 +61,7 @@
<break_after_frontend>5</break_after_frontend> <!-- seconds to wait for a session lock in the frontend; not as critical as admin -->
<break_after_adminhtml>30</break_after_adminhtml>
<bot_lifetime>7200</bot_lifetime> <!-- Bots get shorter session lifetimes. 0 to disable -->
<disable_locking>0</disable_locking> <!-- Disable session locking entirely. -->
</redis_session>
...
</global>
Expand Down
15 changes: 12 additions & 3 deletions code/Model/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class Cm_RedisSession_Model_Session extends Mage_Core_Model_Mysql4_Session
const XML_PATH_MAX_CONCURRENCY = 'global/redis_session/max_concurrency';
const XML_PATH_BREAK_AFTER = 'global/redis_session/break_after_%s';
const XML_PATH_BOT_LIFETIME = 'global/redis_session/bot_lifetime';
const XML_PATH_DISABLE_LOCKING = 'global/redis_session/disable_locking';

const DEFAULT_TIMEOUT = 2.5;
const DEFAULT_COMPRESSION_THRESHOLD = 2048;
Expand All @@ -81,6 +82,7 @@ class Cm_RedisSession_Model_Session extends Mage_Core_Model_Mysql4_Session
const DEFAULT_MAX_CONCURRENCY = 6; /* The maximum number of concurrent lock waiters per session */
const DEFAULT_BREAK_AFTER = 30; /* Try to break the lock after this many seconds */
const DEFAULT_BOT_LIFETIME = 7200; /* The session lifetime for bots - shorter to prevent bots from wasting backend storage */
const DEFAULT_DISABLE_LOCKING = FALSE; /* Session locking is enabled by default */

/** @var bool */
protected $_useRedis;
Expand All @@ -97,6 +99,7 @@ class Cm_RedisSession_Model_Session extends Mage_Core_Model_Mysql4_Session
protected $_maxConcurrency;
protected $_breakAfter;
protected $_botLifetime;
protected $_useLocking;
protected $_isBot = FALSE;
protected $_hasLock;
protected $_sessionWritten; // avoid infinite loops
Expand All @@ -123,6 +126,9 @@ public function __construct()
$this->_maxConcurrency = (int) (Mage::getConfig()->getNode(self::XML_PATH_MAX_CONCURRENCY) ?: self::DEFAULT_MAX_CONCURRENCY);
$this->_breakAfter = (float) (Mage::getConfig()->getNode(sprintf(self::XML_PATH_BREAK_AFTER, session_name())) ?: self::DEFAULT_BREAK_AFTER);
$this->_botLifetime = (int) (Mage::getConfig()->getNode(self::XML_PATH_BOT_LIFETIME) ?: self::DEFAULT_BOT_LIFETIME);
$this->_useLocking = defined('CM_REDISSESSION_LOCKING_ENABLED')
? CM_REDISSESSION_LOCKING_ENABLED
: ! (Mage::getConfig()->getNode(self::XML_PATH_DISABLE_LOCKING) ?: self::DEFAULT_DISABLE_LOCKING);

// Use sleep time multiplier so break time is in seconds
$this->_breakAfter = (int) round((1000000 / self::SLEEP_TIME) * $this->_breakAfter);
Expand Down Expand Up @@ -210,7 +216,7 @@ public function read($sessionId)
if ($this->_dbNum) {
$this->_redis->select($this->_dbNum);
}
while(1)
while ($this->_useLocking)
{
// Increment lock value for this session and retrieve the new value
$oldLock = $lock;
Expand Down Expand Up @@ -412,8 +418,11 @@ public function write($sessionId, $sessionData)
// Do not overwrite the session if it is locked by another pid
try {
if($this->_dbNum) $this->_redis->select($this->_dbNum); // Prevent conflicts with other connections?
$pid = $this->_redis->hGet('sess_'.$sessionId, 'pid'); // PHP Fatal errors cause self::SESSION_PREFIX to not work..
if ( ! $pid || $pid == $this->_getPid()) {
if ( ! $this->_useLocking) {
$this->_writeRawSession($sessionId, $sessionData, $this->getLifeTime());
}
else if ( ! ($pid = $this->_redis->hGet('sess_'.$sessionId, 'pid')) || $pid == $this->_getPid()) {
if ($this->_logLevel >= Zend_Log::DEBUG) {
$this->_log(sprintf("Write lock obtained on ID %s", $sessionId));
}
Expand Down

0 comments on commit 0a03d8c

Please sign in to comment.