From fa883b173e0a7c46105d0396f4471e9fcf6ff841 Mon Sep 17 00:00:00 2001 From: Denis Kuzmenchuk Date: Wed, 8 Dec 2021 18:02:59 +0300 Subject: [PATCH 1/2] [8.x] Fix possible out of memory error when deleting values by reference key from cache in Redis driver --- src/Illuminate/Cache/RedisTaggedCache.php | 13 +++++++++---- tests/Cache/CacheTaggedCacheTest.php | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Cache/RedisTaggedCache.php b/src/Illuminate/Cache/RedisTaggedCache.php index 6a683c10c36b..2c2044dec3c7 100644 --- a/src/Illuminate/Cache/RedisTaggedCache.php +++ b/src/Illuminate/Cache/RedisTaggedCache.php @@ -178,13 +178,18 @@ protected function deleteKeysByReference($reference) */ protected function deleteValues($referenceKey) { - $values = array_unique($this->store->connection()->smembers($referenceKey)); + $defaultCursorValue = '0'; + $cursor = $defaultCursorValue; - if (count($values) > 0) { - foreach (array_chunk($values, 1000) as $valuesChunk) { + do { + [$cursor, $valuesChunk] = $this->store->connection()->sscan($referenceKey, $cursor, ['MATCH' => '*', 'COUNT' => 1000]); + + $valuesChunk = array_unique($valuesChunk); + + if (count($valuesChunk) > 0) { $this->store->connection()->del(...$valuesChunk); } - } + } while ($cursor !== $defaultCursorValue); } /** diff --git a/tests/Cache/CacheTaggedCacheTest.php b/tests/Cache/CacheTaggedCacheTest.php index 05baebd209a4..b449180f249e 100644 --- a/tests/Cache/CacheTaggedCacheTest.php +++ b/tests/Cache/CacheTaggedCacheTest.php @@ -267,16 +267,16 @@ public function testRedisCacheTagsCanBeFlushed() $store->shouldReceive('connection')->andReturn($conn = m::mock(stdClass::class)); // Forever tag keys - $conn->shouldReceive('smembers')->once()->with('prefix:foo:forever_ref')->andReturn(['key1', 'key2']); - $conn->shouldReceive('smembers')->once()->with('prefix:bar:forever_ref')->andReturn(['key3']); + $conn->shouldReceive('sscan')->once()->with('prefix:foo:forever_ref', '0', ['MATCH' => '*', 'COUNT' => 1000])->andReturn(['0', ['key1', 'key2']]); + $conn->shouldReceive('sscan')->once()->with('prefix:bar:forever_ref', '0', ['MATCH' => '*', 'COUNT' => 1000])->andReturn(['0', ['key3']]); $conn->shouldReceive('del')->once()->with('key1', 'key2'); $conn->shouldReceive('del')->once()->with('key3'); $conn->shouldReceive('del')->once()->with('prefix:foo:forever_ref'); $conn->shouldReceive('del')->once()->with('prefix:bar:forever_ref'); // Standard tag keys - $conn->shouldReceive('smembers')->once()->with('prefix:foo:standard_ref')->andReturn(['key4', 'key5']); - $conn->shouldReceive('smembers')->once()->with('prefix:bar:standard_ref')->andReturn(['key6']); + $conn->shouldReceive('sscan')->once()->with('prefix:foo:standard_ref', '0', ['MATCH' => '*', 'COUNT' => 1000])->andReturn(['0', ['key4', 'key5']]); + $conn->shouldReceive('sscan')->once()->with('prefix:bar:standard_ref', '0', ['MATCH' => '*', 'COUNT' => 1000])->andReturn(['0', ['key6']]); $conn->shouldReceive('del')->once()->with('key4', 'key5'); $conn->shouldReceive('del')->once()->with('key6'); $conn->shouldReceive('del')->once()->with('prefix:foo:standard_ref'); From e1bb8acb4d8ee56b58a1a26f02741cc990642f7b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 13 Dec 2021 12:53:53 -0600 Subject: [PATCH 2/2] formatting --- src/Illuminate/Cache/RedisTaggedCache.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Cache/RedisTaggedCache.php b/src/Illuminate/Cache/RedisTaggedCache.php index 2c2044dec3c7..a8c4c177a435 100644 --- a/src/Illuminate/Cache/RedisTaggedCache.php +++ b/src/Illuminate/Cache/RedisTaggedCache.php @@ -178,11 +178,12 @@ protected function deleteKeysByReference($reference) */ protected function deleteValues($referenceKey) { - $defaultCursorValue = '0'; - $cursor = $defaultCursorValue; + $cursor = $defaultCursorValue = '0'; do { - [$cursor, $valuesChunk] = $this->store->connection()->sscan($referenceKey, $cursor, ['MATCH' => '*', 'COUNT' => 1000]); + [$cursor, $valuesChunk] = $this->store->connection()->sscan( + $referenceKey, $cursor, ['MATCH' => '*', 'COUNT' => 1000] + ); $valuesChunk = array_unique($valuesChunk);