[CalendarServer-changes] [8725] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Fri Feb 17 13:16:48 PST 2012
Revision: 8725
http://trac.macosforge.org/projects/calendarserver/changeset/8725
Author: sagen at apple.com
Date: 2012-02-17 13:16:47 -0800 (Fri, 17 Feb 2012)
Log Message:
-----------
Adds a memcache lock around adding/removing sharing invitations.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/sharing.py
CalendarServer/trunk/twistedcaldav/storebridge.py
Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharing.py 2012-02-17 17:42:16 UTC (rev 8724)
+++ CalendarServer/trunk/twistedcaldav/sharing.py 2012-02-17 21:16:47 UTC (rev 8725)
@@ -40,6 +40,7 @@
from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
from twistedcaldav.linkresource import LinkFollowerMixIn
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
from pycalendar.datetime import PyCalendarDateTime
@@ -478,7 +479,40 @@
return results if resultIsList else results[0]
return DeferredList(dl).addCallback(_defer)
+
@inlineCallbacks
+ def _createLock(self, userid, request):
+ """
+ Create an instance of MemcacheLock whose key is based on the sharee's
+ uid and the collection's URL
+ """
+ returnValue(MemcacheLock(
+ "ShareInviteLock",
+ (yield self._lockToken(userid, request)),
+ timeout=config.Scheduling.Options.UIDLockTimeoutSeconds,
+ expire_time=config.Scheduling.Options.UIDLockExpirySeconds,
+ ))
+
+ @inlineCallbacks
+ def _acquireLock(self, lock):
+ """
+ Attempt to acquire a lock -- can raise MemcacheLockTimeoutError
+ """
+ try:
+ yield lock.acquire()
+ except MemcacheLockTimeoutError:
+ self.log_error("Memcache lock timeout for sharing invite")
+ raise
+
+ @inlineCallbacks
+ def _lockToken(self, userid, request):
+ """
+ Generate a string we can use for a memcache lock key
+ """
+ hosturl = (yield self.canonicalURL(request))
+ returnValue("%s:%s" % (hosturl, userid))
+
+ @inlineCallbacks
def inviteSingleUserToShare(self, userid, cn, ace, summary, request):
# Validate userid and cn
@@ -488,33 +522,54 @@
if principalURL is None:
returnValue(False)
- # Look for existing invite and update its fields or create new one
- principalUID = principalURL.split("/")[3]
- record = yield self.invitesDB().recordForPrincipalUID(principalUID)
- if record:
- record.name = cn
- record.access = inviteAccessMapFromXML[type(ace)]
- record.summary = summary
- else:
- record = Invite(str(uuid4()), userid, principalUID, cn, inviteAccessMapFromXML[type(ace)], "NEEDS-ACTION", summary)
-
- # Send invite
- yield self.sendInvite(record, request)
-
- # Add to database
- yield self.invitesDB().addOrUpdateRecord(record)
-
- returnValue(True)
+ # Acquire a memcache lock based on collection URL and sharee UID
+ # TODO: when sharing moves into the store this should be replaced
+ # by DB-level locking
+ lock = (yield self._createLock(userid, request))
+ yield self._acquireLock(lock)
+ try:
+ # Look for existing invite and update its fields or create new one
+ principalUID = principalURL.split("/")[3]
+ record = yield self.invitesDB().recordForPrincipalUID(principalUID)
+ if record:
+ record.name = cn
+ record.access = inviteAccessMapFromXML[type(ace)]
+ record.summary = summary
+ else:
+ record = Invite(str(uuid4()), userid, principalUID, cn, inviteAccessMapFromXML[type(ace)], "NEEDS-ACTION", summary)
+ # Send invite
+ yield self.sendInvite(record, request)
+
+ # Add to database
+ yield self.invitesDB().addOrUpdateRecord(record)
+
+ finally:
+ lock.clean()
+
+ returnValue(True)
+
+
@inlineCallbacks
def uninviteSingleUserFromShare(self, userid, aces, request):
# Cancel invites - we'll just use whatever userid we are given
- record = yield self.invitesDB().recordForUserID(userid)
- if record:
- result = (yield self.uninviteRecordFromShare(record, request))
- else:
- result = False
+
+ # Acquire a memcache lock based on collection URL and sharee UID
+ # TODO: when sharing moves into the store this should be replaced
+ # by DB-level locking
+ lock = (yield self._createLock(userid, request))
+ yield self._acquireLock(lock)
+
+ try:
+ record = yield self.invitesDB().recordForUserID(userid)
+ if record:
+ result = (yield self.uninviteRecordFromShare(record, request))
+ else:
+ result = False
+ finally:
+ lock.clean()
+
returnValue(result)
@@ -772,8 +827,8 @@
))
root = doc.root_element
- if type(root) in self.xmlDocHanders:
- result = (yield self.xmlDocHanders[type(root)](self, request, root))
+ if type(root) in self.xmlDocHandlers:
+ result = (yield self.xmlDocHandlers[type(root)](self, request, root))
returnValue(result)
else:
self.log_error("Unsupported XML (%s)" % (root,))
@@ -783,7 +838,7 @@
"Unsupported XML",
))
- xmlDocHanders = {
+ xmlDocHandlers = {
customxml.InviteShare: _xmlHandleInvite,
customxml.InviteReply: _xmlHandleInviteReply,
}
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2012-02-17 17:42:16 UTC (rev 8724)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2012-02-17 21:16:47 UTC (rev 8725)
@@ -986,7 +986,7 @@
if config.EnableBatchUpload:
self._postHandlers[("text", "calendar")] = _CommonHomeChildCollectionMixin.simpleBatchPOST
- self.xmlDocHanders[customxml.Multiput] = _CommonHomeChildCollectionMixin.crudBatchPOST
+ self.xmlDocHandlers[customxml.Multiput] = _CommonHomeChildCollectionMixin.crudBatchPOST
def __repr__(self):
return "<Calendar Collection Resource %r:%r %s>" % (
@@ -2001,7 +2001,7 @@
if config.EnableBatchUpload:
self._postHandlers[("text", "vcard")] = _CommonHomeChildCollectionMixin.simpleBatchPOST
- self.xmlDocHanders[customxml.Multiput] = _CommonHomeChildCollectionMixin.crudBatchPOST
+ self.xmlDocHandlers[customxml.Multiput] = _CommonHomeChildCollectionMixin.crudBatchPOST
def __repr__(self):
return "<AddressBook Collection Resource %r:%r %s>" % (
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120217/dd80629e/attachment-0001.html>
More information about the calendarserver-changes
mailing list