Sync: each changed or unclaimed card and event is fetched with a GET of its own, and in read-only mode every foreign event is fetched on every run #45
Labels
No labels
bug
documentation
enhancement
performance
security
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-dav#45
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What exists today
On the forge's
main(83710e9):Server.etags(src/postulo_dav/dav.py:347-375) is a Depth 1PROPFINDforgetetagandresourcetype, once per half per run (sync.py:681,sync.py:968). It is the full membership, about 150 to 300 bytes per resource, read toLISTING_LIMIT(2 MB).Server.get(dav.py:377-381) is oneGETper resource. Contacts read every card no link claims (sync.py:700-712) and every linked card whose ETag moved (sync.py:827). Interviews read every unlinked event wheneverwantedis true (sync.py:993-1007), and every linked event whose ETag moved (sync.py:1100).wanted(sync.py:995-1001) is true whenever an interview of the last 90 days has no twin. In read-only mode nothing is ever pushed, so it stays true for as long as such an interview exists, and every event on the calendar that is not Postulo's is fetched again on every run, only to be counted as foreign atsync.py:1184-1192. Cards that are never adopted (noFN, an over-long href or UID,sync.py:935-941) are likewise fetched on every run.tests/test_dav.py:45-120, anhttpx.MockTransporthandler) answersPROPFIND,GET,PUT,DELETE,MKCOLandMKCALENDAR; it has noREPORT.Protocol:
addressbook-multiget(RFC 6352 §8.7) andcalendar-multiget(RFC 4791 §7.9) are mandatory for every CardDAV and CalDAV server, so every server the README names (Nextcloud, Radicale, Baïkal, SOGo, Fastmail, iCloud) answers them; oneREPORTnames many hrefs and returns each one'sgetetagandaddress-dataorcalendar-datain a multistatus. RFC 6578sync-collectionis optional, advertised inDAV:supported-report-set; SabreDAV (Nextcloud, Baïkal), Radicale, Fastmail, iCloud and Google implement it. CTag (getctag) is a non-standard Apple property that RFC 6578'sDAV:sync-tokenreplaces.What would change
Server.multiget(collection, hrefs, kind)that sends oneREPORTper batch of hrefs (sized so the answer stays underLISTING_LIMIT, e.g. 50 cards or 50 events), parses the multistatus with the existingdefusedxmlreader, holds every returned href to the collection exactly asetags()does (#13, #33), and returnshref → Resource. Theread()closures of both halves prefetch every href they are about to need in one call before the loops, and keepget()as the fallback for a resource the multistatus answered with 404 or omitted. The fake server learnsREPORT.In read-only mode the foreign events are still read on every run, but as a few
REPORTs rather than hundreds of GETs; skipping the unchanged ones would need stored state (item 2).DAV:sync-tokenof each collection and asksync-collectionfor the delta; fall back to the full listing onvalid-sync-token(403/409) or when the report is not supported. This turns the listing too into a delta, but the listing is already small; the GETs were the cost.Library: the plugin speaks DAV through the core's guarded
httpxclient by design (#13, #33), socaldav/vobjectclients are not a fit; the multiget body is a few lines of XML beside the existing_ETAGS.What it saves or protects
medium: the GETs of a run become one
REPORTper 50 to 100 resources (a first run against a 300-card address book goes from about 302 requests to about 8); a read-only connection on a shared calendar of 500 events stops making 500 GETs an hourAccessibility
none
Decided by the maintainer (2026-10-31)
DAV multiget now (batches of 50, split on size refusal); sync tokens later, once PR2 exists
Decisions
REPORT, read to its own limit of 50 ×RESOURCE_LIMIT-sized answers capped at a few MB; a batch whose answer is refused for size (cards with photos) is split in two and asked again.Found by the efficiency and reliability audit of 2026-10-30 (finding PR5; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).