Fixed #14596 -- Light refactoring of the cache backends.

* Removes some code duplication,
 * Provides a convenient base class for db-like cache backends
 * Adds tests for an edge case of culling,
 * Marks the memcached tests as "skipped", rather than omitting them.

Thanks to Jonas H for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14434 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2010-11-02 05:55:08 +00:00
parent ed51dd5d64
commit 1fc7c4aee4
5 changed files with 38 additions and 55 deletions

View File

@ -22,6 +22,18 @@ class BaseCache(object):
timeout = 300 timeout = 300
self.default_timeout = timeout self.default_timeout = timeout
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): def add(self, key, value, timeout=None):
""" """
Set a value in the cache if the key does not already exist. If Set a value in the cache if the key does not already exist. If

View File

@ -25,7 +25,7 @@ class Options(object):
self.managed = True self.managed = True
self.proxy = False self.proxy = False
class CacheClass(BaseCache): class BaseDatabaseCacheClass(BaseCache):
def __init__(self, table, params): def __init__(self, table, params):
BaseCache.__init__(self, params) BaseCache.__init__(self, params)
self._table = table self._table = table
@ -34,17 +34,7 @@ class CacheClass(BaseCache):
_meta = Options(table) _meta = Options(table)
self.cache_model_class = CacheEntry self.cache_model_class = CacheEntry
max_entries = params.get('max_entries', 300) class CacheClass(BaseDatabaseCacheClass):
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 get(self, key, default=None): def get(self, key, default=None):
self.validate_key(key) self.validate_key(key)
db = router.db_for_read(self.cache_model_class) db = router.db_for_read(self.cache_model_class)

View File

@ -14,19 +14,6 @@ from django.utils.hashcompat import md5_constructor
class CacheClass(BaseCache): class CacheClass(BaseCache):
def __init__(self, dir, params): def __init__(self, dir, params):
BaseCache.__init__(self, 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 self._dir = dir
if not os.path.exists(self._dir): if not os.path.exists(self._dir):
self._createdir() self._createdir()

View File

@ -14,19 +14,6 @@ class CacheClass(BaseCache):
BaseCache.__init__(self, params) BaseCache.__init__(self, params)
self._cache = {} self._cache = {}
self._expire_info = {} 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() self._lock = RWLock()
def add(self, key, value, timeout=None): def add(self, key, value, timeout=None):

View File

@ -410,6 +410,10 @@ class DBCacheTests(unittest.TestCase, BaseCacheTests):
def test_cull(self): def test_cull(self):
self.perform_cull_test(50, 29) self.perform_cull_test(50, 29)
def test_zero_cull(self):
self.cache = get_cache('db://%s?max_entries=30&cull_frequency=0' % self._table_name)
self.perform_cull_test(50, 18)
class LocMemCacheTests(unittest.TestCase, BaseCacheTests): class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
def setUp(self): def setUp(self):
self.cache = get_cache('locmem://?max_entries=30') self.cache = get_cache('locmem://?max_entries=30')
@ -417,12 +421,15 @@ class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
def test_cull(self): def test_cull(self):
self.perform_cull_test(50, 29) self.perform_cull_test(50, 29)
def test_zero_cull(self):
self.cache = get_cache('locmem://?max_entries=30&cull_frequency=0')
self.perform_cull_test(50, 19)
# memcached backend isn't guaranteed to be available. # memcached backend isn't guaranteed to be available.
# To check the memcached backend, the test settings file will # To check the memcached backend, the test settings file will
# need to contain a CACHE_BACKEND setting that points at # need to contain a CACHE_BACKEND setting that points at
# your memcache server. # your memcache server.
if settings.CACHE_BACKEND.startswith('memcached://'): class MemcachedCacheTests(unittest.TestCase, BaseCacheTests):
class MemcachedCacheTests(unittest.TestCase, BaseCacheTests):
def setUp(self): def setUp(self):
self.cache = get_cache(settings.CACHE_BACKEND) self.cache = get_cache(settings.CACHE_BACKEND)
@ -440,7 +447,7 @@ if settings.CACHE_BACKEND.startswith('memcached://'):
self.assertRaises(Exception, self.cache.set, 'key with spaces', 'value') self.assertRaises(Exception, self.cache.set, 'key with spaces', 'value')
# memcached limits key length to 250 # memcached limits key length to 250
self.assertRaises(Exception, self.cache.set, 'a' * 251, 'value') self.assertRaises(Exception, self.cache.set, 'a' * 251, 'value')
MemcachedCacheTests = unittest.skipUnless(settings.CACHE_BACKEND.startswith('memcached://'), "memcached not available")(MemcachedCacheTests)
class FileBasedCacheTests(unittest.TestCase, BaseCacheTests): class FileBasedCacheTests(unittest.TestCase, BaseCacheTests):
""" """