[CalendarServer-changes] [11652] CalendarServer/branches/users/gaya/sharedgroupfixes/txdav

source_changes at macosforge.org source_changes at macosforge.org
Tue Sep 3 13:21:54 PDT 2013


Revision: 11652
          http://trac.calendarserver.org//changeset/11652
Author:   gaya at apple.com
Date:     2013-09-03 13:21:54 -0700 (Tue, 03 Sep 2013)
Log Message:
-----------
add CommonHomeChild.sharedChildResourceNamesSinceRevision(), broken out of CommongHome.resourceNamesSinceRevision();
add AddressBook.sharedChildResourceNamesSinceRevision().  Rename and fix group members revision queries.

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py

Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/sql.py	2013-09-03 00:40:32 UTC (rev 11651)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/sql.py	2013-09-03 20:21:54 UTC (rev 11652)
@@ -451,6 +451,99 @@
 
 
     @inlineCallbacks
+    def sharedChildResourceNamesSinceRevision(self, revision, depth):
+        """
+        Determine the list of child resources that have changed since the specified sync revision.
+        We do the same SQL query for both depth "1" and "infinity", but filter the results for
+        "1" to only account for a collection change.
+
+        We need to handle shared collection a little differently from owned ones. When a shared collection
+        is bound into a home we record a revision for it using the sharee home id and sharee collection name.
+        That revision is the "starting point" for changes: so if sync occurs with a revision earlier than
+        that, we return the list of all resources in the shared collection since they are all "new" as far
+        as the client is concerned since the shared collection has just appeared. For a later revision, we
+        just report the changes since that one. When a shared collection is removed from a home, we again
+        record a revision for the sharee home and sharee collection name with the "deleted" flag set. That way
+        the shared collection can be reported as removed.
+
+        @param revision: the sync revision to compare to
+        @type revision: C{str}
+        @param depth: depth for determine what changed
+        @type depth: C{str}
+        """
+        assert not self.owned()
+
+        if self.fullyShared():
+            returnValue((yield super(AddressBook, self).sharedChildResourceNamesSinceRevision(revision, depth)))
+
+        changed = set()
+        deleted = set()
+        rev = self._revisionsSchema
+        sharerevision = 0 if revision < self._bindRevision else revision
+        results = [
+            (
+                name if name else "",
+                wasdeleted,
+                changeRevision
+            )
+            for name, wasdeleted, changeRevision in
+            (yield Select([rev.RESOURCE_NAME, rev.RESOURCE_ID, rev.DELETED, rev.REVISION],
+                             From=rev,
+                            Where=(rev.REVISION > sharerevision).And(
+                            rev.RESOURCE_ID == self._resourceID)).on(self._txn))
+            if name
+        ]
+
+        aboMembers = schema.ABO_MEMBERS
+        memberResults = yield Select(
+            [aboMembers.RESOURCE_NAME, aboMembers.MEMBER_ID, aboMembers.REMOVED, aboMembers.REVISION],
+            From=rev,
+            Where=(rev.REVISION > sharerevision).And(
+            aboMembers.ADDRESSBOOK_ID == self._resourceID)
+        ).on(self._txn)
+
+        ''' 
+        Started work here to get missing member names, but that is not needed right now, AFAI can tell
+
+        # member names are not saved until resource is deleted, so get missing names from db
+        idsForMissingNames = list(set([memberID for name, memberID, removed, revision in memberResults in memberResults if not name]))
+
+        abo = schema.ADDRESSBOOK_OBJECT
+        memberIDNameRows = (
+            yield self._columnsWithResourceIDsQuery(
+                [abo.RESOURCE_ID, abo.RESOURCE_NAME],
+                idsForMissingNames
+            ).on(self._txn, resourceIDs=idsForMissingNames)
+        ) if idsForMissingNames else []
+        idToNameMap = dict(memberIDNameRows)
+
+        for i, (name, memberID, removed, revision) in enumerate(copy(memberResults)):
+            memberResults[i] = (name if name else idToNameMap[memberID], memberID, removed, revision)
+        '''
+
+        #TODO: Finish
+
+        path = self.name()
+        for name, wasdeleted, revision in results:
+            if wasdeleted:
+                if sharerevision:
+                    if depth == "1":
+                        changed.add("%s/" % (path,))
+                    else:
+                        deleted.add("%s/%s" % (path, name,))
+
+        for name, wasdeleted in results:
+            # Always report collection as changed
+            changed.add("%s/" % (path,))
+            if name:
+                # Resource changed - for depth "infinity" report resource as changed
+                if depth != "1":
+                    changed.add("%s/%s" % (path, name,))
+
+        returnValue((changed, deleted))
+
+
+    @inlineCallbacks
     def _loadPropertyStore(self, props=None):
         if props is None:
             props = yield PropertyStore.load(
@@ -960,7 +1053,7 @@
         for row in rows:
             bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:cls.bindColumnCount] #@UnusedVariable
             ownerHome = yield home._txn.homeWithResourceID(home._homeType, resourceID, create=True)
