# Phase 8 gate — mongo-lite vs MongoDB 8.3.7, 1g dataset / ~16k docs # Ratio < 1.0 = mongo-lite faster. Reproduce: bash tests/e2e/bench-run.sh 1g 16k # Working tree: c8d547f + uncommitted diff (epilogue-commit/group-commit work) + # three bugs found and fixed while benchmarking (details at the bottom). # Machine-readable copy: tests/e2e/results/bench-latest.txt (auto-diffed on # every bench-run.sh invocation). benchmark mongo-lite mongodb ratio insertOne (sequential) ×200 0.20 ms 14.8 ms 0.0x bulk insert throughput 732.4 MB/s 546.2 MB/s 1.3x docs loaded 65,536 65,536 1.0x createIndex({k: 1}) 74.4 ms 83.6 ms 0.9x countDocuments({}) 3.1 ms 12.4 ms 0.3x findOne({_id: }) 0.59 ms 0.61 ms 1.0x findOne({k: 500}) (indexed) 0.56 ms 0.94 ms 0.6x find({p: {$gte,$lt}}).count() (scan) 13.0 ms 15.0 ms 0.9x find({}).sort({_id:-1}).limit(20) 2.2 ms 2.2 ms 1.0x find({}, {proj}).limit(1000) 3.5 ms 4.4 ms 0.8x aggregate $group by k 8.3 ms 13.2 ms 0.6x updateOne({_id}) ×50 0.14 ms 0.20 ms 0.7x updateMany({k: 7}, {$inc}) 1.9 ms 6.4 ms 0.3x deleteOne({_id}) + insertOne 0.58 ms 4.9 ms 0.1x node client RSS 158 MB 157 MB 1.0x server RSS 553 MB 1486 MB kill -9 reopen 0.8s 1.3s db on disk 97MB 106MB # NEW: concurrent durable writes (sequential insertOne per client, {w:1, j:true}) # through the official driver, both servers, same workload: # clients | mongodb | mongo-lite | ratio # 1 | 232 | 8,435 | 36x # 4 | 491 | 22,480 | 46x # 8 | 966 | 25,920 | 27x # 16 | 1,842 | 31,079 | 17x # 32 | 3,632 | 34,041 | 9x # (mongo-lite scales to ~34k durable docs/s at 32 clients; mongod tops out # around 3.6k on this machine's fsync-per-write path.) # THREE BUGS FOUND AND FIXED WHILE BENCHMARKING # All three were invisible to the single-connection compare.js suite and only # surfaced under the new concurrent harness (tests/e2e/concurrent.js). # # 1. Group-commit deadlock (>=6 concurrent writers froze permanently). # std.Io.Condition.signal() delivers exactly ONE wakeup. The commit # leader's completion woke a single follower on `while (committing)` and # stranded the rest; an append's signal could also be consumed by a # follower, stranding the leader on the pending_appends drain. Signals # were also sent without commit_lock, leaving a lost-wakeup window # between a waiter's epoch snapshot and its futex sleep. # Fix (src/db.zig): all commit_done signals hold commit_lock and use # broadcast(). Reproduced on HEAD too (introduced by the group-commit # work, not the uncommitted diff). # # 2. Racy assertion in commit(): assert(pending_appends == 0) after the # drain loop. A NEW append can start at any moment (the increment takes # no commit_lock), so the assert fired spuriously under load and crashed # the server (32 concurrent clients, "commit would seal while appends # are still in flight"). The seal's real invariant holds via log_lock # ordering; the instant check was wrong. Fix: removed the assert. # # 3. Slab segment-start corruption in Collection.slab_append: a pointer # `last` into slab.items dangled across the slab.append() that starts the # next segment (the list can reallocate), so the new segment's start # offset was computed from freed memory. Docs in the affected segment # were then located at wrong offsets, surfacing as InvalidBson on reads # with a batch limit >~50 (or a crash in Debug builds). Position varied # between runs (heap contents vary). Fix: read the last segment's length # as a value before the append. # # Verification after the fixes: unit suite green, e2e6 72/72 (incl. kill -9 # mid-write recovery), crash pair, concurrent 8-client, indexes, TTL all # green; concurrent stress 1/4/8/16/32 clients x5 sequential rounds clean.