Conversation
…nc scanFiles behavior
…ptimize saveManifest JSON serialization
|
@copilot run the speed run benchmark comparison against current master again and update the PR description and numbers. Then add some short documentation about the manifest loading and lazy index opening behaviour. |
Re-ran against the current state of this branch (includes Scenario A — 1 index per partition (startup ms)
Scenario B — 100 partitions, growing index count (startup ms)
The earlier July 25 run showed only ~15% improvement because the benchmark machinery was still inadvertently bypassing the manifest (orphaned lock → Node v24.18.0, ~150 bytes/doc, 20 docs/partition. |
Secondary indexes were holding open file descriptors throughout startup, and pool LRU evictions (triggered when N > 1024 indexes) unconditionally called
fdatasynceven for indexes with no pending writes — making startup cost superlinear in index count.Changes
WritableIndex.onBeforeClosefdatasyncwhenwriteBufferCursor === 0; previous guard (!this.writeBuffer) was always false sincewriteBufferis allocated ininitializeReadableStorage.openIndex+afterRegisterSecondaryIndexhookindex.open()call with a newafterRegisterSecondaryIndex(index)hookfileHandlePool.evict(index, false)—falsepreservesopened=trueand thedataarray soindex.length/index.lastEntryremain valid; the pool transparently reopens the fd on first real accessWritableStorage.afterRegisterSecondaryIndexopenIndexoverride: performs stale-entry truncation (needed after crash-recoverycheckTornWrites) while the fd is still live, then delegates tosuperto release itbench/bench-scalability.jsmeasureStartup/measureWrite/measureReadto awaitstorage.open(callback)so the async partition scan completes before reads — was causingPartition does not existerrors at runtimeBenchmark (Node v24, ~108 bytes/doc)
Scenario A — 1 index/partition:
Scenario B — 100 partitions, growing index count:
At low index counts the lazy fd release wins (Scenario B/100: −31% vs main); PR #339's snapshot approach dominates at high counts by skipping file opens entirely. The two are complementary. Write/read per-op latency is unchanged.