web/lib/django/core/cache/backends/db.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 "Database cache backend."
       
     2 
       
     3 from django.core.cache.backends.base import BaseCache
       
     4 from django.db import connection, transaction, DatabaseError
       
     5 import base64, time
       
     6 from datetime import datetime
       
     7 try:
       
     8     import cPickle as pickle
       
     9 except ImportError:
       
    10     import pickle
       
    11 
       
    12 class CacheClass(BaseCache):
       
    13     def __init__(self, table, params):
       
    14         BaseCache.__init__(self, params)
       
    15         self._table = table
       
    16         max_entries = params.get('max_entries', 300)
       
    17         try:
       
    18             self._max_entries = int(max_entries)
       
    19         except (ValueError, TypeError):
       
    20             self._max_entries = 300
       
    21         cull_frequency = params.get('cull_frequency', 3)
       
    22         try:
       
    23             self._cull_frequency = int(cull_frequency)
       
    24         except (ValueError, TypeError):
       
    25             self._cull_frequency = 3
       
    26 
       
    27     def get(self, key, default=None):
       
    28         cursor = connection.cursor()
       
    29         cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
       
    30         row = cursor.fetchone()
       
    31         if row is None:
       
    32             return default
       
    33         now = datetime.now()
       
    34         if row[2] < now:
       
    35             cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
       
    36             transaction.commit_unless_managed()
       
    37             return default
       
    38         value = connection.ops.process_clob(row[1])
       
    39         return pickle.loads(base64.decodestring(value))
       
    40 
       
    41     def set(self, key, value, timeout=None):
       
    42         self._base_set('set', key, value, timeout)
       
    43 
       
    44     def add(self, key, value, timeout=None):
       
    45         return self._base_set('add', key, value, timeout)
       
    46 
       
    47     def _base_set(self, mode, key, value, timeout=None):
       
    48         if timeout is None:
       
    49             timeout = self.default_timeout
       
    50         cursor = connection.cursor()
       
    51         cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
       
    52         num = cursor.fetchone()[0]
       
    53         now = datetime.now().replace(microsecond=0)
       
    54         exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0)
       
    55         if num > self._max_entries:
       
    56             self._cull(cursor, now)
       
    57         encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
       
    58         cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
       
    59         try:
       
    60             result = cursor.fetchone()
       
    61             if result and (mode == 'set' or
       
    62                     (mode == 'add' and result[1] < now)):
       
    63                 cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key])
       
    64             else:
       
    65                 cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)])
       
    66         except DatabaseError:
       
    67             # To be threadsafe, updates/inserts are allowed to fail silently
       
    68             transaction.rollback()
       
    69             return False
       
    70         else:
       
    71             transaction.commit_unless_managed()
       
    72             return True
       
    73 
       
    74     def delete(self, key):
       
    75         cursor = connection.cursor()
       
    76         cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
       
    77         transaction.commit_unless_managed()
       
    78 
       
    79     def has_key(self, key):
       
    80         now = datetime.now().replace(microsecond=0)
       
    81         cursor = connection.cursor()
       
    82         cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % self._table, [key, now])
       
    83         return cursor.fetchone() is not None
       
    84 
       
    85     def _cull(self, cursor, now):
       
    86         if self._cull_frequency == 0:
       
    87             cursor.execute("DELETE FROM %s" % self._table)
       
    88         else:
       
    89             cursor.execute("DELETE FROM %s WHERE expires < %%s" % self._table, [str(now)])
       
    90             cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
       
    91             num = cursor.fetchone()[0]
       
    92             if num > self._max_entries:
       
    93                 cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % self._table, [num / self._cull_frequency])
       
    94                 cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % self._table, [cursor.fetchone()[0]])