-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5681 from magento-performance/MC-33275-2
Stale Cache implementation
- Loading branch information
Showing
19 changed files
with
913 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/CacheTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Framework\Lock\Backend; | ||
|
||
use Magento\Framework\Lock\Backend\Cache; | ||
|
||
/** | ||
* \Magento\Framework\Lock\Backend\Cache test case. | ||
*/ | ||
class CacheTest extends \PHPUnit\Framework\TestCase | ||
{ | ||
/** | ||
* @var Cache | ||
*/ | ||
private $cacheInstance1; | ||
|
||
/** | ||
* @var Cache | ||
*/ | ||
private $cacheInstance2; | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
protected function setUp(): void | ||
{ | ||
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); | ||
|
||
$frontendInterface1 = $objectManager->create(\Magento\Framework\App\Cache\Type\Config::class); | ||
$this->cacheInstance1 = new Cache($frontendInterface1); | ||
|
||
$frontendInterface2 = $objectManager->create(\Magento\Framework\App\Cache\Type\Config::class); | ||
$this->cacheInstance2 = new Cache($frontendInterface2); | ||
} | ||
|
||
/** | ||
* Verify lock mechanism in general. | ||
* | ||
* @return void | ||
*/ | ||
public function testParallelLock(): void | ||
{ | ||
$identifier1 = \uniqid('lock_name_1_', true); | ||
|
||
$this->assertTrue($this->cacheInstance1->lock($identifier1, 2)); | ||
|
||
$this->assertFalse($this->cacheInstance1->lock($identifier1, 2)); | ||
$this->assertFalse($this->cacheInstance2->lock($identifier1, 2)); | ||
sleep(4); | ||
$this->assertFalse($this->cacheInstance1->isLocked($identifier1)); | ||
|
||
$this->assertTrue($this->cacheInstance2->lock($identifier1, -1)); | ||
sleep(4); | ||
$this->assertTrue($this->cacheInstance1->isLocked($identifier1)); | ||
} | ||
|
||
/** | ||
* Verify that lock will be released after timeout expiration. | ||
* | ||
* @return void | ||
*/ | ||
public function testParallelLockExpired(): void | ||
{ | ||
$identifier1 = \uniqid('lock_name_1_', true); | ||
|
||
$this->assertTrue($this->cacheInstance1->lock($identifier1, 1)); | ||
sleep(2); | ||
$this->assertFalse($this->cacheInstance1->isLocked($identifier1)); | ||
|
||
$this->assertTrue($this->cacheInstance1->lock($identifier1, 1)); | ||
sleep(2); | ||
$this->assertFalse($this->cacheInstance1->isLocked($identifier1)); | ||
|
||
$this->assertTrue($this->cacheInstance2->lock($identifier1, 1)); | ||
sleep(2); | ||
$this->assertFalse($this->cacheInstance1->isLocked($identifier1)); | ||
} | ||
|
||
/** | ||
* Verify that lock will not be released by another lock name. | ||
* | ||
* @return void | ||
*/ | ||
public function testParallelUnlock(): void | ||
{ | ||
$identifier1 = \uniqid('lock_name_1_', true); | ||
$identifier2 = \uniqid('lock_name_2_', true); | ||
|
||
$this->assertTrue($this->cacheInstance1->lock($identifier1, 30)); | ||
$this->assertTrue($this->cacheInstance2->lock($identifier2, 30)); | ||
|
||
$this->assertFalse($this->cacheInstance2->unlock($identifier1)); | ||
$this->assertTrue($this->cacheInstance2->unlock($identifier2)); | ||
|
||
$this->assertTrue($this->cacheInstance2->isLocked($identifier1)); | ||
$this->assertFalse($this->cacheInstance2->isLocked($identifier2)); | ||
} | ||
|
||
/** | ||
* Verify that lock will not be released by another lock name when both locks will never be expired. | ||
* | ||
* @return void | ||
*/ | ||
public function testParallelUnlockNoExpiration(): void | ||
{ | ||
$identifier1 = \uniqid('lock_name_1_', true); | ||
$identifier2 = \uniqid('lock_name_2_', true); | ||
|
||
$this->assertTrue($this->cacheInstance1->lock($identifier1, -1)); | ||
$this->assertTrue($this->cacheInstance2->lock($identifier2, -1)); | ||
|
||
$this->assertFalse($this->cacheInstance2->unlock($identifier1)); | ||
$this->assertTrue($this->cacheInstance2->unlock($identifier2)); | ||
|
||
$this->assertTrue($this->cacheInstance2->isLocked($identifier1)); | ||
$this->assertFalse($this->cacheInstance2->isLocked($identifier2)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
lib/internal/Magento/Framework/App/Cache/InMemoryState.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
|
||
namespace Magento\Framework\App\Cache; | ||
|
||
/** | ||
* In memory cache state | ||
* | ||
* Used to ease testing of cache state modifications | ||
*/ | ||
class InMemoryState implements StateInterface | ||
{ | ||
/** @var bool[] */ | ||
private $runtimeState = []; | ||
|
||
/** @var bool[] */ | ||
private $persistedState = []; | ||
|
||
/** | ||
* InMemoryState constructor. | ||
* @param array $persistedState | ||
*/ | ||
public function __construct(array $persistedState = []) | ||
{ | ||
$this->persistedState = $persistedState; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function isEnabled($cacheType) | ||
{ | ||
return $this->runtimeState[$cacheType] | ||
?? $this->persistedState[$cacheType] | ||
?? false; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function setEnabled($cacheType, $isEnabled) | ||
{ | ||
$this->runtimeState[$cacheType] = $isEnabled; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function persist() | ||
{ | ||
$this->persistedState = $this->runtimeState + $this->persistedState; | ||
$this->runtimeState = []; | ||
} | ||
|
||
/** | ||
* Creates new instance with persistent state updated values | ||
* | ||
* @param bool[] $state | ||
* @return self | ||
*/ | ||
public function withPersistedState(array $state): self | ||
{ | ||
$newState = new self(); | ||
$newState->persistedState = $state + $this->persistedState; | ||
return $newState; | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
lib/internal/Magento/Framework/App/Cache/RuntimeStaleCacheStateModifier.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
|
||
namespace Magento\Framework\App\Cache; | ||
|
||
use Magento\Framework\Cache\StaleCacheNotifierInterface; | ||
|
||
/** | ||
* Modifier of runtime cache state based on stale data notification from cache loader | ||
*/ | ||
class RuntimeStaleCacheStateModifier implements StaleCacheNotifierInterface | ||
{ | ||
/** @var StateInterface */ | ||
private $cacheState; | ||
|
||
/** @var string[] */ | ||
private $cacheTypes; | ||
|
||
/** | ||
* @param StateInterface $cacheState | ||
* @param string[] $cacheTypes | ||
*/ | ||
public function __construct(StateInterface $cacheState, array $cacheTypes = []) | ||
{ | ||
$this->cacheState = $cacheState; | ||
$this->cacheTypes = $cacheTypes; | ||
} | ||
|
||
/** | ||
* Disabled configures cache types when stale cache was detected in the current request | ||
*/ | ||
public function cacheLoaderIsUsingStaleCache() | ||
{ | ||
foreach ($this->cacheTypes as $type) { | ||
$this->cacheState->setEnabled($type, false); | ||
} | ||
} | ||
} |
Oops, something went wrong.