8000 [Cache] Add nonce based cache invalidation to ApcuAdapter · symfony/symfony@6ef23f0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6ef23f0

Browse files
[Cache] Add nonce based cache invalidation to ApcuAdapter
1 parent b85ab60 commit 6ef23f0

File tree

4 files changed

+45
-3
lines changed

4 files changed

+45
-3
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,7 @@ private function registerPropertyInfoConfiguration(array $config, ContainerBuild
10371037

10381038
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
10391039
{
1040+
$container->setParameter('kernel.cache_nonce', substr(base64_encode(md5(uniqid(mt_rand(), true), true)), 0, 4));
10401041
$container->getDefinition('cache.adapter.filesystem')->replaceArgument(2, $config['directory']);
10411042

10421043
foreach (array('doctrine', 'psr6', 'redis') as $name) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<tag name="monolog.logger" channel="cache" />
2828
<argument /> <!-- namespace -->
2929
<argument /> <!-- default lifetime -->
30+
<argument>%kernel.cache_nonce%</argument>
3031
<call method="setLogger">
3132
<argument type="service" id="logger" on-invalid="ignore" />
3233
</call>

src/Symfony/Component/Cache/Adapter/ApcuAdapter.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
*/
1919
class ApcuAdapter extends AbstractAdapter
2020
{
21-
public function __construct($namespace = '', $defaultLifetime = 0)
21+
private $nonce;
22+
private $nonceLen;
23+
24+
public function __construct($namespace = '', $defaultLifetime = 0, $nonce = null)
2225
{
2326
if (!function_exists('apcu_fetch') || !ini_get('apc.enabled') || ('cli' === PHP_SAPI && !ini_get('apc.enable_cli'))) {
2427
throw new CacheException('APCu is not enabled');
@@ -27,14 +30,30 @@ public function __construct($namespace = '', $defaultLifetime = 0)
2730
ini_set('apc.use_request_time', 0);
2831
}
2932
parent::__construct($namespace, $defaultLifetime);
33+
$this->nonce = (string) $nonce;
34+
$this->nonceLen = strlen($nonce);
3035
}
3136

3237
/**
3338
* {@inheritdoc}
3439
*/
3540
protected function doFetch(array $ids)
3641
{
37-
return apcu_fetch($ids);
42+
$values = apcu_fetch($ids);
43+
44+
if ($this->nonceLen) {
45+
foreach ($values as $id => $v) {
46+
if (0 !== strpos($v, $this->nonce)) {
47+
apcu_delete($id);
48+
unset($values[$id]);
49+
}
50+
}
51+
foreach ($values as $id => $v) {
52+
$values[$id] = unserialize(substr($v, $this->nonceLen));
53+
}
54+
}
55+
56+
return $values;
3857
}
3958

4059
/**
@@ -73,12 +92,18 @@ protected function doDelete(array $ids)
7392
protected function doSave(array $values, $lifetime)
7493
{
7594
try {
95+
if ($this->nonceLen) {
96+
foreach ($values as $id => $v) {
97+
$values[$id] = $this->nonce.serialize($v);
98+
}
99+
}
100+
76101
return array_keys(apcu_store($values, null, $lifetime));
77102
} catch (\Error $e) {
78103
} catch (\Exception $e) {
79104
}
80105

81-
if (1 === count($values)) {
106+
if (!$this->nonceLen && 1 === count($values)) {
82107
// Workaround https://github.com/krakjoe/apcu/issues/170
83108
apcu_delete(key($values));
84109
}

src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,19 @@ public function testUnserializable()
4343
$item = $pool->getItem('foo');
4444
$this->assertFalse($item->isHit());
4545
}
46+
47+
public function testNonce()
48+
{
49+
$namespace = str_replace('\\', '.', __CLASS__);
50+
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
51+
$pool2 = new ApcuAdapter($namespace, 0, 'p2');
52+
53+
$item = $pool1->getItem('foo');
54+
$this->assertFalse($item->isHit());
55+
$this->assertTrue($pool1->save($item->set('bar')));
56+
$item = $pool1->getItem('foo');
57+
$this->assertTrue($item->isHit());
58+
$item = $pool2->getItem('foo');
59+
$this->assertFalse($item->isHit());
60+
}
4661
}

0 commit comments

Comments
 (0)
0