diff --git a/app/code/core/Mage/Adminhtml/Block/Cache.php b/app/code/core/Mage/Adminhtml/Block/Cache.php index 83fb82c0495..afb0c39c86a 100644 --- a/app/code/core/Mage/Adminhtml/Block/Cache.php +++ b/app/code/core/Mage/Adminhtml/Block/Cache.php @@ -30,7 +30,7 @@ public function __construct() parent::__construct(); $this->_removeButton('add'); $this->_addButton('flush_magento', [ - 'label' => Mage::helper('core')->__('Flush OpenMage Cache'), + 'label' => Mage::helper('core')->__('Flush & Apply Updates'), 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getFlushSystemUrl()), 'class' => 'delete', ]); diff --git a/app/code/core/Mage/Adminhtml/controllers/CacheController.php b/app/code/core/Mage/Adminhtml/controllers/CacheController.php index bc86c314abe..80d701b0788 100644 --- a/app/code/core/Mage/Adminhtml/controllers/CacheController.php +++ b/app/code/core/Mage/Adminhtml/controllers/CacheController.php @@ -52,8 +52,8 @@ public function indexAction() */ public function flushAllAction() { - Mage::dispatchEvent('adminhtml_cache_flush_all'); Mage::app()->getCacheInstance()->flush(); + Mage::dispatchEvent('adminhtml_cache_flush_all'); $this->_getSession()->addSuccess(Mage::helper('adminhtml')->__("The cache storage has been flushed.")); $this->_redirect('*/*'); } @@ -63,9 +63,20 @@ public function flushAllAction() */ public function flushSystemAction() { - Mage::app()->cleanCache(); + Mage::app()->getCacheInstance()->banUse('config'); + Mage::getConfig()->reinit(); + Mage::getConfig()->getCacheSaveLock(30, true); + try { + Mage::app()->cleanCache(); + Mage_Core_Model_Resource_Setup::applyAllUpdates(); + Mage_Core_Model_Resource_Setup::applyAllDataUpdates(); + Mage::app()->getCacheInstance()->unbanUse('config'); + Mage::getConfig()->saveCache(); + } finally { + Mage::getConfig()->releaseCacheSaveLock(); + } Mage::dispatchEvent('adminhtml_cache_flush_system'); - $this->_getSession()->addSuccess(Mage::helper('adminhtml')->__("The OpenMage cache storage has been flushed.")); + $this->_getSession()->addSuccess(Mage::helper('adminhtml')->__("The OpenMage cache has been flushed and updates applied.")); $this->_redirect('*/*'); } diff --git a/app/code/core/Mage/Core/Model/App.php b/app/code/core/Mage/Core/Model/App.php index 34061482f52..da7a35c59ce 100644 --- a/app/code/core/Mage/Core/Model/App.php +++ b/app/code/core/Mage/Core/Model/App.php @@ -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; } diff --git a/app/code/core/Mage/Core/Model/Cache.php b/app/code/core/Mage/Core/Model/Cache.php index 06cbe0f8144..fe97c2c491f 100644 --- a/app/code/core/Mage/Core/Model/Cache.php +++ b/app/code/core/Mage/Core/Model/Cache.php @@ -532,6 +532,18 @@ public function banUse($typeCode) return $this; } + /** + * Enable cache usage for specific data type + * + * @param string $typeCode + * @return $this + */ + public function unbanUse($typeCode) + { + $this->_allowedCacheOptions[$typeCode] = true; + return $this; + } + /** * Get cache tags by cache type from configuration * diff --git a/app/code/core/Mage/Core/Model/Config.php b/app/code/core/Mage/Core/Model/Config.php index 7ead406e46f..0e0e7f556e0 100644 --- a/app/code/core/Mage/Core/Model/Config.php +++ b/app/code/core/Mage/Core/Model/Config.php @@ -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; } @@ -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; @@ -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'); } /** @@ -501,13 +491,46 @@ 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($waitTime = null, $ignoreFailure = false) { - return $this->getCacheId() . '.lock'; + if (! Mage::app()->useCache('config')) { + return; + } + $waitTime = $waitTime ?: (PHP_SAPI === 'cli' ? 60 : 3); + $connection = Mage::getSingleton('core/resource')->getConnection('core_write'); + if (!$connection->fetchOne("SELECT GET_LOCK('core_config_cache_save_lock', ?)", [$waitTime])) { + if ($ignoreFailure) { + return; + } elseif (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')"); } /** @@ -524,12 +547,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; @@ -540,7 +557,6 @@ public function saveCache($tags = []) $this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false); } else { parent::saveCache($tags); - $this->_removeCache($cacheLockId); return $this; } @@ -548,7 +564,6 @@ public function saveCache($tags = []) $this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime()); } unset($this->_cachePartsForSave); - $this->_removeCache($cacheLockId); return $this; } diff --git a/app/locale/en_US/Mage_Adminhtml.csv b/app/locale/en_US/Mage_Adminhtml.csv index 0b92426f3f9..0576093a65d 100644 --- a/app/locale/en_US/Mage_Adminhtml.csv +++ b/app/locale/en_US/Mage_Adminhtml.csv @@ -1031,7 +1031,7 @@ "The Layered Navigation indexing queue has been canceled.","The Layered Navigation indexing queue has been canceled." "The Layered Navigation indices were refreshed.","The Layered Navigation indices were refreshed." "The Layered Navigation process has been queued to be killed.","The Layered Navigation process has been queued to be killed." -"The OpenMage cache storage has been flushed.","The OpenMage cache storage has been flushed." +"The OpenMage cache has been flushed and updates applied.":"The OpenMage cache has been flushed and updates applied." "The Special Price is active only when lower than the Actual Price.","The Special Price is active only when lower than the Actual Price." "The URL Rewrite has been deleted.","The URL Rewrite has been deleted." "The URL Rewrite has been saved.","The URL Rewrite has been saved." diff --git a/app/locale/en_US/Mage_Core.csv b/app/locale/en_US/Mage_Core.csv index 91b9d95fadb..cee988a7529 100644 --- a/app/locale/en_US/Mage_Core.csv +++ b/app/locale/en_US/Mage_Core.csv @@ -147,7 +147,7 @@ "File with an extension ""%value%"" is protected and cannot be uploaded","File with an extension ""%value%"" is protected and cannot be uploaded" "First Day of Week","First Day of Week" "Flush Cache Storage","Flush Cache Storage" -"Flush OpenMage Cache","Flush OpenMage Cache" +"Flush & Apply Updates","Flush & Apply Updates" "Footer","Footer" "Forgot Password Email Sender","Forgot Password Email Sender" "Forgot Password Email Template","Forgot Password Email Template"