~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/services/memcache/restful.py

[r=abentley, gmb, rockstar,
        jelmer][ui=none] Implement (but don't enable) a Storm and
        memcached-based representation cache for the web service.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Storm/memcached implementation of lazr.restful's representation cache."""
 
5
 
 
6
import storm
 
7
 
 
8
from zope.component import getUtility
 
9
from zope.security.proxy import removeSecurityProxy
 
10
from zope.traversing.browser import absoluteURL
 
11
 
 
12
from canonical.config import config
 
13
from lp.services.memcache.interfaces import IMemcacheClient
 
14
from lazr.restful.simple import BaseRepresentationCache
 
15
from lazr.restful.utils import get_current_web_service_request
 
16
 
 
17
__metaclass__ = type
 
18
__all__ = [
 
19
    'MemcachedStormRepresentationCache',
 
20
]
 
21
 
 
22
 
 
23
class MemcachedStormRepresentationCache(BaseRepresentationCache):
 
24
    """Caches lazr.restful representations of Storm objects in memcached."""
 
25
 
 
26
    def __init__(self):
 
27
        """Initialize with the memcached client."""
 
28
        self.client = getUtility(IMemcacheClient)
 
29
 
 
30
    def key_for(self, obj, media_type, version):
 
31
        """See `BaseRepresentationCache`."""
 
32
        obj = removeSecurityProxy(obj)
 
33
        try:
 
34
            storm_info = storm.info.get_obj_info(obj)
 
35
        except storm.exceptions.ClassInfoError, e:
 
36
            # There's no Storm data for this object. Don't cache it,
 
37
            # since we don't know how to invalidate the cache.
 
38
            return self.DO_NOT_CACHE
 
39
        table_name = storm_info.cls_info.table
 
40
        primary_key = tuple(var.get() for var in storm_info.primary_vars)
 
41
        identifier = table_name + repr(primary_key)
 
42
 
 
43
        key = (identifier
 
44
               + ',' + config._instance_name
 
45
               + ',' + media_type + ',' + str(version)).replace(' ', '.')
 
46
        return key
 
47
 
 
48
    def get_by_key(self, key, default=None):
 
49
        """See `BaseRepresentationCache`."""
 
50
        value = self.client.get(key)
 
51
        if value is None:
 
52
            value = default
 
53
        return value
 
54
 
 
55
    def set_by_key(self, key, value):
 
56
        """See `BaseRepresentationCache`."""
 
57
        self.client.set(
 
58
            key, value,
 
59
            time=config.vhost.api.representation_cache_expiration_time)
 
60
 
 
61
    def delete_by_key(self, key):
 
62
        """See `BaseRepresentationCache`."""
 
63
        self.client.delete(key)