[fix] cache.ExpireCache: definition of a context name for the key
The definition of a context name belongs in the abstract base class (was previously only in the concrete implementation for the SQLite adapter). Suggested-by: @dalf https://github.com/searxng/searxng/pull/4650#discussion_r2069873853 Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
parent
7351c38e6c
commit
8ef5fbca4e
@ -83,12 +83,12 @@ class ExpireCacheStats:
|
|||||||
"""Dataclass wich provides information on the status of the cache."""
|
"""Dataclass wich provides information on the status of the cache."""
|
||||||
|
|
||||||
cached_items: dict[str, list[tuple[str, typing.Any, int]]]
|
cached_items: dict[str, list[tuple[str, typing.Any, int]]]
|
||||||
"""Values in the cache mapped by table name.
|
"""Values in the cache mapped by context name.
|
||||||
|
|
||||||
.. code: python
|
.. code: python
|
||||||
|
|
||||||
{
|
{
|
||||||
"table name": [
|
"context name": [
|
||||||
("foo key": "foo value", <expire>),
|
("foo key": "foo value", <expire>),
|
||||||
("bar key": "bar value", <expire>),
|
("bar key": "bar value", <expire>),
|
||||||
# ...
|
# ...
|
||||||
@ -98,22 +98,22 @@ class ExpireCacheStats:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def report(self):
|
def report(self):
|
||||||
c_tables = 0
|
c_ctx = 0
|
||||||
c_kv = 0
|
c_kv = 0
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
for table_name, kv_list in self.cached_items.items():
|
for ctx_name, kv_list in self.cached_items.items():
|
||||||
c_tables += 1
|
c_ctx += 1
|
||||||
if not kv_list:
|
if not kv_list:
|
||||||
lines.append(f"[{table_name:20s}] empty")
|
lines.append(f"[{ctx_name:20s}] empty")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for key, value, expire in kv_list:
|
for key, value, expire in kv_list:
|
||||||
valid_until = datetime.datetime.fromtimestamp(expire).strftime("%Y-%m-%d %H:%M:%S")
|
valid_until = datetime.datetime.fromtimestamp(expire).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
c_kv += 1
|
c_kv += 1
|
||||||
lines.append(f"[{table_name:20s}] {valid_until} {key:12}" f" --> ({type(value).__name__}) {value} ")
|
lines.append(f"[{ctx_name:20s}] {valid_until} {key:12}" f" --> ({type(value).__name__}) {value} ")
|
||||||
|
|
||||||
lines.append(f"number of tables: {c_tables}")
|
lines.append(f"Number of contexts: {c_ctx}")
|
||||||
lines.append(f"number of key/value pairs: {c_kv}")
|
lines.append(f"number of key/value pairs: {c_kv}")
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
@ -127,15 +127,27 @@ class ExpireCache(abc.ABC):
|
|||||||
hash_token = "hash_token"
|
hash_token = "hash_token"
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def set(self, key: str, value: typing.Any, expire: int | None) -> bool:
|
def set(self, key: str, value: typing.Any, expire: int | None, ctx: str | None = None) -> bool:
|
||||||
"""Set *key* to *value*. To set a timeout on key use argument
|
"""Set *key* to *value*. To set a timeout on key use argument
|
||||||
``expire`` (in sec.). If expire is unset the default is taken from
|
``expire`` (in sec.). If expire is unset the default is taken from
|
||||||
:py:obj:`ExpireCacheCfg.MAXHOLD_TIME`. After the timeout has expired,
|
:py:obj:`ExpireCacheCfg.MAXHOLD_TIME`. After the timeout has expired,
|
||||||
the key will automatically be deleted.
|
the key will automatically be deleted.
|
||||||
|
|
||||||
|
The ``ctx`` argument specifies the context of the ``key``. A key is
|
||||||
|
only unique in its context.
|
||||||
|
|
||||||
|
The concrete implementations of this abstraction determine how the
|
||||||
|
context is mapped in the connected database. In SQL databases, for
|
||||||
|
example, the context is a DB table or in a Key/Value DB it could be
|
||||||
|
a prefix for the key.
|
||||||
|
|
||||||
|
If the context is not specified (the default is ``None``) then a
|
||||||
|
default context should be used, e.g. a default table for SQL databases
|
||||||
|
or a default prefix in a Key/Value DB.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get(self, key: str, default=None) -> typing.Any:
|
def get(self, key: str, default=None, ctx: str | None = None) -> typing.Any:
|
||||||
"""Return *value* of *key*. If key is unset, ``None`` is returned."""
|
"""Return *value* of *key*. If key is unset, ``None`` is returned."""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
@ -171,7 +183,7 @@ class ExpireCache(abc.ABC):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize_name(name: str) -> str:
|
def normalize_name(name: str) -> str:
|
||||||
"""Returns a normalized name that can be used as a file name or as a SQL
|
"""Returns a normalized name that can be used as a file name or as a SQL
|
||||||
table name."""
|
table name (is used, for example, to normalize the context name)."""
|
||||||
|
|
||||||
_valid = "-_." + string.ascii_letters + string.digits
|
_valid = "-_." + string.ascii_letters + string.digits
|
||||||
return "".join([c for c in name if c in _valid])
|
return "".join([c for c in name if c in _valid])
|
||||||
@ -320,14 +332,15 @@ class ExpireCacheSQLite(sqlitedb.SQLiteAppl, ExpireCache):
|
|||||||
|
|
||||||
# implement ABC methods of ExpireCache
|
# implement ABC methods of ExpireCache
|
||||||
|
|
||||||
def set(self, key: str, value: typing.Any, expire: int | None, table: str | None = None) -> bool:
|
def set(self, key: str, value: typing.Any, expire: int | None, ctx: str | None = None) -> bool:
|
||||||
"""Set key/value in ``table``. If expire is unset the default is taken
|
"""Set key/value in DB table given by argument ``ctx``. If expire is
|
||||||
from :py:obj:`ExpireCacheCfg.MAXHOLD_TIME`. If ``table`` argument is
|
unset the default is taken from :py:obj:`ExpireCacheCfg.MAXHOLD_TIME`.
|
||||||
``None`` (the default), a table name is generated from the
|
If ``ctx`` argument is ``None`` (the default), a table name is
|
||||||
:py:obj:`ExpireCacheCfg.name`. If DB ``table`` does not exists, it will be
|
generated from the :py:obj:`ExpireCacheCfg.name`. If DB table does not
|
||||||
created (on demand) by :py:obj:`self.create_table
|
exists, it will be created (on demand) by :py:obj:`self.create_table
|
||||||
<ExpireCacheSQLite.create_table>`.
|
<ExpireCacheSQLite.create_table>`.
|
||||||
"""
|
"""
|
||||||
|
table = ctx
|
||||||
self.maintenance()
|
self.maintenance()
|
||||||
|
|
||||||
value = self.serialize(value=value)
|
value = self.serialize(value=value)
|
||||||
@ -360,12 +373,14 @@ class ExpireCacheSQLite(sqlitedb.SQLiteAppl, ExpireCache):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get(self, key: str, default=None, table: str | None = None) -> typing.Any:
|
def get(self, key: str, default=None, ctx: str | None = None) -> typing.Any:
|
||||||
"""Get value of ``key`` from ``table``. If ``table`` argument is
|
"""Get value of ``key`` from table given by argument ``ctx``. If
|
||||||
``None`` (the default), a table name is generated from the
|
``ctx`` argument is ``None`` (the default), a table name is generated
|
||||||
:py:obj:`ExpireCacheCfg.name`. If ``key`` not exists (in table), the
|
from the :py:obj:`ExpireCacheCfg.name`. If ``key`` not exists (in
|
||||||
``default`` value is returned.
|
table), the ``default`` value is returned.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
table = ctx
|
||||||
self.maintenance()
|
self.maintenance()
|
||||||
|
|
||||||
if not table:
|
if not table:
|
||||||
|
@ -161,11 +161,11 @@ class EngineCache:
|
|||||||
key=key,
|
key=key,
|
||||||
value=value,
|
value=value,
|
||||||
expire=expire or self.expire,
|
expire=expire or self.expire,
|
||||||
table=self.table_name,
|
ctx=self.table_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, key: str, default=None) -> Any:
|
def get(self, key: str, default=None) -> Any:
|
||||||
return ENGINES_CACHE.get(key, default=default, table=self.table_name)
|
return ENGINES_CACHE.get(key, default=default, ctx=self.table_name)
|
||||||
|
|
||||||
def secret_hash(self, name: str | bytes) -> str:
|
def secret_hash(self, name: str | bytes) -> str:
|
||||||
return ENGINES_CACHE.secret_hash(name=name)
|
return ENGINES_CACHE.secret_hash(name=name)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user