Skip to content

Commit c795099

Browse files
panki3aNyholm
authored andcommitted
Storing items into previous cache pool (#158)
* fix merging loaded items, when return type of getItems method from chained pool is Generator instead of array add unsetting loaded key from next chain pool loading for better performance fix psr2 code style * change array_merge($loadedItems, $hits); * add storing items into previous cache pool in getItems method * change code style * change code style * added test for CachePoolChain * change code style * added testGetItemsWithEmptyCache
1 parent 0cd9a75 commit c795099

File tree

2 files changed

+145
-9
lines changed

2 files changed

+145
-9
lines changed

CachePoolChain.php

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class CachePoolChain implements CacheItemPoolInterface, LoggerAwareInterface
4747
*/
4848
public function __construct(array $pools, array $options = [])
4949
{
50-
$this->pools = $pools;
50+
$this->pools = $pools;
5151

5252
if (!isset($options['skip_on_failure'])) {
5353
$options['skip_on_failure'] = false;
@@ -97,8 +97,10 @@ public function getItem($key)
9797
*/
9898
public function getItems(array $keys = [])
9999
{
100-
$hits = [];
101-
$items = [];
100+
$hits = [];
101+
$loadedItems = [];
102+
$notFoundItems = [];
103+
$keysCount = count($keys);
102104
foreach ($this->getPools() as $poolKey => $pool) {
103105
try {
104106
$items = $pool->getItems($keys);
@@ -107,19 +109,41 @@ public function getItems(array $keys = [])
107109
foreach ($items as $item) {
108110
if ($item->isHit()) {
109111
$hits[$item->getKey()] = $item;
112+
unset($keys[array_search($item->getKey(), $keys)]);
113+
} else {
114+
$notFoundItems[$poolKey][$item->getKey()] = $item->getKey();
110115
}
116+
$loadedItems[$item->getKey()] = $item;
111117
}
112-
113-
if (count($hits) === count($keys)) {
114-
return $hits;
118+
if (count($hits) === $keysCount) {
119+
break;
115120
}
116121
} catch (CachePoolException $e) {
117122
$this->handleException($poolKey, __FUNCTION__, $e);
118123
}
119124
}
120125

121-
// We need to accept that some items where not hits.
122-
return array_merge($hits, $items);
126+
if (!empty($hits) && !empty($notFoundItems)) {
127+
foreach ($notFoundItems as $poolKey => $itemKeys) {
128+
try {
129+
$pool = $this->getPools()[$poolKey];
130+
$found = false;
131+
foreach ($itemKeys as $itemKey) {
132+
if (!empty($hits[$itemKey])) {
133+
$found = true;
134+
$pool->saveDeferred($hits[$itemKey]);
135+
}
136+
}
137+
if ($found) {
138+
$pool->commit();
139+
}
140+
} catch (CachePoolException $e) {
141+
$this->handleException($poolKey, __FUNCTION__, $e);
142+
}
143+
}
144+
}
145+
146+
return array_merge($loadedItems, $hits);
123147
}
124148

125149
/**
@@ -326,7 +350,8 @@ private function handleException($poolKey, $operation, CachePoolException $excep
326350

327351
$this->log(
328352
'warning',
329-
sprintf('Removing pool "%s" from chain because it threw an exception when executing "%s"', $poolKey, $operation),
353+
sprintf('Removing pool "%s" from chain because it threw an exception when executing "%s"', $poolKey,
354+
$operation),
330355
['exception' => $exception]
331356
);
332357

Tests/CachePoolChainTest.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-cache organization.
5+
*
6+
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Cache\Adapter\Chain\Tests;
13+
14+
use Cache\Adapter\Chain\CachePoolChain;
15+
use Cache\Adapter\Common\CacheItem;
16+
use Cache\Adapter\PHPArray\ArrayCachePool;
17+
18+
/**
19+
* Class ChainPoolTest.
20+
*/
21+
class CachePoolChainTest extends \PHPUnit_Framework_TestCase
22+
{
23+
public function testGetItemStoreToPrevious()
24+
{
25+
$firstPool = new ArrayCachePool();
26+
$secondPool = new ArrayCachePool();
27+
$chainPool = new CachePoolChain([$firstPool, $secondPool]);
28+
29+
$key = 'test_key';
30+
$item = new CacheItem($key, true, 'value');
31+
$item->expiresAfter(60);
32+
$secondPool->save($item);
33+
34+
$loadedItem = $firstPool->getItem($key);
35+
$this->assertFalse($loadedItem->isHit());
36+
37+
$loadedItem = $secondPool->getItem($key);
38+
$this->assertTrue($loadedItem->isHit());
39+
40+
$loadedItem = $chainPool->getItem($key);
41+
$this->assertTrue($loadedItem->isHit());
42+
43+
$loadedItem = $firstPool->getItem($key);
44+
$this->assertTrue($loadedItem->isHit());
45+
}
46+
47+
public function testGetItemsStoreToPrevious()
48+
{
49+
$firstPool = new ArrayCachePool();
50+
$secondPool = new ArrayCachePool();
51+
$chainPool = new CachePoolChain([$firstPool, $secondPool]);
52+
53+
$key = 'test_key';
54+
$item = new CacheItem($key, true, 'value');
55+
$item->expiresAfter(60);
56+
$secondPool->save($item);
57+
$firstExpirationTime = $item->getExpirationTimestamp();
58+
59+
$key2 = 'test_key2';
60+
$item = new CacheItem($key2, true, 'value2');
61+
$item->expiresAfter(60);
62+
$secondPool->save($item);
63+
$secondExpirationTime = $item->getExpirationTimestamp();
64+
65+
$loadedItem = $firstPool->getItem($key);
66+
$this->assertFalse($loadedItem->isHit());
67+
68+
$loadedItem = $firstPool->getItem($key2);
69+
$this->assertFalse($loadedItem->isHit());
70+
71+
$loadedItem = $secondPool->getItem($key);
72+
$this->assertTrue($loadedItem->isHit());
73+
74+
$loadedItem = $secondPool->getItem($key2);
75+
$this->assertTrue($loadedItem->isHit());
76+
77+
$items = $chainPool->getItems([$key, $key2]);
78+
79+
$this->assertArrayHasKey($key, $items);
80+
$this->assertArrayHasKey($key2, $items);
81+
82+
$this->assertTrue($items[$key]->isHit());
83+
$this->assertTrue($items[$key2]->isHit());
84+
85+
$loadedItem = $firstPool->getItem($key);
86+
$this->assertTrue($loadedItem->isHit());
87+
$this->assertEquals($firstExpirationTime, $loadedItem->getExpirationTimestamp());
88+
89+
$loadedItem = $firstPool->getItem($key2);
90+
$this->assertTrue($loadedItem->isHit());
91+
$this->assertEquals($secondExpirationTime, $loadedItem->getExpirationTimestamp());
92+
}
93+
94+
public function testGetItemsWithEmptyCache()
95+
{
96+
$firstPool = new ArrayCachePool();
97+
$secondPool = new ArrayCachePool();
98+
$chainPool = new CachePoolChain([$firstPool, $secondPool]);
99+
100+
$key = 'test_key';
101+
$key2 = 'test_key2';
102+
103+
$items = $chainPool->getItems([$key, $key2]);
104+
105+
$this->assertArrayHasKey($key, $items);
106+
$this->assertArrayHasKey($key2, $items);
107+
108+
$this->assertFalse($items[$key]->isHit());
109+
$this->assertFalse($items[$key2]->isHit());
110+
}
111+
}

0 commit comments

Comments
 (0)