results: the M0 gates, measured

PLAN D7's six items, with the numbers and the command that reproduces each in
tests/e2e/results/m0-gates.txt. Unit tests green in both optimize modes, the
whole e2e matrix green, the spec scorecard byte-identical at 131/161/195, and
the large smoke run at the scale D7.3 asked for:

  21.47 GB collection (1,310,720 x 16 KiB)
  data file                 21.75 GB      (+1.3% over the documents)
  log after the load        2.5 MB        (checkpoints reclaim it)
  kill -9 then reopen       0.5 s         (0.5 s at 4 GB too -- flat)
  RSS after reopen          237 MB        (1.1% of the data)
  count after restart       1,310,720     last document byte-intact
  acked writes after kill   200/200

That is the milestone's claim, measured: an open costs the working set rather
than the size of the database. Before M0 the same measurement was 523 MB
resident for a 512 MB database, because recovering each document's `_id` meant
reading every document at open.

Two gates need reading rather than a tick, and m0-gates.txt says so where a
reader would otherwise take a tick for granted.

The churn gate settles at 1.65x live data (delete-heavy) to 2.47x
(update-heavy), flat, above the ~1.3x amendment A2 hoped for. Rebuild-only
reclamation cannot reach that: it needs a whole second copy of the live data
before the first can be freed. The gate existed to decide whether doc-level
free lists are needed after M0, and that is the answer.

Benchmark parity holds for every read and latency row inside the run-to-run
spread, and bulk insert regresses 24% (732 -> 555 MB/s), reproducibly across
three runs. Risk 1 as written: document bytes now reach the disk uncompressed
on top of the LZ4 log. createIndex improves 62% from the same change.

Three measurement bugs fixed while running the gates, because each would have
put a false number in the README:

  - `compare-run.sh` measured "db on disk" as `du` of the log alone against
    `du` of mongod's whole dbpath. It reported 20 MB for a 1 GB collection --
    the documents had moved to <db>.data. Honest figure, measured: 914 MB of
    allocated blocks against mongod's compressed 85 MB.
  - `big.js` counted "compaction events" as "the log shrank", which is a
    *checkpoint* now. It claimed 12 compaction rewrites during a pure insert
    load, which has no garbage to compact.
  - `big.js` labelled peak RSS "in-memory engine: docs live in RAM" and its
    summary said the collection was held "fully in RAM". Both were true of the
    engine this milestone replaced.

README: the storage section described an all-in-RAM engine; the comparison
table mixed one old run's body with three new rows; and `findOne({_id})` was
documented as a full scan for integer ids, which the ordered `_id_` index made
false (2 ms against 55 s for a scan of the same 21.5 GB collection). The table
is now best-of-three for both servers, with the measured variance stated, since
two runs of the same binary moved the sub-10 ms rows by 27-51%.
This commit is contained in:
2026-08-03 23:09:43 +03:00
parent 4b70ce6da9
commit 504179acd1
9 changed files with 505 additions and 87 deletions

View File

@@ -1,36 +1,36 @@
# mongo-lite vs MongoDB benchmark
# date: 2026-08-03T08:53:32Z git: c8d547f+dirty
# multiforadb vs MongoDB benchmark
# date: 2026-08-03T19:54:54Z git: 4b70ce6+dirty
# args: size=1g doc-size=16k wc=j clients=1 4 8 16 32 per-client=2000
# reproduce: bash tests/e2e/bench-run.sh 1g 16k "1 4 8 16 32"
[main]
insertOne (sequential) ×200 0.20 ms 14.8 ms
bulk insert throughput 732.4 MB/s 546.2 MB/s
insertOne (sequential) ×200 0.21 ms 4.4 ms
bulk insert throughput 550.4 MB/s 721.6 MB/s
docs loaded 65,536 65,536
createIndex({k: 1}) 74.4 ms 83.6 ms
countDocuments({}) 3.1 ms 12.4 ms
findOne({_id: <ObjectId>}) 0.59 ms 0.61 ms
findOne({k: 500}) (indexed) 0.56 ms 0.94 ms
find({p: {$gte,$lt}}).count() (scan) 13.0 ms 15.0 ms
find({}).sort({_id:-1}).limit(20) 2.2 ms 2.2 ms
find({}, {proj}).limit(1000) 3.5 ms 4.4 ms
aggregate $group by k 8.3 ms 13.2 ms
updateOne({_id}) ×50 0.14 ms 0.20 ms
updateMany({k: 7}, {$inc}) 1.9 ms 6.4 ms
deleteOne({_id}) + insertOne 0.58 ms 4.9 ms
node client RSS 158 MB 157 MB
createIndex({k: 1}) 28.9 ms 72.5 ms
countDocuments({}) 3.6 ms 11.3 ms
findOne({_id: <ObjectId>}) 0.80 ms 0.76 ms
findOne({k: 500}) (indexed) 0.73 ms 5.4 ms
find({p: {$gte,$lt}}).count() (scan) 14.5 ms 15.4 ms
find({}).sort({_id:-1}).limit(20) 1.9 ms 2.6 ms
find({}, {proj}).limit(1000) 3.8 ms 4.9 ms
aggregate $group by k 11.2 ms 15.5 ms
updateOne({_id}) ×50 0.17 ms 0.21 ms
updateMany({k: 7}, {$inc}) 2.0 ms 6.1 ms
deleteOne({_id}) + insertOne 0.69 ms 4.9 ms
node client RSS 150 MB 156 MB
[concurrency]
clients 1 8435 232 36.4x
clients 4 22480 491 45.8x
clients 8 25920 966 26.8x
clients 16 31079 1842 16.9x
clients 32 34041 3632 9.4x
clients 1 7709 229 33.7x
clients 4 20122 493 40.8x
clients 8 26210 977 26.8x
clients 16 27794 1895 14.7x
clients 32 32817 3249 10.1x
[meta]
ml_rss_mb 553
md_rss_mb 1486
ml_reopen 0.8s
mfdb_rss_mb 1060
md_rss_mb 1178
mfdb_reopen 0.3s
md_reopen 1.3s
ml_disk_mb 97MB
md_disk_mb 106MB
mfdb_disk_mb 20MB
md_disk_mb 85MB