@quereus/quereus 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/common/types.d.ts +19 -0
- package/dist/src/common/types.d.ts.map +1 -1
- package/dist/src/common/types.js.map +1 -1
- package/dist/src/core/database.d.ts +39 -1
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +186 -1
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +86 -0
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/runtime/emit/remote-query.d.ts.map +1 -1
- package/dist/src/runtime/emit/remote-query.js +8 -3
- package/dist/src/runtime/emit/remote-query.js.map +1 -1
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +4 -1
- package/dist/src/runtime/emit/scan.js.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.js +2 -2
- package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +4 -3
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +8 -3
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/types.d.ts +10 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/runtime/utils.d.ts.map +1 -1
- package/dist/src/runtime/utils.js +11 -0
- package/dist/src/runtime/utils.js.map +1 -1
- package/dist/src/util/abort-signal.d.ts +25 -0
- package/dist/src/util/abort-signal.d.ts.map +1 -0
- package/dist/src/util/abort-signal.js +40 -0
- package/dist/src/util/abort-signal.js.map +1 -0
- package/dist/src/vtab/concurrency.d.ts +15 -0
- package/dist/src/vtab/concurrency.d.ts.map +1 -1
- package/dist/src/vtab/concurrency.js +17 -0
- package/dist/src/vtab/concurrency.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.d.ts +10 -0
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +10 -0
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/interface.d.ts +24 -0
- package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +21 -3
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +104 -88
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +11 -0
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +19 -0
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +41 -0
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +41 -0
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts +12 -1
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +12 -1
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/module.d.ts +33 -0
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/test-support/commit-stall.d.ts +53 -0
- package/dist/src/vtab/test-support/commit-stall.d.ts.map +1 -0
- package/dist/src/vtab/test-support/commit-stall.js +73 -0
- package/dist/src/vtab/test-support/commit-stall.js.map +1 -0
- package/dist/src/vtab/test-support/committed-read-conformance.d.ts +96 -0
- package/dist/src/vtab/test-support/committed-read-conformance.d.ts.map +1 -0
- package/dist/src/vtab/test-support/committed-read-conformance.js +364 -0
- package/dist/src/vtab/test-support/committed-read-conformance.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs a commit gate on `db` by wrapping every connection the database
|
|
3
|
+
* registers, so the connection's `commit()` first awaits the gate. Disarmed
|
|
4
|
+
* (the default), commits pass through untouched.
|
|
5
|
+
*
|
|
6
|
+
* Works for any module that registers its write connections with
|
|
7
|
+
* `Database.registerConnection` — which a module must do for the engine to drive
|
|
8
|
+
* its transactions, and which a wrapper module cannot intercept on the target's
|
|
9
|
+
* behalf. A module that commits without ever registering needs its own stall;
|
|
10
|
+
* pass whatever `stallCommit` you can build, or none at all (the conformance
|
|
11
|
+
* harness then reports `observedCommitOverlap: false`).
|
|
12
|
+
*
|
|
13
|
+
* TEST SUPPORT ONLY: the patch is permanent for the life of `db` and there is no
|
|
14
|
+
* uninstall. Use a database you own.
|
|
15
|
+
*/
|
|
16
|
+
export function installCommitStall(db) {
|
|
17
|
+
let gate = null;
|
|
18
|
+
let releaseGate = null;
|
|
19
|
+
let enteredResolve = null;
|
|
20
|
+
const original = db.registerConnection.bind(db);
|
|
21
|
+
db.registerConnection =
|
|
22
|
+
async (conn) => {
|
|
23
|
+
const realCommit = conn.commit.bind(conn);
|
|
24
|
+
conn.commit = async () => {
|
|
25
|
+
if (gate) {
|
|
26
|
+
enteredResolve?.();
|
|
27
|
+
enteredResolve = null;
|
|
28
|
+
await gate;
|
|
29
|
+
}
|
|
30
|
+
await realCommit();
|
|
31
|
+
};
|
|
32
|
+
return original(conn);
|
|
33
|
+
};
|
|
34
|
+
const stall = {
|
|
35
|
+
arm() {
|
|
36
|
+
// Re-arming must not orphan a commit already parked on the previous gate:
|
|
37
|
+
// `release()` only resolves the CURRENT one, so an un-released predecessor
|
|
38
|
+
// would hang forever.
|
|
39
|
+
stall.release();
|
|
40
|
+
const entered = new Promise(resolve => {
|
|
41
|
+
enteredResolve = resolve;
|
|
42
|
+
});
|
|
43
|
+
gate = new Promise(resolve => {
|
|
44
|
+
releaseGate = resolve;
|
|
45
|
+
});
|
|
46
|
+
return entered;
|
|
47
|
+
},
|
|
48
|
+
release() {
|
|
49
|
+
gate = null;
|
|
50
|
+
releaseGate?.();
|
|
51
|
+
releaseGate = null;
|
|
52
|
+
enteredResolve = null;
|
|
53
|
+
},
|
|
54
|
+
asStallCommit() {
|
|
55
|
+
const entered = stall.arm();
|
|
56
|
+
return { entered, release: () => stall.release() };
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
return stall;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Yield the event loop `macrotasks` times, so anything already pending has a fair
|
|
63
|
+
* chance to run: a commit to reach the gate, or a read to settle. Used to pin
|
|
64
|
+
* "this did NOT complete" without inventing a wall-clock timeout.
|
|
65
|
+
*
|
|
66
|
+
* `setTimeout` rather than `setImmediate` — the latter is Node-only.
|
|
67
|
+
*/
|
|
68
|
+
export async function settleMacrotasks(macrotasks = 20) {
|
|
69
|
+
for (let i = 0; i < macrotasks; i++) {
|
|
70
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=commit-stall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-stall.js","sourceRoot":"","sources":["../../../../src/vtab/test-support/commit-stall.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAY;IAC9C,IAAI,IAAI,GAAyB,IAAI,CAAC;IACtC,IAAI,WAAW,GAAwB,IAAI,CAAC;IAC5C,IAAI,cAAc,GAAwB,IAAI,CAAC;IAE/C,MAAM,QAAQ,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,EAAsE,CAAC,kBAAkB;QACzF,KAAK,EAAE,IAA4B,EAAE,EAAE;YACtC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzC,IAAwC,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE;gBAC7D,IAAI,IAAI,EAAE,CAAC;oBACV,cAAc,EAAE,EAAE,CAAC;oBACnB,cAAc,GAAG,IAAI,CAAC;oBACtB,MAAM,IAAI,CAAC;gBACZ,CAAC;gBACD,MAAM,UAAU,EAAE,CAAC;YACpB,CAAC,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAgB;QAC1B,GAAG;YACF,0EAA0E;YAC1E,2EAA2E;YAC3E,sBAAsB;YACtB,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;gBAC3C,cAAc,GAAG,OAAO,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,IAAI,GAAG,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;gBAClC,WAAW,GAAG,OAAO,CAAC;YACvB,CAAC,CAAC,CAAC;YACH,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,OAAO;YACN,IAAI,GAAG,IAAI,CAAC;YACZ,WAAW,EAAE,EAAE,CAAC;YAChB,WAAW,GAAG,IAAI,CAAC;YACnB,cAAc,GAAG,IAAI,CAAC;QACvB,CAAC;QACD,aAAa;YACZ,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YAC5B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,CAAC;KACD,CAAC;IACF,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAU,GAAG,EAAE;IACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Database } from '../../core/database.js';
|
|
2
|
+
import { type CommitStallHandle } from './commit-stall.js';
|
|
3
|
+
/**
|
|
4
|
+
* Conformance check for the committed-snapshot obligation a virtual-table module
|
|
5
|
+
* takes on by declaring `VirtualTableModule.readCommittedSnapshot`. See
|
|
6
|
+
* `docs/module-authoring.md` § "Committed-Snapshot Reads (`_readCommitted`)" for
|
|
7
|
+
* the obligation itself.
|
|
8
|
+
*
|
|
9
|
+
* Framework-agnostic on purpose: it throws a descriptive `Error` on failure and
|
|
10
|
+
* returns a result object on success, so it drops into Mocha, Vitest, or a plain
|
|
11
|
+
* script without pulling an assertion library in. It ships in the published
|
|
12
|
+
* package because an out-of-tree module author needs it at runtime; nothing in
|
|
13
|
+
* the engine imports it.
|
|
14
|
+
*/
|
|
15
|
+
export interface CommittedReadConformanceOptions {
|
|
16
|
+
/** Database with the module under test registered and the table created. */
|
|
17
|
+
db: Database;
|
|
18
|
+
/**
|
|
19
|
+
* Table name to exercise, qualified or not. Used verbatim in SQL, so pass it
|
|
20
|
+
* exactly as you would write it in a query (already quoted if it needs to be).
|
|
21
|
+
* The table must be EMPTY on entry — the harness owns its contents for the run
|
|
22
|
+
* and deletes what it wrote on the way out.
|
|
23
|
+
*/
|
|
24
|
+
table: string;
|
|
25
|
+
/**
|
|
26
|
+
* Primary-key column — seeded with integers and used to drive an index-driven
|
|
27
|
+
* access path. Used verbatim in SQL, like {@link table}.
|
|
28
|
+
*/
|
|
29
|
+
keyColumn: string;
|
|
30
|
+
/**
|
|
31
|
+
* A non-key column the writer mutates; must accept text and be readable in a
|
|
32
|
+
* `select`. Used verbatim in SQL, like {@link table}. Any OTHER column on the
|
|
33
|
+
* table must be nullable or defaulted — the harness writes only these two.
|
|
34
|
+
*/
|
|
35
|
+
valueColumn: string;
|
|
36
|
+
/**
|
|
37
|
+
* Optional: park the module mid-commit so the read provably overlaps the
|
|
38
|
+
* publish window. Called immediately BEFORE the harness issues its writer —
|
|
39
|
+
* arm your gate here. The returned handle is released once the concurrent
|
|
40
|
+
* reads have completed (including on failure). Without it the check is
|
|
41
|
+
* best-effort — a module that commits in one synchronous step may leave no
|
|
42
|
+
* window to observe — and the result reports `observedCommitOverlap: false`.
|
|
43
|
+
*/
|
|
44
|
+
stallCommit?: () => CommitStallHandle;
|
|
45
|
+
/** Rows to seed. Default 200 — enough that a torn publish is observable. */
|
|
46
|
+
rowCount?: number;
|
|
47
|
+
/**
|
|
48
|
+
* How long to wait for a concurrent read to complete while the writer is
|
|
49
|
+
* parked, before declaring that the engine did not route it concurrently.
|
|
50
|
+
* Only applies when `stallCommit` is supplied. Default 5000ms.
|
|
51
|
+
*/
|
|
52
|
+
stallTimeoutMs?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface CommittedReadConformanceResult {
|
|
55
|
+
/**
|
|
56
|
+
* True only when a `stallCommit` was supplied AND the writer was still parked
|
|
57
|
+
* for the whole duration of the concurrent reads. False means "no evidence the
|
|
58
|
+
* read overlapped a commit" — NOT "conformant": with no provable overlap the
|
|
59
|
+
* harness cannot insist on the pre-write snapshot (the writer may legitimately
|
|
60
|
+
* have landed first), so it only checks that each read returned one WHOLE
|
|
61
|
+
* state rather than a mix, and it does not compare the two legs against each
|
|
62
|
+
* other.
|
|
63
|
+
*/
|
|
64
|
+
observedCommitOverlap: boolean;
|
|
65
|
+
/** Rows returned by the full scan. */
|
|
66
|
+
fullScanRows: number;
|
|
67
|
+
/** Rows returned by the index-driven path; 0 when that leg was skipped. */
|
|
68
|
+
indexDrivenRows: number;
|
|
69
|
+
/**
|
|
70
|
+
* Present when the index-driven leg did NOT run, with the reason. The leg is
|
|
71
|
+
* skipped rather than silently degraded into a second full scan, so a module
|
|
72
|
+
* with no seek plan cannot claim index coverage it never had.
|
|
73
|
+
*/
|
|
74
|
+
indexDrivenSkippedReason?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Runs the committed-snapshot conformance check against `options.table`.
|
|
78
|
+
*
|
|
79
|
+
* Shape of the run:
|
|
80
|
+
* 1. refuse unless the table's module declares `readCommittedSnapshot`;
|
|
81
|
+
* 2. seed `rowCount` rows and commit;
|
|
82
|
+
* 3. start an unawaited writer that rewrites EVERY seeded row's value and
|
|
83
|
+
* appends new rows, parked mid-commit via `stallCommit` if supplied;
|
|
84
|
+
* 4. while it is parked, read the table twice with `readConcurrency: 'committed'`
|
|
85
|
+
* — a full scan and an index-driven path over `keyColumn`;
|
|
86
|
+
* 5. assert both reads return exactly the seeded snapshot and agree row-for-row.
|
|
87
|
+
* Without a provable park the bar drops to "each read equals ONE whole state,
|
|
88
|
+
* pre- or post-write" — a mix is still a failure, but a writer that landed
|
|
89
|
+
* before the read is not;
|
|
90
|
+
* 6. release, await the writer, and assert a fresh read now sees the post-write
|
|
91
|
+
* state (so a module that serves permanently stale data fails too).
|
|
92
|
+
*
|
|
93
|
+
* @throws Error with the specific divergence on any failure.
|
|
94
|
+
*/
|
|
95
|
+
export declare function runCommittedReadConformance(options: CommittedReadConformanceOptions): Promise<CommittedReadConformanceResult>;
|
|
96
|
+
//# sourceMappingURL=committed-read-conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"committed-read-conformance.d.ts","sourceRoot":"","sources":["../../../../src/vtab/test-support/committed-read-conformance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAKvD,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,+BAA+B;IAC/C,4EAA4E;IAC5E,EAAE,EAAE,QAAQ,CAAC;IACb;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,iBAAiB,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,8BAA8B;IAC9C;;;;;;;;OAQG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CAClC;AAmJD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,2BAA2B,CAChD,OAAO,EAAE,+BAA+B,GACtC,OAAO,CAAC,8BAA8B,CAAC,CAuBzC"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { TableReferenceNode } from '../../planner/nodes/reference.js';
|
|
2
|
+
import { getModuleReadCommittedSnapshot } from '../concurrency.js';
|
|
3
|
+
import { settleMacrotasks } from './commit-stall.js';
|
|
4
|
+
const KEY_ALIAS = '__crc_key';
|
|
5
|
+
const VALUE_ALIAS = '__crc_value';
|
|
6
|
+
/** Stable, type-independent identity for a key cell (integers may arrive as bigint). */
|
|
7
|
+
function keyToString(value) {
|
|
8
|
+
return typeof value === 'bigint' ? value.toString() : String(value);
|
|
9
|
+
}
|
|
10
|
+
function seedValue(key) {
|
|
11
|
+
return `crc-seed-${key}`;
|
|
12
|
+
}
|
|
13
|
+
function postValue(key) {
|
|
14
|
+
return `crc-post-${key}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Every module reachable from `select * from <table>`. Uses the planner's own
|
|
18
|
+
* name resolution rather than re-parsing the caller's table name.
|
|
19
|
+
*/
|
|
20
|
+
function resolveTableModules(db, table) {
|
|
21
|
+
let root;
|
|
22
|
+
try {
|
|
23
|
+
root = db.getPlan(`select * from ${table}`);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
throw new Error(`committed-read conformance: could not plan 'select * from ${table}' — pass the table name exactly as it would appear in a query. Cause: ${String(e)}`);
|
|
27
|
+
}
|
|
28
|
+
const found = [];
|
|
29
|
+
const stack = [root];
|
|
30
|
+
while (stack.length > 0) {
|
|
31
|
+
const node = stack.pop();
|
|
32
|
+
if (node instanceof TableReferenceNode)
|
|
33
|
+
found.push(node);
|
|
34
|
+
for (const child of node.getChildren())
|
|
35
|
+
stack.push(child);
|
|
36
|
+
}
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Step 1: refuse up front unless the table's module declares the flag. The
|
|
41
|
+
* harness exists to test modules that CLAIM the guarantee; running it against one
|
|
42
|
+
* that declines would fail on the engine's own (correct) fallback to the
|
|
43
|
+
* serialized path, which is a confusing way to report "you never opted in".
|
|
44
|
+
*/
|
|
45
|
+
function assertModuleDeclaresSnapshot(db, table) {
|
|
46
|
+
const refs = resolveTableModules(db, table);
|
|
47
|
+
if (refs.length === 0) {
|
|
48
|
+
throw new Error(`committed-read conformance: '${table}' resolved to no base table (a view over a table-valued function, perhaps). The harness needs a real table.`);
|
|
49
|
+
}
|
|
50
|
+
for (const ref of refs) {
|
|
51
|
+
if (!getModuleReadCommittedSnapshot(ref.vtabModule)) {
|
|
52
|
+
throw new Error(`committed-read conformance: module '${ref.tableSchema.vtabModuleName}' backing '${table}' does not declare readCommittedSnapshot, so the engine will always serialize reads of it. ` +
|
|
53
|
+
`This harness only applies to modules that declare the flag — see docs/module-authoring.md § "Committed-Snapshot Reads (_readCommitted)".`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function collectSnapshot(db, sql, options) {
|
|
58
|
+
const rows = [];
|
|
59
|
+
const iter = options?.readCommitted
|
|
60
|
+
? db.eval(sql, undefined, { readConcurrency: 'committed' })
|
|
61
|
+
: db.eval(sql);
|
|
62
|
+
for await (const row of iter) {
|
|
63
|
+
rows.push({ key: keyToString(row[KEY_ALIAS]), value: row[VALUE_ALIAS] });
|
|
64
|
+
}
|
|
65
|
+
rows.sort((a, b) => Number(a.key) - Number(b.key));
|
|
66
|
+
return rows;
|
|
67
|
+
}
|
|
68
|
+
/** Plan operators for `sql`, via the public `query_plan()` table-valued function. */
|
|
69
|
+
async function planOperators(db, sql) {
|
|
70
|
+
const ops = [];
|
|
71
|
+
for await (const row of db.eval('select op from query_plan(?)', [sql])) {
|
|
72
|
+
ops.push(String(row.op));
|
|
73
|
+
}
|
|
74
|
+
return ops;
|
|
75
|
+
}
|
|
76
|
+
/** Render up to `limit` divergences as `key: expected -> actual`. */
|
|
77
|
+
function describeDivergences(expected, actual, limit = 5) {
|
|
78
|
+
const byKey = new Map(actual.map(r => [r.key, r.value]));
|
|
79
|
+
const parts = [];
|
|
80
|
+
for (const row of expected) {
|
|
81
|
+
if (!byKey.has(row.key)) {
|
|
82
|
+
parts.push(`${row.key}: expected ${JSON.stringify(row.value)}, row missing`);
|
|
83
|
+
}
|
|
84
|
+
else if (byKey.get(row.key) !== row.value) {
|
|
85
|
+
parts.push(`${row.key}: expected ${JSON.stringify(row.value)}, got ${JSON.stringify(byKey.get(row.key))}`);
|
|
86
|
+
}
|
|
87
|
+
if (parts.length >= limit)
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (parts.length < limit) {
|
|
91
|
+
const expectedKeys = new Set(expected.map(r => r.key));
|
|
92
|
+
for (const row of actual) {
|
|
93
|
+
if (!expectedKeys.has(row.key)) {
|
|
94
|
+
parts.push(`${row.key}: unexpected row ${JSON.stringify(row.value)}`);
|
|
95
|
+
if (parts.length >= limit)
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return parts.length > 0 ? parts.join('; ') : '(no per-row divergence — the row sets match)';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reject after `ms` with a message that names the likely cause.
|
|
104
|
+
*
|
|
105
|
+
* NOTE: the timed-out read is abandoned, not cancelled — it drains on its own once
|
|
106
|
+
* the stall is released (which the run always does), and its rejection is already
|
|
107
|
+
* handled here. If the harness ever gains a mode that keeps running on the same
|
|
108
|
+
* database after a timeout, give it a real cancellation instead.
|
|
109
|
+
*/
|
|
110
|
+
function withStallTimeout(work, ms, what) {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const timer = setTimeout(() => {
|
|
113
|
+
reject(new Error(`committed-read conformance: ${what} did not complete within ${ms}ms while the writer was parked mid-commit. ` +
|
|
114
|
+
`The read was queued behind the writer instead of running concurrently — check that the statement is eligible ` +
|
|
115
|
+
`(read-only, autocommit, no open explicit transaction) and that the module really declares readCommittedSnapshot.`));
|
|
116
|
+
}, ms);
|
|
117
|
+
work.then(value => { clearTimeout(timer); resolve(value); }, error => { clearTimeout(timer); reject(error); });
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Runs the committed-snapshot conformance check against `options.table`.
|
|
122
|
+
*
|
|
123
|
+
* Shape of the run:
|
|
124
|
+
* 1. refuse unless the table's module declares `readCommittedSnapshot`;
|
|
125
|
+
* 2. seed `rowCount` rows and commit;
|
|
126
|
+
* 3. start an unawaited writer that rewrites EVERY seeded row's value and
|
|
127
|
+
* appends new rows, parked mid-commit via `stallCommit` if supplied;
|
|
128
|
+
* 4. while it is parked, read the table twice with `readConcurrency: 'committed'`
|
|
129
|
+
* — a full scan and an index-driven path over `keyColumn`;
|
|
130
|
+
* 5. assert both reads return exactly the seeded snapshot and agree row-for-row.
|
|
131
|
+
* Without a provable park the bar drops to "each read equals ONE whole state,
|
|
132
|
+
* pre- or post-write" — a mix is still a failure, but a writer that landed
|
|
133
|
+
* before the read is not;
|
|
134
|
+
* 6. release, await the writer, and assert a fresh read now sees the post-write
|
|
135
|
+
* state (so a module that serves permanently stale data fails too).
|
|
136
|
+
*
|
|
137
|
+
* @throws Error with the specific divergence on any failure.
|
|
138
|
+
*/
|
|
139
|
+
export async function runCommittedReadConformance(options) {
|
|
140
|
+
const { db, table, keyColumn, valueColumn, rowCount = 200 } = options;
|
|
141
|
+
if (!Number.isInteger(rowCount) || rowCount < 2) {
|
|
142
|
+
throw new Error(`committed-read conformance: rowCount must be an integer >= 2, got ${rowCount}`);
|
|
143
|
+
}
|
|
144
|
+
assertModuleDeclaresSnapshot(db, table);
|
|
145
|
+
const plan = buildRunPlan(table, keyColumn, valueColumn, rowCount);
|
|
146
|
+
await assertTableEmpty(db, table, plan.projection);
|
|
147
|
+
// From here on the table holds the harness's rows, so every exit path — thrown
|
|
148
|
+
// assertion, thrown engine error, or success — has to clear them.
|
|
149
|
+
await db.exec(plan.seedSql);
|
|
150
|
+
try {
|
|
151
|
+
const result = await runAgainstSeededTable(options, plan);
|
|
152
|
+
await cleanup(db, table, undefined);
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
await cleanup(db, table, e);
|
|
157
|
+
throw e;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function buildRunPlan(table, keyColumn, valueColumn, rowCount) {
|
|
161
|
+
// Seeded band is 1..rowCount; the writer appends rowCount+1..highKey.
|
|
162
|
+
const appendCount = Math.max(1, Math.floor(rowCount / 10));
|
|
163
|
+
const highKey = rowCount + appendCount;
|
|
164
|
+
const keys = (count) => Array.from({ length: count }, (_, i) => i + 1);
|
|
165
|
+
const tuples = (count, value) => keys(count).map(k => `(${k}, '${value(k)}')`).join(', ');
|
|
166
|
+
// Both legs project identically; only the predicate differs. The range covers
|
|
167
|
+
// the appended keys too, so an index-driven read of a torn publish is short or
|
|
168
|
+
// long in exactly the way the full scan is.
|
|
169
|
+
const projection = `select ${keyColumn} as ${KEY_ALIAS}, ${valueColumn} as ${VALUE_ALIAS} from ${table}`;
|
|
170
|
+
return {
|
|
171
|
+
projection,
|
|
172
|
+
indexDrivenSql: `${projection} where ${keyColumn} >= 1 and ${keyColumn} <= ${highKey}`,
|
|
173
|
+
seedSql: `insert into ${table} (${keyColumn}, ${valueColumn}) values ${tuples(rowCount, seedValue)}`,
|
|
174
|
+
// A single statement, so it commits once: `or replace` rewrites every seeded
|
|
175
|
+
// row's value AND appends new keys. A torn publish therefore shows up two
|
|
176
|
+
// ways — as a mix of old and new values, and as a longer result set.
|
|
177
|
+
writerSql: `insert or replace into ${table} (${keyColumn}, ${valueColumn}) values ${tuples(highKey, postValue)}`,
|
|
178
|
+
keyColumn,
|
|
179
|
+
highKey,
|
|
180
|
+
rowCount,
|
|
181
|
+
expectedPre: keys(rowCount).map(k => ({ key: String(k), value: seedValue(k) })),
|
|
182
|
+
expectedPost: keys(highKey).map(k => ({ key: String(k), value: postValue(k) })),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/** The harness owns the table's contents for the run, so it refuses to share it. */
|
|
186
|
+
async function assertTableEmpty(db, table, projection) {
|
|
187
|
+
const existing = await collectSnapshot(db, projection);
|
|
188
|
+
if (existing.length > 0) {
|
|
189
|
+
throw new Error(`committed-read conformance: '${table}' must be empty on entry (found ${existing.length} rows). ` +
|
|
190
|
+
`The harness owns the table's contents for the run and deletes what it wrote on the way out.`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/** Steps 3–6, with the seeded rows already committed. Always throws or returns; never cleans up. */
|
|
194
|
+
async function runAgainstSeededTable(options, plan) {
|
|
195
|
+
const { db, valueColumn, stallCommit, stallTimeoutMs = 5000 } = options;
|
|
196
|
+
const { seekPlanned, indexDrivenSkippedReason } = await probeIndexPath(db, plan);
|
|
197
|
+
const handle = stallCommit?.();
|
|
198
|
+
try {
|
|
199
|
+
const writer = startWriter(db, plan.writerSql);
|
|
200
|
+
let outcome;
|
|
201
|
+
let readError;
|
|
202
|
+
try {
|
|
203
|
+
outcome = await observeConcurrentReads({
|
|
204
|
+
db, plan, valueColumn, handle, writer, seekPlanned, stallTimeoutMs,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
readError = e;
|
|
209
|
+
}
|
|
210
|
+
handle?.release();
|
|
211
|
+
try {
|
|
212
|
+
await writer.promise;
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
if (readError === undefined)
|
|
216
|
+
readError = e;
|
|
217
|
+
}
|
|
218
|
+
if (readError !== undefined)
|
|
219
|
+
throw readError;
|
|
220
|
+
if (!outcome)
|
|
221
|
+
throw new Error('committed-read conformance: internal error — the reads produced no outcome');
|
|
222
|
+
await assertAdvancesAfterCommit(db, plan);
|
|
223
|
+
return {
|
|
224
|
+
observedCommitOverlap: outcome.parked,
|
|
225
|
+
fullScanRows: outcome.fullScan.length,
|
|
226
|
+
indexDrivenRows: outcome.indexDriven.length,
|
|
227
|
+
...(indexDrivenSkippedReason !== undefined ? { indexDrivenSkippedReason } : {}),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
// Idempotent by contract. Covers the paths that throw before the explicit
|
|
232
|
+
// release above — an armed gate left behind would park the cleanup delete
|
|
233
|
+
// and hang the caller instead of reporting the real failure.
|
|
234
|
+
handle?.release();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Does the planner really seek for the index-driven leg? Probed BEFORE anything
|
|
239
|
+
* parks — `query_plan()` is an ordinary statement and would queue behind the
|
|
240
|
+
* stalled writer.
|
|
241
|
+
*/
|
|
242
|
+
async function probeIndexPath(db, plan) {
|
|
243
|
+
const ops = await planOperators(db, plan.indexDrivenSql);
|
|
244
|
+
if (ops.includes('INDEXSEEK'))
|
|
245
|
+
return { seekPlanned: true };
|
|
246
|
+
return {
|
|
247
|
+
seekPlanned: false,
|
|
248
|
+
indexDrivenSkippedReason: `the planner did not choose a seek for a range predicate on '${plan.keyColumn}' (plan operators: ${ops.join(', ')}); ` +
|
|
249
|
+
`the index-driven leg was skipped rather than run as a second full scan`,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function startWriter(db, sql) {
|
|
253
|
+
let settled = false;
|
|
254
|
+
const promise = db.exec(sql).then(() => { settled = true; }, error => { settled = true; throw error; });
|
|
255
|
+
// Keep an unhandled rejection from escaping before the awaited join below.
|
|
256
|
+
promise.catch(() => { });
|
|
257
|
+
return { promise, settled: () => settled };
|
|
258
|
+
}
|
|
259
|
+
/** Steps 4–5: read twice while the writer is parked, and judge what came back. */
|
|
260
|
+
async function observeConcurrentReads(args) {
|
|
261
|
+
const { db, plan, valueColumn, handle, writer, seekPlanned, stallTimeoutMs } = args;
|
|
262
|
+
if (handle) {
|
|
263
|
+
if (handle.entered) {
|
|
264
|
+
// Deterministic: proceed once a commit is provably inside the gate. If the
|
|
265
|
+
// writer finished first there was no window at all.
|
|
266
|
+
await Promise.race([handle.entered, writer.promise]);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
await settleMacrotasks();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
let parked = handle !== undefined && !writer.settled();
|
|
273
|
+
const guard = (work, what) => parked ? withStallTimeout(work, stallTimeoutMs, what) : work;
|
|
274
|
+
const fullScan = await guard(collectSnapshot(db, plan.projection, { readCommitted: true }), 'the full-scan read');
|
|
275
|
+
const indexDriven = seekPlanned
|
|
276
|
+
? await guard(collectSnapshot(db, plan.indexDrivenSql, { readCommitted: true }), 'the index-driven read')
|
|
277
|
+
: [];
|
|
278
|
+
if (parked && writer.settled()) {
|
|
279
|
+
// The writer landed while we were reading, so neither read is evidence of
|
|
280
|
+
// anything: the "committed snapshot" they saw may simply be the new state.
|
|
281
|
+
parked = false;
|
|
282
|
+
}
|
|
283
|
+
// Parked: the commit provably had NOT landed, so the pre-write snapshot is the
|
|
284
|
+
// only correct answer. Not parked: the writer may have committed before either
|
|
285
|
+
// read began, and serving the post-write state is then equally correct — so
|
|
286
|
+
// accept either whole state, but never a mix of the two (that is a tear no
|
|
287
|
+
// interleaving excuses).
|
|
288
|
+
const acceptable = parked ? [plan.expectedPre] : [plan.expectedPre, plan.expectedPost];
|
|
289
|
+
assertCoherent('full scan', fullScan, acceptable, valueColumn, parked);
|
|
290
|
+
if (seekPlanned) {
|
|
291
|
+
assertCoherent('index-driven read', indexDriven, acceptable, valueColumn, parked);
|
|
292
|
+
// Only meaningful while the writer is parked: unparked, the two legs run at
|
|
293
|
+
// different times and may legitimately straddle the commit.
|
|
294
|
+
if (parked)
|
|
295
|
+
assertLegsAgree(fullScan, indexDriven);
|
|
296
|
+
}
|
|
297
|
+
return { fullScan, indexDriven, parked };
|
|
298
|
+
}
|
|
299
|
+
/** Row-for-row equality, in key order. */
|
|
300
|
+
function matches(actual, expected) {
|
|
301
|
+
return actual.length === expected.length
|
|
302
|
+
&& expected.every((row, i) => actual[i].key === row.key && actual[i].value === row.value);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* `actual` must equal ONE of the `acceptable` whole states. Anything else — a
|
|
306
|
+
* short result set, or a mix of pre- and post-write values — is a torn read.
|
|
307
|
+
*/
|
|
308
|
+
function assertCoherent(leg, actual, acceptable, valueColumn, parked) {
|
|
309
|
+
if (acceptable.some(expected => matches(actual, expected)))
|
|
310
|
+
return;
|
|
311
|
+
const [primary] = acceptable;
|
|
312
|
+
const alternative = acceptable.length > 1
|
|
313
|
+
? ` (the post-write state would also have been accepted — the writer was not provably parked — but this is neither.)`
|
|
314
|
+
: '';
|
|
315
|
+
throw new Error(`committed-read conformance: the ${leg}${parked ? " taken during another connection's commit" : ''} did not return a coherent committed snapshot. ` +
|
|
316
|
+
`Expected ${primary.length} rows, each with '${valueColumn}' at its pre-write value; got ${actual.length} rows.${alternative} ` +
|
|
317
|
+
`Divergences — ${describeDivergences(primary, actual)}. ` +
|
|
318
|
+
`A module declaring readCommittedSnapshot must pin the state it serves for the life of the scan.`);
|
|
319
|
+
}
|
|
320
|
+
function assertLegsAgree(fullScan, indexDriven) {
|
|
321
|
+
if (matches(indexDriven, fullScan))
|
|
322
|
+
return;
|
|
323
|
+
throw new Error(`committed-read conformance: the full scan and the index-driven read disagree (${fullScan.length} vs ${indexDriven.length} rows). ` +
|
|
324
|
+
`Divergences — ${describeDivergences(fullScan, indexDriven)}. ` +
|
|
325
|
+
`The obligation requires an index-driven plan and a full scan of one connection to agree, so base rows and index entries ` +
|
|
326
|
+
`must become visible together.`);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Step 6: a module that pins a snapshot but never advances it would pass every
|
|
330
|
+
* check above. After the writer lands, a fresh read must see the new state.
|
|
331
|
+
*/
|
|
332
|
+
async function assertAdvancesAfterCommit(db, plan) {
|
|
333
|
+
const after = await collectSnapshot(db, plan.projection);
|
|
334
|
+
if (after.length !== plan.highKey) {
|
|
335
|
+
throw new Error(`committed-read conformance: after the writer committed, a fresh read returned ${after.length} rows, expected ${plan.highKey}. ` +
|
|
336
|
+
`The module is serving a stale snapshot to ordinary reads.`);
|
|
337
|
+
}
|
|
338
|
+
const stale = after.filter(row => row.value !== postValue(Number(row.key)));
|
|
339
|
+
if (stale.length > 0) {
|
|
340
|
+
throw new Error(`committed-read conformance: after the writer committed, ${stale.length} of ${after.length} rows still held their pre-write value ` +
|
|
341
|
+
`(first: key ${stale[0].key} = ${JSON.stringify(stale[0].value)}). A pinned snapshot must advance once the commit lands ` +
|
|
342
|
+
`— seeding was ${plan.rowCount} rows.`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* The harness entered on an empty table, so removing everything removes exactly
|
|
347
|
+
* what it wrote. A cleanup failure never masks the real error.
|
|
348
|
+
*/
|
|
349
|
+
async function cleanup(db, table, pendingError) {
|
|
350
|
+
try {
|
|
351
|
+
await db.exec(`delete from ${table}`);
|
|
352
|
+
}
|
|
353
|
+
catch (e) {
|
|
354
|
+
if (pendingError === undefined) {
|
|
355
|
+
throw new Error(`committed-read conformance: passed, but cleaning up '${table}' failed: ${String(e)}`);
|
|
356
|
+
}
|
|
357
|
+
// A cleanup failure after a real failure is a symptom, not the cause, so it
|
|
358
|
+
// must not displace the thrown error. `console.error` rather than the
|
|
359
|
+
// package's debug-namespaced logger: this runs under a test runner, where
|
|
360
|
+
// the note has to be visible without anyone enabling a debug namespace.
|
|
361
|
+
console.error(`committed-read conformance: cleanup of '${table}' also failed:`, e);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=committed-read-conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"committed-read-conformance.js","sourceRoot":"","sources":["../../../../src/vtab/test-support/committed-read-conformance.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/quereus",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pure TypeScript SQL engine — no WASM, no native bindings. Runs in browsers, Node.js, React Native, edge workers, and anywhere JS runs.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"mutation:subsystem": "node mutation-subsystem.mjs"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@quereus/plugin-leveldb": "^4.
|
|
74
|
+
"@quereus/plugin-leveldb": "^4.8.0",
|
|
75
75
|
"@quereus/plugin-loader": "*",
|
|
76
|
-
"@quereus/store": "^4.
|
|
76
|
+
"@quereus/store": "^4.8.0",
|
|
77
77
|
"@stryker-mutator/core": "^9.6.1",
|
|
78
78
|
"@stryker-mutator/mocha-runner": "^9.6.1",
|
|
79
79
|
"@stryker-mutator/typescript-checker": "^9.6.1",
|