# HG changeset patch # User Marcin Kuzminski # Date 2018-06-22 15:31:48 # Node ID 45a75c508a9fad4c5a0977123a93049c9f30ff76 # Parent fc1dc7881ff1ed0d23516f44d005c27369964873 caches: use different namespaces for conditional_cache wrapper. Before we used one namespace for ALL meaning caches were kept in single file, or single DB row. While this makes sense for single functions, a per-user, per-group cache should be divided to single files. diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -1079,7 +1079,7 @@ class AuthUser(object): 'with caching: %s[%ss]' % (user, scope, cache_on, cache_seconds)) start = time.time() compute = caches.conditional_cache( - 'short_term', 'cache_desc', + 'short_term', 'cache_desc.{}'.format(user_id), condition=cache_on, func=_cached_perms_data) result = compute(user_id, scope, user_is_admin, user_inherit_default_permissions, explicit, algo, @@ -1154,7 +1154,7 @@ class AuthUser(object): RepoList(qry, perm_set=perm_def)] compute = caches.conditional_cache( - 'long_term', 'repo_acl_ids', + 'long_term', 'repo_acl_ids.{}'.format(self.user_id), condition=cache, func=_cached_repo_acl) return compute(self.user_id, perms, name_filter) @@ -1180,7 +1180,7 @@ class AuthUser(object): RepoGroupList(qry, perm_set=perm_def)] compute = caches.conditional_cache( - 'long_term', 'repo_group_acl_ids', + 'long_term', 'repo_group_acl_ids.{}'.format(self.user_id), condition=cache, func=_cached_repo_group_acl) return compute(self.user_id, perms, name_filter) @@ -1206,7 +1206,7 @@ class AuthUser(object): UserGroupList(qry, perm_set=perm_def)] compute = caches.conditional_cache( - 'long_term', 'user_group_acl_ids', + 'long_term', 'user_group_acl_ids.{}'.format(self.user_id), condition=cache, func=_cached_user_group_acl) return compute(self.user_id, perms, name_filter) diff --git a/rhodecode/lib/caches.py b/rhodecode/lib/caches.py --- a/rhodecode/lib/caches.py +++ b/rhodecode/lib/caches.py @@ -17,7 +17,7 @@ # This program is dual-licensed. If you wish to learn more about the # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ - +import functools import beaker import logging @@ -148,7 +148,7 @@ def get_repo_namespace_key(prefix, repo_ return '{0}_{1}'.format(prefix, compute_key_from_params(repo_name)) -def conditional_cache(region, prefix, condition, func): +def conditional_cache(region, cache_namespace, condition, func): """ Conditional caching function use like:: def _c(arg): @@ -161,7 +161,7 @@ def conditional_cache(region, prefix, co return compute(arg) :param region: name of cache region - :param prefix: cache region prefix + :param cache_namespace: cache namespace :param condition: condition for cache to be triggered, and return data cached :param func: wrapped heavy function to compute @@ -171,8 +171,34 @@ def conditional_cache(region, prefix, co if condition: log.debug('conditional_cache: True, wrapping call of ' 'func: %s into %s region cache', region, func) - cached_region = _cache_decorate((prefix,), None, None, region) + + def _cache_wrap(region_name, cache_namespace): + """Return a caching wrapper""" + + def decorate(func): + @functools.wraps(func) + def cached(*args, **kwargs): + if kwargs: + raise AttributeError( + 'Usage of kwargs is not allowed. ' + 'Use only positional arguments in wrapped function') + manager = get_cache_manager(region_name, cache_namespace) + cache_key = compute_key_from_params(*args) + + def go(): + return func(*args, **kwargs) + + # save org function name + go.__name__ = '_cached_%s' % (func.__name__,) + + return manager.get(cache_key, createfunc=go) + return cached + + return decorate + + cached_region = _cache_wrap(region, cache_namespace) wrapped = cached_region(func) + return wrapped