Skip to content

Commit a520699

Browse files
authored
Fix #182: Better handle cache/flush-all command when cache component is using shared database
1 parent bdcda9c commit a520699

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Yii Framework 2 redis extension Change Log
44
2.0.12 under development
55
------------------------
66

7+
- Bug #182: Better handle `cache/flush-all` command when cache component is using shared database (rob006)
78
- Enh #195: Use `Instance::ensure()` to initialize `Session::$redis` (rob006)
89
- Enh #199: Increase frequency of lock tries when `$timeout` is used in `Mutex::acquire()` (rob006)
910

src/Cache.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616
*
1717
* Redis Cache requires redis version 2.6.12 or higher to work properly.
1818
*
19-
* It needs to be configured with a redis [[Connection]] that is also configured as an application component.
20-
* By default it will use the `redis` application component.
19+
* It needs to be configured with a redis [[Connection]]. By default it will use the `redis` application component.
2120
*
22-
* See [[Cache]] manual for common cache operations that redis Cache supports.
21+
* > Note: It is recommended to use separate [[Connection::$database|database]] for cache and do not share it with
22+
* > other components. If you need to share database, you should set [[$shareDatabase]] to `true` and make sure that
23+
* > [[$keyPrefix]] has unique value which will allow to distinguish between cache keys and other data in database.
2324
*
24-
* Unlike the [[Cache]], redis Cache allows the expire parameter of [[set]], [[add]], [[mset]] and [[madd]] to
25+
* See [[yii\caching\Cache]] manual for common cache operations that redis Cache supports.
26+
*
27+
* Unlike the [[yii\caching\Cache]], redis Cache allows the expire parameter of [[set]], [[add]], [[mset]] and [[madd]] to
2528
* be a floating point number, so you may specify the time in milliseconds (e.g. 0.1 will be 100 milliseconds).
2629
*
2730
* To use redis Cache as the cache application component, configure the application as follows,
@@ -137,6 +140,15 @@ class Cache extends \yii\caching\Cache
137140
* @since 2.0.11
138141
*/
139142
public $forceClusterMode;
143+
/**
144+
* @var bool whether redis [[Connection::$database|database]] is shared and can contain other data than cache.
145+
* Setting this to `true` will change [[flush()]] behavior - instead of using [`FLUSHDB`](https://redis.io/commands/flushdb)
146+
* command, component will iterate through all keys in database and remove only these with matching [[$keyPrefix]].
147+
* Note that this will no longer be an atomic operation and it is much less efficient than `FLUSHDB` command. It is
148+
* recommended to use separate database for cache and leave this value as `false`.
149+
* @since 2.0.12
150+
*/
151+
public $shareDatabase = false;
140152

141153
/**
142154
* @var Connection currently active connection.
@@ -334,6 +346,17 @@ protected function deleteValue($key)
334346
*/
335347
protected function flushValues()
336348
{
349+
if ($this->shareDatabase) {
350+
$cursor = 0;
351+
do {
352+
list($cursor, $keys) = $this->redis->scan($cursor, 'MATCH', $this->keyPrefix . '*');
353+
$cursor = (int) $cursor;
354+
$this->redis->executeCommand('DEL', $keys);
355+
} while ($cursor !== 0);
356+
357+
return true;
358+
}
359+
337360
return $this->redis->executeCommand('FLUSHDB');
338361
}
339362

tests/RedisCacheTest.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected function getCacheInstance()
4141

4242
protected function resetCacheInstance()
4343
{
44-
$this->getCacheInstance()->flush();
44+
$this->getCacheInstance()->redis->flushdb();
4545
$this->_cacheInstance = null;
4646
}
4747

@@ -183,4 +183,24 @@ public function testReplica()
183183

184184
$this->resetCacheInstance();
185185
}
186+
187+
public function testFlushWithSharedDatabase()
188+
{
189+
$instance = $this->getCacheInstance();
190+
$instance->shareDatabase = true;
191+
$instance->keyPrefix = 'myprefix_';
192+
$instance->redis->set('testkey', 'testvalue');
193+
194+
for ($i = 0; $i < 1000; $i++) {
195+
$instance->set(sha1($i), uniqid('', true));
196+
}
197+
$keys = $instance->redis->keys('*');
198+
$this->assertCount(1001, $keys);
199+
200+
$instance->flush();
201+
202+
$keys = $instance->redis->keys('*');
203+
$this->assertCount(1, $keys);
204+
$this->assertSame(['testkey'], $keys);
205+
}
186206
}

0 commit comments

Comments
 (0)