Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit db2cf05

Browse filesBrowse files
[Cache] Add LRU + max-lifetime capabilities to ArrayCache
1 parent b350c80 commit db2cf05
Copy full SHA for db2cf05

File tree

3 files changed

+115
-9
lines changed
Filter options

3 files changed

+115
-9
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+78-9Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@
1515
use Psr\Log\LoggerAwareInterface;
1616
use Psr\Log\LoggerAwareTrait;
1717
use Symfony\Component\Cache\CacheItem;
18+
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1819
use Symfony\Component\Cache\ResettableInterface;
1920
use Symfony\Contracts\Cache\CacheInterface;
2021

2122
/**
23+
* An in-memory cache storage.
24+
*
25+
* Acts as a least-recently-used (LRU) storage when configured with a maximum number of items.
26+
*
2227
* @author Nicolas Grekas <p@tchwork.com>
2328
*/
2429
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
@@ -29,13 +34,25 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
2934
private $values = [];
3035
private $expiries = [];
3136
private $createCacheItem;
37+
private $maxLifetime;
38+
private $maxItems;
3239

3340
/**
3441
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
3542
*/
36-
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
43+
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true, int $maxLifetime = 0, int $maxItems = 0)
3744
{
45+
if (0 > $maxLifetime) {
46+
throw new InvalidArgumentException(sprintf('Argument $maxLifetime must be a positive integer, %d passed.', $maxLifetime));
47+
}
48+
49+
if (0 > $maxItems) {
50+
throw new InvalidArgumentException(sprintf('Argument $maxItems must be a positive integer, %d passed.', $maxItems));
51+
}
52+
3853
$this->storeSerialized = $storeSerialized;
54+
$this->maxLifetime = $maxLifetime;
55+
$this->maxItems = $maxItems;
3956
$this->createCacheItem = \Closure::bind(
4057
static function ($key, $value, $isHit) use ($defaultLifetime) {
4158
$item = new CacheItem();
@@ -84,6 +101,13 @@ public function delete(string $key): bool
84101
public function hasItem($key)
85102
{
86103
if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
104+
if ($this->maxItems) {
105+
// Move the item last in the storage
106+
$value = $this->values[$key];
107+
unset($this->values[$key]);
108+
$this->values[$key] = $value;
109+
}
110+
87111
return true;
88112
}
89113
CacheItem::validateKey($key);
@@ -97,7 +121,12 @@ public function hasItem($key)
97121
public function getItem($key)
98122
{
99123
if (!$isHit = $this->hasItem($key)) {
100-
$this->values[$key] = $value = null;
124+
$value = null;
125+
126+
if (!$this->maxItems) {
127+
// Track misses in non-LRU mode only
128+
$this->values[$key] = null;
129+
}
101130
} else {
102131
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
103132
}
@@ -164,7 +193,9 @@ public function save(CacheItemInterface $item)
164193
$value = $item["\0*\0value"];
165194
$expiry = $item["\0*\0expiry"];
166195

167-
if (null !== $expiry && $expiry <= microtime(true)) {
196+
$now = microtime(true);
197+
198+
if (null !== $expiry && $expiry <= $now) {
168199
$this->deleteItem($key);
169200

170201
return true;
@@ -173,7 +204,23 @@ public function save(CacheItemInterface $item)
173204
return false;
174205
}
175206
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
176-
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];
207+
$expiry = $item["\0*\0defaultLifetime"];
208+
$expiry = $now + ($expiry > ($this->maxLifetime ?: $expiry) : $this->maxLifetime : $expiry);
209+
} elseif ($this->maxLifetime && (null === $expiry || $expiry > $now + $this->maxLifetime)) {
210+
$expiry = $now + $this->maxLifetime;
211+
}
212+
213+
if ($this->maxItems) {
214+
unset($this->values[$key]);
215+
216+
// Iterate items and vacuum expired ones while we are at it
217+
foreach ($this->values as $k => $v) {
218+
if ($this->expiries[$k] > $now && \count($this->values) < $this->maxItems) {
219+
break;
220+
}
221+
222+
unset($this->values[$k], $this->expiries[$k]);
223+
}
177224
}
178225

179226
$this->values[$key] = $value;
@@ -210,15 +257,21 @@ public function commit()
210257
public function clear(string $prefix = '')
211258
{
212259
if ('' !== $prefix) {
260+
$now = microtime(true);
261+
213262
foreach ($this->values as $key => $value) {
214-
if (0 === strpos($key, $prefix)) {
263+
if (!isset($this->expiries[$key]) || $this->expiries[$key] <= $now || 0 === strpos($key, $prefix)) {
215264
unset($this->values[$key], $this->expiries[$key]);
216265
}
217266
}
218-
} else {
219-
$this->values = $this->expiries = [];
267+
268+
if ($this->values) {
269+
return true;
270+
}
220271
}
221272

273+
$this->values = $this->expiries = [];
274+
222275
return true;
223276
}
224277

@@ -258,8 +311,20 @@ private function generateItems(array $keys, $now, $f)
258311
{
259312
foreach ($keys as $i => $key) {
260313
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
261-
$this->values[$key] = $value = null;
314+
$value = null;
315+
316+
if (!$this->maxItems) {
317+
// Track misses in non-LRU mode only
318+
$this->values[$key] = null;
319+
}
262320
} else {
321+
if ($this->maxItems) {
322+
// Move the item last in the storage
323+
$value = $this->values[$key];
324+
unset($this->values[$key]);
325+
$this->values[$key] = $value;
326+
}
327+
263328
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
264329
}
265330
unset($keys[$i]);
@@ -314,8 +379,12 @@ private function unfreeze(string $key, bool &$isHit)
314379
$value = false;
315380
}
316381
if (false === $value) {
317-
$this->values[$key] = $value = null;
382+
$value = null;
318383
$isHit = false;
384+
385+
if (!$this->maxItems) {
386+
$this->values[$key] = null;
387+
}
319388
}
320389
}
321390

‎src/Symfony/Component/Cache/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/CHANGELOG.md
+5Lines 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 max-items + LRU + max-lifetime capabilities to `ArrayCache`
8+
49
5.0.0
510
-----
611

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php
+32Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.