Revision: 9318 http://trac.macosforge.org/projects/calendarserver/changeset/9318 Author: cdaboo@apple.com Date: 2012-05-31 10:46:35 -0700 (Thu, 31 May 2012) Log Message: ----------- Make sure we don't keeping expanding instances when we have a valid cache. Modified Paths: -------------- CalendarServer/trunk/twistedcaldav/ical.py CalendarServer/trunk/twistedcaldav/test/test_icalendar.py Modified: CalendarServer/trunk/twistedcaldav/ical.py =================================================================== --- CalendarServer/trunk/twistedcaldav/ical.py 2012-05-31 00:06:04 UTC (rev 9317) +++ CalendarServer/trunk/twistedcaldav/ical.py 2012-05-31 17:46:35 UTC (rev 9318) @@ -1025,7 +1025,9 @@ def cacheExpandedTimeRanges(self, limit, ignoreInvalidInstances=False): """ Expand instances up to the specified limit and cache the results in this object - so we can return cached results in the future. + so we can return cached results in the future. The limit value is the actual value + that the requester needs, but we will cache an addition 365-days worth to give us some + breathing room to return results for future instances. @param limit: the max datetime to cache up to. @type limit: L{PyCalendarDateTime} @@ -1039,8 +1041,11 @@ # so return cached instances return self.cachedInstances - self.cachedInstances = self.expandTimeRanges(limit, - ignoreInvalidInstances=ignoreInvalidInstances) + lookAheadLimit = limit + PyCalendarDuration(days=365) + self.cachedInstances = self.expandTimeRanges( + lookAheadLimit, + ignoreInvalidInstances=ignoreInvalidInstances + ) return self.cachedInstances def expandTimeRanges(self, limit, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex): @@ -1182,9 +1187,7 @@ # Check whether we have a truncated RRULE rrules = master.properties("RRULE") if len(tuple(rrules)): - limit = rid.duplicate() - limit += PyCalendarDuration(days=365) - instances = self.cacheExpandedTimeRanges(limit) + instances = self.cacheExpandedTimeRanges(rid) rids = set([instances[key].rid for key in instances]) instance_rid = normalizeForIndex(rid) if instance_rid not in rids: @@ -1243,6 +1246,7 @@ valid = set() non_master_rids = [rid for rid in rids if rid is not None] if non_master_rids: + # Pre-cache instance expansion up to the highest rid highest_rid = max(non_master_rids) self.cacheExpandedTimeRanges( highest_rid + PyCalendarDuration(days=1), @@ -1271,7 +1275,7 @@ # Get expansion instances = self.cacheExpandedTimeRanges( - rid + PyCalendarDuration(days=1), + rid, ignoreInvalidInstances=ignoreInvalidInstances ) new_rids = set([instances[key].rid for key in instances]) Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py =================================================================== --- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-05-31 00:06:04 UTC (rev 9317) +++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-05-31 17:46:35 UTC (rev 9318) @@ -4161,6 +4161,45 @@ derived = str(derived).replace("\r", "") if derived else None self.assertEqual(derived, result, "Failed derive instance test: %s" % (title,)) + def test_derive_instance_cache(self): + """ + Test that derivation of instances only triggers an instance cache re-expansion when it + goes past the end of the last cache. + """ + + event = """BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN +BEGIN:VEVENT +UID:12345-67890-1 +DTSTART:20090101T080000Z +DTEND:20090101T090000Z +DTSTAMP:20080601T120000Z +RRULE:FREQ=DAILY +END:VEVENT +END:VCALENDAR +""" + + ical = Component.fromString(event) + self.assertFalse(hasattr(ical, "cachedInstances")) + + # Derive one day apart - no re-cache + ical.deriveInstance(PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True))) + self.assertTrue(hasattr(ical, "cachedInstances")) + oldLimit = ical.cachedInstances.limit + ical.deriveInstance(PyCalendarDateTime(2009, 1, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True))) + self.assertEqual(ical.cachedInstances.limit, oldLimit) + + # Derive several years ahead - re-cached + ical.deriveInstance(PyCalendarDateTime(2011, 1, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True))) + self.assertNotEqual(ical.cachedInstances.limit, oldLimit) + oldLimit = ical.cachedInstances.limit + + # Check one day ahead again - no re-cache + ical.deriveInstance(PyCalendarDateTime(2011, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True))) + self.assertEqual(ical.cachedInstances.limit, oldLimit) + + def test_truncate_recurrence(self): data = (