Anonymous committed 0ee7467

- doc fixes, simplify serialization
- think about key mangling and cache versions

Comments (0)

Files changed (4)

     (payload, metadata)
 Where "payload" is the thing being cached, and "metadata" is information
-we store in the cache regarding the created time, expiration time.  The
-tuple can be pickled assuming the payload is pickleable, or to get a serialized
-version of just the metadata, you can call the ``serialized_metadata`` accessor,
-which is then turned back into a ``CachedValue`` via the ``deserialize``
-    from dogpile.cache.backend import CachedValue
-    def get(self, key):
-        my_cached_value = my_cache.get(key)
-        serialized_metadata, payload = my_cached_value.split("|")
-        return CachedValue.deserialize(payload, serialized_metadata)
-    def put(self, key, value):
-        my_value_to_cache = value.serialized_metadata + "|" + repr(value.payload)
-        my_cache.put(key, my_value_to_cache)
+we store in the cache - a dictionary which currently has just the "creation time"
+and a "version identifier" as key/values.  If the cache backend requires serialization, 
+pickle or similar can be used on the tuple - the "metadata" portion will always
+be a small and easily serializable Python structure.
 Region Arguments


 class CacheBackend(object):
     """Base class for backend implementations."""
+    key_mangler = None
+    """Key mangling function.  
+    May be None.
+    """
     def __init__(self, arguments):
         """Construct a new :class:`.CacheBackend`.


+from dogpile import Dogpile, NeedRegenerationException
 from dogpile.cache.util import function_key_generator, PluginLoader
+from dogpile.cache.api import NO_VALUE, CachedValue
+import time
 _backend_loader = PluginLoader("dogpile.cache")
 register_backend = _backend_loader.register
 import backends
+value_version = 1
+"""An integer placed in the :class:`.CachedValue`
+so that new versions of dogpile.cache can detect cached
+values from a previous, backwards-incompatible version.
 class CacheRegion(object):
     """A front end to a particular cache backend."""
     def __init__(self, name, 
-            function_key_generator=function_key_generator
+            function_key_generator=function_key_generator,
         """Construct a new :class:`.CacheRegion`.
         :function_key_generator: Key generator used by
         :key_mangler: Function which will be used on all incoming
-         keys before passing to the backend.  Defaults to ``None``.
-         A simple key mangler is the SHA1 mangler function
-         found at :meth:`.sha1_mangle_key`.
+         keys before passing to the backend.  Defaults to ``None``,
+         in which case the key mangling function recommended by
+         the cache backend will be used.    A typical mangler
+         is the SHA1 mangler found at found at :meth:`.sha1_mangle_key` 
+         which coerces keys into a SHA1
+         hash, so that the string length is fixed.  To
+         disable all key mangling, set to ``False``.
         self.backend = _backend_loader.load(name)(arguments)
         self.function_key_generator = function_key_generator
-        self.key_mangler = key_mangler
+        if key_mangler:
+            self.key_mangler = key_mangler
+        elif key_mangler is False:
+            self.key_mangler = None
+        else:
+            self.key_mangler = backend.key_mangler
         self.dogpile_registry = Dogpile.registry(expiration_time)
     def get(self, key):
         def get_value():
             value = self.backend.get(key)
-            if value is NO_VALUE:
+            if value is NO_VALUE or \
+                value.metadata['version'] != value_version:
                 raise NeedRegenerationException()
             return value.payload, value.metadata["creation_time"]
         def gen_value():
-            value = CachedValue(creator(), {"creation_time":time.time()})
+            value = CachedValue(
+                        creator(), 
+                        {
+                            "creation_time":time.time(), 
+                            "version":value_version
+                        })
             self.backend.put(key, value)
             return value


                 self.impls[name] = impl.load
                 return impl.load()
-                raise exceptions.RuntimeException(
+                raise Exception(
                         "Can't load plugin %s %s" % 
                         (, name))
     if kls:
         namespace = '%s.%s' % (kls.__module__, kls.__name__)
-        namespace = '%s|%s' % (inspect.getsourcefile(func), func.__name__)
+        namespace = '%s|%s' % (inspect.getsourcefile(fn), fn.__name__)
-    args = inspect.getargspec(func)
+    args = inspect.getargspec(fn)
     has_self = args[0] and args[0][0] in ('self', 'cls')
     def generate_key(*args, **kw):
         if kw:
                     "function does not accept keyword arguments.")
         if has_self:
             args = args[1:]
-        return  " ".join(map(unicode, deco_args + args))
+        return namespace + "|" + " ".join(map(unicode, args))
     return generate_key
 def sha1_mangle_key(key):
     """a SHA1 key mangler."""
     return sha1(key).hexdigest()
+def length_conditional_mangler(length, mangler):
+    """a key mangler that mangles if the length of the key is
+    past a certain threshold.
+    """
+    def mangle(key):
+        if len(key) >= length:
+            return mangler(key)
+        else:
+            return key
+    return mangle