[CalendarServer-changes] [2468] CalendarServer/branches/unified-cache/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Fri May 23 16:46:12 PDT 2008
Revision: 2468
http://trac.macosforge.org/projects/calendarserver/changeset/2468
Author: dreid at apple.com
Date: 2008-05-23 16:46:11 -0700 (Fri, 23 May 2008)
Log Message:
-----------
Add a very hacky MemcacheChangeNotifier
Modified Paths:
--------------
CalendarServer/branches/unified-cache/twistedcaldav/cache.py
CalendarServer/branches/unified-cache/twistedcaldav/test/test_cache.py
CalendarServer/branches/unified-cache/twistedcaldav/test/util.py
Modified: CalendarServer/branches/unified-cache/twistedcaldav/cache.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/cache.py 2008-05-23 23:45:33 UTC (rev 2467)
+++ CalendarServer/branches/unified-cache/twistedcaldav/cache.py 2008-05-23 23:46:11 UTC (rev 2468)
@@ -40,8 +40,8 @@
from twistedcaldav.log import LoggingMixIn
from twistedcaldav.memcache import MemCacheProtocol
+from twistedcaldav.config import config
-
class CacheTokensProperty(davxml.WebDAVTextElement):
namespace = davxml.twisted_private_namespace
name = "cacheTokens"
@@ -71,6 +71,55 @@
return succeed(True)
+
+class MemcacheChangeNotifier(LoggingMixIn):
+ def __init__(self, propertyStore):
+ self._path = propertyStore.resource.fp.path
+ self._host = config.Memcached['BindAddress']
+ self._port = config.Memcached['Port']
+
+ from twisted.internet import reactor
+ self._reactor = reactor
+
+ self._memcacheProtocol = None
+
+
+ def _newCacheToken(self):
+ return uuid.uuid4()
+
+
+ def _getMemcacheProtocol(self):
+ if self._memcacheProtocol is not None:
+ return succeed(self._memcacheProtocol)
+
+ d = ClientCreator(self._reactor, MemCacheProtocol).connectTCP(
+ self._host,
+ self._port)
+
+ def _cacheProtocol(proto):
+ self._memcacheProtocol = proto
+ return proto
+
+ return d.addCallback(_cacheProtocol)
+
+
+ def changed(self):
+ """
+ Change the cache token for a resource
+
+ return: A L{Deferred} that fires when the token has been changed.
+ """
+ def _updateCacheToken(proto):
+ return proto.set('cacheToken:%s' % (self._path,),
+ self._newCacheToken())
+
+ self.log_debug("Changing Cache Token for %r" % (self._path,))
+ d = self._getMemcacheProtocol()
+ d.addCallback(_updateCacheToken)
+ return d
+
+
+
class BaseResponseCache(LoggingMixIn):
"""
A base class which provides some common operations
@@ -318,6 +367,37 @@
self._memcacheProtocol = None
+ def _tokenForURI(self, uri):
+ """
+ Get a property store for the given C{uri}.
+
+ @param uri: The URI we'd like the token for.
+ @return: A C{str} representing the token for the URI.
+ """
+
+ class __FauxStaticResource(object):
+ def __init__(self, fp):
+ self.fp = fp
+
+
+ fp = self._docroot
+ for childPath in uri.split('/')[:4]:
+ fp = fp.child(childPath)
+
+ return self._getMemcacheProtocol().get('cacheToken:%s' % (fp.path,))
+
+
+ def _getTokens(self, principalURI, requestURI):
+ def _getSecondToken(pToken):
+ d1 = self._tokenForURI(requestURI)
+ d1.addCallback(lambda uToken: (pToken, uToken))
+ return d1
+
+ d = self._tokenForURI(principalURI)
+ d.addCallback(_getSecondToken)
+ return d
+
+
def _getMemcacheProtocol(self):
if self._memcacheProtocol is not None:
return succeed(self._memcacheProtocol)
@@ -382,7 +462,7 @@
(principalToken, uriToken,
resp) = cPickle.loads(value)
- d2 = self._getTokensInThread(self._principalURI(request.authnUser),
+ d2 = self._getTokens(self._principalURI(request.authnUser),
request.uri)
d2.addCallback(_checkTokens, (principalToken, uriToken), resp)
@@ -408,22 +488,26 @@
return proto.set(key, cacheEntry).addCallback(
lambda _: response)
+ def _makeCacheEntry((pToken, uToken), (key, responseBody)):
+ cacheEntry = cPickle.dumps(
+ (pToken,
+ uToken,
+ (response.code,
+ dict(list(response.headers.getAllRawHeaders())),
+ responseBody)))
+
+ d2 = self._getMemcacheProtocol()
+ d2.addCallback(_setCacheEntry, key, cacheEntry)
+ return d2
+
def _cacheResponse((key, responseBody)):
principalURI = self._principalURI(request.authnUser)
response.headers.removeHeader('date')
response.stream = MemoryStream(responseBody)
- cacheEntry = cPickle.dumps(
- (self._tokenForURI(principalURI),
- self._tokenForURI(request.uri),
- (response.code,
- dict(list(response.headers.getAllRawHeaders())),
- responseBody)))
-
- d1 = self._getMemcacheProtocol()
- d1.addCallback(_setCacheEntry, key, cacheEntry)
-
+ d1 = self._getTokens(principalURI, request.uri)
+ d1.addCallback(_makeCacheEntry, (key, responseBody))
return d1
if hasattr(request, 'cacheKey'):
Modified: CalendarServer/branches/unified-cache/twistedcaldav/test/test_cache.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/test/test_cache.py 2008-05-23 23:45:33 UTC (rev 2467)
+++ CalendarServer/branches/unified-cache/twistedcaldav/test/test_cache.py 2008-05-23 23:46:11 UTC (rev 2468)
@@ -33,6 +33,7 @@
from twistedcaldav.cache import CacheTokensProperty
from twistedcaldav.cache import ResponseCache
from twistedcaldav.cache import MemcacheResponseCache
+from twistedcaldav.cache import MemcacheChangeNotifier
from twistedcaldav.test.util import InMemoryPropertyStore
@@ -120,6 +121,35 @@
return d
+class MemCacheChangeNotifierTests(TestCase):
+ def setUp(self):
+ self.memcache = InMemoryMemcacheProtocol()
+ self.ccn = MemcacheChangeNotifier(InMemoryPropertyStore())
+ self.ccn._memcacheProtocol = self.memcache
+ self.ccn._newCacheToken = instancemethod(_newCacheToken,
+ self.ccn,
+ MemcacheChangeNotifier)
+
+
+ def assertToken(self, expectedToken):
+ token = self.memcache._cache['cacheToken::memory:'][1]
+ self.assertEquals(token, expectedToken)
+
+
+ def test_cacheTokenPropertyIsProvisioned(self):
+ d = self.ccn.changed()
+ d.addCallback(lambda _: self.assertToken('token0'))
+ return d
+
+
+ def test_changedChangesToken(self):
+ d = self.ccn.changed()
+ d.addCallback(lambda _: self.ccn.changed())
+ d.addCallback(lambda _: self.assertToken('token1'))
+ return d
+
+
+
class BaseCacheTestMixin(object):
def assertResponse(self, response, expected):
self.assertEquals(response.code, expected[0])
@@ -335,14 +365,18 @@
def setUp(self):
memcacheStub = InMemoryMemcacheProtocol()
self.rc = MemcacheResponseCache(None, None, None, None)
+ self.rc.logger.setLevel('debug')
self.tokens = {}
self.tokens['/calendars/users/cdaboo/'] = 'uriToken0'
self.tokens['/principals/users/cdaboo/'] = 'principalToken0'
self.tokens['/principals/users/dreid/'] = 'principalTokenX'
- self.rc._tokenForURI = self.tokens.get
+ def _getToken(uri):
+ return succeed(self.tokens.get(uri))
+ self.rc._tokenForURI = _getToken
+
self.expected_response = (200, Headers({}), "Foo")
expected_key = hashlib.md5(':'.join([str(t) for t in (
Modified: CalendarServer/branches/unified-cache/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/test/util.py 2008-05-23 23:45:33 UTC (rev 2467)
+++ CalendarServer/branches/unified-cache/twistedcaldav/test/util.py 2008-05-23 23:46:11 UTC (rev 2468)
@@ -18,6 +18,7 @@
from twisted.web2.http import HTTPError, StatusResponse
from twisted.internet.defer import succeed
+from twisted.python.filepath import FilePath
from twistedcaldav.static import CalDAVFile
@@ -28,11 +29,14 @@
class InMemoryPropertyStore(object):
def __init__(self):
- class __FauxResource(object):
- fp = ':memory:'
+ class _FauxPath(object):
+ path = ':memory:'
+ class _FauxResource(object):
+ fp = _FauxPath()
+
self._properties = {}
- self.resource = __FauxResource()
+ self.resource = _FauxResource()
def get(self, qname):
data = self._properties.get(qname)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080523/6a6b763b/attachment-0001.htm
More information about the calendarserver-changes
mailing list