[CalendarServer-changes] [7016] CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/ sql.py
source_changes at macosforge.org
source_changes at macosforge.org
Wed Feb 16 06:42:01 PST 2011
Revision: 7016
http://trac.macosforge.org/projects/calendarserver/changeset/7016
Author: glyph at apple.com
Date: 2011-02-16 06:41:59 -0800 (Wed, 16 Feb 2011)
Log Message:
-----------
move syncToken stuff to common superclass, de-duplicate resourceNamesSinceToken
Modified Paths:
--------------
CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/sql.py
Modified: CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/sql.py 2011-02-16 14:41:48 UTC (rev 7015)
+++ CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/sql.py 2011-02-16 14:41:59 UTC (rev 7016)
@@ -919,8 +919,284 @@
self._txn.postCommit(notifier.notify)
-class CommonHomeChild(LoggingMixIn, FancyEqMixin):
+
+class _SharedSyncLogic(object):
"""
+ Logic for maintaining sync-token shared between notification collections and
+ shared collections.
+ """
+
+ @classproperty
+ def _childSyncTokenQuery(cls):
+ """
+ DAL query for retrieving the sync token of a L{CommonHomeChild} based on
+ its resource ID.
+ """
+ rev = cls._revisionsSchema
+ return Select([Max(rev.REVISION)], From=rev,
+ Where=rev.RESOURCE_ID == Parameter("resourceID"))
+
+
+ @inlineCallbacks
+ def syncToken(self):
+ if self._syncTokenRevision is None:
+ self._syncTokenRevision = (yield self._childSyncTokenQuery.on(
+ self._txn, resourceID=self._resourceID))[0][0]
+ returnValue(("%s#%s" % (self._resourceID, self._syncTokenRevision,)))
+
+
+ def objectResourcesSinceToken(self, token):
+ raise NotImplementedError()
+
+
+ @classproperty
+ def _objectNamesSinceRevisionQuery(cls):
+ """
+ DAL query for (resource, deleted-flag)
+ """
+ rev = cls._revisionsSchema
+ return Select([rev.RESOURCE_NAME, rev.DELETED],
+ From=rev,
+ Where=(rev.REVISION > Parameter("revision")).And(
+ rev.RESOURCE_ID == Parameter("resourceID")))
+
+
+ @inlineCallbacks
+ def resourceNamesSinceToken(self, token):
+ results = [
+ (name if name else "", deleted)
+ for name, deleted in
+ (yield self._objectNamesSinceRevisionQuery.on(
+ self._txn, revision=token, resourceID=self._resourceID))
+ ]
+ results.sort(key=lambda x:x[1])
+
+ changed = []
+ deleted = []
+ for name, wasdeleted in results:
+ if name:
+ if wasdeleted:
+ if token:
+ deleted.append(name)
+ else:
+ changed.append(name)
+
+ returnValue((changed, deleted))
+
+
+ @classproperty
+ def _removeDeletedRevision(cls):
+ rev = cls._revisionsSchema
+ return Delete(From=rev,
+ Where=(rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
+ rev.COLLECTION_NAME == Parameter("collectionName")))
+
+
+ @classproperty
+ def _addNewRevision(cls):
+ rev = cls._revisionsSchema
+ return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
+ rev.RESOURCE_ID: Parameter("resourceID"),
+ rev.COLLECTION_NAME: Parameter("collectionName"),
+ rev.RESOURCE_NAME: None,
+ # Always starts false; may be updated to be a tombstone
+ # later.
+ rev.DELETED: False},
+ Return=[rev.REVISION])
+
+
+ @inlineCallbacks
+ def _initSyncToken(self):
+ yield self._removeDeletedRevision.on(
+ self._txn, homeID=self._home._resourceID, collectionName=self._name
+ )
+ self._syncTokenRevision = (yield (
+ self._addNewRevision.on(self._txn, homeID=self._home._resourceID,
+ resourceID=self._resourceID,
+ collectionName=self._name)))[0][0]
+
+
+ @classproperty
+ def _renameSyncTokenQuery(cls):
+ """
+ DAL query to change sync token for a rename (increment and adjust
+ resource name).
+ """
+ rev = cls._revisionsSchema
+ return Update({
+ rev.REVISION: schema.REVISION_SEQ,
+ rev.COLLECTION_NAME: Parameter("name")},
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")
+ ).And(rev.RESOURCE_NAME == None),
+ Return=rev.REVISION
+ )
+
+
+ @inlineCallbacks
+ def _renameSyncToken(self):
+ self._syncTokenRevision = (yield self._renameSyncTokenQuery.on(
+ self._txn, name=self._name, resourceID=self._resourceID))[0][0]
+
+
+ @classproperty
+ def _deleteSyncTokenQuery(cls):
+ """
+ DAL query to update a sync revision to be a tombstone instead.
+ """
+ rev = cls._revisionsSchema
+ return Delete(From=rev, Where=(
+ rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
+ rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.COLLECTION_NAME == None))
+
+
+ @classproperty
+ def _sharedRemovalQuery(cls):
+ """
+ DAL query to update the sync token for a shared collection.
+ """
+ rev = cls._revisionsSchema
+ return Update({rev.RESOURCE_ID: None,
+ rev.REVISION: schema.REVISION_SEQ,
+ rev.DELETED: True},
+ Where=(rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
+ rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == None),
+ #Return=rev.REVISION
+ )
+
+
+ @classproperty
+ def _unsharedRemovalQuery(cls):
+ """
+ DAL query to update the sync token for an owned collection.
+ """
+ rev = cls._revisionsSchema
+ return Update({rev.RESOURCE_ID: None,
+ rev.REVISION: schema.REVISION_SEQ,
+ rev.DELETED: True},
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == None),
+ # Return=rev.REVISION,
+ )
+
+
+ @inlineCallbacks
+ def _deletedSyncToken(self, sharedRemoval=False):
+ # Remove all child entries
+ yield self._deleteSyncTokenQuery.on(self._txn,
+ homeID=self._home._resourceID,
+ resourceID=self._resourceID)
+
+ # If this is a share being removed then we only mark this one specific
+ # home/resource-id as being deleted. On the other hand, if it is a
+ # non-shared collection, then we need to mark all collections
+ # with the resource-id as being deleted to account for direct shares.
+ if sharedRemoval:
+ yield self._sharedRemovalQuery.on(self._txn,
+ homeID=self._home._resourceID,
+ resourceID=self._resourceID)
+ else:
+ yield self._unsharedRemovalQuery.on(self._txn,
+ resourceID=self._resourceID)
+ self._syncTokenRevision = None
+
+
+ def _insertRevision(self, name):
+ return self._changeRevision("insert", name)
+
+
+ def _updateRevision(self, name):
+ return self._changeRevision("update", name)
+
+
+ def _deleteRevision(self, name):
+ return self._changeRevision("delete", name)
+
+
+ @classproperty
+ def _deleteBumpTokenQuery(cls):
+ rev = cls._revisionsSchema
+ return Update({rev.REVISION: schema.REVISION_SEQ,
+ rev.DELETED: True},
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == Parameter("name")),
+ Return=rev.REVISION)
+
+
+ @classproperty
+ def _updateBumpTokenQuery(cls):
+ rev = cls._revisionsSchema
+ return Update({rev.REVISION: schema.REVISION_SEQ},
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == Parameter("name")),
+ Return=rev.REVISION)
+
+
+ @classproperty
+ def _insertFindPreviouslyNamedQuery(cls):
+ rev = cls._revisionsSchema
+ return Select([rev.RESOURCE_ID], From=rev,
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == Parameter("name")))
+
+
+ @classproperty
+ def _updatePreviouslyNamedQuery(cls):
+ rev = cls._revisionsSchema
+ return Update({rev.REVISION: schema.REVISION_SEQ,
+ rev.DELETED: False},
+ Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_NAME == Parameter("name")),
+ Return=rev.REVISION)
+
+
+ @classproperty
+ def _completelyNewRevisionQuery(cls):
+ rev = cls._revisionsSchema
+ return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
+ rev.RESOURCE_ID: Parameter("resourceID"),
+ rev.RESOURCE_NAME: Parameter("name"),
+ rev.REVISION: schema.REVISION_SEQ,
+ rev.DELETED: False},
+ Return=rev.REVISION)
+
+
+ @inlineCallbacks
+ def _changeRevision(self, action, name):
+ if action == "delete":
+ self._syncTokenRevision = (
+ yield self._deleteBumpTokenQuery.on(
+ self._txn, resourceID=self._resourceID, name=name))[0][0]
+ elif action == "update":
+ self._syncTokenRevision = (
+ yield self._updateBumpTokenQuery.on(
+ self._txn, resourceID=self._resourceID, name=name))[0][0]
+ elif action == "insert":
+ # Note that an "insert" may happen for a resource that previously
+ # existed and then was deleted. In that case an entry in the
+ # REVISIONS table still exists so we have to detect that and do db
+ # INSERT or UPDATE as appropriate
+
+ found = bool( (
+ yield self._insertFindPreviouslyNamedQuery.on(
+ self._txn, resourceID=self._resourceID, name=name)) )
+ if found:
+ self._syncTokenRevision = (
+ yield self._updatePreviouslyNamedQuery.on(
+ self._txn, resourceID=self._resourceID, name=name)
+ )[0][0]
+ else:
+ self._syncTokenRevision = (
+ yield self._completelyNewRevisionQuery.on(
+ self._txn, homeID=self._home._resourceID,
+ resourceID=self._resourceID, name=name)
+ )[0][0]
+
+
+
+class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic):
+ """
Common ancestor class of AddressBooks and Calendars.
"""
@@ -1609,272 +1885,6 @@
self.notifyChanged()
- @classproperty
- def _childSyncTokenQuery(cls):
- """
- DAL query for retrieving the sync token of a L{CommonHomeChild} based on
- its resource ID.
- """
- rev = cls._revisionsSchema
- return Select([Max(rev.REVISION)], From=rev,
- Where=rev.RESOURCE_ID == Parameter("resourceID"))
-
-
- @inlineCallbacks
- def syncToken(self):
- if self._syncTokenRevision is None:
- self._syncTokenRevision = (yield self._childSyncTokenQuery.on(
- self._txn, resourceID=self._resourceID))[0][0]
- returnValue(("%s#%s" % (self._resourceID, self._syncTokenRevision,)))
-
-
- def objectResourcesSinceToken(self, token):
- raise NotImplementedError()
-
-
- @classproperty
- def _objectNamesSinceRevisionQuery(cls):
- """
- DAL query for (resource, deleted-flag)
- """
- rev = cls._revisionsSchema
- return Select([rev.RESOURCE_NAME, rev.DELETED],
- From=rev,
- Where=(rev.REVISION > Parameter("revision")).And(
- rev.RESOURCE_ID == Parameter("resourceID")))
-
-
- @inlineCallbacks
- def resourceNamesSinceToken(self, token):
- results = [
- (name if name else "", deleted)
- for name, deleted in
- (yield self._objectNamesSinceRevisionQuery.on(
- self._txn, revision=token, resourceID=self._resourceID))
- ]
- results.sort(key=lambda x:x[1])
-
- changed = []
- deleted = []
- for name, wasdeleted in results:
- if name:
- if wasdeleted:
- if token:
- deleted.append(name)
- else:
- changed.append(name)
-
- returnValue((changed, deleted))
-
-
- @classproperty
- def _removeDeletedRevision(cls):
- rev = cls._revisionsSchema
- return Delete(From=rev,
- Where=(rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
- rev.COLLECTION_NAME == Parameter("collectionName")))
-
- @classproperty
- def _addNewRevision(cls):
- rev = cls._revisionsSchema
- return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
- rev.RESOURCE_ID: Parameter("resourceID"),
- rev.COLLECTION_NAME: Parameter("collectionName"),
- rev.RESOURCE_NAME: None,
- # Always starts false; may be updated to be a tombstone
- # later.
- rev.DELETED: False},
- Return=[rev.REVISION])
-
-
- @inlineCallbacks
- def _initSyncToken(self):
- yield self._removeDeletedRevision.on(
- self._txn, homeID=self._home._resourceID, collectionName=self._name
- )
- self._syncTokenRevision = (yield (
- self._addNewRevision.on(self._txn, homeID=self._home._resourceID,
- resourceID=self._resourceID,
- collectionName=self._name)))[0][0]
-
-
- @classproperty
- def _renameSyncTokenQuery(cls):
- """
- DAL query to change sync token for a rename (increment and adjust
- resource name).
- """
- rev = cls._revisionsSchema
- return Update({
- rev.REVISION: schema.REVISION_SEQ,
- rev.COLLECTION_NAME: Parameter("name")},
- Where=(rev.RESOURCE_ID == Parameter("resourceID")
- ).And(rev.RESOURCE_NAME == None),
- Return=rev.REVISION
- )
-
-
- @inlineCallbacks
- def _renameSyncToken(self):
- self._syncTokenRevision = (yield self._renameSyncTokenQuery.on(
- self._txn, name=self._name, resourceID=self._resourceID))[0][0]
-
-
- @classproperty
- def _deleteSyncTokenQuery(cls):
- """
- DAL query to update a sync revision to be a tombstone instead.
- """
- rev = cls._revisionsSchema
- return Delete(From=rev, Where=(
- rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
- rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.COLLECTION_NAME == None))
-
-
- @classproperty
- def _sharedRemovalQuery(cls):
- """
- DAL query to update the sync token for a shared collection.
- """
- rev = cls._revisionsSchema
- return Update({rev.RESOURCE_ID: None,
- rev.REVISION: schema.REVISION_SEQ,
- rev.DELETED: True},
- Where=(rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
- rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == None),
- #Return=rev.REVISION
- )
-
-
- @classproperty
- def _unsharedRemovalQuery(cls):
- """
- DAL query to update the sync token for an owned collection.
- """
- rev = cls._revisionsSchema
- return Update({rev.RESOURCE_ID: None,
- rev.REVISION: schema.REVISION_SEQ,
- rev.DELETED: True},
- Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == None),
- # Return=rev.REVISION,
- )
-
-
- @inlineCallbacks
- def _deletedSyncToken(self, sharedRemoval=False):
- # Remove all child entries
- yield self._deleteSyncTokenQuery.on(self._txn,
- homeID=self._home._resourceID,
- resourceID=self._resourceID)
-
- # If this is a share being removed then we only mark this one specific
- # home/resource-id as being deleted. On the other hand, if it is a
- # non-shared collection, then we need to mark all collections
- # with the resource-id as being deleted to account for direct shares.
- if sharedRemoval:
- yield self._sharedRemovalQuery.on(self._txn,
- homeID=self._home._resourceID,
- resourceID=self._resourceID)
- else:
- yield self._unsharedRemovalQuery.on(self._txn,
- resourceID=self._resourceID)
- self._syncTokenRevision = None
-
-
- def _insertRevision(self, name):
- return self._changeRevision("insert", name)
-
- def _updateRevision(self, name):
- return self._changeRevision("update", name)
-
- def _deleteRevision(self, name):
- return self._changeRevision("delete", name)
-
-
- @classproperty
- def _deleteBumpTokenQuery(cls):
- rev = cls._revisionsSchema
- return Update({rev.REVISION: schema.REVISION_SEQ,
- rev.DELETED: True},
- Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == Parameter("name")),
- Return=rev.REVISION)
-
-
- @classproperty
- def _updateBumpTokenQuery(cls):
- rev = cls._revisionsSchema
- return Update({rev.REVISION: schema.REVISION_SEQ},
- Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == Parameter("name")),
- Return=rev.REVISION)
-
-
- @classproperty
- def _insertFindPreviouslyNamedQuery(cls):
- rev = cls._revisionsSchema
- return Select([rev.RESOURCE_ID], From=rev,
- Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == Parameter("name")))
-
-
- @classproperty
- def _updatePreviouslyNamedQuery(cls):
- rev = cls._revisionsSchema
- return Update({rev.REVISION: schema.REVISION_SEQ,
- rev.DELETED: False},
- Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
- rev.RESOURCE_NAME == Parameter("name")),
- Return=rev.REVISION)
-
-
- @classproperty
- def _completelyNewRevisionQuery(cls):
- rev = cls._revisionsSchema
- return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
- rev.RESOURCE_ID: Parameter("resourceID"),
- rev.RESOURCE_NAME: Parameter("name"),
- rev.REVISION: schema.REVISION_SEQ,
- rev.DELETED: False},
- Return=rev.REVISION)
-
-
- @inlineCallbacks
- def _changeRevision(self, action, name):
-
- if action == "delete":
- self._syncTokenRevision = (
- yield self._deleteBumpTokenQuery.on(
- self._txn, resourceID=self._resourceID, name=name))[0][0]
- elif action == "update":
- self._syncTokenRevision = (
- yield self._updateBumpTokenQuery.on(
- self._txn, resourceID=self._resourceID, name=name))[0][0]
- elif action == "insert":
- # Note that an "insert" may happen for a resource that previously
- # existed and then was deleted. In that case an entry in the
- # REVISIONS table still exists so we have to detect that and do db
- # INSERT or UPDATE as appropriate
-
- found = bool( (
- yield self._insertFindPreviouslyNamedQuery.on(
- self._txn, resourceID=self._resourceID, name=name)) )
- if found:
- self._syncTokenRevision = (
- yield self._updatePreviouslyNamedQuery.on(
- self._txn, resourceID=self._resourceID, name=name)
- )[0][0]
- else:
- self._syncTokenRevision = (
- yield self._completelyNewRevisionQuery.on(
- self._txn, homeID=self._home._resourceID,
- resourceID=self._resourceID, name=name)
- )[0][0]
-
-
def objectResourcesHaveProperties(self):
return False
@@ -2283,7 +2293,7 @@
-class NotificationCollection(LoggingMixIn, FancyEqMixin):
+class NotificationCollection(LoggingMixIn, FancyEqMixin, _SharedSyncLogic):
implements(INotificationCollection)
@@ -2496,55 +2506,7 @@
returnValue("%s#%s" % (self._resourceID, self._syncTokenRevision))
- def objectResourcesSinceToken(self, token):
- raise NotImplementedError()
-
-
- _resourceNamesSinceTokenQuery = Select(
- [_revisionsSchema.RESOURCE_NAME, _revisionsSchema.DELETED],
- From=_revisionsSchema,
- Where=(_revisionsSchema.REVISION > Parameter("revision")).And(
- _revisionsSchema.HOME_RESOURCE_ID == Parameter("homeID")
- )
- )
-
-
@inlineCallbacks
- def resourceNamesSinceToken(self, token):
- results = [
- (name if name else "", deleted)
- for name, deleted in
- (yield self._resourceNamesSinceTokenQuery.on(
- self._txn, revision=token, homeID=self._resourceID))
- ]
- results.sort(key=lambda x:x[1])
-
- changed = []
- deleted = []
- for name, wasdeleted in results:
- if name:
- if wasdeleted:
- if token:
- deleted.append(name)
- else:
- changed.append(name)
-
- returnValue((changed, deleted))
-
-
- def _insertRevision(self, name):
- return self._changeRevision("insert", name)
-
-
- def _updateRevision(self, name):
- return self._changeRevision("update", name)
-
-
- def _deleteRevision(self, name):
- return self._changeRevision("delete", name)
-
-
- @inlineCallbacks
def _changeRevision(self, action, name):
if action == "delete":
@@ -2608,6 +2570,7 @@
else:
return None
+
@inlineCallbacks
def nodeName(self, label="default"):
if self._notifiers:
@@ -2618,6 +2581,7 @@
else:
returnValue(None)
+
def notifyChanged(self):
"""
Trigger a notification of a change
@@ -2627,6 +2591,7 @@
self._txn.postCommit(notifier.notify)
+
class NotificationObject(LoggingMixIn, FancyEqMixin):
implements(INotificationObject)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110216/a975e4fa/attachment-0001.html>
More information about the calendarserver-changes
mailing list