.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
searx.cache.ExpireCacheSQLite Class Reference
+ Inheritance diagram for searx.cache.ExpireCacheSQLite:
+ Collaboration diagram for searx.cache.ExpireCacheSQLite:

Public Member Functions

 __init__ (self, ExpireCacheCfg cfg)
 
bool init (self, sqlite3.Connection conn)
 
bool maintenance (self, bool force=False, bool truncate=False)
 
bool create_table (self, str table)
 
list[str] table_names (self)
 
 truncate_tables (self, list[str] table_names)
 
int next_maintenance_time (self)
 
bool set (self, str key, typing.Any value, int|None expire, str|None ctx=None)
 
typing.Any get (self, str key, default=None, str|None ctx=None)
 
ExpireCacheStats state (self)
 
- Public Member Functions inherited from searx.sqlitedb.SQLiteAppl
 __init__ (self, db_url)
 
sqlite3.Connection connect (self)
 
 register_functions (self, conn)
 
sqlite3.Connection DB (self)
 
 create_schema (self, sqlite3.Connection conn)
 
- Public Member Functions inherited from searx.cache.ExpireCache
bytes serialize (self, typing.Any value)
 
typing.Any deserialize (self, bytes value)
 
str secret_hash (self, str|bytes name)
 

Public Attributes

 cfg = cfg
 
 next_maintenance_time
 
 table_names
 
- Public Attributes inherited from searx.sqlitedb.SQLiteAppl
 db_url = db_url
 
 properties = SQLiteProperties(db_url)
 

Static Public Attributes

str CACHE_TABLE_PREFIX = "CACHE-TABLE-"
 
- Static Public Attributes inherited from searx.sqlitedb.SQLiteAppl
dict DDL_CREATE_TABLES = {}
 
int DB_SCHEMA = 1
 
dict SQLITE_THREADING_MODE
 
str SQLITE_JOURNAL_MODE = "WAL"
 
dict SQLITE_CONNECT_ARGS
 
- Static Public Attributes inherited from searx.cache.ExpireCache
ExpireCacheCfg hash_token = "hash_token"
 

Additional Inherited Members

- Static Public Member Functions inherited from searx.cache.ExpireCache
ExpireCache build_cache (ExpireCacheCfg cfg)
 
str normalize_name (str name)
 
- Protected Member Functions inherited from searx.sqlitedb.SQLiteAppl
 _compatibility (self)
 
sqlite3.Connection _connect (self)
 
- Protected Attributes inherited from searx.sqlitedb.SQLiteAppl
bool _init_done = False
 
 _DB = None
 

Detailed Description

Cache that manages key/value pairs in a SQLite DB.  The DB model in the
SQLite DB is implemented in abstract class :py:obj:`SQLiteAppl
<searx.sqlitedb.SQLiteAppl>`.

The following configurations are required / supported:

- :py:obj:`ExpireCacheCfg.db_url`
- :py:obj:`ExpireCacheCfg.MAXHOLD_TIME`
- :py:obj:`ExpireCacheCfg.MAINTENANCE_PERIOD`
- :py:obj:`ExpireCacheCfg.MAINTENANCE_MODE`

Definition at line 211 of file cache.py.

Constructor & Destructor Documentation

◆ __init__()

searx.cache.ExpireCacheSQLite.__init__ ( self,
ExpireCacheCfg cfg )
An instance of the SQLite expire cache is build up from a
:py:obj:`config <ExpireCacheCfg>`.

Definition at line 231 of file cache.py.

231 def __init__(self, cfg: ExpireCacheCfg):
232 """An instance of the SQLite expire cache is build up from a
233 :py:obj:`config <ExpireCacheCfg>`."""
234
235 self.cfg = cfg
236 if cfg.db_url == ":memory:":
237 log.critical("don't use SQLite DB in :memory: in production!!")
238 super().__init__(cfg.db_url)
239

Member Function Documentation

