USER adrian REVISION 2287 3f0790d500a9 false DATE 2006-02-24 LINE 1 CONTENT "Database cache backend." jezdez 16338 bf038debb499 false 2011-07-13 2 import base64 jezdez 16338 bf038debb499 false 2011-07-13 3 import time jezdez 16338 bf038debb499 false 2011-07-13 4 from datetime import datetime adrian 2287 3f0790d500a9 false 2006-02-24 2 adrian 2287 3f0790d500a9 false 2006-02-24 7 try: adrian 2287 3f0790d500a9 false 2006-02-24 8 import cPickle as pickle adrian 2287 3f0790d500a9 false 2006-02-24 9 except ImportError: adrian 2287 3f0790d500a9 false 2006-02-24 10 import pickle adrian 2287 3f0790d500a9 false 2006-02-24 11 jezdez 16338 bf038debb499 false 2011-07-13 11 from django.core.cache.backends.base import BaseCache jezdez 16338 bf038debb499 false 2011-07-13 12 from django.db import connections, router, transaction, DatabaseError jezdez 16338 bf038debb499 false 2011-07-13 13 jezdez 16338 bf038debb499 false 2011-07-13 14 russellm 13275 4dd52d4f3f50 false 2010-08-05 12 class Options(object): russellm 13275 4dd52d4f3f50 false 2010-08-05 13 """A class that will quack like a Django model _meta class. russellm 13275 4dd52d4f3f50 false 2010-08-05 14 russellm 13275 4dd52d4f3f50 false 2010-08-05 15 This allows cache operations to be controlled by the router russellm 13275 4dd52d4f3f50 false 2010-08-05 16 """ russellm 13275 4dd52d4f3f50 false 2010-08-05 17 def __init__(self, table): russellm 13275 4dd52d4f3f50 false 2010-08-05 18 self.db_table = table russellm 13275 4dd52d4f3f50 false 2010-08-05 19 self.app_label = 'django_cache' russellm 13275 4dd52d4f3f50 false 2010-08-05 20 self.module_name = 'cacheentry' russellm 13275 4dd52d4f3f50 false 2010-08-05 21 self.verbose_name = 'cache entry' russellm 13275 4dd52d4f3f50 false 2010-08-05 22 self.verbose_name_plural = 'cache entries' russellm 13275 4dd52d4f3f50 false 2010-08-05 23 self.object_name = 'CacheEntry' russellm 13275 4dd52d4f3f50 false 2010-08-05 24 self.abstract = False russellm 13275 4dd52d4f3f50 false 2010-08-05 25 self.managed = True russellm 13275 4dd52d4f3f50 false 2010-08-05 26 self.proxy = False russellm 13275 4dd52d4f3f50 false 2010-08-05 27 russellm 14807 905c4a7e1f19 false 2010-12-21 28 class BaseDatabaseCache(BaseCache): russellm 14807 905c4a7e1f19 false 2010-12-21 29 def __init__(self, table, params): russellm 14807 905c4a7e1f19 false 2010-12-21 30 BaseCache.__init__(self, params) russellm 13275 4dd52d4f3f50 false 2010-08-05 31 self._table = table russellm 13275 4dd52d4f3f50 false 2010-08-05 32 russellm 13275 4dd52d4f3f50 false 2010-08-05 33 class CacheEntry(object): russellm 13275 4dd52d4f3f50 false 2010-08-05 34 _meta = Options(table) russellm 13275 4dd52d4f3f50 false 2010-08-05 35 self.cache_model_class = CacheEntry russellm 13275 4dd52d4f3f50 false 2010-08-05 36 russellm 14807 905c4a7e1f19 false 2010-12-21 37 class DatabaseCache(BaseDatabaseCache): russellm 14425 793e94ba2037 false 2010-11-19 38 def get(self, key, default=None, version=None): russellm 14425 793e94ba2037 false 2010-11-19 39 key = self.make_key(key, version=version) mtredinnick 13568 7e0b7bf098d2 false 2010-09-12 49 self.validate_key(key) russellm 13275 4dd52d4f3f50 false 2010-08-05 49 db = router.db_for_read(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 50 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 51 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 52 russellm 13275 4dd52d4f3f50 false 2010-08-05 53 cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % table, [key]) adrian 2287 3f0790d500a9 false 2006-02-24 30 row = cursor.fetchone() adrian 2287 3f0790d500a9 false 2006-02-24 31 if row is None: adrian 2287 3f0790d500a9 false 2006-02-24 32 return default adrian 2287 3f0790d500a9 false 2006-02-24 33 now = datetime.now() adrian 2287 3f0790d500a9 false 2006-02-24 34 if row[2] < now: russellm 13275 4dd52d4f3f50 false 2010-08-05 59 db = router.db_for_write(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 60 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 61 cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key]) russellm 13275 4dd52d4f3f50 false 2010-08-05 62 transaction.commit_unless_managed(using=db) adrian 2287 3f0790d500a9 false 2006-02-24 37 return default russellm 13275 4dd52d4f3f50 false 2010-08-05 64 value = connections[db].ops.process_clob(row[1]) ikelly 9862 8739c35149dd false 2009-03-13 39 return pickle.loads(base64.decodestring(value)) adrian 2287 3f0790d500a9 false 2006-02-24 39 russellm 14425 793e94ba2037 false 2010-11-19 59 def set(self, key, value, timeout=None, version=None): russellm 14425 793e94ba2037 false 2010-11-19 60 key = self.make_key(key, version=version) mtredinnick 13568 7e0b7bf098d2 false 2010-09-12 69 self.validate_key(key) mtredinnick 8110 c787c7f62142 false 2008-08-10 41 self._base_set('set', key, value, timeout) mtredinnick 6421 b4175804cc7b false 2007-10-20 45 russellm 14425 793e94ba2037 false 2010-11-19 64 def add(self, key, value, timeout=None, version=None): russellm 14425 793e94ba2037 false 2010-11-19 65 key = self.make_key(key, version=version) mtredinnick 13568 7e0b7bf098d2 false 2010-09-12 73 self.validate_key(key) mtredinnick 6438 5096a56a9ac6 false 2007-10-21 44 return self._base_set('add', key, value, timeout) mtredinnick 6438 5096a56a9ac6 false 2007-10-21 45 mtredinnick 6421 b4175804cc7b false 2007-10-20 46 def _base_set(self, mode, key, value, timeout=None): adrian 2287 3f0790d500a9 false 2006-02-24 41 if timeout is None: adrian 2287 3f0790d500a9 false 2006-02-24 42 timeout = self.default_timeout russellm 13275 4dd52d4f3f50 false 2010-08-05 76 db = router.db_for_write(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 77 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 78 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 79 russellm 13275 4dd52d4f3f50 false 2010-08-05 80 cursor.execute("SELECT COUNT(*) FROM %s" % table) adrian 2287 3f0790d500a9 false 2006-02-24 45 num = cursor.fetchone()[0] adrian 2287 3f0790d500a9 false 2006-02-24 46 now = datetime.now().replace(microsecond=0) adrian 2287 3f0790d500a9 false 2006-02-24 47 exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0) adrian 2287 3f0790d500a9 false 2006-02-24 48 if num > self._max_entries: russellm 13275 4dd52d4f3f50 false 2010-08-05 85 self._cull(db, cursor, now) adrian 2287 3f0790d500a9 false 2006-02-24 50 encoded = base64.encodestring(pickle.dumps(value, 2)).strip() russellm 13275 4dd52d4f3f50 false 2010-08-05 87 cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % table, [key]) adrian 2287 3f0790d500a9 false 2006-02-24 52 try: mtredinnick 9753 0ab5ef23e1bc false 2009-03-02 59 result = cursor.fetchone() mtredinnick 9753 0ab5ef23e1bc false 2009-03-02 60 if result and (mode == 'set' or mtredinnick 9753 0ab5ef23e1bc false 2009-03-02 61 (mode == 'add' and result[1] < now)): russellm 13275 4dd52d4f3f50 false 2010-08-05 92 cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % table, russellm 13275 4dd52d4f3f50 false 2010-08-05 93 [encoded, connections[db].ops.value_to_db_datetime(exp), key]) adrian 2287 3f0790d500a9 false 2006-02-24 55 else: russellm 13275 4dd52d4f3f50 false 2010-08-05 95 cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % table, russellm 13275 4dd52d4f3f50 false 2010-08-05 96 [key, encoded, connections[db].ops.value_to_db_datetime(exp)]) adrian 2287 3f0790d500a9 false 2006-02-24 57 except DatabaseError: adrian 2287 3f0790d500a9 false 2006-02-24 58 # To be threadsafe, updates/inserts are allowed to fail silently russellm 13275 4dd52d4f3f50 false 2010-08-05 99 transaction.rollback_unless_managed(using=db) mtredinnick 8110 c787c7f62142 false 2008-08-10 65 return False adrian 2287 3f0790d500a9 false 2006-02-24 60 else: russellm 13275 4dd52d4f3f50 false 2010-08-05 102 transaction.commit_unless_managed(using=db) mtredinnick 8110 c787c7f62142 false 2008-08-10 68 return True adrian 2287 3f0790d500a9 false 2006-02-24 62 russellm 14425 793e94ba2037 false 2010-11-19 101 def delete(self, key, version=None): russellm 14425 793e94ba2037 false 2010-11-19 102 key = self.make_key(key, version=version) mtredinnick 13568 7e0b7bf098d2 false 2010-09-12 109 self.validate_key(key) russellm 14425 793e94ba2037 false 2010-11-19 104 russellm 13275 4dd52d4f3f50 false 2010-08-05 106 db = router.db_for_write(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 107 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 108 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 109 russellm 13275 4dd52d4f3f50 false 2010-08-05 110 cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key]) russellm 13275 4dd52d4f3f50 false 2010-08-05 111 transaction.commit_unless_managed(using=db) adrian 2287 3f0790d500a9 false 2006-02-24 67 russellm 14425 793e94ba2037 false 2010-11-19 112 def has_key(self, key, version=None): russellm 14425 793e94ba2037 false 2010-11-19 113 key = self.make_key(key, version=version) mtredinnick 13568 7e0b7bf098d2 false 2010-09-12 118 self.validate_key(key) russellm 14425 793e94ba2037 false 2010-11-19 115 russellm 13275 4dd52d4f3f50 false 2010-08-05 114 db = router.db_for_read(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 115 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 116 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 117 mtredinnick 9753 0ab5ef23e1bc false 2009-03-02 78 now = datetime.now().replace(microsecond=0) russellm 13275 4dd52d4f3f50 false 2010-08-05 119 cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % table, russellm 13275 4dd52d4f3f50 false 2010-08-05 120 [key, connections[db].ops.value_to_db_datetime(now)]) adrian 2287 3f0790d500a9 false 2006-02-24 71 return cursor.fetchone() is not None adrian 2287 3f0790d500a9 false 2006-02-24 72 russellm 13275 4dd52d4f3f50 false 2010-08-05 123 def _cull(self, db, cursor, now): adrian 2287 3f0790d500a9 false 2006-02-24 74 if self._cull_frequency == 0: russellm 12116 c1ad14c551a9 false 2010-01-27 87 self.clear() adrian 2287 3f0790d500a9 false 2006-02-24 76 else: russellm 13480 7351411944a9 false 2010-08-31 127 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 127 cursor.execute("DELETE FROM %s WHERE expires < %%s" % table, russellm 13275 4dd52d4f3f50 false 2010-08-05 128 [connections[db].ops.value_to_db_datetime(now)]) russellm 13275 4dd52d4f3f50 false 2010-08-05 129 cursor.execute("SELECT COUNT(*) FROM %s" % table) adrian 2287 3f0790d500a9 false 2006-02-24 79 num = cursor.fetchone()[0] adrian 2287 3f0790d500a9 false 2006-02-24 80 if num > self._max_entries: russellm 13275 4dd52d4f3f50 false 2010-08-05 132 cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % table, [num / self._cull_frequency]) russellm 13275 4dd52d4f3f50 false 2010-08-05 133 cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % table, [cursor.fetchone()[0]]) russellm 12116 c1ad14c551a9 false 2010-01-27 95 russellm 12116 c1ad14c551a9 false 2010-01-27 96 def clear(self): russellm 13275 4dd52d4f3f50 false 2010-08-05 136 db = router.db_for_write(self.cache_model_class) russellm 13275 4dd52d4f3f50 false 2010-08-05 137 table = connections[db].ops.quote_name(self._table) russellm 13275 4dd52d4f3f50 false 2010-08-05 138 cursor = connections[db].cursor() russellm 13275 4dd52d4f3f50 false 2010-08-05 139 cursor.execute('DELETE FROM %s' % table) russellm 14807 905c4a7e1f19 false 2010-12-21 143 russellm 14807 905c4a7e1f19 false 2010-12-21 144 # For backwards compatibility russellm 14807 905c4a7e1f19 false 2010-12-21 145 class CacheClass(DatabaseCache): russellm 14807 905c4a7e1f19 false 2010-12-21 146 pass