[CalendarServer-changes] [7802] CalendarServer/trunk/contrib/performance/loadtest
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jul 15 08:56:51 PDT 2011
Revision: 7802
http://trac.macosforge.org/projects/calendarserver/changeset/7802
Author: cdaboo at apple.com
Date: 2011-07-15 08:56:51 -0700 (Fri, 15 Jul 2011)
Log Message:
-----------
Batch multiget requests like clients do.
Modified Paths:
--------------
CalendarServer/trunk/contrib/performance/loadtest/ical.py
CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report.request
CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
Added Paths:
-----------
CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report_href.request
Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py 2011-07-15 14:47:18 UTC (rev 7801)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py 2011-07-15 15:56:51 UTC (rev 7802)
@@ -181,6 +181,9 @@
# configuration. This is also the actual value used by Snow
# Leopard iCal.
CALENDAR_HOME_POLL_INTERVAL = 15 * 60
+
+ # The maximum number of resources to retrieve in a single multiget
+ MULTIGET_BATCH_SIZE = 200
_STARTUP_PRINCIPAL_PROPFIND = loadRequestBody('sl_startup_principal_propfind')
_STARTUP_PRINCIPALS_REPORT = loadRequestBody('sl_startup_principals_report')
@@ -190,6 +193,7 @@
_CALENDAR_PROPFIND = loadRequestBody('sl_calendar_propfind')
_CALENDAR_REPORT = loadRequestBody('sl_calendar_report')
+ _CALENDAR_REPORT_HREF = loadRequestBody('sl_calendar_report_href')
_USER_LIST_PRINCIPAL_PROPERTY_SEARCH = loadRequestBody('sl_user_list_principal_property_search')
_POST_AVAILABILITY = loadRequestBody('sl_post_availability')
@@ -396,6 +400,7 @@
body = yield readBody(response)
result = self._parseMultiStatus(body)
+ changed = []
for responseHref in result:
if responseHref == calendar.url:
continue
@@ -411,9 +416,17 @@
event = self._events[responseHref]
if event.etag != etag:
- response = yield self._eventReport(url, responseHref)
- body = yield readBody(response)
- res = self._parseMultiStatus(body)[responseHref]
+ changed.append(responseHref)
+
+ while changed:
+ batchedHrefs = changed[:self.MULTIGET_BATCH_SIZE]
+ changed = changed[self.MULTIGET_BATCH_SIZE:]
+
+ response = yield self._eventReport(url, batchedHrefs)
+ body = yield readBody(response)
+ multistatus = self._parseMultiStatus(body)
+ for responseHref in batchedHrefs:
+ res = multistatus[responseHref]
if res.getStatus() is None or " 404 " not in res.getStatus():
text = res.getTextProperties()
etag = text[davxml.getetag]
@@ -434,15 +447,16 @@
self.catalog["eventChanged"].issue(href)
- def _eventReport(self, calendar, event):
- # Next do a REPORT on each event that might have information
+ def _eventReport(self, calendar, events):
+ # Next do a REPORT on events that might have information
# we don't know about.
+ hrefs = "".join([self._CALENDAR_REPORT_HREF % {'href': event} for event in events])
return self._request(
MULTI_STATUS,
'REPORT',
self.root + calendar,
Headers({'content-type': ['text/xml']}),
- StringProducer(self._CALENDAR_REPORT % {'href': event}))
+ StringProducer(self._CALENDAR_REPORT % {'hrefs': hrefs}))
def _checkCalendarsForEvents(self, calendarHomeSet):
Modified: CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report.request
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report.request 2011-07-15 14:47:18 UTC (rev 7801)
+++ CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report.request 2011-07-15 15:56:51 UTC (rev 7802)
@@ -1,2 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
-<x0:calendar-multiget xmlns:x0="urn:ietf:params:xml:ns:caldav" xmlns:x1="DAV:"><x1:prop><x1:getetag/><x0:calendar-data/><x0:schedule-tag/></x1:prop><x1:href>%(href)s</x1:href></x0:calendar-multiget>
+<x0:calendar-multiget xmlns:x0="urn:ietf:params:xml:ns:caldav" xmlns:x1="DAV:">
+ <x1:prop>
+ <x1:getetag/>
+ <x0:calendar-data/>
+ <x0:schedule-tag/>
+ </x1:prop>
+%(hrefs)s
+</x0:calendar-multiget>
Added: CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report_href.request
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report_href.request (rev 0)
+++ CalendarServer/trunk/contrib/performance/loadtest/request-data/sl_calendar_report_href.request 2011-07-15 15:56:51 UTC (rev 7802)
@@ -0,0 +1 @@
+ <x1:href>%(href)s</x1:href>
Modified: CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_ical.py 2011-07-15 14:47:18 UTC (rev 7801)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_ical.py 2011-07-15 15:56:51 UTC (rev 7802)
@@ -971,10 +971,10 @@
self.client._events[event.url] = event
self.client.changeEventAttendee(event.url, old, new)
- result, req = requests.pop(0)
+ _ignore_result, req = requests.pop(0)
# iCal PUTs the new VCALENDAR object.
- expectedResponseCode, method, url, headers, body = req
+ _ignore_expectedResponseCode, method, url, headers, body = req
self.assertEquals(method, 'PUT')
self.assertEquals(url, 'http://127.0.0.1' + event.url)
self.assertIsInstance(url, str)
@@ -1146,8 +1146,87 @@
<href>/something/anotherthing.ics</href>
<status>HTTP/1.1 404 Not Found</status>
</response>
+ <response>
+ <href>/something/else.ics</href>
+ <propstat>
+ <prop>
+ <getetag>"ef70beb4cb7da4b2e2950350b09e9a01"</getetag>
+ <calendar-data xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:CD54161A13AA8A4649D3781E at caldav.corp.apple.com
+DTSTART:20110715T140000Z
+DURATION:PT1H
+DTSTAMP:20110715T144217Z
+SUMMARY:Test2
+END:VEVENT
+END:VCALENDAR
+]]></calendar-data>
+ </prop>
+ <status>HTTP/1.1 200 OK</status>
+ </propstat>
+ </response>
</multistatus>
"""
+
+ _CALENDAR_REPORT_RESPONSE_BODY_1 = """\
+<?xml version='1.0' encoding='UTF-8'?>
+<multistatus xmlns='DAV:'>
+ <response>
+ <href>/something/anotherthing.ics</href>
+ <propstat>
+ <prop>
+ <getetag>"ef70beb4cb7da4b2e2950350b09e9a01"</getetag>
+ <calendar-data xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:anotherthing at caldav.corp.apple.com
+DTSTART:20110715T140000Z
+DURATION:PT1H
+DTSTAMP:20110715T144217Z
+SUMMARY:Test1
+END:VEVENT
+END:VCALENDAR
+]]></calendar-data>
+ </prop>
+ <status>HTTP/1.1 200 OK</status>
+ </propstat>
+ </response>
+</multistatus>
+"""
+
+ _CALENDAR_REPORT_RESPONSE_BODY_2 = """\
+<?xml version='1.0' encoding='UTF-8'?>
+<multistatus xmlns='DAV:'>
+ <response>
+ <href>/something/else.ics</href>
+ <propstat>
+ <prop>
+ <getetag>"ef70beb4cb7da4b2e2950350b09e9a01"</getetag>
+ <calendar-data xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:else at caldav.corp.apple.com
+DTSTART:20110715T140000Z
+DURATION:PT1H
+DTSTAMP:20110715T144217Z
+SUMMARY:Test2
+END:VEVENT
+END:VCALENDAR
+]]></calendar-data>
+ </prop>
+ <status>HTTP/1.1 200 OK</status>
+ </propstat>
+ </response>
+</multistatus>
+"""
+
def test_eventMissing(self):
"""
If an event included in the calendar PROPFIND response no longer exists
@@ -1160,7 +1239,7 @@
self.client._calendars[calendar.url] = calendar
self.client._updateCalendar(calendar)
result, req = requests.pop(0)
- expectedResponseCode, method, url, headers, body = req
+ expectedResponseCode, method, url, _ignore_headers, _ignore_body = req
self.assertEqual('PROPFIND', method)
self.assertEqual('http://127.0.0.1/something/', url)
self.assertEqual(MULTI_STATUS, expectedResponseCode)
@@ -1171,7 +1250,7 @@
StringProducer(self._CALENDAR_PROPFIND_RESPONSE_BODY)))
result, req = requests.pop(0)
- expectedResponseCode, method, url, headers, body = req
+ expectedResponseCode, method, url, _ignore_headers, _ignore_body = req
self.assertEqual('REPORT', method)
self.assertEqual('http://127.0.0.1/something/', url)
self.assertEqual(MULTI_STATUS, expectedResponseCode)
@@ -1189,7 +1268,59 @@
self.assertIn('/something/else.ics', self.client._events)
+ def test_multigetBatch(self):
+ """
+ If an event included in the calendar PROPFIND response no longer exists
+ by the time a REPORT is issued for that event, the 404 is handled and
+ the rest of the normal update logic for that event is skipped.
+ """
+ requests = self.interceptRequests()
+ self.patch(self.client, "MULTIGET_BATCH_SIZE", 1)
+
+ calendar = Calendar(None, 'calendar', '/something/', None)
+ self.client._calendars[calendar.url] = calendar
+ self.client._updateCalendar(calendar)
+ result, req = requests.pop(0)
+ expectedResponseCode, method, url, _ignore_headers, _ignore_body = req
+ self.assertEqual('PROPFIND', method)
+ self.assertEqual('http://127.0.0.1/something/', url)
+ self.assertEqual(MULTI_STATUS, expectedResponseCode)
+
+ result.callback(
+ MemoryResponse(
+ ('HTTP', '1', '1'), MULTI_STATUS, "Multi-status", None,
+ StringProducer(self._CALENDAR_PROPFIND_RESPONSE_BODY)))
+
+ result, req = requests.pop(0)
+ expectedResponseCode, method, url, _ignore_headers, _ignore_body = req
+ self.assertEqual('REPORT', method)
+ self.assertEqual('http://127.0.0.1/something/', url)
+ self.assertEqual(MULTI_STATUS, expectedResponseCode)
+
+ result.callback(
+ MemoryResponse(
+ ('HTTP', '1', '1'), MULTI_STATUS, "Multi-status", None,
+ StringProducer(self._CALENDAR_REPORT_RESPONSE_BODY_1)))
+
+ self.assertTrue(self.client._events['/something/anotherthing.ics'].etag is not None)
+ self.assertTrue(self.client._events['/something/else.ics'].etag is None)
+
+ result, req = requests.pop(0)
+ expectedResponseCode, method, url, _ignore_headers, _ignore_body = req
+ self.assertEqual('REPORT', method)
+ self.assertEqual('http://127.0.0.1/something/', url)
+ self.assertEqual(MULTI_STATUS, expectedResponseCode)
+
+ result.callback(
+ MemoryResponse(
+ ('HTTP', '1', '1'), MULTI_STATUS, "Multi-status", None,
+ StringProducer(self._CALENDAR_REPORT_RESPONSE_BODY_2)))
+
+ self.assertTrue(self.client._events['/something/anotherthing.ics'].etag is not None)
+ self.assertTrue(self.client._events['/something/else.ics'].etag is not None)
+
+
class VFreeBusyTests(SnowLeopardMixin, TestCase):
"""
Tests for L{SnowLeopard.requestAvailability}.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110715/acd89ece/attachment-0001.html>
More information about the calendarserver-changes
mailing list