[CalendarServer-changes] [4011] CalendarServer/branches/users/wsanchez/mo-cache

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 13 16:28:20 PDT 2009


Revision: 4011
          http://trac.macosforge.org/projects/calendarserver/changeset/4011
Author:   sagen at apple.com
Date:     2009-04-13 16:28:19 -0700 (Mon, 13 Apr 2009)
Log Message:
-----------
Got unit tests to pass

Modified Paths:
--------------
    CalendarServer/branches/users/wsanchez/mo-cache/memcache.py
    CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/memcacheprops.py
    CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/test/util.py

Modified: CalendarServer/branches/users/wsanchez/mo-cache/memcache.py
===================================================================
--- CalendarServer/branches/users/wsanchez/mo-cache/memcache.py	2009-04-13 20:59:08 UTC (rev 4010)
+++ CalendarServer/branches/users/wsanchez/mo-cache/memcache.py	2009-04-13 23:28:19 UTC (rev 4011)
@@ -49,6 +49,8 @@
 import os
 import re
 import types
+from twistedcaldav.config import config
+
 try:
     import cPickle as pickle
 except ImportError:
@@ -103,7 +105,27 @@
     class local(object):
         pass
 
+class ClientFactory(object):
 
+    # unit tests should set this to True to enable the fake test cache
+    allowTestCache = False
+
+    @classmethod
+    def getClient(cls, servers, debug=0, pickleProtocol=0,
+                 pickler=pickle.Pickler, unpickler=pickle.Unpickler,
+                 pload=None, pid=None):
+
+        if config.Memcached.ClientEnabled:
+            return Client(servers, debug=debug, pickleProtocol=pickleProtocol,
+                pickler=pickler, unpickler=unpickler, pload=pload, pid=pid)
+        elif cls.allowTestCache:
+            return TestClient(servers, debug=debug,
+                pickleProtocol=pickleProtocol, pickler=pickler,
+                unpickler=unpickler, pload=pload, pid=pid)
+        else:
+            return None
+
+
 class Client(local):
     """
     Object representing a pool of memcache servers.
@@ -929,6 +951,157 @@
         return val
 
 
+
+class TestClient(Client):
+    """
+    Fake memcache client for unit tests
+
+    """
+
+    def __init__(self, servers, debug=0, pickleProtocol=0,
+                 pickler=pickle.Pickler, unpickler=pickle.Unpickler,
+                 pload=None, pid=None):
+
+        local.__init__(self)
+
+        super(TestClient, self).__init__(servers, debug=debug,
+            pickleProtocol=pickleProtocol, pickler=pickler, unpickler=unpickler,
+            pload=pload, pid=pid)
+
+        self.data = {}
+        self.token = 0
+
+
+
+    def get_stats(self):
+        raise NotImplementedError()
+
+    def get_slabs(self):
+        raise NotImplementedError()
+
+    def flush_all(self):
+        raise NotImplementedError()
+
+    def forget_dead_hosts(self):
+        raise NotImplementedError()
+
+    def delete_multi(self, keys, time=0, key_prefix=''):
+        '''
+        Delete multiple keys in the memcache doing just one query.
+
+        >>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'})
+        >>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'}
+        1
+        >>> mc.delete_multi(['key1', 'key2'])
+        1
+        >>> mc.get_multi(['key1', 'key2']) == {}
+        1
+        '''
+
+        self._statlog('delete_multi')
+        for key in keys:
+            key = key_prefix + key
+            del self.data[key]
+        return 1
+
+    def delete(self, key, time=0):
+        '''Deletes a key from the memcache.
+
+        @return: Nonzero on success.
+        @param time: number of seconds any subsequent set / update commands should fail. Defaults to 0 for no delay.
+        @rtype: int
+        '''
+        check_key(key)
+        del self.data[key]
+        return 1
+
+
+    def incr(self, key, delta=1):
+        raise NotImplementedError()
+
+    def decr(self, key, delta=1):
+        raise NotImplementedError()
+
+    def add(self, key, val, time = 0, min_compress_len = 0):
+        raise NotImplementedError()
+
+    def append(self, key, val, time=0, min_compress_len=0):
+        raise NotImplementedError()
+
+    def prepend(self, key, val, time=0, min_compress_len=0):
+        raise NotImplementedError()
+
+    def replace(self, key, val, time=0, min_compress_len=0):
+        raise NotImplementedError()
+
+    def set(self, key, val, time=0, min_compress_len=0, token=None):
+        self._statlog('set')
+        return self._set("set", key, val, time, min_compress_len, token=token)
+
+    def set_multi(self, mapping, time=0, key_prefix='', min_compress_len=0):
+        self._statlog('set_multi')
+        for key, val in mapping.iteritems():
+            key = key_prefix + key
+            self._set("set", key, val, time, min_compress_len)
+        return []
+
+    def _set(self, cmd, key, val, time, min_compress_len = 0, token=None):
+        check_key(key)
+        self._statlog(cmd)
+
+        serialized = pickle.dumps(val, pickle.HIGHEST_PROTOCOL)
+
+        if token is not None:
+            if self.data.has_key(key):
+                stored_val, stored_token = self.data[key]
+                if token != stored_token:
+                    return False
+
+        self.data[key] = (serialized, str(self.token))
+        self.token += 1
+
+        return True
+
+    def get(self, key):
+        check_key(key)
+
+        self._statlog('get')
+        if self.data.has_key(key):
+            stored_val, stored_token = self.data[key]
+            val = pickle.loads(stored_val)
+            return val
+        return None
+
+
+    def gets(self, key):
+        check_key(key)
+        if self.data.has_key(key):
+            stored_val, stored_token = self.data[key]
+            val = pickle.loads(stored_val)
+            return (val, stored_token)
+        return (None, None)
+
+    def get_multi(self, keys, key_prefix=''):
+        self._statlog('get_multi')
+
+        results = {}
+        for key in keys:
+            key = key_prefix + key
+            val = self.get(key)
+            results[key] = val
+        return results
+
+    def gets_multi(self, keys, key_prefix=''):
+        self._statlog('gets_multi')
+        results = {}
+        for key in keys:
+            key = key_prefix + key
+            result = self.gets(key)
+            if result[1] is not None:
+                results[key] = result
+        return results
+
+
 class _Host:
     _DEAD_RETRY = 30  # number of seconds before retrying a dead server.
     _SOCKET_TIMEOUT = 3  #  number of seconds before sockets timeout.

Modified: CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/memcacheprops.py
===================================================================
--- CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/memcacheprops.py	2009-04-13 20:59:08 UTC (rev 4010)
+++ CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/memcacheprops.py	2009-04-13 23:28:19 UTC (rev 4011)
@@ -32,7 +32,7 @@
 except ImportError:
     from md5 import new as md5
 
-from memcache import Client as MemcacheClient, MemcacheError
+from memcache import ClientFactory as MemcacheClientFactory, MemcacheError
 
 from twisted.python.filepath import FilePath
 from twisted.web2 import responsecode
@@ -202,12 +202,12 @@
     @classmethod
     def memcacheClient(cls, refresh=False):
         if not hasattr(MemcachePropertyCollection, "_memcacheClient"):
-            if not config.Memcached.ClientEnabled:
-                return None
 
+            # if not config.Memcached.ClientEnabled:
+            #     return None
+
             log.info("Instantiating memcache connection for MemcachePropertyCollection")
-            MemcachePropertyCollection._memcacheClient = MemcacheClient(
-                ["%s:%s" % (config.Memcached.BindAddress, config.Memcached.Port)],
+            MemcachePropertyCollection._memcacheClient = MemcacheClientFactory.getClient(["%s:%s" % (config.Memcached.BindAddress, config.Memcached.Port)],
                 debug=0,
                 pickleProtocol=2,
             )

Modified: CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/test/util.py	2009-04-13 20:59:08 UTC (rev 4010)
+++ CalendarServer/branches/users/wsanchez/mo-cache/twistedcaldav/test/util.py	2009-04-13 23:28:19 UTC (rev 4011)
@@ -25,6 +25,7 @@
 
 from twistedcaldav.config import config
 from twistedcaldav.static import CalDAVFile
+import memcache
 
 import twisted.web2.dav.test.util
 
@@ -40,6 +41,7 @@
         config.DataRoot = dataroot
         config.Memcached.ClientEnabled = False
         config.Memcached.ServerEnabled = False
+        memcache.ClientFactory.allowTestCache = True
 
     def createHierarchy(self, structure):
         root = self.mktemp()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090413/0a430708/attachment-0001.html>


More information about the calendarserver-changes mailing list