-            names |= set([ownerHome.shareeAddressBookName()])
+            names.add(ownerHome.shareeAddressBookName())
 
         groupRows = yield AddressBookObject._acceptedBindForHomeID.on(
             home._txn, homeID=home._resourceID
@@ -969,7 +1062,7 @@
             bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupRow[:AddressBookObject.bindColumnCount] #@UnusedVariable
             ownerAddressBookID = yield AddressBookObject.ownerAddressBookIDFromGroupID(home._txn, resourceID)
             ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerAddressBookID, create=True)
-            names |= set([ownerHome.shareeAddressBookName()])
+            names.add(ownerHome.shareeAddressBookName())
         returnValue(tuple(names))
 
 
@@ -1075,7 +1168,7 @@
             rows = yield self._allColumnsWithParent(self)
             ids = set([row[1] for row in rows])
             if self.fullyShared():
-                ids |= set([self._resourceID, ])
+                ids.add(self._resourceID)
             if self.owned() or self._bindMode == _BIND_MODE_WRITE:
                 returnValue(tuple(readOnlyIDs), tuple(readWriteIDs))
             readOnlyIDs = set(ids)
@@ -1351,7 +1444,7 @@
             )
             groupIDs = [groupIDRow[0] for groupIDRow in groupIDRows]
             if groupIDs:
