@@ -313,16 +313,19 @@ public function init($options = [])
313
313
$ this ->setOptions ($ options );
314
314
$ this ->loadBase ();
315
315
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
+ }
319
328
}
320
-
321
- $ this ->_useCache = false ;
322
-
323
- $ this ->loadModules ();
324
- $ this ->loadDb ();
325
- $ this ->saveCache ();
326
329
return $ this ;
327
330
}
328
331
@@ -354,15 +357,13 @@ public function loadBase()
354
357
*/
355
358
public function loadModulesCache ()
356
359
{
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 ;
366
367
}
367
368
}
368
369
return false ;
@@ -474,20 +475,9 @@ protected function _canUseLocalModules()
474
475
*/
475
476
protected function _canUseCacheForInit ()
476
477
{
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 ' );
491
481
}
492
482
493
483
/**
@@ -501,13 +491,43 @@ public function getCache()
501
491
}
502
492
503
493
/**
504
- * Get lock flag cache identifier
494
+ * Call before building and saving cache to ensure only one process can save the cache
505
495
*
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
507
502
*/
508
- protected function _getCacheLockId ()
503
+ public function getCacheSaveLock ()
509
504
{
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') " );
511
531
}
512
532
513
533
/**
@@ -524,12 +544,6 @@ public function saveCache($tags = [])
524
544
if (!in_array (self ::CACHE_TAG , $ tags )) {
525
545
$ tags [] = self ::CACHE_TAG ;
526
546
}
527
- $ cacheLockId = $ this ->_getCacheLockId ();
528
- if ($ this ->_loadCache ($ cacheLockId )) {
529
- return $ this ;
530
- }
531
-
532
- $ this ->_saveCache (time (), $ cacheLockId , [], 60 );
533
547
534
548
if (!empty ($ this ->_cacheSections )) {
535
549
$ xml = clone $ this ->_xml ;
@@ -540,15 +554,13 @@ public function saveCache($tags = [])
540
554
$ this ->_cachePartsForSave [$ this ->getCacheId ()] = $ xml ->asNiceXml ('' , false );
541
555
} else {
542
556
parent ::saveCache ($ tags );
543
- $ this ->_removeCache ($ cacheLockId );
544
557
return $ this ;
545
558
}
546
559
547
560
foreach ($ this ->_cachePartsForSave as $ cacheId => $ cacheData ) {
548
561
$ this ->_saveCache ($ cacheData , $ cacheId , $ tags , $ this ->getCacheLifetime ());
549
562
}
550
563
unset($ this ->_cachePartsForSave );
551
- $ this ->_removeCache ($ cacheLockId );
552
564
553
565
return $ this ;
554
566
}
0 commit comments