diff --git a/src/Illuminate/Cache/RedisTaggedCache.php b/src/Illuminate/Cache/RedisTaggedCache.php index 6a683c10c36..7863dbc0a60 100644 --- a/src/Illuminate/Cache/RedisTaggedCache.php +++ b/src/Illuminate/Cache/RedisTaggedCache.php @@ -178,13 +178,26 @@ protected function deleteKeysByReference($reference) */ protected function deleteValues($referenceKey) { - $values = array_unique($this->store->connection()->smembers($referenceKey)); + $cursor = $defaultCursorValue = '0'; + + do { + [$cursor, $valuesChunk] = $this->store->connection()->sscan( + $referenceKey, $cursor, ['match' => '*', 'count' => 1000] + ); + + // PhpRedis client returns false if set does not exist or empty. Array destruction + // on false stores null in each variable. If valuesChunk is null, it means that + // there were not results from the previously executed "sscan" Redis command. + if (is_null($valuesChunk)) { + break; + } + + $valuesChunk = array_unique($valuesChunk); - if (count($values) > 0) { - foreach (array_chunk($values, 1000) as $valuesChunk) { + if (count($valuesChunk) > 0) { $this->store->connection()->del(...$valuesChunk); } - } + } while (((string) $cursor) !== $defaultCursorValue); } /** diff --git a/tests/Cache/CacheTaggedCacheTest.php b/tests/Cache/CacheTaggedCacheTest.php index 05baebd209a..b2493694d13 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');