-                yield self._removeGroupIDsQuery(groupIDs).on(self._txn,
+                yield self._removeMemberIDFromGroupIDsQuery(groupIDs).on(self._txn,
                     groupIDs=groupIDs,
                     addressbookID=self._ownerAddressBookResourceID,
                     memberID=self._resourceID,
@@ -1373,7 +1466,7 @@
         if self.owned() or self.addressbook().fullyShared():
             # remove memberships
             if groupIDs:
-                yield self._removeGroupIDsQuery(groupIDs).on(self._txn,
+                yield self._removeMemberIDFromGroupIDsQuery(groupIDs).on(self._txn,
                     groupIDs=groupIDs,
                     addressbookID=self._ownerAddressBookResourceID,
                     memberID=self._resourceID,
@@ -1400,7 +1493,13 @@
             ).on(self._txn)
             memberIDsToRemove = [memberIDRow[0] for memberIDRow in memberIDRows]
 
-            yield self._markMemberIDsDeleted(memberIDsToRemove)
+            yield self._removeMemberIDsFromGroupIDQuery(memberIDsToRemove).on(
+                self._txn,
+                groupID=self._resourceID,
+                addressbookID=self._ownerAddressBookResourceID,
+                memberIDs=memberIDsToRemove,
+                revision=self.addressbook()._syncTokenRevision,
+           )
 
         yield super(AddressBookObject, self).remove()
         self._kind = None
@@ -1790,7 +1889,7 @@
     @classproperty
     def _insertMemberIDQuery(cls): #@NoSelf
         """
-        DAL statement insert a group member
+        DAL statement to add a member table row
         """
         aboMembers = schema.ABO_MEMBERS
         return Insert(
@@ -1804,31 +1903,14 @@
         )
 
 
-    @classproperty
-    def _addRemovedMemberIDQuery(cls): #@NoSelf
-        """
-        DAL statement update a group member
-        """
-        aboMembers = schema.ABO_MEMBERS
-        return Update(
-            {#aboMembers.RESOURCE_NAME: Parameter("resourceName"),
-             aboMembers.REVISION: Parameter("revision"),
-             aboMembers.REMOVED: False, },
-            Where=(aboMembers.GROUP_ID == Parameter("groupID"))
-              .And(aboMembers.ADDRESSBOOK_ID == Parameter("addressbookID"))
-              .And(aboMembers.MEMBER_ID == Parameter("memberID")),
-       )
-
-
     @classmethod
-    def _addRemovedMemberIDsQuery(cls, memberIDs): #@NoSelf
+    def _addRemovedMemberIDsToGroupIDQuery(cls, memberIDs): #@NoSelf
         """
-        DAL statement update a group member
+        DAL statement to mark a member table rows as not removed
         """
         aboMembers = schema.ABO_MEMBERS
         return Update(
-            {#aboMembers.RESOURCE_NAME: Parameter("resourceName"),
-             aboMembers.REVISION: Parameter("revision"),
+            {aboMembers.REVISION: Parameter("revision"),
              aboMembers.REMOVED: False, },
             Where=(aboMembers.GROUP_ID == Parameter("groupID"))
               .And(aboMembers.ADDRESSBOOK_ID == Parameter("addressbookID"))
@@ -1837,9 +1919,9 @@
 
 
     @classmethod
-    def _removeMemberIDsQuery(cls, memberIDs): #@NoSelf
+    def _removeMemberIDsFromGroupIDQuery(cls, memberIDs): #@NoSelf
         """
-        DAL statement update a group member
+        DAL statement to mark a member table row to as removed
         """
         aboMembers = schema.ABO_MEMBERS
         return Update(
@@ -1852,7 +1934,7 @@
 
 
     @classmethod
-    def _removeGroupIDsQuery(cls, groupIDs): #@NoSelf
+    def _removeMemberIDFromGroupIDsQuery(cls, groupIDs): #@NoSelf
         """
         DAL statement update a group member
         """
@@ -1866,43 +1948,7 @@
        )
 
 
-    @classproperty
-    def _removeMemberIDQuery(cls): #@NoSelf
-        """
-        DAL statement update a group member
-        """
-        aboMembers = schema.ABO_MEMBERS
-        return Update(
-            {aboMembers.RESOURCE_NAME: Parameter("resourceName"),
-             aboMembers.REVISION: Parameter("revision"),
-             aboMembers.REMOVED: True, },
-            Where=(aboMembers.GROUP_ID == Parameter("groupID"))
-              .And(aboMembers.ADDRESSBOOK_ID == Parameter("addressbookID"))
-              .And(aboMembers.MEMBER_ID == Parameter("memberID")),
-       )
-
-
     @inlineCallbacks
-    def _markMemberIDsDeleted(self, memberIDsToRemove): #@NoSelf
-        abo = schema.ADDRESSBOOK_OBJECT
-        memberIDNameRows = (
-            yield self._columnsWithResourceIDsQuery(
-                [abo.RESOURCE_ID, abo.RESOURCE_NAME],
-                memberIDsToRemove
-            ).on(self._txn, resourceIDs=memberIDsToRemove)
-        ) if memberIDsToRemove else []
-
-        for memberIDToRemove, memberNameToRemove in memberIDNameRows:
-            yield self._removeMemberIDQuery.on(self._txn,
-                groupID=self._resourceID,
-                addressbookID=self._ownerAddressBookResourceID,
-                memberID=memberIDToRemove,
-                resourceName=memberNameToRemove,
-                revision=self.addressbook()._syncTokenRevision,
-           )
-
-
-    @inlineCallbacks
     def updateDatabase(self, component, expand_until=None, reCreate=False, #@UnusedVariable
                        inserting=False):
         """
@@ -1963,7 +2009,7 @@
 
             # sort unique members
             component.removeProperties("X-ADDRESSBOOKSERVER-MEMBER")
-            for memberAddress in sorted(list(memberAddresses)): # sort unique
+            for memberAddress in sorted(memberAddresses):
                 component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
             componentText = str(component)
 
@@ -2060,7 +2106,7 @@
                )
 
             if memberIDsToReadd:
-                yield self._addRemovedMemberIDsQuery(memberIDsToReadd).on(self._txn,
+                yield self._addRemovedMemberIDsToGroupIDQuery(memberIDsToReadd).on(self._txn,
                     groupID=self._resourceID,
                     addressbookID=self._ownerAddressBookResourceID,
                     memberIDs=memberIDsToReadd,
@@ -2068,7 +2114,7 @@
                )
 
             if memberIDsToRemove:
-                yield self._removeMemberIDsQuery(memberIDsToRemove).on(
+                yield self._removeMemberIDsFromGroupIDQuery(memberIDsToRemove).on(
                     self._txn,
                     groupID=self._resourceID,
                     addressbookID=self._ownerAddressBookResourceID,

Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py	2013-09-03 00:40:32 UTC (rev 11651)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py	2013-09-03 20:21:54 UTC (rev 11652)
@@ -1918,7 +1918,6 @@
         changed = set()
         deleted = set()
         deleted_collections = set()
-        changed_collections = set()
         for path, name, wasdeleted in results:
             if wasdeleted:
                 if revision:
@@ -1942,47 +1941,16 @@
                     # Resource changed - for depth "infinity" report resource as changed
                     if depth != "1":
                         changed.add("%s/%s" % (path, name,))
-                else:
-                    # Collection was changed
-                    changed_collections.add(path)
 
         # Now deal with shared collections
         # TODO: think about whether this can be done in one query rather than looping over each share
-        rev = self._revisionsSchema
         shares = yield self.children()
         for share in shares:
             if not share.owned():
-                sharerevision = 0 if revision < share._bindRevision else revision
-                results = [
-                    (
-                        share.name(),
-                        name if name else "",
-                        wasdeleted
-                    )
-                    for name, wasdeleted in
-                    (yield Select([rev.RESOURCE_NAME, rev.DELETED],
-                                     From=rev,
-                                    Where=(rev.REVISION > sharerevision).And(
-                                    rev.RESOURCE_ID == share._resourceID)).on(self._txn))
-                    if name
-                ]
+                sharedChanged, sharedDeleted = yield share.sharedChildResourceNamesSinceRevision(revision, depth)
+                changed |= sharedChanged
+                deleted |= sharedDeleted
 
-                for path, name, wasdeleted in results:
-                    if wasdeleted:
-                        if sharerevision:
-                            if depth == "1":
-                                changed.add("%s/" % (path,))
-                            else:
-                                deleted.add("%s/%s" % (path, name,))
-
-                for path, name, wasdeleted in results:
-                    # Always report collection as changed
-                    changed.add("%s/" % (path,))
-                    if name:
-                        # Resource changed - for depth "infinity" report resource as changed
-                        if depth != "1":
-                            changed.add("%s/%s" % (path, name,))
-
         changed = sorted(changed)
         deleted = sorted(deleted)
         returnValue((changed, deleted))
@@ -4146,6 +4114,66 @@
 
 
     @inlineCallbacks
+    def sharedChildResourceNamesSinceRevision(self, revision, depth):
+        """
+        Determine the list of child resources that have changed since the specified sync revision.
+        We do the same SQL query for both depth "1" and "infinity", but filter the results for
+        "1" to only account for a collection change.
+
+        We need to handle shared collection a little differently from owned ones. When a shared collection
+        is bound into a home we record a revision for it using the sharee home id and sharee collection name.
+        That revision is the "starting point" for changes: so if sync occurs with a revision earlier than
+        that, we return the list of all resources in the shared collection since they are all "new" as far
+        as the client is concerned since the shared collection has just appeared. For a later revision, we
+        just report the changes since that one. When a shared collection is removed from a home, we again
+        record a revision for the sharee home and sharee collection name with the "deleted" flag set. That way
+        the shared collection can be reported as removed.
+
+        @param revision: the sync revision to compare to
+        @type revision: C{str}
+        @param depth: depth for determine what changed
+        @type depth: C{str}
+        """
+        assert not self.owned()
+
+        changed = set()
+        deleted = set()
+        rev = self._revisionsSchema
+        sharerevision = 0 if revision < self._bindRevision else revision
+        results = [
+            (
+                self.name(),
+                name if name else "",
+                wasdeleted
+            )
+            for name, wasdeleted in
+            (yield Select([rev.RESOURCE_NAME, rev.DELETED],
+                             From=rev,
+                            Where=(rev.REVISION > sharerevision).And(
+                            rev.RESOURCE_ID == self._resourceID)).on(self._txn))
+            if name
+        ]
+
+        for path, name, wasdeleted in results:
+            if wasdeleted:
+                if sharerevision:
+                    if depth == "1":
+                        changed.add("%s/" % (path,))
+                    else:
+                        deleted.add("%s/%s" % (path, name,))
+
+        for path, name, wasdeleted in results:
+            # Always report collection as changed
+            changed.add("%s/" % (path,))
+            if name:
+                # Resource changed - for depth "infinity" report resource as changed
+                if depth != "1":
+                    changed.add("%s/%s" % (path, name,))
+
+        returnValue((changed, deleted))
+
+
+    @inlineCallbacks
     def _loadPropertyStore(self, props=None):
         if props is None:
             props = yield PropertyStore.load(
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130903/e9870bb8/attachment-0001.html>


More information about the calendarserver-changes mailing list