8000 [Cache] Add namespace based invalidation with ForkableAdapterInterface · symfony/symfony@87b6c58 · GitHub
[go: up one dir, main page]

Skip to content

Commit 87b6c58

Browse files
[Cache] Add namespace based invalidation with ForkableAdapterInterface
1 parent 64ace10 commit 87b6c58

15 files changed

+240
-9
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/**
2121
* @author Nicolas Grekas <p@tchwork.com>
2222
*/
23-
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
23+
abstract class AbstractAdapter implements ForkableAdapterInterface, LoggerAwareInterface
2424
{
2525
use LoggerAwareTrait;
2626

@@ -363,13 +363,33 @@ public function commit()
363363
return $ok;
364364
}
365365

366+
/**
367+
* {@inheritdoc}
368+
*/
369+
public function fork($namespace)
370+
{
371+
$fork = clone $this;
372+
$fork->deferred = array();
373+
$fork->namespace = $this->forkNamespace($namespace, $this->namespace);
374+
375+
return $fork;
376+
}
377+
366378
public function __destruct()
367379
{
368380
if ($this->deferred) {
369381
$this->commit();
370382
}
371383
}
372384

385+
/**
386+
* @return string A new key prefix derivated from a sub-namespace and its parent
387+
*/
388+
protected function forkNamespace($namespace, $parentNamespace)
389+
{
390+
return substr(str_replace('/', '-', base64_encode(md5($parentNamespace.'.'.$this->getId($namespace), true))), 0, 10);
391+
}
392+
373393
private function getId($key)
374394
{
375395
CacheItem::validateKey($key);

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
/**
1818
* @author Nicolas Grekas <p@tchwork.com>
1919
*/
20-
abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface
20+
abstract class AbstractTagAwareAdapter implements ForkableAdapterInterface, TagAwareAdapterInterface
2121
{
2222
private $adapter;
2323
private $deferred = array();
@@ -42,7 +42,7 @@ abstract protected function filterInvalidatedKeys(array &$keys);
4242
*/
4343
abstract protected function doSaveTags(array $tags);
4444

45-
public function __construct(AdapterInterface $adapter, $defaultLifetime)
45+
public function __construct(ForkableAdapterInterface $adapter, $defaultLifetime)
4646
{
4747
$this->adapter = $adapter;
4848
$this->createCacheItem = \Closure::bind(
@@ -197,6 +197,18 @@ public function commit()
197197
return $this->adapter->commit() && $ok;
198198
}
199199

200+
/**
201+
* {@inheritdoc}
202+
*/
203+
public function fork($namespace)
204+
{
205+
$fork = clone $this;
206+
$fork->adapter = $this->adapter->fork($namespace);
207+
$fork->deferred = array();
208+
209+
return $fork;
210+
}
211+
200212
public function __destruct()
201213
{
202214
$this->commit();

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
/**
2020
* @author Nicolas Grekas <p@tchwork.com>
2121
*/
22-
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
22+
class ArrayAdapter implements ForkableAdapterInterface, LoggerAwareInterface
2323
{
2424
use LoggerAwareTrait;
2525

@@ -187,6 +187,19 @@ public function commit()
187187
return true;
188188
}
189189

190+
/**
191+
* {@inheritdoc}
192+
*/
193+
public function fork($namespace)
194+
{
195+
CacheItem::validateKey($namespace);
196+
197+
$fork = clone $this;
198+
$fork->values = $fork->expiries = array();
199+
200+
return $fork;
201+
}
202+
190203
private function generateItems(array $keys, $now)
191204
{
192205
$f = $this->createCacheItem;

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*
2525
* @author Kévin Dunglas <dunglas@gmail.com>
2626
*/
27-
class ChainAdapter implements AdapterInterface
27+
class ChainAdapter implements ForkableAdapterInterface
2828
{
2929
private $adapters = array();
3030
private $saveUp;
@@ -44,7 +44,7 @@ public function __construct(array $adapters, $maxLifetime = 0)
4444
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_class($adapter), CacheItemPoolInterface::class));
4545
}
4646

47-
if ($adapter instanceof AdapterInterface) {
47+
if ($adapter instanceof ForkableAdapterInterface) {
4848
$this->adapters[] = $adapter;
4949
} else {
5050
$this->adapters[] = new ProxyAdapter($adapter);
@@ -223,4 +223,19 @@ public function commit()
223223

224224
return $committed;
225225
}
226+
227+
/**
228+
* {@inheritdoc}
229+
*/
230+
public function fork($namespace)
231+
{
232+
$fork = clone $this;
233+
$fork->adapters = array();
234+
235+
foreach ($this->adapters as $adapter) {
236+
$fork->adapters[] = $adapter->fork($namespace);
237+
}
238+
239+
return $fork;
240+
}
226241
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Doctrine\Common\Cache\CacheProvider;
15+
use Symfony\Component\Cache\Exception\CacheException;
1516

1617
/**
1718
* @author Nicolas Grekas <p@tchwork.com>
@@ -27,6 +28,23 @@ public function __construct(CacheProvider $provider, $namespace = '', $defaultLi
2728
$provider->setNamespace($namespace);
2829
}
2930

31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function fork($namespace)
35+
{
36+
$fork = clone $this;
37+
38+
try {
39+
$fork->provider = clone $this->provider;
40+
} catch (\Exception $e) {
41+
throw new CacheException($e->getMessage(), $e->getCode(), $e);
42+
}
43+
$fork->provider->setNamespace($this->forkNamespace($namespace, $this->provider->getNamespace()));
44+
45+
return $fork;
46+
}
47+
3048
/**
3149
* {@inheritdoc}
3250
*/

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212
namespace Symfony\Component\Cache\Adapter;
1313

14+
use Symfony\Component\Cache\CacheItem;
1415
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @author Nicolas Grekas <p@tchwork.com>
1819
*/
1920
trait FilesystemAdapterTrait
2021
{
22+
private $namespace = '';
2123
private $directory;
2224
private $tmp;
2325

@@ -79,6 +81,20 @@ protected function doDelete(array $ids)
7981
return $ok;
8082
}
8183

84+
/**
85+
* {@inheritdoc}
86+
*/
87+
public function fork($namespace)
88+
{
89+
CacheItem::validateKey($namespace);
90+
91+
$fork = clone $this;
92+
$fork->init($this->forkNamespace($namespace, $this->namespace), $this->directory);
93+
$fork->namespace = $namespace;
94+
95+
return $fork;
96+
}
97+
8298
private function write($file, $data, $expiresAt = null)
8399
{
84100
if (false === @file_put_contents($this->tmp, $data)) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Adapter;
13+
14+
use Psr\Cache\CacheException;
15+
use Psr\Cache\InvalidArgumentException;
16+
17+
/**
18+
* Interface for forking new cache key spaces by derivating existing pools using a namespace.
19+
*
20+
* @author Nicolas Grekas <p@tchwork.com>
21+
*/
22+
interface ForkableAdapterInterface extends AdapterInterface
23+
{
24+
/**
25+
* Forks a cache pool by creating a namespace isolated cache keys space.
26+
*
27+
* Namespace adds to each others when forking in chain.
28+
* Clearing a parent is not required to clear its forks.
29+
*
30+
* @param string $namespace A namespace where cache keys will be isolated
31+
*
32+
* @return self A clone of the current instance, where cache keys are isolated from its parent
33+
*
34+
* @throws InvalidArgumentException When $namespace contains invalid characters
35+
* @throws CacheException When the adapter can't be forked
36+
*/
37+
public function fork($namespace);
38+
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
/**
1818
* @author Titouan Galopin <galopintitouan@gmail.com>
1919
*/
20-
class NullAdapter implements AdapterInterface
20+
class NullAdapter implements ForkableAdapterInterface
2121
{
2222
private $createCacheItem;
2323

@@ -110,6 +110,14 @@ public function commit()
110110
return false;
111111
}
112112

113+
/**
114+
* {@inheritdoc}
115+
*/
116+
public function fork($namespace)
117+
{
118+
return clone $this;
119+
}
120+
113121
private function generateItems(array $keys)
114122
{
115123
$f = $this->createCacheItem;

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/**
1919
* @author Nicolas Grekas <p@tchwork.com>
2020
*/
21-
class ProxyAdapter implements AdapterInterface
21+
class ProxyAdapter implements ForkableAdapterInterface
2222
{
2323
private $pool;
2424
private $namespace;
@@ -137,6 +137,18 @@ public function commit()
137137
return $this->pool->commit();
138138
}
139139

140+
/**
141+
* {@inheritdoc}
142+
*/
143+
public function fork($namespace)
144+
{
145+
$fork = clone $this;
146+
$fork->namespace = substr(str_replace('/', '-', base64_encode(md5($this->namespace.'.'.$this->getId($namespace), true))), 0, 10);
147+
$fork->namespaceLen = strlen($fork->namespace);
148+
149+
return $fork;
150+
}
151+
140152
private function doSave(CacheItemInterface $item, $method)
141153
{
142154
if (!$item instanceof CacheItem) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TagAwareRedisAdapter extends AbstractTagAwareAdapter
2323
/**
2424
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
2525
*/
26-
public function __construct($redisClient, $namespace = '', $defaultLifetime = 0, AdapterInterface $adapter = null)
26+
public function __construct($redisClient, $namespace = '', $defaultLifetime = 0, ForkableAdapterInterface $adapter = null)
2727
{
2828
parent::__construct($adapter ?: new RedisAdapter($redisClient, $namespace, $defaultLifetime), $defaultLifetime);
2929
$this->setRedis($redisClient, $namespace);

0 commit comments

Comments
 (0)
0