dogpile.cache-dict-config / docs / build / usage.rst

zzzeek b91b2ce 

zzzeek e87b051 

zzzeek b91b2ce 

zzzeek e87b051 
zzzeek b91b2ce 

zzzeek e87b051 
zzzeek b91b2ce 

zzzeek e87b051 

zzzeek b91b2ce 

zzzeek e87b051 
Mike Bayer bf5be08 
zzzeek b91b2ce 

zzzeek e87b051 
zzzeek b91b2ce 
Mike Bayer bf5be08 
zzzeek b91b2ce 

zzzeek e87b051 
zzzeek b91b2ce 

zzzeek e87b051 

Mike Bayer b4b1b54 
zzzeek e87b051 

zzzeek b91b2ce 

Mike Bayer b4b1b54 

zzzeek e87b051 
zzzeek b91b2ce 

zzzeek e87b051 

zzzeek b91b2ce 

Mike Bayer bf5be08 
zzzeek b91b2ce 

Mike Bayer 8a6571a 

zzzeek e87b051 

zzzeek b91b2ce 
zzzeek e87b051 

Mike Bayer bf5be08 
zzzeek e87b051 

Mike Bayer bf5be08 
zzzeek e87b051 

Usage Guide

.. note:: dogpile.cache is **not released or completed** at this time.   Development
   is currently in progress and the current code is not yet functional.


At the time of this writing, popular key/value servers include 
`Memcached <>`_, `Redis <>`_, and `Riak <>`_.
While these tools all have different usage focuses, they all have in common that the storage model
is based on the retrieval of a value based on a key; as such, they are all potentially
suitable for caching, particularly Memcached which is first and foremost designed for

With a caching system in mind, dogpile.cache provides an interface to a particular Python API
targeted at that system.  In this document, we'll illustrate Memcached usage 
using the `pylibmc <>`_ backend, which is a high performing 
Python library for Memcached.  It can be compared to the `python-memcached <>`_
client, which is also an excellent product.  Pylibmc is written against Memcached's native API
so is markedly faster, though might be considered to have rougher edges.   The API is actually a bit 
more verbose to allow for correct multithreaded usage.

A dogpile.cache configuration consists of the following components:

* A *region*, which is an instance of :class:`.CacheRegion`, and defines the configuration
  details for a particular cache backend.  The :class:`.CacheRegion` can be considered
  the "front end" used by applications.
* A *backend*, which is an instance of :class:`.CacheBackend`, describing how values
  are stored and retrieved from a backend.  This interface specifies only
  :meth:`~.CacheBackend.get`, :meth:`~.CacheBackend.set` and :meth:`~.CacheBackend.delete`.
  The actual kind of :class:`.CacheBackend` in use for a particular :class:`.CacheRegion`
  is determined by the underlying Python API being used to talk to the cache, such
  as Pylibmc.  The :class:`.CacheBackend` is instantiated behind the scenes and 
  not directly accessed by applications under normal circumstances.
* Value generation functions.   These are user-defined functions that generate
  new values to be placed in the cache.   While dogpile.cache offers the usual
  "set" approach of placing data into the cache, the usual mode of usage is to only instruct
  it to "get" a value, passing it a *creation function* which will be used to 
  generate a new value if and only if one is needed.   This "get-or-create" pattern
  is the entire key to the "Dogpile" system, which coordinates a single value creation 
  operation among many concurrent get operations for a particular key, eliminating
  the issue of an expired value being redundantly re-generated by many workers simultaneously.

Rudimentary Usage

dogpile.cache includes a Pylibmc backend.  A basic configuration looks like::

    from dogpile.cache import make_region

    region = make_region().configure(
        expiration_time = 3600,
        arguments = {

    def load_user_info(user_id):
        return some_database.lookup_user_by_id(user_id)

Above, we create a :class:`.CacheRegion` using the :func:`.make_region` function, then
apply the backend configuration via the :meth:`.CacheRegion.configure` method, which returns the 
region.  The name of the backend is the only argument required by :meth:`.CacheRegion.configure`
itself, in this case ``dogpile.cache.pylibmc``.  However, in this specific case, the ``pylibmc`` 
backend also requires that the URL of the memcached server be passed within the ``arguments`` dictionary.

The configuration is separated into two sections.  Upon construction via :func:`.make_region`,
the :class:`.CacheRegion` object is available, typically at module
import time, for usage in decorating functions.   Additional configuration details passed to
:meth:`.CacheRegion.configure` are typically loaded from a configuration file and therefore
not necessarily available until runtime, hence the two-step configurational process.

Key arguments passed to :meth:`.CacheRegion.configure` include *expiration_time*, which is the expiration 
time passed to the Dogpile lock, and *arguments*, which are arguments used directly
by the backend - in this case we are using arguments that are passed directly
to the pylibmc module.

Region Configuration

The :func:`.make_region` function currently calls the :class:`.CacheRegion` constructor directly.

.. autoclass:: dogpile.cache.region.CacheRegion

One you have a :class:`.CacheRegion`, the :meth:`.CacheRegion.cache_on_arguments` method can
be used to decorate functions, but the cache itself can't be used until
:meth:`.CacheRegion.configure` is called.  The interface for that method is as follows:

.. automethod:: dogpile.cache.region.CacheRegion.configure

The :class:`.CacheRegion` can also be configured from a dictionary, using the :meth:`.CacheRegion.configure_from_config`

.. automethod:: dogpile.cache.region.CacheRegion.configure_from_config

Using a Region

The :class:`.CacheRegion` object is our front-end interface to a cache.  It includes
the following methods:

.. automethod:: dogpile.cache.region.CacheRegion.get

.. automethod:: dogpile.cache.region.CacheRegion.get_or_create

.. automethod:: dogpile.cache.region.CacheRegion.set

.. automethod:: dogpile.cache.region.CacheRegion.delete

.. automethod:: dogpile.cache.region.CacheRegion.cache_on_arguments

.. _creating_backends:

Creating Backends

Backends are located using the setuptools entrypoint system.  To make life easier
for writers of ad-hoc backends, a helper function is included which registers any
backend in the same way as if it were part of the existing sys.path.

For example, to create a backend called ``DictionaryBackend``, we subclass

    from dogpile.cache import CacheBackend, NO_VALUE

    class DictionaryBackend(CacheBackend):
        def __init__(self, arguments):
            self.cache = {}

        def get(self, key):
            return self.cache.get(key, NO_VALUE)

        def set(self, key, value):
            self.cache[key] = value

        def delete(self, key):

Then make sure the class is available underneath the entrypoint
``dogpile.cache``.  If we did this in a ```` file, it would be 
in ``setup()`` as::

      dictionary = mypackage.mybackend:DictionaryBackend

Alternatively, if we want to register the plugin in the same process 
space without bothering to install anything, we can use ``register_backend``::

    from dogpile.cache import register_backend

    register_backend("dictionary", "mypackage.mybackend", "DictionaryBackend")

Our new backend would be usable in a region like this::

    from dogpile.cache import make_region

    region = make_region("dictionary")

    data = region.set("somekey", "somevalue")

The values we receive for the backend here are instances of
``CachedValue``.  This is a tuple subclass of length two, of the form::

    (payload, metadata)

Where "payload" is the thing being cached, and "metadata" is information
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.