Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLIPublic
Assigneesstack72

Relationships

#3418 v3 first clone on Linux is 2.6x slower than v2: batch the catalog refresh during catch-up

Opened by stack72 · 10/13/2026· Shipped 10/14/2026

Background (read this first)

swamp is reworking its datastore layer (tracking: swamp-club#2865). In the new format, v3, every change is a commit in a single-writer SQLite commits.db. Content is stored as content-addressed chunks, and each checkout rebuilds its files from the commits. v3 is opt-in today for filesystem datastores (swamp-club#3279), and swamp-uat's filesystem-v3 backend tests it in CI.

Phase 4 is "solo mode on buckets":

  • the CLI is the single writer of a local commits.db;
  • Litestream replicates it to the bucket;
  • chunks go to the bucket through storage/1;
  • a fenced writer lease makes sure only one machine writes.

Done so far:

  • A, swamp-club#3357: replication cost on a bucket model, choosing an idle sidecar. See design/enablers/datastore-litestream.md, section "Phase 4A".
  • B, swamp-club#3358: download, verify and cache a pinned Litestream (0.5.17), dormant: src/infrastructure/datastore_v3/litestream/litestream_binary_provider.ts.
  • C, swamp-club#3359: the fenced writer lease (src/domain/datastore_v3/writer_lease.ts, src/infrastructure/datastore_v3/v3_writer_lock.ts). Every CLI write command takes a new fence, and serve keeps one for its lifetime. commits.db keeps a store-wide writer_fence.

The decisions are in design/enablers/datastore-litestream.md, under "Decision" and "What changes for Phase 4D and 4E", and in design/enablers/datastores.md, under the "v3 …" sections.

The gap

swamp-club#3337 removed the per-file fsync from v3's catch-up. On macOS a fresh checkout of 1,000 items fell from 26.0 s to 1.6 s, 1.45× v2. Linux still lags.

swamp-uat's Remote Datastore Benchmarks job (run 38477551054, ubuntu x86_64, release 20261013.220021.0-sha.a3fab18f, 3 samples), "first clone: setup + data list (1000 items)":

Backend p50 p95
filesystem (v2) 1,894 ms 1,924 ms
filesystem-v3 4,845 ms (2.6×) 5,738 ms

#3337's PR measured 1.9 s against 0.9 s (2.1×) in a linux-arm64 container on a Mac, and named two causes:

  • overlay-filesystem mkdir, which may be a container artifact;
  • the catalog's per-version SQLite transaction: the catch-up refreshes the query catalog (.swamp/_catalog_v3.db, through v2's CatalogStore) one version at a time, each in its own transaction.

Batching that touches v2's CatalogStore, so #3337 left it out.

Goal

Bring a Linux v3 first clone close to v2: within 1.5× on the CI job's first-clone line, as macOS is.

  1. Profile first, on a Linux host or the CI runner, not a container on a Mac. Say where the time goes before changing anything. scripts/bench_read_model_catch_up.ts benches the catch-up in-process.
  2. If the catalog dominates: add a batched path to CatalogStore, so one catch-up page refreshes the catalog in one transaction, and use it from the v3 read model.
    • v2 keeps calling the existing per-version path, unchanged.
    • Apply the v2 gate: v2 suites unedited, and the route recorder identical.
  3. Keep #3337's invariants:
    • the cursor never runs ahead of durable files;
    • the boot-id check stays;
    • the barrier on platforms without a boot id stays.

Tests

  • Existing suites pass unchanged: the read-model crash safety, shared keys, the v2 oracle, the reference-model property test, and CatalogStore's.
  • New: the batched catalog path gives the same catalog as the per-version path for the same commits (a property test over random commit sequences).
  • The figure: put the swamp-uat benchmark's filesystem-v3 and filesystem first-clone lines in the PR, from a Linux run against the branch build if possible.

Acceptance

  • Linux filesystem-v3 first clone (1,000 items) is within 1.5× of filesystem v2 on swamp-uat's benchmark job.
  • v2's behaviour and performance don't change.

Blocked by: nothing. Runs in parallel with D1. Phase 4's dogfood and benchmark item (I) waits on it.

02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 12 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/14/2026, 8:41:40 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/13/2026, 10:48:29 PM

Sign in to post a ripple.