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

source_changes at macosforge.org source_changes at macosforge.org
Fri Oct 21 11:35:10 PDT 2011


Revision: 8216
          http://trac.macosforge.org/projects/calendarserver/changeset/8216
Author:   sagen at apple.com
Date:     2011-10-21 11:35:09 -0700 (Fri, 21 Oct 2011)
Log Message:
-----------
Adds a principal cache during the calendar-user-address normalization process of upgrades.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/test/test_upgrade.py
    CalendarServer/trunk/twistedcaldav/upgrade.py

Modified: CalendarServer/trunk/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_upgrade.py	2011-10-20 22:23:12 UTC (rev 8215)
+++ CalendarServer/trunk/twistedcaldav/test/test_upgrade.py	2011-10-21 18:35:09 UTC (rev 8216)
@@ -23,7 +23,7 @@
 from twistedcaldav.mail import MailGatewayTokensDatabase
 from twistedcaldav.upgrade import (
     xattrname, UpgradeError, upgradeData, updateFreeBusySet,
-    removeIllegalCharacters
+    removeIllegalCharacters, normalizeCUAddrs
 )
 from twistedcaldav.test.util import TestCase
 from calendarserver.tools.util import getDirectory
@@ -1422,6 +1422,69 @@
         self.assertFalse(changed)
 
 
+    def test_normalizeCUAddrs(self):
+        """
+        Ensure that calendar user addresses (CUAs) are cached so we can
+        reduce the number of principal lookup calls during upgrade.
+        """
+
+        class StubPrincipal(object):
+            def __init__(self, record):
+                self.record = record
+
+        class StubRecord(object):
+            def __init__(self, fullName, guid, cuas):
+                self.fullName = fullName
+                self.guid = guid
+                self.calendarUserAddresses = cuas
+
+        class StubDirectory(object):
+            def __init__(self):
+                self.count = 0
+
+            def principalForCalendarUserAddress(self, cuaddr):
+                self.count += 1
+                record = records.get(cuaddr, None)
+                if record is not None:
+                    return StubPrincipal(record)
+                else:
+                    raise Exception
+
+        records = {
+            "mailto:a at example.com" :
+                StubRecord("User A", 123, ("mailto:a at example.com", "urn:uuid:123")),
+            "mailto:b at example.com" :
+                StubRecord("User B", 234, ("mailto:b at example.com", "urn:uuid:234")),
+        }
+
+        directory = StubDirectory()
+        cuaCache = {}
+        normalizeCUAddrs(normalizeEvent, directory, cuaCache)
+        normalizeCUAddrs(normalizeEvent, directory, cuaCache)
+
+        # Ensure we only called principalForCalendarUserAddress 3 times.  It
+        # would have been 8 times without the cuaCache.
+        self.assertEquals(directory.count, 3)
+
+normalizeEvent = """BEGIN:VCALENDAR
+VERSION:2.0
+BEGIN:VEVENT
+TRANSP:OPAQUE
+UID:1E238CA1-3C95-4468-B8CD-C8A399F78C71
+DTSTART:20090203
+DTEND:20090204
+ORGANIZER;CN="User A":mailto:a at example.com
+SUMMARY:New Event
+DESCRIPTION:Foo
+ATTENDEE;CN="User A";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:a at example.com
+ATTENDEE;CN="User B";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:b at example.com
+ATTENDEE;CN="Unknown";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:unknown at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+
+
 event01_before = """BEGIN:VCALENDAR
 VERSION:2.0
 PRODID:-//Apple Inc.//iCal 3.0//EN

Modified: CalendarServer/trunk/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/upgrade.py	2011-10-20 22:23:12 UTC (rev 8215)
+++ CalendarServer/trunk/twistedcaldav/upgrade.py	2011-10-21 18:35:09 UTC (rev 8216)
@@ -115,38 +115,10 @@
 
 
 
-    def normalizeCUAddrs(data, directory):
-        cal = Component.fromString(data)
 
-        def lookupFunction(cuaddr):
-            try:
-                principal = directory.principalForCalendarUserAddress(cuaddr)
-            except Exception, e:
-                log.debug("Lookup of %s failed: %s" % (cuaddr, e))
-                principal = None
 
