Skip to content

Commit d3b029c

Browse files
committed
Suggestion #2 - Clean up of expired cache items
1 parent 70ac4ac commit d3b029c

File tree

8 files changed

+323
-73
lines changed

8 files changed

+323
-73
lines changed

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Before you use, make sure you have the required PHP modules installed on the sys
5656
- setMultiple
5757
- deleteMultiple
5858
- clear
59+
- clearExpiredItems `(Non-PSR-16)`
5960
- Build Data Schema
6061
- MySQL
6162
- SQLite
@@ -173,6 +174,7 @@ Those API methods are defined on `Psr\SimpleCache\CacheInterface`. Please check
173174
- getMultiple
174175
- deleteMultiple
175176
- clear
177+
- clearExpiredItems *(Non-PSR-16)*
176178

177179
### set
178180

@@ -369,6 +371,38 @@ if ($cache->clear()) {
369371
// All cached data has been deleted successfully.
370372
```
371373

374+
### clearExpiredItems `Non-PSR-16`
375+
376+
```php
377+
public function clearExpiredItems(): array
378+
```
379+
380+
This method will return a list of the removed cache keys.
381+
382+
*Note*: **Redis** and **Memcache**, **Memcached** drivers will always return an empty array. See *Garbage Collection* section below.
383+
384+
Example:
385+
386+
```php
387+
$cache->set('foo', 'bar', 300);
388+
$cache->set('foo2', 'bar2', 5);
389+
$cache->set('foo3', 'bar3', 5);
390+
391+
sleep(6);
392+
393+
$expiredItems = $cache->clearExpiredItems();
394+
var_dump($expiredItems);
395+
396+
/*
397+
array(2) {
398+
["foo2"]=>
399+
string(4) "bar2"
400+
["foo3"]=>
401+
string(4) "bar3"
402+
}
403+
*/
404+
```
405+
372406
---
373407

374408
## Build Data Schema
@@ -402,6 +436,39 @@ CREATE TABLE IF NOT EXISTS cache_data (
402436
);
403437
```
404438

439+
---
440+
441+
## Garbage Collection
442+
443+
For built-in drivers, you can enable the garbage collection to clear expired cache from your system automatically.
444+
445+
Use those parameters:
446+
```php
447+
$config = [
448+
'gc_enable' => true,
449+
'gc_divisor' => 100, // default
450+
'gc_probability' => 1, // default
451+
];
452+
```
453+
It means there will be a `1%` chance of performing the garbage collection.
454+
Do not use it as 100% chance becasue it will fetch all keys and check them one by one, totally unnecessary.
455+
456+
Example:
457+
```php
458+
$driver = new \Shieldon\SimpleCache\Cache('file', [
459+
'storage' => __DIR__ . '/../tmp',
460+
'gc_enable' => true,
461+
]);
462+
```
463+
464+
You can just use the `gc_enable` to enable garbage collection.
465+
466+
### Note
467+
468+
For **Redis** and **Memcache**, **Memcached** drivers, there is no need to use this method becasue that the expired items will be cleared automatically.
469+
470+
471+
405472
---
406473

407474
## Author

src/SimpleCache/Cache.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function __construct($driver = '', array $settings = [])
5151
$class = '\Shieldon\SimpleCache\Driver\\' . $class;
5252

5353
$this->driver = new $class($settings);
54+
$this->gc($settings);
5455
}
5556
}
5657

@@ -126,7 +127,7 @@ public function deleteMultiple($keys)
126127
}
127128

128129
/**
129-
* Create or rebuid the data schema.
130+
* Create or rebuid the data schema. [Non-PSR-16]
130131
* This method is avaialbe for Mysql and Sqlite drivers.
131132
*
132133
* @return bool
@@ -139,4 +140,45 @@ public function rebuild(): bool
139140

140141
return false;
141142
}
143+
144+
/**
145+
* Clear all expired items. [Non-PSR-16]
146+
*
147+
* @return array The list of the removed items.
148+
*/
149+
public function clearExpiredItems(): array
150+
{
151+
return $this->gc([
152+
'gc_enable' => true,
153+
'gc_probability' => 1,
154+
'gc_divisor' => 1,
155+
]);
156+
}
157+
158+
/**
159+
* Performing cache data garbage collection for drivers that don't have
160+
* ability to remove expired items automatically.
161+
* This method is not needed for Redis and Memcached driver.
162+
*
163+
* @param array $settings [bool $gc_enable, int $gc_probability, int $gc_divisor]
164+
*
165+
* @return array The list of the removed items.
166+
*/
167+
protected function gc(array $settings = []): array
168+
{
169+
if (empty($settings['gc_enable'])) {
170+
return [];
171+
}
172+
173+
$removedList = [];
174+
175+
$probability = $settings['gc_probability'] ?? 1;
176+
$divisor = $settings['gc_divisor'] ?? 100;
177+
178+
if (method_exists($this->driver, 'gc')) {
179+
$removedList = $this->driver->gc($probability, $divisor);
180+
}
181+
182+
return $removedList;
183+
}
142184
}

