10000 [Cache] Optimize Chain adapter · symfony/symfony@f270645 · GitHub
[go: up one dir, main page]

Skip to content

Commit f270645

Browse files
[Cache] Optimize Chain adapter
1 parent ebdcd16 commit f270645

File tree

3 files changed

+67
-22
lines changed

3 files changed

+67
-22
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Psr\Cache\CacheItemPoolInterface;
15+
use Symfony\Component\Cache\CacheItem;
1516

1617
/**
17-
* Marker interface for adapters managing {@see \Symfony\Component\Cache\CacheItem} instances.
18+
* Interface for adapters managing instances of Symfony's {@see CacheItem}.
1819
*
1920
* @author Kévin Dunglas <dunglas@gmail.com>
2021
*/

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

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,30 @@
1313

1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Cache\CacheItemPoolInterface;
16+
use Symfony\Component\Cache\CacheItem;
1617
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1718

1819
/**
19-
* Chains adapters together.
20+
* Chains several adapters together.
2021
*
21-
* Saves, deletes and clears all registered adapter.
22-
* Gets data from the first chained adapter having it in cache.
22+
* Cached items are fetched from the first adapter having them in its data store.
23+
* They are saved and deleted in all adapters at one.
2324
*
2425
* @author Kévin Dunglas <dunglas@gmail.com>
2526
*/
2627
class ChainAdapter implements AdapterInterface
2728
{
2829
private $adapters = array();
30+
private $saveUp;
2931

3032
/**
31-
* @param AdapterInterface[] $adapters
33+
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items.
34+
* @param int $maxLifetime The max lifetime of items propagated from lower adapters to upper ones.
3235
*/
33-
public function __construct(array $adapters)
36+
public function __construct(array $adapters, $maxLifetime = 0)
3437
{
35-
if (2 > count($adapters)) {
36-
throw new InvalidArgumentException('At least two adapters must be chained.');
38+
if (!$adapters) {
39+
throw new InvalidArgumentException('At least one adapter must be specified.');
3740
}
3841

3942
foreach ($adapters as $adapter) {
@@ -47,17 +50,38 @@ public function __construct(array $adapters)
4750
$this->adapters[] = new ProxyAdapter($adapter);
4851
}
4952
}
53+
54+
$this->saveUp = \Closure::bind(
55+
function ($adapter, $item) use ($maxLifetime) {
56+
$origDefaultLifetime = $item->defaultLifetime;
57+
58+
if (0 < $maxLifetime && ($origDefaultLifetime <= 0 || $maxLifetime < $origDefaultLifetime)) {
59+
$item->defaultLifetime = $maxLifetime;
60+
}
61+
62+
$adapter->save($item);
63+
$item->defaultLifetime = $origDefaultLifetime;
64+
},
65+
$this,
66+
CacheItem::class
67+
);
5068
}
5169

5270
/**
5371
* {@inheritdoc}
5472
*/
5573
public function getItem($key)
5674
{
57-
foreach ($this->adapters as $adapter) {
75+
$saveUp = $this->saveUp;
76+
77+
foreach ($this->adapters as $i => $adapter) {
5878
$item = $adapter->getItem($key);
5979

6080
if ($item->isHit()) {
81+
for ($j = $i; $j--; ) {
82+
$saveUp($this->adapters[$j], $item);
83+
}
84+
6185
return $item;
6286
}
6387
}
@@ -70,12 +94,36 @@ public function getItem($key)
7094
*/
7195
public function getItems(array $keys = array())
7296
{
73-
$items = array();
74-
foreach ($keys as $key) {
75-
$items[$key] = $this->getItem($key);
97+
return $this->generateItems($this->adapters[0]->getItems($keys), 0);
98+
}
99+
100+
private function generateItems($items, $adapterIndex)
101+
{
102+
$missing = array();
103+
$nextAdapterIndex = $adapterIndex + 1;
104+
$nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
105+
106+
foreach ($items as $k => $item) {
107+
if (!$nextAdapter || $item->isHit()) {
108+
yield $k => $item;
109+
} else {
110+
$missing[] = $k;
111+
}
76112
}
77113

78-
return $items;
114+
if ($missing) {
115+
$saveUp = $this->saveUp;
116+
$adapter = $this->adapters[$adapterIndex];
117+
$items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
118+
119+
foreach ($items as $k => $item) {
120+
if ($item->isHit()) {
121+
$saveUp($adapter, $item);
122+
}
123+
124+
yield $k => $item;
125+
}
126+
}
79127
}
80128

81129
/**

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@
2222
*/
2323
class ChainAdapterTest extends CachePoolTest
2424
{
25-
protected $skippedTests = array(
26-
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
27-
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
28-
'testDeferredExpired' => 'Failing for now, needs to be fixed.',
29-
);
30-
3125
public function createCachePool()
3226
{
3327
if (defined('HHVM_VERSION')) {
@@ -37,22 +31,24 @@ pub E4DA lic function createCachePool()
3731
$this->markTestSkipped('APCu extension is required.');
3832
}
3933

40-
return new ChainAdapter(array(new ArrayAdapter(), new ExternalAdapter(), new ApcuAdapter(__CLASS__)));
34+
return new ChainAdapter(array(new ArrayAdapter(), new ExternalAdapter(), new ApcuAdapter()));
4135
}
4236

4337
/**
4438
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
39+
* @expectedExceptionMessage At least one adapter must be specified.
4540
*/
46-
public function testLessThanTwoAdapterException()
41+
public function testEmptyAdaptersException()
4742
{
4843
new ChainAdapter(array());
4944
}
5045

5146
/**
5247
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
48+
* @expectedExceptionMessage The class "stdClass" does not implement
5349
*/
5450
public function testInvalidAdapterException()
5551
{
56-
new ChainAdapter(array(new \stdClass(), new \stdClass()));
52+
new ChainAdapter(array(new \stdClass()));
5753
}
5854
}

0 commit comments

Comments
 (0)
0