diff --git a/isso/__init__.py b/isso/__init__.py index 60149fb..aeaf569 100644 --- a/isso/__init__.py +++ b/isso/__init__.py @@ -180,7 +180,7 @@ def make_app(conf): if uwsgi is not None: cacheobj = cache.uWSGICache(timeout=3600) else: - cacheobj = cache.SACache(dbobj, threshold=2048) + cacheobj = cache.SACache(conf.get("general", "dbpath"), threshold=2048) jobs = tasks.Jobs() jobs.register("db-purge", dbobj, conf.getint("moderation", "purge-after")) diff --git a/isso/cache/sa.py b/isso/cache/sa.py index c70ef70..40c70a3 100644 --- a/isso/cache/sa.py +++ b/isso/cache/sa.py @@ -4,64 +4,79 @@ from __future__ import absolute_import, unicode_literals import time +from sqlalchemy import Table, Column, MetaData, create_engine +from sqlalchemy import Float, String, LargeBinary from sqlalchemy.sql import select, func from . import Base +def get(con, cache, key): + rv = con.execute( + select([cache.c.value]).where( + cache.c.key == key)).fetchone() + + if rv is None: + raise KeyError + + return rv[0] + + +def set(con, cache, key, value, threshold): + cnt = con.execute( + select([func.count(cache)])).fetchone()[0] + + if cnt + 1 > threshold: + con.execute( + cache.delete().where( + cache.c.key.in_(select( + [cache.c.key]) + .order_by(cache.c.time) + .limit(1)))) + + try: + get(con, cache, key) + except KeyError: + insert = True + else: + insert = False + + if insert: + stmt = cache.insert().values(key=key, value=value, time=time.time()) + else: + stmt = cache.update().values(value=value, time=time.time()) \ + .where(cache.c.key == key) + + con.execute(stmt) + + +def delete(con, cache, key): + con.execute(cache.delete(cache.c.key == key)) + + class SACache(Base): """Implements cache using SQLAlchemy Core. - - JSON is used for safe serialization of python primitives. """ serialize = True def __init__(self, db, threshold=1024, timeout=-1): super(SACache, self).__init__(threshold, timeout) - self.db = db + self.metadata = MetaData() + self.engine = create_engine(db) - def _get(self, ns, key): - rv = self.db.engine.execute( - select([self.db.cache.c.value]).where( - self.db.cache.c.key == ns + b'-' + key)).fetchone() + self.cache = Table("cache", self.metadata, + Column("key", String(255), primary_key=True), + Column("value", LargeBinary(65535)), + Column("time", Float)) - if rv is None: - raise KeyError + self.metadata.create_all(self.engine) - return rv[0] + def _get(self, ns, key): + return get(self.engine.connect(), self.cache, ns + b'-' + key) def _set(self, ns, key, value): - with self.db.transaction: - cnt = self.db.engine.execute( - select([func.count(self.db.cache)])).fetchone()[0] - - if cnt + 1 > self.threshold: - self.db.engine.execute( - self.db.cache.delete().where( - self.db.cache.c.key.in_(select( - [self.db.cache.c.key]) - .order_by(self.db.cache.c.time) - .limit(1)))) - - try: - self._get(ns, key) - except KeyError: - insert = True - else: - insert = False - - if insert: - stmt = self.db.cache.insert().values( - key=ns + b'-' + key, value=value, time=time.time()) - else: - stmt = self.db.cache.update().values( - value=value, time=time.time()).where( - self.db.cache.c.key == ns + b'-' + key) - - self.db.engine.execute(stmt) + set(self.engine.connect(), self.cache, ns + b'-' + key, value, self.threshold) def _delete(self, ns, key): - with self.db.transaction: - self.db.engine.execute( - self.db.cache.delete(self.db.cache.c.key == ns + b'-' + key)) + delete(self.engine.connect(), self.cache, ns + b'-' + key) diff --git a/isso/db.py b/isso/db.py index ebaf3d8..c1e4d38 100644 --- a/isso/db.py +++ b/isso/db.py @@ -52,10 +52,6 @@ class Adapter(object): Column("key", String(255), primary_key=True), Column("value", String(255))) - self.cache = Table("cache", self.metadata, - Column("key", String(255), primary_key=True), - Column("value", LargeBinary(65535)), - Column("time", Float)) self.metadata.create_all(self.engine) self.preferences = Preferences(self.engine, preferences)