perf(resolution): worker connection recycling — WAL-depth writes-under-readers fix, superphase −11.4% at 8c (#1362)
The §7a.6 anomaly probed to its mechanism with five discriminating runs (§7a.7 table): main-thread B-tree writes triple under attached readers because READERS PIN WAL checkpoint progress — the deep WAL taxes every writer page operation (deletes 42.6s pool-off vs 118.8s pool-4 on identical hardware; an aggressive 64MB valve recovers the writes but overpays +129s in full-park folds; the v2 cache resurrection was falsified — long-tail name traffic is uncacheable at any capacity). Fix: workers close and reopen their read-only connections every 8 batches at the double-buffer's worker-idle boundary (ResolverPool.recycleWorkers + QueryBuilder.rebind + a cadence call). Reopens are sub-millisecond, resolver caches survive (only prepared statements re-prepare), and the existing checkpoints advance instead of parking. Failed recycle downgrades to sequential, same as a failed fan-out. Measured (8c pool-4, linux v7.2-rc2, cadence 25 → 8 iterated): resolution superphase 715.0 → 633.6s (−11.4%), envelope best 14.8min, recreate 59.7 → 45.3s. Byte-neutral everywhere: git dumps byte-identical old-vs-new, linux dump sha 6dd1185b reproduced (10,446,478 lines), counts 2,049,153/6,413,518, suite 2517 green. 2c unchanged by construction (no pool → no recycling). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5955d04c97
commit
971a5a0483
@@ -291,6 +291,24 @@ export class QueryBuilder {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the underlying connection in place. Used by pool workers'
|
||||
* connection recycling (plan §7a.6, writes-under-readers): a long-lived
|
||||
* read connection pins WAL checkpoint progress, and the deep WAL that
|
||||
* accumulates behind it taxes every main-thread B-tree page operation
|
||||
* (deletes measured 42.6s → 118.8s from 0 to 4 attached readers on
|
||||
* identical hardware). Workers therefore close and reopen their read-only
|
||||
* connection at the pool-idle boundary; everything above the connection —
|
||||
* this QueryBuilder, the resolver and its warm caches — survives, and only
|
||||
* connection-derived state (prepared statements) resets, re-preparing
|
||||
* lazily on next use.
|
||||
*/
|
||||
rebind(db: SqliteDatabase): void {
|
||||
this.db = db;
|
||||
this.stmts = {};
|
||||
this.batchStmts.clear();
|
||||
}
|
||||
|
||||
/** Set the normalized project-name tokens used to down-weight non-discriminative
|
||||
* query words in path scoring (#720). Called once when the project opens. */
|
||||
setProjectNameTokens(tokens: Set<string>): void {
|
||||
|
||||
Reference in New Issue
Block a user