Skip to content

Commit

Permalink
Merge pull request #5681 from magento-performance/MC-33275-2
Browse files Browse the repository at this point in the history
Stale Cache implementation
  • Loading branch information
vzabaznov authored May 27, 2020
2 parents 0333859 + 7b6668b commit 55af84f
Show file tree
Hide file tree
Showing 19 changed files with 913 additions and 31 deletions.
7 changes: 7 additions & 0 deletions app/code/Magento/PageCache/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@
<type name="Magento\Framework\App\FrontControllerInterface">
<plugin name="page_cache_from_key_from_cookie" type="Magento\PageCache\Plugin\RegisterFormKeyFromCookie" />
</type>
<type name="Magento\Framework\App\Cache\RuntimeStaleCacheStateModifier">
<arguments>
<argument name="cacheTypes" xsi:type="array">
<item name="full_page_cache" xsi:type="const">Magento\PageCache\Model\Cache\Type::TYPE_IDENTIFIER</item>
</argument>
</arguments>
</type>
<preference for="Magento\PageCache\Model\VclGeneratorInterface" type="Magento\PageCache\Model\Varnish\VclGenerator"/>
<preference for="Magento\PageCache\Model\VclTemplateLocatorInterface" type="Magento\PageCache\Model\Varnish\VclTemplateLocator"/>
</config>
7 changes: 7 additions & 0 deletions app/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,13 @@
<argument name="locker" xsi:type="object">Magento\Framework\Lock\Backend\Database</argument>
</arguments>
</type>
<type name="Magento\Framework\Cache\CompositeStaleCacheNotifier">
<arguments>
<argument name="notifiers" xsi:type="array">
<item name="runtime_cache_modifier" xsi:type="object">Magento\Framework\App\Cache\RuntimeStaleCacheStateModifier</item>
</argument>
</arguments>
</type>
<preference for="Magento\Framework\HTTP\AsyncClientInterface" type="Magento\Framework\HTTP\AsyncClient\GuzzleAsyncClient" />
<preference for="Magento\Framework\MessageQueue\PoisonPill\PoisonPillCompareInterface" type="Magento\Framework\MessageQueue\PoisonPill\PoisonPillCompare"/>
<preference for="Magento\Framework\MessageQueue\PoisonPill\PoisonPillPutInterface" type="Magento\Framework\MessageQueue\PoisonPill\PoisonPillPut"/>
Expand Down
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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Magento\Framework\App\DeploymentConfig;

/**
* \Magento\Framework\Lock\Backend\Database test case
* \Magento\Framework\Lock\Backend\Database test case.
*/
class DatabaseTest extends \PHPUnit\Framework\TestCase
{
Expand Down
70 changes: 70 additions & 0 deletions lib/internal/Magento/Framework/App/Cache/InMemoryState.php
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;
}
}
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);
}
}
}
Loading

0 comments on commit 55af84f

Please sign in to comment.