-            if principal is None:
-                return (None, None, None)
-            else:
-                rec = principal.record
+    def upgradeCalendarCollection(calPath, directory, cuaCache):
 
-                # RFC5545 syntax does not allow backslash escaping in
-                # parameter values. A double-quote is thus not allowed
-                # in a parameter value except as the start/end delimiters.
-                # Single quotes are allowed, so we convert any double-quotes
-                # to single-quotes.
-                fullName = rec.fullName.replace('"', "'")
-
-                return (fullName, rec.guid, rec.calendarUserAddresses)
-
-        cal.normalizeCalendarUserAddresses(lookupFunction)
-
-        newData = str(cal)
-        return newData, not newData == data
-
-
-    def upgradeCalendarCollection(calPath, directory):
-
         errorOccurred = False
         collectionUpdated = False
 
@@ -189,7 +161,7 @@
                     continue
 
                 try:
-                    data, fixed = normalizeCUAddrs(data, directory)
+                    data, fixed = normalizeCUAddrs(data, directory, cuaCache)
                     if fixed:
                         log.debug("Normalized CUAddrs in %s" % (resPath,))
                         needsRewrite = True
@@ -236,7 +208,7 @@
         return errorOccurred
 
 
-    def upgradeCalendarHome(homePath, directory):
+    def upgradeCalendarHome(homePath, directory, cuaCache):
 
         errorOccurred = False
 
@@ -254,7 +226,7 @@
                     rmdir(calPath)
                     continue
                 log.debug("Upgrading calendar: %s" % (calPath,))
-                if not upgradeCalendarCollection(calPath, directory):
+                if not upgradeCalendarCollection(calPath, directory, cuaCache):
                     errorOccurred = True
 
                 # Change the calendar-free-busy-set xattrs of the inbox to the
@@ -392,6 +364,7 @@
 
 
     directory = getDirectory()
+    cuaCache = {}
 
     docRoot = config.DocumentRoot
 
@@ -515,7 +488,7 @@
                                         continue
 
                                     if not upgradeCalendarHome(homePath,
-                                        directory):
+                                        directory, cuaCache):
                                         errorOccurred = True
 
                                     count += 1
@@ -532,6 +505,55 @@
         raise UpgradeError("Data upgrade failed, see error.log for details")
 
 
+def normalizeCUAddrs(data, directory, cuaCache):
+    """
+    Normalize calendar user addresses to urn:uuid: form.
+
+    @param data: the calendar data to convert
+    @type data: C{str}
+    @param directory: the directory service to lookup CUAs with
+    @type data: L{DirectoryService}
+    @param cuaCache: the dictionary to use as a cache across calls, which is
+        updated as a side-effect
+    @type cuaCache: C{dict}
+    @return: tuple of (converted calendar data, boolean signaling whether
+        there were any changes to the data)
+    """
+    cal = Component.fromString(data)
+
+    def lookupFunction(cuaddr):
+        try:
+            if cuaCache.has_key(cuaddr):
+                principal = cuaCache[cuaddr]
+            else:
+                principal = directory.principalForCalendarUserAddress(cuaddr)
+        except Exception, e:
+            log.debug("Lookup of %s failed: %s" % (cuaddr, e))
+            principal = None
+
+        cuaCache[cuaddr] = principal
+
+        if principal is None:
+            return (None, None, None)
+        else:
+            rec = principal.record
+
+            # RFC5545 syntax does not allow backslash escaping in
+            # parameter values. A double-quote is thus not allowed
+            # in a parameter value except as the start/end delimiters.
+            # Single quotes are allowed, so we convert any double-quotes
+            # to single-quotes.
+            fullName = rec.fullName.replace('"', "'")
+
+            return (fullName, rec.guid, rec.calendarUserAddresses)
+
+    cal.normalizeCalendarUserAddresses(lookupFunction)
+
+    newData = str(cal)
+    return newData, not newData == data
+
+
+
 @inlineCallbacks
 def upgrade_to_2(config):
     
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20111021/5fbbd86a/attachment.html>


More information about the calendarserver-changes mailing list