details: https://code.tryton.org/tryton/commit/e74f0ea22b53
branch: 7.0
user: Cédric Krier <[email protected]>
date: Wed Nov 04 16:07:16 2026 +0100
description:
Lock the modification and iteration of the cache dictionary of instances
Closes #15172
(grafted from c6520525a35a337adb4b8f5fc1ab449d9310f84a)
diffstat:
trytond/trytond/cache.py | 36 +++++++++++++++++++++---------------
1 files changed, 21 insertions(+), 15 deletions(-)
diffs (79 lines):
diff -r 86195e587130 -r e74f0ea22b53 trytond/trytond/cache.py
--- a/trytond/trytond/cache.py Sun Nov 08 23:50:53 2026 +0100
+++ b/trytond/trytond/cache.py Wed Nov 04 16:07:16 2026 +0100
@@ -67,12 +67,14 @@
def __call__(cls, *args, **kwargs):
inst = super().__call__(*args, **kwargs)
assert inst._name not in BaseCache._instances, inst._name
- BaseCache._instances[inst._name] = inst
+ with BaseCache._instances_lock:
+ BaseCache._instances[inst._name] = inst
return inst
class BaseCache(metaclass=_CacheMeta):
_instances = {}
+ _instances_lock = threading.Lock()
context_ignored_keys = {
'client', '_request', '_check_access', '_skip_warnings',
}
@@ -103,12 +105,13 @@
@classmethod
def stats(cls):
- for name, inst in cls._instances.items():
- yield {
- 'name': name,
- 'hit': inst.hit,
- 'miss': inst.miss,
- }
+ with cls._instances_lock:
+ for name, inst in cls._instances.items():
+ yield {
+ 'name': name,
+ 'hit': inst.hit,
+ 'miss': inst.miss,
+ }
def _key(self, key):
if self.context:
@@ -130,8 +133,9 @@
@classmethod
def clear_all(cls):
- for inst in cls._instances.values():
- inst.clear()
+ with cls._instances_lock:
+ for inst in cls._instances.values():
+ inst.clear()
@classmethod
def sync(cls, transaction):
@@ -230,8 +234,9 @@
@classmethod
def _clear_all(cls, dbname):
- for inst in cls._instances.values():
- inst._clear(dbname)
+ with cls._instances_lock:
+ for inst in cls._instances.values():
+ inst._clear(dbname)
@classmethod
def sync(cls, transaction):
@@ -355,10 +360,11 @@
finally:
database.put_connection(conn)
listener.join()
- for inst in cls._instances.values():
- inst._timestamp.pop(dbname, None)
- inst._database_cache.pop(dbname, None)
- inst._transaction_lower.pop(dbname, None)
+ with cls._instances_lock:
+ for inst in cls._instances.values():
+ inst._timestamp.pop(dbname, None)
+ inst._database_cache.pop(dbname, None)
+ inst._transaction_lower.pop(dbname, None)
@classmethod
def refresh_pool(cls, transaction):