◆ create_table()

bool searx.cache.ExpireCacheSQLite.create_table ( self,
str table )
Create DB ``table`` if it has not yet been created, no recreates are
initiated if the table already exists.

Definition at line 285 of file cache.py.

285 def create_table(self, table: str) -> bool:
286 """Create DB ``table`` if it has not yet been created, no recreates are
287 initiated if the table already exists.
288 """
289 if table in self.table_names:
290 # log.debug("key/value table %s exists in DB (no need to recreate)", table)
291 return False
292
293 log.info("key/value table '%s' NOT exists in DB -> create DB table ..", table)
294 sql_table = "\n".join(
295 [
296 f"CREATE TABLE IF NOT EXISTS {table} (",
297 " key TEXT,",
298 " value BLOB,",
299 f" expire INTEGER DEFAULT (strftime('%s', 'now') + {self.cfg.MAXHOLD_TIME}),",
300 "PRIMARY KEY (key))",
301 ]
302 )
303 sql_index = f"CREATE INDEX IF NOT EXISTS index_expire_{table} ON {table}(expire);"
304 with self.connect() as conn:
305 conn.execute(sql_table)
306 conn.execute(sql_index)
307 conn.close()
308
309 self.properties.set(f"{self.CACHE_TABLE_PREFIX}-{table}", table)
310 return True
311

References searx.sqlitedb.SQLiteAppl.connect(), searx.sqlitedb.SQLiteAppl.properties, set(), and table_names.

Referenced by set().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get()

typing.Any searx.cache.ExpireCacheSQLite.get ( self,
str key,
default = None,
str | None ctx = None )
Get value of ``key`` from table given by argument ``ctx``.  If
``ctx`` argument is ``None`` (the default), a table name is generated
from the :py:obj:`ExpireCacheCfg.name`.  If ``key`` not exists (in
table), the ``default`` value is returned.

Reimplemented from searx.cache.ExpireCache.

Definition at line 376 of file cache.py.

376 def get(self, key: str, default=None, ctx: str | None = None) -> typing.Any:
377 """Get value of ``key`` from table given by argument ``ctx``. If
378 ``ctx`` argument is ``None`` (the default), a table name is generated
379 from the :py:obj:`ExpireCacheCfg.name`. If ``key`` not exists (in
380 table), the ``default`` value is returned.
381
382 """
383 table = ctx
384 self.maintenance()
385
386 if not table:
387 table = self.normalize_name(self.cfg.name)
388
389 if table not in self.table_names:
390 return default
391
392 sql = f"SELECT value FROM {table} WHERE key = ?"
393 row = self.DB.execute(sql, (key,)).fetchone()
394 if row is None:
395 return default
396
397 return self.deserialize(row[0])
398

References searx.botdetection.config.Config.cfg, cfg, DB, searx.cache.ExpireCache.deserialize(), searx.cache.ExpireCache.maintenance(), searx.cache.ExpireCache.normalize_name(), and table_names.

Referenced by searx.result_types._base.LegacyResult.__init__(), searx.result_types._base.LegacyResult.defaults_from(), and searx.answerers._core.AnswerStorage.register().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init()

bool searx.cache.ExpireCacheSQLite.init ( self,
sqlite3.Connection conn )
Initializes the DB schema and properties, is only executed once even
if called several times.

If the initialization has not yet taken place, it is carried out and a
`True` is returned to the caller at the end.  If the initialization has
already been carried out in the past, `False` is returned.

Reimplemented from searx.sqlitedb.SQLiteAppl.

Definition at line 240 of file cache.py.

240 def init(self, conn: sqlite3.Connection) -> bool:
241 ret_val = super().init(conn)
242 if not ret_val:
243 return False
244
245 new = hashlib.sha256(self.cfg.password).hexdigest()
246 old = self.properties(self.hash_token)
247 if old != new:
248 if old is not None:
249 log.warning("[%s] hash token changed: truncate all cache tables", self.cfg.name)
250 self.maintenance(force=True, truncate=True)
251 self.properties.set(self.hash_token, new)
252
253 return True
254

