Skip to content

Commit 0b0d05f

Browse files
Replace using cache record for locking with MySQL GET_LOCK function.
1 parent 5655b4b commit 0b0d05f

File tree

2 files changed

+70
-51
lines changed

2 files changed

+70
-51
lines changed

app/code/core/Mage/Core/Model/App.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,21 @@ protected function _initCache(array $cacheInitOptions = [])
432432
protected function _initModules()
433433
{
434434
if (!$this->_config->loadModulesCache()) {
435-
$this->_config->loadModules();
436-
if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) {
437-
Varien_Profiler::start('mage::app::init::apply_db_schema_updates');
438-
Mage_Core_Model_Resource_Setup::applyAllUpdates();
439-
Varien_Profiler::stop('mage::app::init::apply_db_schema_updates');
435+
try {
436+
$this->_config->getCacheSaveLock();
437+
if (!$this->_config->loadModulesCache()) {
438+
$this->_config->loadModules();
439+
if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) {
440+
Varien_Profiler::start('mage::app::init::apply_db_schema_updates');
441+
Mage_Core_Model_Resource_Setup::applyAllUpdates();
442+
Varien_Profiler::stop('mage::app::init::apply_db_schema_updates');
443+
}
444+
$this->_config->loadDb();
445+
$this->_config->saveCache();
446+
}
447+
} finally {
448+
$this->_config->releaseCacheSaveLock();
440449
}
441-
$this->_config->loadDb();
442-
$this->_config->saveCache();
443450
}
444451
return $this;
445452
}

app/code/core/Mage/Core/Model/Config.php

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,19 @@ public function init($options = [])
313313
$this->setOptions($options);
314314
$this->loadBase();
315315

316-
$cacheLoad = $this->loadModulesCache();
317-
if ($cacheLoad) {
318-
return $this;
316+
if (!$this->loadModulesCache()) {
317+
try {
318+
$this->getCacheSaveLock();
319+
if (!$this->loadModulesCache()) {
320+
$this->_useCache = false;
321+
$this->loadModules();
322+
$this->loadDb();
323+
$this->saveCache();
324+
}
325+
} finally {
326+
$this->releaseCacheSaveLock();
327+
}
319328
}
320-
321-
$this->_useCache = false;
322-
323-
$this->loadModules();
324-
$this->loadDb();
325-
$this->saveCache();
326329
return $this;
327330
}
328331

@@ -354,15 +357,13 @@ public function loadBase()
354357
*/
355358
public function loadModulesCache()
356359
{
357-
if (Mage::isInstalled(['etc_dir' => $this->getOptions()->getEtcDir()])) {
358-
if ($this->_canUseCacheForInit()) {
359-
Varien_Profiler::start('mage::app::init::config::load_cache');
360-
$loaded = $this->loadCache();
361-
Varien_Profiler::stop('mage::app::init::config::load_cache');
362-
if ($loaded) {
363-
$this->_useCache = true;
364-
return true;
365-
}
360+
if ($this->_canUseCacheForInit()) {
361+
Varien_Profiler::start('mage::app::init::config::load_cache');
362+
$loaded = $this->loadCache();
363+
Varien_Profiler::stop('mage::app::init::config::load_cache');
364+
if ($loaded) {
365+
$this->_useCache = true;
366+
return true;
366367
}
367368
}
368369
return false;
@@ -474,20 +475,9 @@ protected function _canUseLocalModules()
474475
*/
475476
protected function _canUseCacheForInit()
476477
{
477-
if (Mage::app()->useCache('config') && $this->_allowCacheForInit) {
478-
$retries = 10;
479-
do {
480-
if ($this->_loadCache($this->_getCacheLockId())) {
481-
if ($retries) {
482-
usleep(500000); // 0.5 seconds
483-
}
484-
} else {
485-
return true;
486-
}
487-
} while ($retries--);
488-
}
489-
490-
return false;
478+
return $this->_allowCacheForInit
479+
&& Mage::isInstalled(['etc_dir' => $this->getOptions()->getEtcDir()])
480+
&& Mage::app()->useCache('config');
491481
}
492482

493483
/**
@@ -501,13 +491,43 @@ public function getCache()
501491
}
502492

503493
/**
504-
* Get lock flag cache identifier
494+
* Call before building and saving cache to ensure only one process can save the cache
505495
*
506-
* @return string
496+
* If failed to get cache lock:
497+
* - CLI: throws exception
498+
* - Other: 503 error
499+
*
500+
* @return void
501+
* @throws Exception
507502
*/
508-
protected function _getCacheLockId()
503+
public function getCacheSaveLock()
509504
{
510-
return $this->getCacheId() . '.lock';
505+
if ( ! Mage::app()->useCache('config')) {
506+
return;
507+
}
508+
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
509+
if (!$connection->fetchOne("SELECT GET_LOCK('core_config_cache_save_lock', ?)", [PHP_SAPI === 'cli' ? 60 : 3])) {
510+
if (PHP_SAPI === 'cli') {
511+
throw new Exception('Could not get lock on cache save operation.');
512+
} else {
513+
require_once Mage::getBaseDir() . DS . 'errors' . DS . '503.php';
514+
die();
515+
}
516+
}
517+
}
518+
519+
/**
520+
* Release the cache saving lock after it is saved or no longer needed
521+
*
522+
* @return void
523+
*/
524+
public function releaseCacheSaveLock()
525+
{
526+
if ( ! Mage::app()->useCache('config')) {
527+
return;
528+
}
529+
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
530+
$connection->fetchOne("SELECT RELEASE_LOCK('core_config_cache_save_lock')");
511531
}
512532

513533
/**
@@ -524,12 +544,6 @@ public function saveCache($tags = [])
524544
if (!in_array(self::CACHE_TAG, $tags)) {
525545
$tags[] = self::CACHE_TAG;
526546
}
527-
$cacheLockId = $this->_getCacheLockId();
528-
if ($this->_loadCache($cacheLockId)) {
529-
return $this;
530-
}
531-
532-
$this->_saveCache(time(), $cacheLockId, [], 60);
533547

534548
if (!empty($this->_cacheSections)) {
535549
$xml = clone $this->_xml;
@@ -540,15 +554,13 @@ public function saveCache($tags = [])
540554
$this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
541555
} else {
542556
parent::saveCache($tags);
543-
$this->_removeCache($cacheLockId);
544557
return $this;
545558
}
546559

547560
foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
548561
$this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
549562
}
550563
unset($this->_cachePartsForSave);
551-
$this->_removeCache($cacheLockId);
552564

553565
return $this;
554566
}

0 commit comments

Comments
 (0)