Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f4e7876

Browse files
[Cache] Add LRU + max-lifetime capabilities to ArrayCache
1 parent b350c80 commit f4e7876

File tree

3 files changed

+103
-10
lines changed

3 files changed

+103
-10
lines changed

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

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
use Symfony\Contracts\Cache\CacheInterface;
2020

2121
/**
22+
* An in-memory cache storage.
23+
*
24+
* Acts as Least Recently Used (LRU) storage when configured with a maximum number of items.
25+
*
2226
* @author Nicolas Grekas <[email protected]>
2327
*/
2428
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
@@ -29,13 +33,17 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
2933
private $values = [];
3034
private $expiries = [];
3135
private $createCacheItem;
36+
private $maxLifetime;
37+
private $maxItems;
3238

3339
/**
3440
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
3541
*/
36-
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
42+
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true, int $maxLifetime = 0, int $maxItems = 0)
3743
{
3844
$this->storeSerialized = $storeSerialized;
45+
$this->maxLifetime = 0 < $maxLifetime ? $maxLifetime : 0;
46+
$this->maxItems = 0 < $maxItems ? $maxItems : 0;
3947
$this->createCacheItem = \Closure::bind(
4048
static function ($key, $value, $isHit) use ($defaultLifetime) {
4149
$item = new CacheItem();
@@ -84,6 +92,13 @@ public function delete(string $key): bool
8492
public function hasItem($key)
8593
{
8694
if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
95+
if ($this->maxItems) {
96+
// move the item last in the storage
97+
$value = $this->values[$key];
98+
unset($this->values[$key]);
99+
$this->values[$key] = $value;
100+
}
101+
87102
return true;
88103
}
89104
CacheItem::validateKey($key);
@@ -97,7 +112,11 @@ public function hasItem($key)
97112
public function getItem($key)
98113
{
99114
if (!$isHit = $this->hasItem($key)) {
100-
$this->values[$key] = $value = null;
115+
$value = null;
116+
117+
if (!$this->maxItems) {
118+
$this->values[$key] = null;
119+
}
101120
} else {
102121
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
103122
}
@@ -164,16 +183,32 @@ public function save(CacheItemInterface $item)
164183
$value = $item["\0*\0value"];
165184
$expiry = $item["\0*\0expiry"];
166185

167-
if (null !== $expiry && $expiry <= microtime(true)) {
186+
$now = microtime(true);
187+
188+
if (null !== $expiry && $expiry <= $now) {
168189
$this->deleteItem($key);
169190

170191
return true;
171192
}
172193
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
173194
return false;
174195
}
175-
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
176-
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];
196+
if ($this->maxLifetime && (null === $expiry || $expiry > $now + $this->maxLifetime)) {
197+
$expiry = $now + $this->maxLifetime;
198+
} elseif (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
199+
$expiry = $now + $item["\0*\0defaultLifetime"];
200+
}
201+
202+
if ($this->maxItems) {
203+
unset($this->values[$key]);
204+
205+
foreach ($this->values as $k => $v) {
206+
if ($this->expiries[$k] > $now && \count($this->values) < $this->maxItems) {
207+
break;
208+
}
209+
210+
unset($this->values[$k], $this->expiries[$k]);
211+
}
177212
}
178213

179214
$this->values[$key] = $value;
@@ -210,15 +245,21 @@ public function commit()
210245
public function clear(string $prefix = '')
211246
{
212247
if ('' !== $prefix) {
248+
$now = microtime(true);
249+
213250
foreach ($this->values as $key => $value) {
214-
if (0 === strpos($key, $prefix)) {
251+
if (!isset($this->expiries[$key]) || $this->expiries[$key] <= $now || 0 === strpos($key, $prefix)) {
215252
unset($this->values[$key], $this->expiries[$key]);
216253
}
217254
}
218-
} else {
219-
$this->values = $this->expiries = [];
255+
256+
if ($this->values) {
257+
return true;
258+
}
220259
}
221260

261+
$this->values = $this->expiries = [];
262+
222263
return true;
223264
}
224265

@@ -258,8 +299,19 @@ private function generateItems(array $keys, $now, $f)
258299
{
259300
foreach ($keys as $i => $key) {
260301
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
261-
$this->values[$key] = $value = null;
302+
$value = null;
303+
304+
if (!$this->maxItems) {
305+
$this->values[$key] = null;
306+
}
262307
} else {
308+
if ($this->maxItems) {
309+
// move the item last in the storage
310+
$value = $this->values[$key];
311+
unset($this->values[$key]);
312+
$this->values[$key] = $value;
313+
}
314+
263315
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
264316
}
265317
unset($keys[$i]);
@@ -314,8 +366,12 @@ private function unfreeze(string $key, bool &$isHit)
314366
$value = false;
315367
}
316368
if (false === $value) {
317-
$this->values[$key] = $value = null;
369+
$value = null;
318370
$isHit = false;
371+
372+
if (!$this->maxItems) {
373+
$this->values[$key] = null;
374+
}
319375
}
320376
}
321377

src/Symfony/Component/Cache/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* added LRU + max-lifetime capabilities to `ArrayCache`
8+
49
5.0.0
510
-----
611

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,36 @@ public function testGetValuesHitAndMiss()
5555
$this->assertArrayHasKey('bar', $values);
5656
$this->assertNull($values['bar']);
5757
}
58+
59+
public function testMaxLifetime()
60+
{
61+
$cache = new ArrayAdapter(0, false, 1);
62+
63+
$item = $cache->getItem('foo');
64+
$item->expiresAfter(2);
65+
$cache->save($item->set(123));
66+
67+
$this->assertTrue($cache->hasItem('foo'));
68+
sleep(1);
69+
$this->assertFalse($cache->hasItem('foo'));
70+
}
71+
72+
public function testMaxItems()
73+
{
74+
$cache = new ArrayAdapter(0, false, 0, 2);
75+
76+
$cache->save($cache->getItem('foo'));
77+
$cache->save($cache->getItem('bar'));
78+
$cache->save($cache->getItem('buz'));
79+
80+
$this->assertFalse($cache->hasItem('foo'));
81+
$this->assertTrue($cache->hasItem('bar'));
82+
$this->assertTrue($cache->hasItem('buz'));
83+
84+
$cache->save($cache->getItem('foo'));
85+
86+
$this->assertFalse($cache->hasItem('bar'));
87+
$this->assertTrue($cache->hasItem('buz'));
88+
$this->assertTrue($cache->hasItem('foo'));
89+
}
5890
}

0 commit comments

Comments
 (0)