[CalendarServer-changes] [2502] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Mon May 26 09:18:20 PDT 2008


Revision: 2502
          http://trac.macosforge.org/projects/calendarserver/changeset/2502
Author:   cdaboo at apple.com
Date:     2008-05-26 09:18:19 -0700 (Mon, 26 May 2008)

Log Message:
-----------
Allow the Memcacher to use other caching backends. There is now a simple dict based cacher that is used for
single instance servers when memcached is not available. There is a "null" cacher used when memcached is not
available in multi-instance mode (no caching is done).

This allows us to hide the cache availability behind the Memcacher class making the logic a little easier
where ever the class is used. It also allows us to run tests with the full caching logic in place so we
can properly exercise that without the need to have memcached running.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/memcacher.py

Added Paths:
-----------
    CalendarServer/trunk/twistedcaldav/test/test_memcacher.py

Modified: CalendarServer/trunk/twistedcaldav/memcacher.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/memcacher.py	2008-05-26 01:22:56 UTC (rev 2501)
+++ CalendarServer/trunk/twistedcaldav/memcacher.py	2008-05-26 16:18:19 UTC (rev 2502)
@@ -24,6 +24,51 @@
 class Memcacher(LoggingMixIn):
     _memcacheProtocol = None
 
+    class memoryCacher():
+        """
+        A class implementing the memcache client API we care about but
+        using a dict to store the results in memory. This can be used
+        for caching on a single instance server, and for tests, where
+        memcached may not be running.
+        """
+        
+        def __init__(self):
+            self._cache = {}
+
+        def set(self, key, value):
+            self._cache[key] = value
+            return succeed(True)
+            
+        def get(self, key):
+            return succeed((0, self._cache.get(key, None),))
+        
+        def delete(self, key):
+            try:
+                del self._cache[key]
+                return succeed(True)
+            except KeyError:
+                return succeed(False)
+
+    #TODO: an sqlite based cacher that can be used for multiple instance servers
+    # in the absence of memcached. This is not ideal and we may want to not implement
+    # this, but it is being documented for completeness.
+    #
+    # For now we implement a cacher that does not cache.
+    class nullCacher():
+        """
+        A class implementing the memcache client API we care about but
+        does not actually cache anything.
+        """
+        
+        def set(self, key, value):
+            return succeed(True)
+            
+        def get(self, key):
+            return succeed((0, None,))
+        
+        def delete(self, key):
+            return succeed(True)
+
     def __init__(self, namespace):
         self._namespace = namespace
         self._host = config.Memcached['BindAddress']
@@ -34,17 +79,28 @@
 
     def _getMemcacheProtocol(self):
         if Memcacher._memcacheProtocol is not None:
-            return succeed(self._memcacheProtocol)
+            return succeed(Memcacher._memcacheProtocol)
 
-        d = ClientCreator(self._reactor, MemCacheProtocol).connectTCP(
-            self._host,
-            self._port)
+        if config.Memcached['ClientEnabled']:
+            d = ClientCreator(self._reactor, MemCacheProtocol).connectTCP(
+                self._host,
+                self._port)
+    
+            def _cacheProtocol(proto):
+                Memcacher._memcacheProtocol = proto
+                return proto
+    
+            return d.addCallback(_cacheProtocol)
 
-        def _cacheProtocol(proto):
-            Memcacher._memcacheProtocol = proto
-            return proto
+        elif config.ProcessType == "Single":
+            
+            Memcacher._memcacheProtocol = Memcacher.memoryCacher()
+            return succeed(Memcacher._memcacheProtocol)
 
-        return d.addCallback(_cacheProtocol)
+        else:
+            
+            Memcacher._memcacheProtocol = Memcacher.nullCacher()
+            return succeed(Memcacher._memcacheProtocol)
 
     def set(self, key, value):
 

Added: CalendarServer/trunk/twistedcaldav/test/test_memcacher.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_memcacher.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/test/test_memcacher.py	2008-05-26 16:18:19 UTC (rev 2502)
@@ -0,0 +1,69 @@
+# Copyright (c) 2007 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Test the memcacher cache abstraction.
+"""
+
+from twisted.internet.defer import inlineCallbacks
+from twisted.trial.unittest import TestCase
+
+from twistedcaldav.config import config
+from twistedcaldav.memcacher import Memcacher
+
+class MemcacherTestCase(TestCase):
+    """
+    Test Memcacher abstract cache.
+    """
+
+    @inlineCallbacks
+    def test_setget(self):
+
+        for processType in ("Single", "Combined",):
+            config.processType = processType
+
+            cacher = Memcacher("testing")
+    
+            result = yield cacher.set("akey", "avalue")
+            self.assertTrue(result)
+
+            result = yield cacher.get("akey")
+            if isinstance(cacher._memcacheProtocol, Memcacher.nullCacher):
+                self.assertEquals(None, result)
+            else:
+                self.assertEquals("avalue", result)
+
+    @inlineCallbacks
+    def test_missingget(self):
+
+        for processType in ("Single", "Combined",):
+            config.processType = processType
+
+            cacher = Memcacher("testing")
+    
+            result = yield cacher.get("akey")
+            self.assertEquals(None, result)
+
+    @inlineCallbacks
+    def test_delete(self):
+
+        for processType in ("Single", "Combined",):
+            config.processType = processType
+
+            cacher = Memcacher("testing")
+    
+            result = yield cacher.set("akey", "avalue")
+            self.assertTrue(result)
+    
+            result = yield cacher.get("akey")
+            if isinstance(cacher._memcacheProtocol, Memcacher.nullCacher):
+                self.assertEquals(None, result)
+            else:
+                self.assertEquals("avalue", result)
+    
+            result = yield cacher.delete("akey")
+            self.assertTrue(result)
+    
+            result = yield cacher.get("akey")
+            self.assertEquals(None, result)
+

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080526/8ed1a12c/attachment-0001.htm 


More information about the calendarserver-changes mailing list