Skip to content

Commit

Permalink
jazzband#609, use pipeline for delete_pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
Vasyl Dizhak committed Jul 5, 2022
1 parent 38e630f commit 338cdad
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,15 @@ pattern syntax as the ``keys`` function and returns the number of deleted keys.
>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*")
To achieve the best performance while deleting many keys, you should set ``DJANGO_REDIS_SCAN_ITERSIZE`` to a relatively
high number (e.g., 100_000) by default in Django settings or pass it directly to the ``delete_pattern``.


.. code-block:: pycon
>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*", itersize=100_000)
Redis native commands
~~~~~~~~~~~~~~~~~~~~~

Expand Down
6 changes: 5 additions & 1 deletion django_redis/client/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,13 @@ def delete_pattern(

try:
count = 0
pipeline = client.pipeline()

for key in client.scan_iter(match=pattern, count=itersize):
client.delete(key)
pipeline.delete(key)
count += 1
pipeline.execute()

return count
except _main_exceptions as e:
raise ConnectionInterrupted(connection=client) from e
Expand Down
24 changes: 23 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Iterable
from unittest.mock import Mock, patch
from unittest.mock import Mock, call, patch

import pytest
from django.core.cache import DEFAULT_CACHE_ALIAS
Expand Down Expand Up @@ -104,6 +104,28 @@ def test_delete_pattern_calls_scan_iter_with_count_if_itersize_given(
count=90210, match=make_pattern_mock.return_value
)

@patch("test_client.DefaultClient.make_pattern")
@patch("test_client.DefaultClient.get_client", return_value=Mock())
@patch("test_client.DefaultClient.__init__", return_value=None)
def test_delete_pattern_calls_pipeline_delete_and_execute(
self, init_mock, get_client_mock, make_pattern_mock
):
client = DefaultClient()
client._backend = Mock()
client._backend.key_prefix = ""
get_client_mock.return_value.scan_iter.return_value = [":1:foo", ":1:foo-a"]
get_client_mock.return_value.pipeline.return_value = Mock()
get_client_mock.return_value.pipeline.return_value.delete = Mock()
get_client_mock.return_value.pipeline.return_value.execute = Mock()

client.delete_pattern(pattern="foo*")

assert get_client_mock.return_value.pipeline.return_value.delete.call_count == 2
get_client_mock.return_value.pipeline.return_value.delete.assert_has_calls(
[call(":1:foo"), call(":1:foo-a")]
)
get_client_mock.return_value.pipeline.return_value.execute.assert_called_once()


class TestShardClient:
@patch("test_client.DefaultClient.make_pattern")
Expand Down

0 comments on commit 338cdad

Please sign in to comment.