Skip to content

Commit

Permalink
Replace using cache record for locking with MySQL GET_LOCK function.
Browse files Browse the repository at this point in the history
  • Loading branch information
colinmollenhour committed Sep 21, 2023
1 parent 5655b4b commit 0b0d05f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 51 deletions.
21 changes: 14 additions & 7 deletions app/code/core/Mage/Core/Model/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,21 @@ protected function _initCache(array $cacheInitOptions = [])
protected function _initModules()
{
if (!$this->_config->loadModulesCache()) {
$this->_config->loadModules();
if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) {
Varien_Profiler::start('mage::app::init::apply_db_schema_updates');
Mage_Core_Model_Resource_Setup::applyAllUpdates();
Varien_Profiler::stop('mage::app::init::apply_db_schema_updates');
try {
$this->_config->getCacheSaveLock();
if (!$this->_config->loadModulesCache()) {
$this->_config->loadModules();
if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) {
Varien_Profiler::start('mage::app::init::apply_db_schema_updates');
Mage_Core_Model_Resource_Setup::applyAllUpdates();
Varien_Profiler::stop('mage::app::init::apply_db_schema_updates');
}
$this->_config->loadDb();
$this->_config->saveCache();
}
} finally {
$this->_config->releaseCacheSaveLock();
}
$this->_config->loadDb();
$this->_config->saveCache();
}
return $this;
}
Expand Down
100 changes: 56 additions & 44 deletions app/code/core/Mage/Core/Model/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,19 @@ public function init($options = [])
$this->setOptions($options);
$this->loadBase();

$cacheLoad = $this->loadModulesCache();
if ($cacheLoad) {
return $this;
if (!$this->loadModulesCache()) {
try {
$this->getCacheSaveLock();
if (!$this->loadModulesCache()) {
$this->_useCache = false;
$this->loadModules();
$this->loadDb();
$this->saveCache();
}
} finally {
$this->releaseCacheSaveLock();
}
}

$this->_useCache = false;

$this->loadModules();
$this->loadDb();
$this->saveCache();
return $this;
}

Expand Down Expand Up @@ -354,15 +357,13 @@ public function loadBase()
*/
public function loadModulesCache()
{
if (Mage::isInstalled(['etc_dir' => $this->getOptions()->getEtcDir()])) {
if ($this->_canUseCacheForInit()) {
Varien_Profiler::start('mage::app::init::config::load_cache');
$loaded = $this->loadCache();
Varien_Profiler::stop('mage::app::init::config::load_cache');
if ($loaded) {
$this->_useCache = true;
return true;
}
if ($this->_canUseCacheForInit()) {
Varien_Profiler::start('mage::app::init::config::load_cache');
$loaded = $this->loadCache();
Varien_Profiler::stop('mage::app::init::config::load_cache');
if ($loaded) {
$this->_useCache = true;
return true;
}
}
return false;
Expand Down Expand Up @@ -474,20 +475,9 @@ protected function _canUseLocalModules()
*/
protected function _canUseCacheForInit()
{
if (Mage::app()->useCache('config') && $this->_allowCacheForInit) {
$retries = 10;
do {
if ($this->_loadCache($this->_getCacheLockId())) {
if ($retries) {
usleep(500000); // 0.5 seconds
}
} else {
return true;
}
} while ($retries--);
}

return false;
return $this->_allowCacheForInit
&& Mage::isInstalled(['etc_dir' => $this->getOptions()->getEtcDir()])
&& Mage::app()->useCache('config');
}

/**
Expand All @@ -501,13 +491,43 @@ public function getCache()
}

/**
* Get lock flag cache identifier
* Call before building and saving cache to ensure only one process can save the cache
*
* @return string
* If failed to get cache lock:
* - CLI: throws exception
* - Other: 503 error
*
* @return void
* @throws Exception
*/
protected function _getCacheLockId()
public function getCacheSaveLock()
{
return $this->getCacheId() . '.lock';
if ( ! Mage::app()->useCache('config')) {
return;
}
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
if (!$connection->fetchOne("SELECT GET_LOCK('core_config_cache_save_lock', ?)", [PHP_SAPI === 'cli' ? 60 : 3])) {
if (PHP_SAPI === 'cli') {
throw new Exception('Could not get lock on cache save operation.');
} else {
require_once Mage::getBaseDir() . DS . 'errors' . DS . '503.php';
die();
}
}
}

/**
* Release the cache saving lock after it is saved or no longer needed
*
* @return void
*/
public function releaseCacheSaveLock()
{
if ( ! Mage::app()->useCache('config')) {
return;
}
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
$connection->fetchOne("SELECT RELEASE_LOCK('core_config_cache_save_lock')");
}

/**
Expand All @@ -524,12 +544,6 @@ public function saveCache($tags = [])
if (!in_array(self::CACHE_TAG, $tags)) {
$tags[] = self::CACHE_TAG;
}
$cacheLockId = $this->_getCacheLockId();
if ($this->_loadCache($cacheLockId)) {
return $this;
}

$this->_saveCache(time(), $cacheLockId, [], 60);

if (!empty($this->_cacheSections)) {
$xml = clone $this->_xml;
Expand All @@ -540,15 +554,13 @@ public function saveCache($tags = [])
$this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
} else {
parent::saveCache($tags);
$this->_removeCache($cacheLockId);
return $this;
}

foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
$this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
}
unset($this->_cachePartsForSave);
$this->_removeCache($cacheLockId);

return $this;
}
Expand Down

0 comments on commit 0b0d05f

Please sign in to comment.