19
19
use Symfony \Contracts \Cache \CacheInterface ;
20
20
21
21
/**
22
+ * An in-memory cache storage.
23
+ *
24
+ * Acts as Least Recently Used (LRU) storage when configured with a maximum number of items.
25
+ *
22
26
* @author Nicolas Grekas <[email protected] >
23
27
*/
24
28
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
@@ -29,13 +33,17 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
29
33
private $ values = [];
30
34
private $ expiries = [];
31
35
private $ createCacheItem ;
36
+ private $ maxLifetime ;
37
+ private $ maxItems ;
32
38
33
39
/**
34
40
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
35
41
*/
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 )
37
43
{
38
44
$ this ->storeSerialized = $ storeSerialized ;
45
+ $ this ->maxLifetime = 0 < $ maxLifetime ? $ maxLifetime : 0 ;
46
+ $ this ->maxItems = 0 < $ maxItems ? $ maxItems : 0 ;
39
47
$ this ->createCacheItem = \Closure::bind (
40
48
static function ($ key , $ value , $ isHit ) use ($ defaultLifetime ) {
41
49
$ item = new CacheItem ();
@@ -84,6 +92,13 @@ public function delete(string $key): bool
84
92
public function hasItem ($ key )
85
93
{
86
94
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
+
87
102
return true ;
88
103
}
89
104
CacheItem::validateKey ($ key );
@@ -97,7 +112,11 @@ public function hasItem($key)
97
112
public function getItem ($ key )
98
113
{
99
114
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
+ }
101
120
} else {
102
121
$ value = $ this ->storeSerialized ? $ this ->unfreeze ($ key , $ isHit ) : $ this ->values [$ key ];
103
122
}
@@ -164,16 +183,32 @@ public function save(CacheItemInterface $item)
164
183
$ value = $ item ["\0* \0value " ];
165
184
$ expiry = $ item ["\0* \0expiry " ];
166
185
167
- if (null !== $ expiry && $ expiry <= microtime (true )) {
186
+ $ now = microtime (true );
187
+
188
+ if (null !== $ expiry && $ expiry <= $ now ) {
168
189
$ this ->deleteItem ($ key );
169
190
170
191
return true ;
171
192
}
172
193
if ($ this ->storeSerialized && null === $ value = $ this ->freeze ($ value , $ key )) {
173
194
return false ;
174
195
}
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
+ }
177
212
}
178
213
179
214
$ this ->values [$ key ] = $ value ;
@@ -210,15 +245,21 @@ public function commit()
210
245
public function clear (string $ prefix = '' )
211
246
{
212
247
if ('' !== $ prefix ) {
248
+ $ now = microtime (true );
249
+
213
250
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 )) {
215
252
unset($ this ->values [$ key ], $ this ->expiries [$ key ]);
216
253
}
217
254
}
218
- } else {
219
- $ this ->values = $ this ->expiries = [];
255
+
256
+ if ($ this ->values ) {
257
+ return true ;
258
+ }
220
259
}
221
260
261
+ $ this ->values = $ this ->expiries = [];
262
+
222
263
return true ;
223
264
}
224
265
@@ -258,8 +299,19 @@ private function generateItems(array $keys, $now, $f)
258
299
{
259
300
foreach ($ keys as $ i => $ key ) {
260
301
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
+ }
262
307
} 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
+
263
315
$ value = $ this ->storeSerialized ? $ this ->unfreeze ($ key , $ isHit ) : $ this ->values [$ key ];
264
316
}
265
317
unset($ keys [$ i ]);
@@ -314,8 +366,12 @@ private function unfreeze(string $key, bool &$isHit)
314
366
$ value = false ;
315
367
}
316
368
if (false === $ value ) {
317
- $ this -> values [ $ key ] = $ value = null ;
369
+ $ value = null ;
318
370
$ isHit = false ;
371
+
372
+ if (!$ this ->maxItems ) {
373
+ $ this ->values [$ key ] = null ;
374
+ }
319
375
}
320
376
}
321
377
0 commit comments