Add duration on Cache
issue8249 review283181002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Add duration on Cache
|
||||
* Add strip wildcards helpers
|
||||
* Add list-form view
|
||||
* Do not set id for on_change calls if cached
|
||||
|
||||
+10
-9
@@ -5,16 +5,17 @@
|
||||
Cache
|
||||
=====
|
||||
|
||||
.. class:: Cache(name[, size_limit[, context]])
|
||||
.. class:: Cache(name[, size_limit[, duration[, context]]])
|
||||
|
||||
The class is used to cache values between server requests. The `name` should
|
||||
be unique and it's used to identify the cache. We usually use
|
||||
`<class_name>.<content_name>` to make it unique. The `size_limit` field can
|
||||
be used to limit the number of values cached and the `context` parameter
|
||||
is used to indicate if the cache depends on the user context and is true
|
||||
by default.
|
||||
The cache is cleaned on :class:`Transaction` starts and resets on
|
||||
:class:`Transaction` commit or rollback.
|
||||
The class is used to cache values between server requests. The `name` should be
|
||||
unique and it's used to identify the cache. We usually use
|
||||
`<class_name>.<content_name>` to make it unique. The `size_limit` parameter can
|
||||
be used to limit the number of values cached and it has 1024 as the default
|
||||
value. The `duration` parameter defines how long a cached value stays valid
|
||||
but if it is not set the value remains valid until it is cleared. And the
|
||||
`context` parameter is used to indicate if the cache depends on the user
|
||||
context and is true by default. The cache is cleaned on :class:`Transaction`
|
||||
starts and resets on :class:`Transaction` commit or rollback.
|
||||
|
||||
.. warning::
|
||||
As there is no deepcopy of the values cached, they must never be mutated
|
||||
|
||||
+22
-6
@@ -1,5 +1,6 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import datetime as dt
|
||||
import json
|
||||
import logging
|
||||
import select
|
||||
@@ -44,10 +45,18 @@ def freeze(o):
|
||||
class BaseCache(object):
|
||||
_instances = {}
|
||||
|
||||
def __init__(self, name, size_limit=1024, context=True):
|
||||
def __init__(self, name, size_limit=1024, duration=None, context=True):
|
||||
self._name = name
|
||||
self.size_limit = size_limit
|
||||
self.context = context
|
||||
if isinstance(duration, dt.timedelta):
|
||||
self.duration = duration
|
||||
elif isinstance(duration, (int, float)):
|
||||
self.duration = dt.timedelta(seconds=duration)
|
||||
elif duration:
|
||||
self.duration = dt.timedelta(**duration)
|
||||
else:
|
||||
self.duration = None
|
||||
assert self._name not in self._instances
|
||||
self._instances[self._name] = self
|
||||
|
||||
@@ -94,9 +103,9 @@ class MemoryCache(BaseCache):
|
||||
_table = 'ir_cache'
|
||||
_channel = _table
|
||||
|
||||
def __init__(self, name, size_limit=1024, context=True):
|
||||
super(MemoryCache, self).__init__(name, size_limit, context)
|
||||
self._database_cache = defaultdict(lambda: LRUDict(size_limit))
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MemoryCache, self).__init__(*args, **kwargs)
|
||||
self._database_cache = defaultdict(lambda: LRUDict(self.size_limit))
|
||||
self._transaction_cache = WeakKeyDictionary()
|
||||
self._transaction_lower = {}
|
||||
self._timestamp = {}
|
||||
@@ -120,7 +129,10 @@ class MemoryCache(BaseCache):
|
||||
key = self._key(key)
|
||||
cache = self._get_cache()
|
||||
try:
|
||||
result = cache[key] = cache.pop(key)
|
||||
(expire, result) = cache.pop(key)
|
||||
if expire and expire < dt.datetime.now():
|
||||
return default
|
||||
cache[key] = (expire, result)
|
||||
return result
|
||||
except (KeyError, TypeError):
|
||||
return default
|
||||
@@ -128,8 +140,12 @@ class MemoryCache(BaseCache):
|
||||
def set(self, key, value):
|
||||
key = self._key(key)
|
||||
cache = self._get_cache()
|
||||
if self.duration:
|
||||
expire = dt.datetime.now() + self.duration
|
||||
else:
|
||||
expire = None
|
||||
try:
|
||||
cache[key] = value
|
||||
cache[key] = (expire, value)
|
||||
except TypeError:
|
||||
pass
|
||||
return value
|
||||
|
||||
@@ -12,6 +12,7 @@ from trytond.transaction import Transaction
|
||||
|
||||
|
||||
cache = MemoryCache('test.cache')
|
||||
cache_expire = MemoryCache('test.cache_expire', duration=1)
|
||||
|
||||
|
||||
class CacheTestCase(unittest.TestCase):
|
||||
@@ -134,6 +135,14 @@ class MemoryCacheTestCase(unittest.TestCase):
|
||||
self.addCleanup(transaction3.stop)
|
||||
self.assertEqual(cache.get('foo'), None)
|
||||
|
||||
@with_transaction()
|
||||
def test_memory_cache_expire(self):
|
||||
"Test expired cache"
|
||||
cache_expire.set('foo', "bar")
|
||||
time.sleep(cache_expire.duration.total_seconds())
|
||||
|
||||
self.assertEqual(cache_expire.get('foo'), None)
|
||||
|
||||
|
||||
@unittest.skipIf(backend.name() == 'sqlite', "SQLite has not channel")
|
||||
class MemoryCacheChannelTestCase(MemoryCacheTestCase):
|
||||
|
||||
Reference in New Issue
Block a user