diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 837158a0a4..187eb0645e 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -293,7 +293,7 @@ SESSION_FILE_PATH = '/tmp/' # Directory to store ses # The cache backend to use. See the docstring in django.core.cache for the # possible values. -CACHE_BACKEND = 'simple://' +CACHE_BACKEND = 'locmem://' CACHE_MIDDLEWARE_KEY_PREFIX = '' CACHE_MIDDLEWARE_SECONDS = 600 diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py index 6da8e883b9..495cc92822 100644 --- a/django/core/cache/__init__.py +++ b/django/core/cache/__init__.py @@ -22,19 +22,28 @@ from django.core.cache.backends.base import InvalidCacheBackendError BACKENDS = { # name for use in settings file --> name of module in "backends" directory 'memcached': 'memcached', - 'simple': 'simple', 'locmem': 'locmem', 'file': 'filebased', 'db': 'db', 'dummy': 'dummy', } +DEPRECATED_BACKENDS = { + # deprecated backend --> replacement module + 'simple': 'locmem', +} + def get_cache(backend_uri): if backend_uri.find(':') == -1: raise InvalidCacheBackendError, "Backend URI must start with scheme://" scheme, rest = backend_uri.split(':', 1) if not rest.startswith('//'): raise InvalidCacheBackendError, "Backend URI must start with scheme://" + if scheme in DEPRECATED_BACKENDS: + import warnings + warnings.warn("'%s' backend is deprecated. Use '%s' instead." % + (scheme, DEPRECATED_BACKENDS[scheme]), DeprecationWarning) + scheme = DEPRECATED_BACKENDS[scheme] if scheme not in BACKENDS: raise InvalidCacheBackendError, "%r is not a valid cache backend" % scheme diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py index 690193ac81..72cb877f6f 100644 --- a/django/core/cache/backends/filebased.py +++ b/django/core/cache/backends/filebased.py @@ -1,21 +1,32 @@ "File-based cache backend" -from django.core.cache.backends.simple import CacheClass as SimpleCacheClass -from django.utils.http import urlquote_plus import os, time try: import cPickle as pickle except ImportError: import pickle +from django.core.cache.backends.base import BaseCache +from django.utils.http import urlquote_plus -class CacheClass(SimpleCacheClass): +class CacheClass(BaseCache): def __init__(self, dir, params): + BaseCache.__init__(self, params) + + max_entries = params.get('max_entries', 300) + try: + self._max_entries = int(max_entries) + except (ValueError, TypeError): + self._max_entries = 300 + + cull_frequency = params.get('cull_frequency', 3) + try: + self._cull_frequency = int(cull_frequency) + except (ValueError, TypeError): + self._cull_frequency = 3 + self._dir = dir if not os.path.exists(self._dir): self._createdir() - SimpleCacheClass.__init__(self, dir, params) - del self._cache - del self._expire_info def add(self, key, value, timeout=None): fname = self._key_to_file(key) diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py index 2d74e2b132..2734cef86a 100644 --- a/django/core/cache/backends/locmem.py +++ b/django/core/cache/backends/locmem.py @@ -6,20 +6,44 @@ try: except ImportError: import pickle -from django.core.cache.backends.simple import CacheClass as SimpleCacheClass +from django.core.cache.backends.base import BaseCache from django.utils.synch import RWLock -class CacheClass(SimpleCacheClass): - def __init__(self, host, params): - SimpleCacheClass.__init__(self, host, params) +class CacheClass(BaseCache): + def __init__(self, _, params): + BaseCache.__init__(self, params) + self._cache = {} + self._expire_info = {} + + max_entries = params.get('max_entries', 300) + try: + self._max_entries = int(max_entries) + except (ValueError, TypeError): + self._max_entries = 300 + + cull_frequency = params.get('cull_frequency', 3) + try: + self._cull_frequency = int(cull_frequency) + except (ValueError, TypeError): + self._cull_frequency = 3 + self._lock = RWLock() + def _add(self, key, value, timeout=None): + if len(self._cache) >= self._max_entries: + self._cull() + if timeout is None: + timeout = self.default_timeout + if key not in self._cache.keys(): + self._cache[key] = value + self._expire_info[key] = time.time() + timeout + def add(self, key, value, timeout=None): self._lock.writer_enters() # Python 2.3 and 2.4 don't allow combined try-except-finally blocks. try: try: - super(CacheClass, self).add(key, pickle.dumps(value), timeout) + self._add(key, pickle.dumps(value), timeout) except pickle.PickleError: pass finally: @@ -51,20 +75,50 @@ class CacheClass(SimpleCacheClass): finally: self._lock.writer_leaves() + def _set(self, key, value, timeout=None): + if len(self._cache) >= self._max_entries: + self._cull() + if timeout is None: + timeout = self.default_timeout + self._cache[key] = value + self._expire_info[key] = time.time() + timeout + def set(self, key, value, timeout=None): self._lock.writer_enters() # Python 2.3 and 2.4 don't allow combined try-except-finally blocks. try: try: - super(CacheClass, self).set(key, pickle.dumps(value), timeout) + self._set(key, pickle.dumps(value), timeout) except pickle.PickleError: pass finally: self._lock.writer_leaves() + def has_key(self, key): + return key in self._cache + + def _cull(self): + if self._cull_frequency == 0: + self._cache.clear() + self._expire_info.clear() + else: + doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0] + for k in doomed: + self.delete(k) + + def _delete(self, key): + try: + del self._cache[key] + except KeyError: + pass + try: + del self._expire_info[key] + except KeyError: + pass + def delete(self, key): self._lock.writer_enters() try: - SimpleCacheClass.delete(self, key) + self._delete(key) finally: self._lock.writer_leaves() diff --git a/django/core/cache/backends/simple.py b/django/core/cache/backends/simple.py deleted file mode 100644 index ff60d49066..0000000000 --- a/django/core/cache/backends/simple.py +++ /dev/null @@ -1,73 +0,0 @@ -"Single-process in-memory cache backend." - -from django.core.cache.backends.base import BaseCache -import time - -class CacheClass(BaseCache): - def __init__(self, host, params): - BaseCache.__init__(self, params) - self._cache = {} - self._expire_info = {} - - max_entries = params.get('max_entries', 300) - try: - self._max_entries = int(max_entries) - except (ValueError, TypeError): - self._max_entries = 300 - - cull_frequency = params.get('cull_frequency', 3) - try: - self._cull_frequency = int(cull_frequency) - except (ValueError, TypeError): - self._cull_frequency = 3 - - def add(self, key, value, timeout=None): - if len(self._cache) >= self._max_entries: - self._cull() - if timeout is None: - timeout = self.default_timeout - if key not in self._cache.keys(): - self._cache[key] = value - self._expire_info[key] = time.time() + timeout - - def get(self, key, default=None): - now = time.time() - exp = self._expire_info.get(key) - if exp is None: - return default - elif exp < now: - del self._cache[key] - del self._expire_info[key] - return default - else: - return self._cache[key] - - def set(self, key, value, timeout=None): - if len(self._cache) >= self._max_entries: - self._cull() - if timeout is None: - timeout = self.default_timeout - self._cache[key] = value - self._expire_info[key] = time.time() + timeout - - def delete(self, key): - try: - del self._cache[key] - except KeyError: - pass - try: - del self._expire_info[key] - except KeyError: - pass - - def has_key(self, key): - return key in self._cache - - def _cull(self): - if self._cull_frequency == 0: - self._cache.clear() - self._expire_info.clear() - else: - doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0] - for k in doomed: - self.delete(k) diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py index e94ea33139..9ac2722b0a 100644 --- a/tests/regressiontests/cache/tests.py +++ b/tests/regressiontests/cache/tests.py @@ -72,6 +72,8 @@ class Cache(unittest.TestCase): 'function' : f, 'class' : C, } + cache.set("stuff", stuff) + self.assertEqual(cache.get("stuff"), stuff) def test_expiration(self): # expiration