References searx.botdetection.config.Config.cfg, cfg, searx.cache.ExpireCache.hash_token, init(), searx.cache.ExpireCache.maintenance(), and searx.sqlitedb.SQLiteAppl.properties.

Referenced by searx.sqlitedb.SQLiteAppl.connect(), searx.sqlitedb.SQLiteAppl.DB(), and init().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maintenance()

bool searx.cache.ExpireCacheSQLite.maintenance ( self,
bool force = False,
bool truncate = False )
Performs maintenance on the cache.

``force``:
  Maintenance should be carried out even if the maintenance interval has
  not yet been reached.

``truncate``:
  Truncate the entire cache, which is necessary, for example, if the
  password has changed.

Reimplemented from searx.cache.ExpireCache.

Definition at line 255 of file cache.py.

255 def maintenance(self, force: bool = False, truncate: bool = False) -> bool:
256
257 if not force and int(time.time()) < self.next_maintenance_time:
258 # log.debug("no maintenance required yet, next maintenance interval is in the future")
259 return False
260
261 # Prevent parallel DB maintenance cycles from other DB connections
262 # (e.g. in multi thread or process environments).
263 self.properties.set("LAST_MAINTENANCE", "") # hint: this (also) sets the m_time of the property!
264
265 if truncate:
266 self.truncate_tables(self.table_names)
267 return True
268
269 # drop items by expire time stamp ..
270 expire = int(time.time())
271
272 with self.connect() as conn:
273 for table in self.table_names:
274 res = conn.execute(f"DELETE FROM {table} WHERE expire < ?", (expire,))
275 log.debug("deleted %s keys from table %s (expire date reached)", res.rowcount, table)
276
277 # Vacuuming the WALs
278 # https://www.theunterminatedstring.com/sqlite-vacuuming/
279
280 conn.execute("PRAGMA wal_checkpoint(TRUNCATE)")
281 conn.close()
282
283 return True
284

Referenced by searx.favicons.cache.FaviconCacheSQLite.set().

+ Here is the caller graph for this function:

◆ next_maintenance_time()

int searx.cache.ExpireCacheSQLite.next_maintenance_time ( self)
Returns (unix epoch) time of the next maintenance.

Definition at line 328 of file cache.py.

328 def next_maintenance_time(self) -> int:
329 """Returns (unix epoch) time of the next maintenance."""
330
331 return self.cfg.MAINTENANCE_PERIOD + self.properties.m_time("LAST_MAINTENANCE", int(time.time()))
332

References searx.botdetection.config.Config.cfg, cfg, and searx.sqlitedb.SQLiteAppl.properties.

◆ set()

bool searx.cache.ExpireCacheSQLite.set ( self,
str key,
typing.Any value,
int | None expire,
str | None ctx = None )
Set key/value in DB table given by argument ``ctx``.  If expire is
unset the default is taken from :py:obj:`ExpireCacheCfg.MAXHOLD_TIME`.
If ``ctx`` argument is ``None`` (the default), a table name is
generated from the :py:obj:`ExpireCacheCfg.name`.  If DB table does not
exists, it will be created (on demand) by :py:obj:`self.create_table
<ExpireCacheSQLite.create_table>`.

Reimplemented from searx.cache.ExpireCache.

Definition at line 335 of file cache.py.

