Skip to content

Commit 03ae4df

Browse files
author
Denis Kuzmenchuk
committed
[8.x] Fix possible out of memory error when deleting values by reference key from cache in Redis driver
1 parent f1d8ed5 commit 03ae4df

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

src/Illuminate/Cache/RedisTaggedCache.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,26 @@ protected function deleteKeysByReference($reference)
178178
*/
179179
protected function deleteValues($referenceKey)
180180
{
181-
$values = array_unique($this->store->connection()->smembers($referenceKey));
181+
$cursor = $defaultCursorValue = '0';
182+
183+
do {
184+
[$cursor, $valuesChunk] = $this->store->connection()->sscan(
185+
$referenceKey, $cursor, ['match' => '*', 'count' => 1000]
186+
);
187+
188+
// PhpRedis client returns false if set does not exist or empty. Destruction on false stores null
189+
// in each variable. If valuesChunk is null, it means that there is no results from sscan command.
190+
// Iteration over set could be finished.
191+
if ($valuesChunk === null) {
192+
break;
193+
}
194+
195+
$valuesChunk = array_unique($valuesChunk);
182196

183-
if (count($values) > 0) {
184-
foreach (array_chunk($values, 1000) as $valuesChunk) {
197+
if (count($valuesChunk) > 0) {
185198
$this->store->connection()->del(...$valuesChunk);
186199
}
187-
}
200+
} while (((string) $cursor) !== $defaultCursorValue);
188201
}
189202

190203
/**

tests/Cache/CacheTaggedCacheTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,16 +267,16 @@ public function testRedisCacheTagsCanBeFlushed()
267267
$store->shouldReceive('connection')->andReturn($conn = m::mock(stdClass::class));
268268

269269
// Forever tag keys
270-
$conn->shouldReceive('smembers')->once()->with('prefix:foo:forever_ref')->andReturn(['key1', 'key2']);
271-
$conn->shouldReceive('smembers')->once()->with('prefix:bar:forever_ref')->andReturn(['key3']);
270+
$conn->shouldReceive('sscan')->once()->with('prefix:foo:forever_ref', '0', ['match' => '*', 'count' => 1000])->andReturn(['0', ['key1', 'key2']]);
271+
$conn->shouldReceive('sscan')->once()->with('prefix:bar:forever_ref', '0', ['match' => '*', 'count' => 1000])->andReturn(['0', ['key3']]);
272272
$conn->shouldReceive('del')->once()->with('key1', 'key2');
273273
$conn->shouldReceive('del')->once()->with('key3');
274274
$conn->shouldReceive('del')->once()->with('prefix:foo:forever_ref');
275275
$conn->shouldReceive('del')->once()->with('prefix:bar:forever_ref');
276276

277277
// Standard tag keys
278-
$conn->shouldReceive('smembers')->once()->with('prefix:foo:standard_ref')->andReturn(['key4', 'key5']);
279-
$conn->shouldReceive('smembers')->once()->with('prefix:bar:standard_ref')->andReturn(['key6']);
278+
$conn->shouldReceive('sscan')->once()->with('prefix:foo:standard_ref', '0', ['match' => '*', 'count' => 1000])->andReturn(['0', ['key4', 'key5']]);
279+
$conn->shouldReceive('sscan')->once()->with('prefix:bar:standard_ref', '0', ['match' => '*', 'count' => 1000])->andReturn(['0', ['key6']]);
280280
$conn->shouldReceive('del')->once()->with('key4', 'key5');
281281
$conn->shouldReceive('del')->once()->with('key6');
282282
$conn->shouldReceive('del')->once()->with('prefix:foo:standard_ref');

0 commit comments

Comments
 (0)