Implemented request-local DB cache

This commit is contained in:
krateng 2022-02-27 02:51:44 +01:00
parent a1ef5a7791
commit af57103300
3 changed files with 43 additions and 16 deletions

View File

@ -10,18 +10,24 @@ from doreah.logging import log
from ..globalconf import malojaconfig
USE_CACHE = True
HIGH_NUMBER = 1000000
cache = lru.LRU(HIGH_NUMBER)
hits, misses = 0, 0
if malojaconfig['USE_GLOBAL_CACHE']:
log("Using global DB Cache")
if malojaconfig['USE_REQUEST_CACHE']:
log("Using request-local DB Cache")
@runhourly
def maintenance():
print_stats()
trim_cache()
if malojaconfig['USE_GLOBAL_CACHE']:
print_stats()
trim_cache()
def print_stats():
log(f"Cache Size: {len(cache)}, System RAM Utilization: {psutil.virtual_memory().percent}%, Cache Hits: {hits}/{hits+misses}")
@ -29,7 +35,7 @@ def print_stats():
def cached_wrapper(inner_func):
if not USE_CACHE: return inner_func
if not malojaconfig['USE_GLOBAL_CACHE']: return inner_func
def outer_func(*args,**kwargs):
if 'dbconn' in kwargs:
conn = kwargs.pop('dbconn')
@ -53,15 +59,16 @@ def cached_wrapper(inner_func):
def invalidate_caches(scrobbletime):
cleared, kept = 0, 0
for k in cache.keys():
# VERY BIG TODO: differentiate between None as in 'unlimited timerange' and None as in 'time doesnt matter here'!
if (k[3] is None or scrobbletime >= k[3]) and (k[4] is None or scrobbletime <= k[4]):
cleared += 1
del cache[k]
else:
kept += 1
log(f"Invalidated {cleared} of {cleared+kept} DB cache entries")
if malojaconfig['USE_GLOBAL_CACHE']:
cleared, kept = 0, 0
for k in cache.keys():
# VERY BIG TODO: differentiate between None as in 'unlimited timerange' and None as in 'time doesnt matter here'!
if (k[3] is None or scrobbletime >= k[3]) and (k[4] is None or scrobbletime <= k[4]):
cleared += 1
del cache[k]
else:
kept += 1
log(f"Invalidated {cleared} of {cleared+kept} DB cache entries")

View File

@ -1,12 +1,19 @@
from .. import database
from . sqldb import engine
from .dbcache import serialize
from ..globalconf import malojaconfig
# this is a wrapper object that provides a DB connection so that one jinja page
# (with all its included partials) can use it for all functions
# it also translates the non-unpacked calls to unpacked calls that the DB wants
# it also maintains a request-local cache since many webpages use the same stats
# several times
class JinjaDBConnection:
def __init__(self):
self.cache = {}
def __enter__(self):
self.conn = engine.connect()
return self
@ -19,6 +26,17 @@ class JinjaDBConnection:
kwargs = {}
for k in keys:
kwargs.update(k)
return originalmethod(**kwargs,dbconn=self.conn)
if malojaconfig['USE_REQUEST_CACHE']:
cachekey = serialize((id(originalmethod),kwargs))
if cachekey in self.cache:
return self.cache[cachekey]
else:
result = originalmethod(**kwargs,dbconn=self.conn)
self.cache[cachekey] = result
return result
else:
result = originalmethod(**kwargs,dbconn=self.conn)
return result
return packedmethod

View File

@ -149,7 +149,9 @@ malojaconfig = Configuration(
"Technical":{
"cache_expire_positive":(tp.Integer(), "Image Cache Expiration", 60, "Days until images are refetched"),
"cache_expire_negative":(tp.Integer(), "Image Cache Negative Expiration", 5, "Days until failed image fetches are reattempted"),
"db_max_memory":(tp.Integer(min=0,max=100), "RAM Percentage soft limit", 80, "RAM Usage in percent at which Maloja should no longer increase its database cache.")
"db_max_memory":(tp.Integer(min=0,max=100), "RAM Percentage soft limit", 80, "RAM Usage in percent at which Maloja should no longer increase its database cache."),
"use_request_cache":(tp.Boolean(), "Use request-local DB Cache", True),
"use_global_cache":(tp.Boolean(), "Use global DB Cache", True)
},
"Fluff":{
"scrobbles_gold":(tp.Integer(), "Scrobbles for Gold", 250, "How many scrobbles a track needs to be considered 'Gold' status"),