##// END OF EJS Templates
cache: updated cache decorators based on latest code from dogpile
marcink -
r751:fb55dc24 default
parent child Browse files
Show More
@@ -1,151 +1,153 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2019 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import os
19 19 import logging
20 20 import functools
21 from decorator import decorate
21 22
22 23 from dogpile.cache import CacheRegion
23 24 from dogpile.cache.util import compat
24 25
25 26 from vcsserver.utils import safe_str, sha1
26 27
27 28
28 29 log = logging.getLogger(__name__)
29 30
30 31
31 32 class RhodeCodeCacheRegion(CacheRegion):
32 33
33 34 def conditional_cache_on_arguments(
34 35 self, namespace=None,
35 36 expiration_time=None,
36 37 should_cache_fn=None,
37 38 to_str=compat.string_type,
38 39 function_key_generator=None,
39 40 condition=True):
40 41 """
41 42 Custom conditional decorator, that will not touch any dogpile internals if
42 43 condition isn't meet. This works a bit different than should_cache_fn
43 44 And it's faster in cases we don't ever want to compute cached values
44 45 """
45 46 expiration_time_is_callable = compat.callable(expiration_time)
46 47
47 48 if function_key_generator is None:
48 49 function_key_generator = self.function_key_generator
49 50
50 def decorator(fn):
51 def get_or_create_for_user_func(key_generator, user_func, *arg, **kw):
52
53 if not condition:
54 log.debug('Calling un-cached func:%s', user_func)
55 return user_func(*arg, **kw)
56
57 key = key_generator(*arg, **kw)
58
59 timeout = expiration_time() if expiration_time_is_callable \
60 else expiration_time
61
62 log.debug('Calling cached fn:%s', user_func)
63 return self.get_or_create(key, user_func, timeout, should_cache_fn, (arg, kw))
64
65 def cache_decorator(user_func):
51 66 if to_str is compat.string_type:
52 67 # backwards compatible
53 key_generator = function_key_generator(namespace, fn)
68 key_generator = function_key_generator(namespace, user_func)
54 69 else:
55 key_generator = function_key_generator(namespace, fn, to_str=to_str)
56
57 @functools.wraps(fn)
58 def decorate(*arg, **kw):
59 key = key_generator(*arg, **kw)
70 key_generator = function_key_generator(namespace, user_func, to_str=to_str)
60 71
61 @functools.wraps(fn)
62 def creator():
63 return fn(*arg, **kw)
64
65 if not condition:
66 log.debug('Calling un-cached func:%s', fn)
67 return creator()
68
69 timeout = expiration_time() if expiration_time_is_callable \
70 else expiration_time
71
72 log.debug('Calling cached fn:%s', fn)
73 return self.get_or_create(key, creator, timeout, should_cache_fn)
72 def refresh(*arg, **kw):
73 """
74 Like invalidate, but regenerates the value instead
75 """
76 key = key_generator(*arg, **kw)
77 value = user_func(*arg, **kw)
78 self.set(key, value)
79 return value
74 80
75 81 def invalidate(*arg, **kw):
76 82 key = key_generator(*arg, **kw)
77 83 self.delete(key)
78 84
79 85 def set_(value, *arg, **kw):
80 86 key = key_generator(*arg, **kw)
81 87 self.set(key, value)
82 88
83 89 def get(*arg, **kw):
84 90 key = key_generator(*arg, **kw)
85 91 return self.get(key)
86 92
87 def refresh(*arg, **kw):
88 key = key_generator(*arg, **kw)
89 value = fn(*arg, **kw)
90 self.set(key, value)
91 return value
93 user_func.set = set_
94 user_func.invalidate = invalidate
95 user_func.get = get
96 user_func.refresh = refresh
97 user_func.key_generator = key_generator
98 user_func.original = user_func
92 99
93 decorate.set = set_
94 decorate.invalidate = invalidate
95 decorate.refresh = refresh
96 decorate.get = get
97 decorate.original = fn
98 decorate.key_generator = key_generator
99 decorate.__wrapped__ = fn
100 # Use `decorate` to preserve the signature of :param:`user_func`.
100 101
101 return decorate
102 return decorate(user_func, functools.partial(
103 get_or_create_for_user_func, key_generator))
102 104
103 return decorator
105 return cache_decorator
104 106
105 107
106 108 def make_region(*arg, **kw):
107 109 return RhodeCodeCacheRegion(*arg, **kw)
108 110
109 111
110 112 def get_default_cache_settings(settings, prefixes=None):
111 113 prefixes = prefixes or []
112 114 cache_settings = {}
113 115 for key in settings.keys():
114 116 for prefix in prefixes:
115 117 if key.startswith(prefix):
116 118 name = key.split(prefix)[1].strip()
117 119 val = settings[key]
118 120 if isinstance(val, compat.string_types):
119 121 val = val.strip()
120 122 cache_settings[name] = val
121 123 return cache_settings
122 124
123 125
124 126 def compute_key_from_params(*args):
125 127 """
126 128 Helper to compute key from given params to be used in cache manager
127 129 """
128 130 return sha1("_".join(map(safe_str, args)))
129 131
130 132
131 133 def backend_key_generator(backend):
132 134 """
133 135 Special wrapper that also sends over the backend to the key generator
134 136 """
135 137 def wrapper(namespace, fn):
136 138 return key_generator(backend, namespace, fn)
137 139 return wrapper
138 140
139 141
140 142 def key_generator(backend, namespace, fn):
141 143 fname = fn.__name__
142 144
143 145 def generate_key(*args):
144 146 backend_prefix = getattr(backend, 'key_prefix', None) or 'backend_prefix'
145 147 namespace_pref = namespace or 'default_namespace'
146 148 arg_key = compute_key_from_params(*args)
147 149 final_key = "{}:{}:{}_{}".format(backend_prefix, namespace_pref, fname, arg_key)
148 150
149 151 return final_key
150 152
151 153 return generate_key
General Comments 0
You need to be logged in to leave comments. Login now