src/SimpleCache/CacheProvider.php

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -154,70 +154,77 @@ public function deleteMultiple($keys)
154154
return true;
155155
}
156156

157-
/**
158-
* Check if the TTL is expired or not.
159-
*
160-
* @param int $ttl The time to live of a cached data.
161-
* @param int $timestamp The unix timesamp that want to check.
162-
*
163-
* @return bool
164-
*/
165-
protected function isExpired(int $ttl, int $timestamp): bool
166-
{
167-
$now = time();
168-
169-
// If $ttl equal to 0 means that never expires.
170-
if (empty($ttl)) {
171-
return false;
172-
173-
} elseif ($now - $timestamp < $ttl) {
174-
return false;
175-
}
176-
177-
return true;
178-
}
179-
180157
/**
181158
* Performing cache data garbage collection for drivers that don't have
182159
* ability to remove expired items automatically.
183160
* This method is not needed for Redis and Memcached driver.
184161
*
185-
* @param int $expires The time of expiring.
186162
* @param int $probability Numerator.
187163
* @param int $divisor Denominator.
188164
*
189-
* @return bool
165+
* @return array
190166
*/
191-
protected function gc(int $expires, int $probability, int $divisor): bool
167+
public function gc(int $probability, int $divisor): array
192168
{
169+
if ($probability > $divisor) {
170+
$probability = $divisor;
171+
}
193172
$chance = intval($divisor / $probability);
194-
$hit = rand(1, $chance);
173+
$hit = rand(1, $chance);
174+
$list = [];
195175

196176
if ($hit === 1) {
197-
177+
178+
// Always return [] from Redis and Memcached driver.
198179
$data = $this->getAll();
199180

200181
if (!empty($data)) {
201182
foreach ($data as $key => $value) {
183+
$ttl = (int) $value['ttl'];
202184
$lasttime = (int) $value['timestamp'];
203-
204-
if (time() - $lasttime > $expires) {
185+
186+
if ($this->isExpired($ttl, $lasttime)) {
205187
$this->delete($key);
188+
189+
$list[] = $key;
206190
}
207191
}
208192
}
209-
return true;
210193
}
211-
return false;
194+
return $list;
195+
}
196+
197+
/**
198+
* Check if the TTL is expired or not.
199+
*
200+
* @param int $ttl The time to live of a cached data.
201+
* @param int $timestamp The unix timesamp that want to check.
202+
*
203+
* @return bool
204+
*/
205+
protected function isExpired(int $ttl, int $timestamp): bool
206+
{
207+
$now = time();
208+
209+
// If $ttl equal to 0 means that never expires.
210+
if (empty($ttl)) {
211+
return false;
212+
213+
} elseif ($now - $timestamp < $ttl) {
214+
return false;
215+
}
216+
217+
return true;
212218
}
213219

214220
/**
215221
* Fetch all cache items to prepare removing expired items.
216-
* This method is used only in `gc()`.
222+
* This method is not needed for Redis and Memcached driver because that
223+
* it is used only in `gc()`.
217224
*
218225
* @return array
219226
*/
220-
private function getAll(): array
227+
protected function getAll(): array
221228
{
222229
return [];
223230
}

src/SimpleCache/Driver/Redis.php

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -228,26 +228,6 @@ protected function doHas(string $key): bool
228228
// @codeCoverageIgnoreEnd
229229
}
230230

231-
/**
232-
* Fetch all cache items.
233-
*
234-
* @return array
235-
*/
236-
protected function getAll(): array
237-
{
238-
$list = [];
239-
$keys = $this->redis->keys('sc:*');
240-
241-
if (!empty($keys)) {
242-
foreach ($keys as $key) {
243-
$value = $this->doGet($key);
244-
$key = str_replace('sc_', '', $key);
245-
$list[$key] = $value;
246-
}
247-
}
248-
return $list;
249-
}
250-
251231
/**
252232
* Get the key name of a cache.
253233
*

0 commit comments

Comments
 (0)