Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dramatically speed up CachedOrderedDict.__init__() #625

Merged
merged 4 commits into from
Feb 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pottery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@


__title__: Final[str] = 'pottery'
__version__: Final[str] = '2.3.6'
__version__: Final[str] = '2.3.7'
__description__: Final[str] = __doc__.split(sep='\n\n', maxsplit=1)[0]
__url__: Final[str] = 'https://github.com/brainix/pottery'
__author__: Final[str] = 'Rajiv Bakulesh Shah'
Expand Down
2 changes: 1 addition & 1 deletion pottery/bloom.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
from typing_extensions import final

from .annotations import F
from .annotations import JSONTypes
from .base import Container
from .base import JSONTypes


# TODO: When we drop support for Python 3.7, stop using @_store_on_self(). Use
Expand Down
41 changes: 26 additions & 15 deletions pottery/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@
from typing import Collection
from typing import Hashable
from typing import Iterable
from typing import Mapping
from typing import NamedTuple
from typing import Tuple
from typing import TypeVar
from typing import Union
from typing import cast

from redis import Redis
Expand All @@ -39,15 +42,20 @@
# from typing import Final
from typing_extensions import Final

from .base import JSONTypes
from .annotations import JSONTypes
from .base import _default_redis
from .base import logger
from .base import random_key
from .dict import InitArg
from .dict import InitIter
from .dict import RedisDict


F = TypeVar('F', bound=Callable[..., JSONTypes])

UpdateMap = Mapping[JSONTypes, Union[JSONTypes, object]]
UpdateItem = Tuple[JSONTypes, Union[JSONTypes, object]]
UpdateIter = Iterable[UpdateItem]
UpdateArg = Union[UpdateMap, UpdateIter]

_DEFAULT_TIMEOUT: Final[int] = 60 # seconds


Expand All @@ -68,9 +76,6 @@ def _arg_hash(*args: Hashable, **kwargs: Hashable) -> int:
return hash((args, kwargs_items))


F = TypeVar('F', bound=Callable[..., JSONTypes])


def redis_cache(*, # NoQA: C901
redis: Redis | None = None,
key: str | None = None,
Expand Down Expand Up @@ -248,13 +253,14 @@ def __init__(self,
)
for dict_key, encoded_value in zip(dict_keys, encoded_values):
if encoded_value is None:
value = self._SENTINEL
self._misses.add(dict_key)
value = self._SENTINEL
else:
value = self._cache._decode(encoded_value)
item = (dict_key, value)
items.append(item)
return super().__init__(items)
super().__init__()
self.__update(items)

def misses(self) -> Collection[JSONTypes]:
return frozenset(self._misses)
Expand All @@ -265,7 +271,7 @@ def __setitem__(self,
value: JSONTypes | object,
) -> None:
'Set self[dict_key] to value.'
if value is not self._SENTINEL:
if value is not self._SENTINEL: # pragma: no cover
self._cache[dict_key] = value
self._misses.discard(dict_key)
return super().__setitem__(dict_key, value)
Expand Down Expand Up @@ -318,24 +324,29 @@ def __retry(self, callable: Callable[[], Any], *, try_num: int = 0) -> Any:
raise

@_set_expiration
def update(self, arg: InitArg = tuple(), **kwargs: JSONTypes) -> None: # type: ignore
def update(self, # type: ignore
arg: UpdateArg = tuple(),
**kwargs: JSONTypes | object,
) -> None:
'''D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
If E is present and has an .items() method, then does: for k in E: D[k] = E[k]
If E is present and lacks an .items() method, then does: for k, v in E: D[k] = v
In either case, this is followed by: for k in F: D[k] = F[k]

The base class, OrderedDict, has an .update() method that works just
fine. The trouble is that it executes multiple calls to .__setitem__()
therefore multiple round trips to Redis. This overridden .update()
makes a single bulk call to Redis.
fine. The trouble is that it executes multiple calls to
self.__setitem__() therefore multiple round trips to Redis. This
overridden .update() makes a single bulk call to Redis.
'''
to_cache = {}
if isinstance(arg, collections.abc.Mapping):
arg = arg.items()
items = itertools.chain(cast(InitIter, arg), kwargs.items())
items = itertools.chain(arg, kwargs.items())
for dict_key, value in items:
if value is not self._SENTINEL:
to_cache[dict_key] = value
self._misses.discard(dict_key)
self._misses.discard(cast(JSONTypes, dict_key))
super().__setitem__(dict_key, value)
self._cache.update(to_cache)

__update = update
2 changes: 1 addition & 1 deletion pottery/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from redis.client import Pipeline
from typing_extensions import Counter

from .base import JSONTypes
from .annotations import JSONTypes
from .dict import RedisDict


Expand Down
2 changes: 1 addition & 1 deletion pottery/deque.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from redis import Redis
from redis.client import Pipeline

from .base import JSONTypes
from .annotations import JSONTypes
from .exceptions import InefficientAccessWarning
from .list import RedisList

Expand Down
2 changes: 1 addition & 1 deletion pottery/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
from redis import Redis
from redis.client import Pipeline

from .annotations import JSONTypes
from .base import Container
from .base import Iterable_
from .base import JSONTypes
from .exceptions import InefficientAccessWarning
from .exceptions import KeyExistsError

Expand Down
2 changes: 1 addition & 1 deletion pottery/hyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@

from redis import Redis

from .annotations import JSONTypes
from .annotations import RedisValues
from .base import Container
from .base import JSONTypes
from .base import random_key


Expand Down
2 changes: 1 addition & 1 deletion pottery/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
from typing_extensions import final

from .annotations import F
from .annotations import JSONTypes
from .base import Container
from .base import JSONTypes
from .exceptions import InefficientAccessWarning
from .exceptions import KeyExistsError

Expand Down
2 changes: 1 addition & 1 deletion pottery/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@

from redis import WatchError

from .annotations import JSONTypes
from .base import Container
from .base import JSONTypes
from .exceptions import QueueEmptyError
from .timer import ContextTimer

Expand Down
2 changes: 1 addition & 1 deletion pottery/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
from redis.client import Pipeline
from typing_extensions import Literal

from .annotations import JSONTypes
from .base import Container
from .base import Iterable_
from .base import JSONTypes
from .exceptions import InefficientAccessWarning
from .exceptions import KeyExistsError

Expand Down