# HG changeset patch # User Marcin Kuzminski # Date 2018-07-14 16:17:02 # Node ID 63610fd137c3a58dc42a0a0d4abb0610fef19c82 # Parent 30b993642c1d675cded8b91c1057fdd8ac784e25 caches: introduce new conditional cache function. diff --git a/rhodecode/lib/rc_cache/__init__.py b/rhodecode/lib/rc_cache/__init__.py --- a/rhodecode/lib/rc_cache/__init__.py +++ b/rhodecode/lib/rc_cache/__init__.py @@ -20,7 +20,6 @@ import logging from dogpile.cache import register_backend -from dogpile.cache import make_region register_backend( "dogpile.cache.rc.memory_lru", "rhodecode.lib.rc_cache.backends", @@ -40,7 +39,7 @@ log = logging.getLogger(__name__) from . import region_meta from .utils import ( get_default_cache_settings, key_generator, get_or_create_region, - clear_cache_namespace) + clear_cache_namespace, make_region) def configure_dogpile_cache(settings): diff --git a/rhodecode/lib/rc_cache/utils.py b/rhodecode/lib/rc_cache/utils.py --- a/rhodecode/lib/rc_cache/utils.py +++ b/rhodecode/lib/rc_cache/utils.py @@ -19,7 +19,10 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ import os import logging -from dogpile.cache import make_region +import functools + +from dogpile.cache import CacheRegion +from dogpile.cache.util import compat from rhodecode.lib.utils import safe_str, sha1 from . import region_meta @@ -27,6 +30,82 @@ from . import region_meta log = logging.getLogger(__name__) +class RhodeCodeCacheRegion(CacheRegion): + + def conditional_cache_on_arguments( + self, namespace=None, + expiration_time=None, + should_cache_fn=None, + to_str=compat.string_type, + function_key_generator=None, + condition=True): + """ + Custom conditional decorator, that will not touch any dogpile internals if + condition isn't meet. This works a bit different than should_cache_fn + And it's faster in cases we don't ever want to compute cached values + """ + expiration_time_is_callable = compat.callable(expiration_time) + + if function_key_generator is None: + function_key_generator = self.function_key_generator + + def decorator(fn): + if to_str is compat.string_type: + # backwards compatible + key_generator = function_key_generator(namespace, fn) + else: + key_generator = function_key_generator(namespace, fn, to_str=to_str) + + @functools.wraps(fn) + def decorate(*arg, **kw): + key = key_generator(*arg, **kw) + + @functools.wraps(fn) + def creator(): + return fn(*arg, **kw) + + if not condition: + return creator() + + timeout = expiration_time() if expiration_time_is_callable \ + else expiration_time + + return self.get_or_create(key, creator, timeout, should_cache_fn) + + def invalidate(*arg, **kw): + key = key_generator(*arg, **kw) + self.delete(key) + + def set_(value, *arg, **kw): + key = key_generator(*arg, **kw) + self.set(key, value) + + def get(*arg, **kw): + key = key_generator(*arg, **kw) + return self.get(key) + + def refresh(*arg, **kw): + key = key_generator(*arg, **kw) + value = fn(*arg, **kw) + self.set(key, value) + return value + + decorate.set = set_ + decorate.invalidate = invalidate + decorate.refresh = refresh + decorate.get = get + decorate.original = fn + decorate.key_generator = key_generator + + return decorate + + return decorator + + +def make_region(*arg, **kw): + return RhodeCodeCacheRegion(*arg, **kw) + + def get_default_cache_settings(settings, prefixes=None): prefixes = prefixes or [] cache_settings = {} diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py --- a/rhodecode/lib/utils.py +++ b/rhodecode/lib/utils.py @@ -120,7 +120,6 @@ def get_repo_group_slug(request): # pyramid _group = request.matchdict.get('repo_group_name') - if _group: _group = _group.rstrip('/') return _group