335 def set(self, key: str, value: typing.Any, expire: int | None, ctx: str | None = None) -> bool:
336 """Set key/value in DB table given by argument ``ctx``. If expire is
337 unset the default is taken from :py:obj:`ExpireCacheCfg.MAXHOLD_TIME`.
338 If ``ctx`` argument is ``None`` (the default), a table name is
339 generated from the :py:obj:`ExpireCacheCfg.name`. If DB table does not
340 exists, it will be created (on demand) by :py:obj:`self.create_table
341 <ExpireCacheSQLite.create_table>`.
342 """
343 table = ctx
344 self.maintenance()
345
346 value = self.serialize(value=value)
347 if len(value) > self.cfg.MAX_VALUE_LEN:
348 log.warning("ExpireCache.set(): %s.key='%s' - value too big to cache (len: %s) ", table, value, len(value))
349 return False
350
351 if not expire:
352 expire = self.cfg.MAXHOLD_TIME
353 expire = int(time.time()) + expire
354
355 table_name = table
356 if not table_name:
357 table_name = self.normalize_name(self.cfg.name)
358 self.create_table(table_name)
359
360 sql = (
361 f"INSERT INTO {table_name} (key, value, expire) VALUES (?, ?, ?)"
362 f" ON CONFLICT DO "
363 f"UPDATE SET value=?, expire=?"
364 )
365
366 if table:
367 with self.DB:
368 self.DB.execute(sql, (key, value, expire, value, expire))
369 else:
370 with self.connect() as conn:
371 conn.execute(sql, (key, value, expire, value, expire))
372 conn.close()
373
374 return True
375

References searx.botdetection.config.Config.cfg, cfg, create_table(), searx.cache.ExpireCache.maintenance(), searx.cache.ExpireCache.normalize_name(), and searx.cache.ExpireCache.serialize().

Referenced by create_table().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ state()

ExpireCacheStats searx.cache.ExpireCacheSQLite.state ( self)
Returns a :py:obj:`ExpireCacheStats`, which provides information
about the status of the cache.

Reimplemented from searx.cache.ExpireCache.

Definition at line 399 of file cache.py.

399 def state(self) -> ExpireCacheStats:
400 cached_items = {}
401 for table in self.table_names:
402 cached_items[table] = []
403 for row in self.DB.execute(f"SELECT key, value, expire FROM {table}"):
404 cached_items[table].append((row[0], self.deserialize(row[1]), row[2]))
405 return ExpireCacheStats(cached_items=cached_items)

References DB, searx.cache.ExpireCache.deserialize(), and table_names.

+ Here is the call graph for this function:

◆ table_names()

list[str] searx.cache.ExpireCacheSQLite.table_names ( self)
List of key/value tables already created in the DB.

Definition at line 313 of file cache.py.

313 def table_names(self) -> list[str]:
314 """List of key/value tables already created in the DB."""
315 sql = f"SELECT value FROM properties WHERE name LIKE '{self.CACHE_TABLE_PREFIX}%%'"
316 rows = self.DB.execute(sql).fetchall() or []
317 return [r[0] for r in rows]
318

References DB.

◆ truncate_tables()

searx.cache.ExpireCacheSQLite.truncate_tables ( self,
list[str] table_names )

Definition at line 319 of file cache.py.

319 def truncate_tables(self, table_names: list[str]):
320 log.debug("truncate table: %s", ",".join(table_names))
321 with self.connect() as conn:
322 for table in table_names:
323 conn.execute(f"DELETE FROM {table}")
324 conn.close()
325 return True
326

References searx.sqlitedb.SQLiteAppl.connect().

+ Here is the call graph for this function:

Member Data Documentation

◆ CACHE_TABLE_PREFIX

str searx.cache.ExpireCacheSQLite.CACHE_TABLE_PREFIX = "CACHE-TABLE-"
static

Definition at line 229 of file cache.py.

◆ cfg

◆ next_maintenance_time

searx.cache.ExpireCacheSQLite.next_maintenance_time

Definition at line 257 of file cache.py.

Referenced by searx.favicons.cache.FaviconCacheSQLite.set().

◆ table_names

searx.cache.ExpireCacheSQLite.table_names

Definition at line 266 of file cache.py.

Referenced by create_table(), get(), and state().


The documentation for this class was generated from the following file: