Files
mdcaldav/tests
Tyler Perkins cbe69ec1d7
Some checks failed
CI / test (push) Failing after 5s
CI / image (push) Has been skipped
Serialize index access between the watcher and request threads
The watcher thread crashed in production with "database is locked", and
under load the damage is worse than a stalled rescan:

    sqlite3.InterfaceError: bad parameter or other API misuse
    TypeError: 'NoneType' object is not subscriptable

Radicale serializes its request threads with Storage.acquire_lock, but the
watcher calls index.rescan() outside it. Both share one sqlite3 connection,
and rescan is a multi-statement read-modify-write — bump the generation,
reparse, reconcile identities, prune, commit. Interleaving two of those
corrupts the reconcile pass and misuses the connection.

Give Index an RLock and take it in every public method. Writer holds it
across validate → write → reindex, since a rescan landing between _load
and the splice would invalidate the byte spans about to be written.

Two supporting fixes:

  - _rebuild_memory assigned an empty dict before refilling it, so a reader
    could observe a half-populated task list. Build, then swap.
  - Open the database in WAL with a 30s busy_timeout, so `mdcaldav doctor`
    run against a live server waits instead of failing.

This is also a second, independent cause of the ETag churn fixed in
2552545: a corrupted reconcile pass reassigns last_modified on tasks that
never changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 14:13:53 -04:00
..
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00
2026-08-01 21:03:35 -04:00