Skip to content

Commit fe124e1

Browse files
committed
Added eviction policy configuration
1 parent d184d6b commit fe124e1

File tree

5 files changed

+181
-25
lines changed

5 files changed

+181
-25
lines changed

redis/cache.py

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
from typing import Callable, TypeVar, Any, NoReturn, List, Union
2-
from typing import Optional
1+
from abc import ABC, abstractmethod
2+
from typing import TypeVar
33
from enum import Enum
44

5-
from cachetools import TTLCache, Cache, LRUCache
6-
from cachetools.keys import hashkey
7-
8-
from redis.typing import ResponseT
5+
from cachetools import LRUCache, LFUCache, RRCache, Cache, TTLCache
96

107
T = TypeVar('T')
118

129

1310
class EvictionPolicy(Enum):
14-
LRU = "lru"
15-
LFU = "lfu"
16-
RANDOM = "random"
11+
LRU = "LRU"
12+
LFU = "LFU"
13+
RANDOM = "RANDOM"
14+
TTL = "TTL"
1715

1816

1917
class CacheConfiguration:
@@ -97,18 +95,61 @@ class CacheConfiguration:
9795
]
9896

9997
def __init__(self, **kwargs):
100-
self._max_size = kwargs.get("cache_size", 10000)
101-
self._ttl = kwargs.get("cache_ttl", 0)
102-
self._eviction_policy = kwargs.get("eviction_policy", self.DEFAULT_EVICTION_POLICY)
98+
self._max_size = kwargs.get("cache_size", None)
99+
self._ttl = kwargs.get("cache_ttl", None)
100+
self._eviction_policy = kwargs.get("cache_eviction", None)
101+
if self._max_size is None:
102+
self._max_size = 10000
103+
if self._ttl is None:
104+
self._ttl = 0
105+
if self._eviction_policy is None:
106+
self._eviction_policy = EvictionPolicy.LRU
107+
108+
if self._eviction_policy not in EvictionPolicy:
109+
raise ValueError(f"Invalid eviction_policy {self._eviction_policy}")
103110

104111
def get_ttl(self) -> int:
105112
return self._ttl
106113

114+
def get_max_size(self) -> int:
115+
return self._max_size
116+
107117
def get_eviction_policy(self) -> EvictionPolicy:
108118
return self._eviction_policy
109119

110120
def is_exceeds_max_size(self, count: int) -> bool:
111121
return count > self._max_size
112122

113123
def is_allowed_to_cache(self, command: str) -> bool:
114-
return command in self.DEFAULT_ALLOW_LIST
124+
return command in self.DEFAULT_ALLOW_LIST
125+
126+
127+
class CacheClass(Enum):
128+
LRU = LRUCache
129+
LFU = LFUCache
130+
RANDOM = RRCache
131+
TTL = TTLCache
132+
133+
134+
class CacheFactoryInterface(ABC):
135+
@abstractmethod
136+
def get_cache(self) -> Cache:
137+
pass
138+
139+
140+
class CacheFactory(CacheFactoryInterface):
141+
def __init__(self, conf: CacheConfiguration):
142+
self._conf = conf
143+
144+
def get_cache(self) -> Cache:
145+
eviction_policy = self._conf.get_eviction_policy()
146+
cache_class = self._get_cache_class(eviction_policy).value
147+
148+
if eviction_policy == EvictionPolicy.TTL:
149+
return cache_class(self._conf.get_max_size(), self._conf.get_ttl())
150+
151+
return cache_class(self._conf.get_max_size())
152+
153+
def _get_cache_class(self, eviction_policy: EvictionPolicy) -> CacheClass:
154+
return CacheClass[eviction_policy.value]
155+

