Keep all transaction caches still referenced

The LRUDict is replaced by a WeakValueDictionary to keep all used transaction
caches such as they can be cleared by ModelStorage.
But we still keep the latest cache used so they are not removed from the
WeakValueDictionary too soon when such cache has been created to be pre-filled
like in ModelSQL.search.

Closes #12119
This commit is contained in:
Cédric Krier committed 2023-03-07 15:43:53 +01:00
1 parent ba701d5a38
commit 0d0cd7ee45
1 file changed
+16 -12
+16 -12
View File
@@ -2,9 +2,10 @@
# this repository contains the full copyright notices and license terms.
import logging
import time
from collections import defaultdict
from collections import defaultdict, deque
from functools import wraps
from threading import local
from weakref import WeakValueDictionary
from sql import Flavor
@@ -105,8 +106,6 @@ class Transaction(object):
cache_keys = {'language', 'fuzzy_translation', '_datetime'}
def __new__(cls, new=False):
from trytond.cache import LRUDict
from trytond.pool import Pool
transactions = cls._local.transactions
if new or not transactions:
instance = super(Transaction, cls).__new__(cls)
@@ -122,14 +121,8 @@ class Transaction(object):
instance.check_warnings = None
instance.timestamp = None
instance.started_at = None
instance.cache = LRUDict(
_cache_transaction,
lambda: LRUDict(
_cache_model,
lambda name: LRUDict(
record_cache_size(instance),
Pool().get(name)._record),
default_factory_with_key=True))
instance.cache = WeakValueDictionary()
instance._cache_deque = deque(maxlen=_cache_transaction)
instance._atexit = []
transactions.append(instance)
else:
@@ -148,10 +141,21 @@ class Transaction(object):
return self._local.tasks
def get_cache(self):
from trytond.cache import LRUDict
from trytond.pool import Pool
keys = tuple(((key, self.context[key])
for key in sorted(self.cache_keys)
if key in self.context))
return self.cache[(self.user, keys)]
cache = self.cache.setdefault(
(self.user, keys), LRUDict(
_cache_model,
lambda name: LRUDict(
record_cache_size(self),
Pool().get(name)._record),
default_factory_with_key=True))
# Keep last used cache references to allow to pre-fill them
self._cache_deque.append(cache)
return cache
def start(self, database_name, user, readonly=False, context=None,
close=False, autocommit=False, **extras):