##// END OF EJS Templates
caches: use delete_multi for clearing out cache keys....
marcink -
r2888:fc338c66 default
parent child Browse files
Show More
@@ -1,107 +1,106 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2015-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
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 Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 import os
21 21 import logging
22 22 from dogpile.cache import make_region
23 23
24 24 from rhodecode.lib.utils import safe_str, sha1
25 25 from . import region_meta
26 26
27 27 log = logging.getLogger(__name__)
28 28
29 29
30 30 def get_default_cache_settings(settings, prefixes=None):
31 31 prefixes = prefixes or []
32 32 cache_settings = {}
33 33 for key in settings.keys():
34 34 for prefix in prefixes:
35 35 if key.startswith(prefix):
36 36 name = key.split(prefix)[1].strip()
37 37 val = settings[key]
38 38 if isinstance(val, basestring):
39 39 val = val.strip()
40 40 cache_settings[name] = val
41 41 return cache_settings
42 42
43 43
44 44 def compute_key_from_params(*args):
45 45 """
46 46 Helper to compute key from given params to be used in cache manager
47 47 """
48 48 return sha1("_".join(map(safe_str, args)))
49 49
50 50
51 51 def key_generator(namespace, fn):
52 52 fname = fn.__name__
53 53
54 54 def generate_key(*args):
55 55 namespace_pref = namespace or 'default'
56 56 arg_key = compute_key_from_params(*args)
57 57 final_key = "{}:{}_{}".format(namespace_pref, fname, arg_key)
58 58
59 59 return final_key
60 60
61 61 return generate_key
62 62
63 63
64 64 def get_or_create_region(region_name, region_namespace=None):
65 65 from rhodecode.lib.rc_cache.backends import FileNamespaceBackend
66 66 region_obj = region_meta.dogpile_cache_regions.get(region_name)
67 67 if not region_obj:
68 68 raise EnvironmentError(
69 69 'Region `{}` not in configured: {}.'.format(
70 70 region_name, region_meta.dogpile_cache_regions.keys()))
71 71
72 72 region_uid_name = '{}:{}'.format(region_name, region_namespace)
73 73 if isinstance(region_obj.actual_backend, FileNamespaceBackend):
74 74 region_exist = region_meta.dogpile_cache_regions.get(region_namespace)
75 75 if region_exist:
76 76 log.debug('Using already configured region: %s', region_namespace)
77 77 return region_exist
78 78 cache_dir = region_meta.dogpile_config_defaults['cache_dir']
79 79 expiration_time = region_obj.expiration_time
80 80
81 81 if not os.path.isdir(cache_dir):
82 82 os.makedirs(cache_dir)
83 83 new_region = make_region(
84 84 name=region_uid_name, function_key_generator=key_generator
85 85 )
86 86 namespace_filename = os.path.join(
87 87 cache_dir, "{}.cache.dbm".format(region_namespace))
88 88 # special type that allows 1db per namespace
89 89 new_region.configure(
90 90 backend='dogpile.cache.rc.file_namespace',
91 91 expiration_time=expiration_time,
92 92 arguments={"filename": namespace_filename}
93 93 )
94 94
95 95 # create and save in region caches
96 96 log.debug('configuring new region: %s',region_uid_name)
97 97 region_obj = region_meta.dogpile_cache_regions[region_namespace] = new_region
98 98
99 99 return region_obj
100 100
101 101
102 102 def clear_cache_namespace(cache_region, cache_namespace_uid):
103 103 region = get_or_create_region(cache_region, cache_namespace_uid)
104 104 cache_keys = region.backend.list_keys(prefix=cache_namespace_uid)
105 for k in cache_keys:
106 region.delete(k)
105 region.delete_multi(cache_keys)
107 106 return len(cache_keys)
@@ -1,109 +1,108 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
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 Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import time
22 22
23 23 import pytest
24 24
25 25 from rhodecode.lib import rc_cache
26 26
27 27
28 28 @pytest.mark.usefixtures( 'app')
29 29 class TestCaches(object):
30 30
31 31 def test_cache_decorator_init_not_configured(self):
32 32 with pytest.raises(EnvironmentError):
33 33 rc_cache.get_or_create_region('dontexist')
34 34
35 35 @pytest.mark.parametrize('region_name', [
36 36 'cache_perms', u'cache_perms',
37 37 ])
38 38 def test_cache_decorator_init(self, region_name):
39 39 namespace = region_name
40 40 cache_region = rc_cache.get_or_create_region(
41 41 region_name, region_namespace=namespace)
42 42 assert cache_region
43 43
44 44 @pytest.mark.parametrize('example_input', [
45 45 ('',),
46 46 (u'/ac',),
47 47 (u'/ac', 1, 2, object()),
48 48 (u'/Δ™Δ‡c', 1, 2, object()),
49 49 ('/Δ…ac',),
50 50 (u'/ac', ),
51 51 ])
52 52 def test_cache_manager_create_key(self, example_input):
53 53 key = rc_cache.utils.compute_key_from_params(*example_input)
54 54 assert key
55 55
56 56 @pytest.mark.parametrize('example_namespace', [
57 57 'namespace', None
58 58 ])
59 59 @pytest.mark.parametrize('example_input', [
60 60 ('',),
61 61 (u'/ac',),
62 62 (u'/ac', 1, 2, object()),
63 63 (u'/Δ™Δ‡c', 1, 2, object()),
64 64 ('/Δ…ac',),
65 65 (u'/ac', ),
66 66 ])
67 67 def test_cache_keygen(self, example_input, example_namespace):
68 68 def func_wrapped():
69 69 return 1
70 70 func = rc_cache.utils.key_generator(example_namespace, func_wrapped)
71 71 key = func(*example_input)
72 72 assert key
73 73
74 74 def test_store_value_in_cache(self):
75 75 cache_region = rc_cache.get_or_create_region('cache_perms')
76 76 # make sure we empty the cache now
77 for key in cache_region.backend.list_keys():
78 cache_region.delete(key)
77 cache_region.delete_multi(cache_region.backend.list_keys())
79 78
80 79 assert cache_region.backend.list_keys() == []
81 80
82 81 @cache_region.cache_on_arguments(expiration_time=5)
83 82 def compute(key):
84 83 return time.time()
85 84
86 85 for x in range(10):
87 86 compute(x)
88 87
89 88 assert len(set(cache_region.backend.list_keys())) == 10
90 89
91 90 def test_store_and_get_value_from_region(self):
92 91 cache_region = rc_cache.get_or_create_region('cache_perms')
93 92 # make sure we empty the cache now
94 93 for key in cache_region.backend.list_keys():
95 94 cache_region.delete(key)
96 95 assert cache_region.backend.list_keys() == []
97 96
98 97 @cache_region.cache_on_arguments(expiration_time=5)
99 98 def compute(key):
100 99 return time.time()
101 100
102 101 result = set()
103 102 for x in range(10):
104 103 ret = compute('x')
105 104 result.add(ret)
106 105
107 106 # once computed we have only one value (the same from cache)
108 107 # after executing it 10x
109 108 assert len(result) == 1
General Comments 0
You need to be logged in to leave comments. Login now