redis/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
_RedisCallbacksRESP3,
1616
bool_ok,
1717
)
18+
from redis.cache import EvictionPolicy
1819
from redis.commands import (
1920
CoreCommands,
2021
RedisModuleCommands,
@@ -216,6 +217,7 @@ def __init__(
216217
protocol: Optional[int] = 2,
217218
use_cache: bool = False,
218219
cache: Optional[Cache] = None,
220+
cache_eviction: Optional[EvictionPolicy] = None,
219221
cache_size: int = 128,
220222
cache_ttl: int = 300,
221223
) -> None:
@@ -315,6 +317,7 @@ def __init__(
315317
{
316318
"use_cache": use_cache,
317319
"cache": cache,
320+
"cache_eviction": cache_eviction,
318321
"cache_size": cache_size,
319322
"cache_ttl": cache_ttl,
320323
}

redis/cluster.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from redis._parsers import CommandsParser, Encoder
1212
from redis._parsers.helpers import parse_scan
1313
from redis.backoff import default_backoff
14+
from redis.cache import EvictionPolicy
1415
from redis.client import CaseInsensitiveDict, PubSub, Redis
1516
from redis.commands import READ_COMMANDS, RedisClusterCommands
1617
from redis.commands.helpers import list_or_args
@@ -505,6 +506,7 @@ def __init__(
505506
address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
506507
use_cache: bool = False,
507508
cache: Optional[Cache] = None,
509+
cache_eviction: Optional[EvictionPolicy] = None,
508510
cache_size: int = 128,
509511
cache_ttl: int = 300,
510512
**kwargs,
@@ -648,6 +650,7 @@ def __init__(
648650
address_remap=address_remap,
649651
use_cache=use_cache,
650652
cache=cache,
653+
cache_eviction=cache_eviction,
651654
cache_size=cache_size,
652655
cache_ttl=cache_ttl,
653656
**kwargs,
@@ -1331,6 +1334,7 @@ def __init__(
13311334
address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
13321335
use_cache: bool = False,
13331336
cache: Optional[Cache] = None,
1337+
cache_eviction: Optional[EvictionPolicy] = None,
13341338
cache_size: int = 128,
13351339
cache_ttl: int = 300,
13361340
**kwargs,
@@ -1347,6 +1351,7 @@ def __init__(
13471351
self.address_remap = address_remap
13481352
self.use_cache = use_cache
13491353
self.cache = cache
1354+
self.cache_eviction = cache_eviction
13501355
self.cache_size = cache_size
13511356
self.cache_ttl = cache_ttl
13521357
self._moved_exception = None
@@ -1494,6 +1499,7 @@ def create_redis_node(self, host, port, **kwargs):
14941499
kwargs.update({"port": port})
14951500
kwargs.update({"use_cache": self.use_cache})
14961501
kwargs.update({"cache": self.cache})
1502+
kwargs.update({"cache_eviction": self.cache_eviction})
14971503
kwargs.update({"cache_size": self.cache_size})
14981504
kwargs.update({"cache_ttl": self.cache_ttl})
14991505
r = Redis(connection_pool=self.connection_pool_class(**kwargs))
@@ -1503,6 +1509,7 @@ def create_redis_node(self, host, port, **kwargs):
15031509
port=port,
15041510
use_cache=self.use_cache,
15051511
cache=self.cache,
1512+
cache_eviction=self.cache_eviction,
15061513
cache_size=self.cache_size,
15071514
cache_ttl=self.cache_ttl,
15081515
**kwargs,
@@ -1682,9 +1689,6 @@ def remap_host_port(self, host: str, port: int) -> Tuple[str, int]:
16821689
return self.address_remap((host, port))
16831690
return host, port
16841691

1685-
def get_cache(self) -> Optional[Cache]:
1686-
return self.connection_pool.cache
1687-
16881692

16891693
class ClusterPubSub(PubSub):
16901694
"""

redis/connection.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from apscheduler.schedulers.background import BackgroundScheduler
1616
from cachetools import TTLCache, Cache, LRUCache
1717
from cachetools.keys import hashkey
18-
from redis.cache import CacheConfiguration
18+
from redis.cache import CacheConfiguration, CacheFactory
1919

2020
from ._parsers import Encoder, _HiredisParser, _RESP2Parser, _RESP3Parser
2121
from .backoff import NoBackoff
@@ -1246,6 +1246,7 @@ def __init__(
12461246
self.max_connections = max_connections
12471247
self.cache = None
12481248
self._cache_conf = None
1249+
self._cache_factory = None
12491250
self.cache_lock = None
12501251
self.scheduler = None
12511252

@@ -1260,13 +1261,15 @@ def __init__(
12601261
if cache is not None:
12611262
self.cache = cache
12621263
else:
1263-
self.cache = TTLCache(self.connection_kwargs["cache_size"], self.connection_kwargs["cache_ttl"])
1264+
cache_factory = CacheFactory(self._cache_conf)
1265+
self.cache = cache_factory.get_cache()
12641266

12651267
self.scheduler = BackgroundScheduler()
12661268
self.scheduler.add_job(self._perform_health_check, "interval", seconds=2, id="cache_health_check")
12671269
self.scheduler.start()
12681270

12691271
connection_kwargs.pop("use_cache", None)
1272+
connection_kwargs.pop("cache_eviction", None)
12701273
connection_kwargs.pop("cache_size", None)
12711274
connection_kwargs.pop("cache_ttl", None)
12721275
connection_kwargs.pop("cache", None)

0 commit comments

Comments
 (0)