##// END OF EJS Templates
fix(permission-flush): use delete method for permission cache invalidation as it's multi-process safe....
super-admin -
r5266:a1331d35 default
parent child Browse files
Show More
@@ -145,7 +145,7 b' dev-srv:'
145 .PHONY: dev-srv-g
145 .PHONY: dev-srv-g
146 ## run gunicorn multi process workers
146 ## run gunicorn multi process workers
147 dev-srv-g:
147 dev-srv-g:
148 gunicorn --workers=2 --paste .dev/dev.ini --bind=0.0.0.0:10020 --config=.dev/gunicorn_config.py
148 gunicorn --paste .dev/dev.ini --bind=0.0.0.0:10020 --config=.dev/gunicorn_config.py --timeout=120
149
149
150
150
151 # Default command on calling make
151 # Default command on calling make
@@ -44,7 +44,7 b' def trigger_user_permission_flush(event)'
44 for user_id in affected_user_ids:
44 for user_id in affected_user_ids:
45 for cache_namespace_uid_tmpl in cache_namespaces:
45 for cache_namespace_uid_tmpl in cache_namespaces:
46 cache_namespace_uid = cache_namespace_uid_tmpl.format(user_id)
46 cache_namespace_uid = cache_namespace_uid_tmpl.format(user_id)
47 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid, method=rc_cache.CLEAR_INVALIDATE)
47 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid, method=rc_cache.CLEAR_DELETE)
48 log.debug('Invalidated %s cache keys for user_id: %s and namespace %s',
48 log.debug('Invalidated %s cache keys for user_id: %s and namespace %s',
49 del_keys, user_id, cache_namespace_uid)
49 del_keys, user_id, cache_namespace_uid)
50
50
@@ -1313,7 +1313,7 b' class UsersView(UserAppView):'
1313 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1313 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1314
1314
1315 cache_namespace_uid = f'cache_user_auth.{rc_cache.PERMISSIONS_CACHE_VER}.{self.db_user.user_id}'
1315 cache_namespace_uid = f'cache_user_auth.{rc_cache.PERMISSIONS_CACHE_VER}.{self.db_user.user_id}'
1316 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1316 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid, method=rc_cache.CLEAR_DELETE)
1317
1317
1318 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1318 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1319
1319
@@ -74,10 +74,20 b' class LRUMemoryBackend(memory_backend.Me'
74 # we don't care if key isn't there at deletion
74 # we don't care if key isn't there at deletion
75 pass
75 pass
76
76
77 def list_keys(self, prefix):
78 return list(self._cache.keys())
79
77 def delete_multi(self, keys):
80 def delete_multi(self, keys):
78 for key in keys:
81 for key in keys:
79 self.delete(key)
82 self.delete(key)
80
83
84 def delete_multi_by_prefix(self, prefix):
85 cache_keys = self.list_keys(prefix=prefix)
86 num_affected_keys = len(cache_keys)
87 if num_affected_keys:
88 self.delete_multi(cache_keys)
89 return num_affected_keys
90
81
91
82 class PickleSerializer:
92 class PickleSerializer:
83 serializer: None | Serializer = staticmethod( # type: ignore
93 serializer: None | Serializer = staticmethod( # type: ignore
@@ -178,6 +188,13 b' class FileNamespaceBackend(PickleSeriali'
178 log.error('Failed to fetch DBM keys from DB: %s', self.get_store())
188 log.error('Failed to fetch DBM keys from DB: %s', self.get_store())
179 raise
189 raise
180
190
191 def delete_multi_by_prefix(self, prefix):
192 cache_keys = self.list_keys(prefix=prefix)
193 num_affected_keys = len(cache_keys)
194 if num_affected_keys:
195 self.delete_multi(cache_keys)
196 return num_affected_keys
197
181 def get_store(self):
198 def get_store(self):
182 return self.filename
199 return self.filename
183
200
@@ -227,6 +244,25 b' class BaseRedisBackend(redis_backend.Red'
227 prefix = self._get_keys_pattern(prefix)
244 prefix = self._get_keys_pattern(prefix)
228 return self.reader_client.keys(prefix)
245 return self.reader_client.keys(prefix)
229
246
247 def delete_multi_by_prefix(self, prefix, use_lua=False):
248 if use_lua:
249 # high efficient LUA script to delete ALL keys by prefix...
250 lua = """local keys = redis.call('keys', ARGV[1])
251 for i=1,#keys,5000 do
252 redis.call('del', unpack(keys, i, math.min(i+(5000-1), #keys)))
253 end
254 return #keys"""
255 num_affected_keys = self.writer_client.eval(
256 lua,
257 0,
258 f"{prefix}*")
259 else:
260 cache_keys = self.list_keys(prefix=prefix)
261 num_affected_keys = len(cache_keys)
262 if num_affected_keys:
263 self.delete_multi(cache_keys)
264 return num_affected_keys
265
230 def get_store(self):
266 def get_store(self):
231 return self.reader_client.connection_pool
267 return self.reader_client.connection_pool
232
268
@@ -232,14 +232,15 b' def get_or_create_region(region_name, re'
232 return region_obj
232 return region_obj
233
233
234
234
235 def clear_cache_namespace(cache_region: str | RhodeCodeCacheRegion, cache_namespace_uid: str, method: str):
235 def clear_cache_namespace(cache_region: str | RhodeCodeCacheRegion, cache_namespace_uid: str, method: str) -> int:
236 from . import CLEAR_DELETE, CLEAR_INVALIDATE
236 from . import CLEAR_DELETE, CLEAR_INVALIDATE
237
237
238 if not isinstance(cache_region, RhodeCodeCacheRegion):
238 if not isinstance(cache_region, RhodeCodeCacheRegion):
239 cache_region = get_or_create_region(cache_region, cache_namespace_uid)
239 cache_region = get_or_create_region(cache_region, cache_namespace_uid)
240 log.debug('clearing cache region: %s with method=%s', cache_region, method)
240 log.debug('clearing cache region: %s [prefix:%s] with method=%s',
241 cache_region, cache_namespace_uid, method)
241
242
242 num_affected_keys = None
243 num_affected_keys = 0
243
244
244 if method == CLEAR_INVALIDATE:
245 if method == CLEAR_INVALIDATE:
245 # NOTE: The CacheRegion.invalidate() method’s default mode of
246 # NOTE: The CacheRegion.invalidate() method’s default mode of
@@ -248,10 +249,7 b' def clear_cache_namespace(cache_region: '
248 cache_region.invalidate(hard=True)
249 cache_region.invalidate(hard=True)
249
250
250 if method == CLEAR_DELETE:
251 if method == CLEAR_DELETE:
251 cache_keys = cache_region.backend.list_keys(prefix=cache_namespace_uid)
252 num_affected_keys = cache_region.backend.delete_multi_by_prefix(prefix=cache_namespace_uid)
252 num_affected_keys = len(cache_keys)
253 if num_affected_keys:
254 cache_region.delete_multi(cache_keys)
255
253
256 return num_affected_keys
254 return num_affected_keys
257
255
General Comments 0
You need to be logged in to leave comments. Login now