SQLite3Cache uses SA now

pull/108/head
Martin Zimmermann 10 years ago
parent 6245a8dc17
commit db9bfddc13

@ -180,7 +180,7 @@ def make_app(conf):
if uwsgi is not None: if uwsgi is not None:
cacheobj = cache.uWSGICache(timeout=3600) cacheobj = cache.uWSGICache(timeout=3600)
else: else:
cacheobj = cache.SQLite3Cache(db.SQLite3("/dev/shm/isso"), threshold=2048) cacheobj = cache.SQLite3Cache(dbobj, threshold=2048)
jobs = queue.Jobs() jobs = queue.Jobs()
jobs.register("db-purge", dbobj, conf.getint("moderation", "purge-after")) jobs.register("db-purge", dbobj, conf.getint("moderation", "purge-after"))

@ -4,42 +4,27 @@ from __future__ import absolute_import, unicode_literals
import time import time
from sqlalchemy.sql import select, func
from . import Base from . import Base
class SQLite3Cache(Base): class SQLite3Cache(Base):
"""Implements a shared cache using SQLite3. Works across multiple processes """Implements cache using SQLAlchemy Core.
and threads, concurrent writes are not supported.
JSON is used to serialize python primitives in a safe way. JSON is used for safe serialization of python primitives.
""" """
serialize = True serialize = True
def __init__(self, connection, threshold=1024, timeout=-1): def __init__(self, db, threshold=1024, timeout=-1):
super(SQLite3Cache, self).__init__(threshold, timeout) super(SQLite3Cache, self).__init__(threshold, timeout)
self.connection = connection self.db = db
self.connection.execute(
'CREATE TABLE IF NOT EXISTS cache (' def _get(self, ns, key):
' key TEXT PRIMARY KEY,' rv = self.db.engine.execute(
' value BLOB,' select([self.db.cache.c.value]).where(
' time FLOAT)') self.db.cache.c.key == ns + b'-' + key)).fetchone()
# drop trigger, in case threshold has changed
self.connection.execute('DROP TRIGGER IF EXISTS sweeper')
self.connection.execute([
'CREATE TRIGGER sweeper AFTER INSERT ON cache',
'BEGIN',
' DELETE FROM cache WHERE key NOT IN ('
' SELECT key FROM cache',
' ORDER BY time DESC LIMIT {0}'.format(threshold),
' );',
'END'])
def _get(self, ns, key, default=None):
rv = self.connection.execute(
'SELECT value FROM cache WHERE key = ?',
(ns + b'-' + key, )).fetchone()
if rv is None: if rv is None:
raise KeyError raise KeyError
@ -47,11 +32,36 @@ class SQLite3Cache(Base):
return rv[0] return rv[0]
def _set(self, ns, key, value): def _set(self, ns, key, value):
with self.connection.transaction as con: with self.db.transaction:
con.execute( cnt = self.db.engine.execute(
'INSERT OR REPLACE INTO cache (key, value, time) VALUES (?, ?, ?)', select([func.count(self.db.cache)])).fetchone()[0]
(ns + b'-' + key, value, time.time()))
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)
def _delete(self, ns, key): def _delete(self, ns, key):
with self.connection.transaction as con: with self.db.transaction:
con.execute('DELETE FROM cache WHERE key = ?', (ns + b'-' + key, )) self.db.engine.execute(
self.db.cache.delete(self.db.cache.c.key == ns + b'-' + key))

@ -50,6 +50,11 @@ class Adapter(object):
Column("key", String(255), primary_key=True), Column("key", String(255), primary_key=True),
Column("value", String(255))) 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.metadata.create_all(self.engine)
self.preferences = Preferences(self.engine, preferences) self.preferences = Preferences(self.engine, preferences)

@ -6,7 +6,7 @@ import unittest
from isso.compat import text_type as str from isso.compat import text_type as str
from isso.db import SQLite3 from isso.db import Adapter
from isso.cache import Cache, SQLite3Cache from isso.cache import Cache, SQLite3Cache
ns = "test" ns = "test"
@ -56,4 +56,4 @@ class TestCache(unittest.TestCase):
class TestSQLite3Cache(TestCache): class TestSQLite3Cache(TestCache):
def setUp(self): def setUp(self):
self.cache = SQLite3Cache(SQLite3(":memory:"), threshold=8) self.cache = SQLite3Cache(Adapter("sqlite:///:memory:"), threshold=8)

Loading…
Cancel
Save