# HG changeset patch # User RhodeCode Admin # Date 2024-02-16 08:56:59 # Node ID cf300ad3f7f2cde435dd57cdb77416b554734e48 # Parent b35336c87917d11d5a011b03f768f3053522d647 fix(caches): synced rc_cache module with rhodecode-ce diff --git a/vcsserver/lib/rc_cache/__init__.py b/vcsserver/lib/rc_cache/__init__.py --- a/vcsserver/lib/rc_cache/__init__.py +++ b/vcsserver/lib/rc_cache/__init__.py @@ -58,12 +58,12 @@ CLEAR_DELETE = 'delete' CLEAR_INVALIDATE = 'invalidate' -def async_creation_runner(cache, somekey, creator, mutex): +def async_creation_runner(cache, cache_key, creator, mutex): def runner(): try: value = creator() - cache.set(somekey, value) + cache.set(cache_key, value) finally: mutex.release() diff --git a/vcsserver/lib/rc_cache/backends.py b/vcsserver/lib/rc_cache/backends.py --- a/vcsserver/lib/rc_cache/backends.py +++ b/vcsserver/lib/rc_cache/backends.py @@ -73,10 +73,20 @@ class LRUMemoryBackend(memory_backend.Me # we don't care if key isn't there at deletion pass + def list_keys(self, prefix): + return list(self._cache.keys()) + def delete_multi(self, keys): for key in keys: self.delete(key) + def delete_multi_by_prefix(self, prefix): + cache_keys = self.list_keys(prefix=prefix) + num_affected_keys = len(cache_keys) + if num_affected_keys: + self.delete_multi(cache_keys) + return num_affected_keys + class PickleSerializer: serializer: None | Serializer = staticmethod( # type: ignore @@ -146,6 +156,13 @@ class FileNamespaceBackend(PickleSeriali log.error('Failed to fetch DBM keys from DB: %s', self.get_store()) raise + def delete_multi_by_prefix(self, prefix): + cache_keys = self.list_keys(prefix=prefix) + num_affected_keys = len(cache_keys) + if num_affected_keys: + self.delete_multi(cache_keys) + return num_affected_keys + def get_store(self): return self.filename @@ -195,6 +212,25 @@ class BaseRedisBackend(redis_backend.Red prefix = self._get_keys_pattern(prefix) return self.reader_client.keys(prefix) + def delete_multi_by_prefix(self, prefix, use_lua=False): + if use_lua: + # high efficient LUA script to delete ALL keys by prefix... + lua = """local keys = redis.call('keys', ARGV[1]) + for i=1,#keys,5000 do + redis.call('del', unpack(keys, i, math.min(i+(5000-1), #keys))) + end + return #keys""" + num_affected_keys = self.writer_client.eval( + lua, + 0, + f"{prefix}*") + else: + cache_keys = self.list_keys(prefix=prefix) + num_affected_keys = len(cache_keys) + if num_affected_keys: + self.delete_multi(cache_keys) + return num_affected_keys + def get_store(self): return self.reader_client.connection_pool diff --git a/vcsserver/lib/rc_cache/utils.py b/vcsserver/lib/rc_cache/utils.py --- a/vcsserver/lib/rc_cache/utils.py +++ b/vcsserver/lib/rc_cache/utils.py @@ -37,7 +37,7 @@ log = logging.getLogger(__name__) class RhodeCodeCacheRegion(CacheRegion): def __repr__(self): - return f'{self.__class__}(name={self.name})' + return f'`{self.__class__.__name__}(name={self.name}, backend={self.backend.__class__})`' def conditional_cache_on_arguments( self, namespace=None, @@ -224,14 +224,15 @@ def get_or_create_region(region_name, re return region_obj -def clear_cache_namespace(cache_region: str | RhodeCodeCacheRegion, cache_namespace_uid: str, method: str): +def clear_cache_namespace(cache_region: str | RhodeCodeCacheRegion, cache_namespace_uid: str, method: str) -> int: from . import CLEAR_DELETE, CLEAR_INVALIDATE if not isinstance(cache_region, RhodeCodeCacheRegion): cache_region = get_or_create_region(cache_region, cache_namespace_uid) - log.debug('clearing cache region: %s with method=%s', cache_region, method) + log.debug('clearing cache region: %s [prefix:%s] with method=%s', + cache_region, cache_namespace_uid, method) - num_affected_keys = None + num_affected_keys = 0 if method == CLEAR_INVALIDATE: # NOTE: The CacheRegion.invalidate() method’s default mode of @@ -240,9 +241,5 @@ def clear_cache_namespace(cache_region: cache_region.invalidate(hard=True) if method == CLEAR_DELETE: - cache_keys = cache_region.backend.list_keys(prefix=cache_namespace_uid) - num_affected_keys = len(cache_keys) - if num_affected_keys: - cache_region.delete_multi(cache_keys) - + num_affected_keys = cache_region.backend.delete_multi_by_prefix(prefix=cache_namespace_uid) return num_affected_keys