@minnowdb/core 0.3.0 → 0.4.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/README.md +4 -2
- package/dist/block-format/block.d.ts +32 -13
- package/dist/block-format/block.js +179 -55
- package/dist/block-format/checksum.d.ts +2 -1
- package/dist/block-format/checksum.js +5 -2
- package/dist/block-format/codecs.d.ts +7 -2
- package/dist/block-format/codecs.js +53 -12
- package/dist/block-format/column.d.ts +3 -2
- package/dist/block-format/column.js +96 -30
- package/dist/block-format/index.d.ts +2 -2
- package/dist/block-format/index.js +2 -2
- package/dist/block-format/physical.d.ts +8 -2
- package/dist/block-format/physical.js +14 -6
- package/dist/block-format/types.d.ts +7 -3
- package/dist/block-format/types.js +0 -1
- package/dist/block-format/unicode.d.ts +11 -0
- package/dist/block-format/unicode.js +46 -0
- package/dist/date-value.d.ts +15 -0
- package/dist/date-value.js +64 -0
- package/dist/engine/artifact-cache.d.ts +0 -1
- package/dist/engine/artifact-cache.js +0 -1
- package/dist/engine/batch.d.ts +5 -2
- package/dist/engine/batch.js +0 -1
- package/dist/engine/buffered-writer.d.ts +2 -1
- package/dist/engine/buffered-writer.js +34 -9
- package/dist/engine/cache-limits.d.ts +25 -0
- package/dist/engine/cache-limits.js +25 -0
- package/dist/engine/catalog.d.ts +5 -6
- package/dist/engine/catalog.js +5 -5
- package/dist/engine/client.d.ts +27 -7
- package/dist/engine/client.js +197 -31
- package/dist/engine/database.d.ts +161 -38
- package/dist/engine/database.js +4320 -1523
- package/dist/engine/defaults.d.ts +0 -1
- package/dist/engine/defaults.js +2 -4
- package/dist/engine/errors.d.ts +19 -1
- package/dist/engine/errors.js +32 -2
- package/dist/engine/fts.d.ts +0 -6
- package/dist/engine/fts.js +39 -14
- package/dist/engine/group-index.d.ts +0 -1
- package/dist/engine/group-index.js +6 -11
- package/dist/engine/index.d.ts +16 -11
- package/dist/engine/index.js +12 -10
- package/dist/engine/join-index.d.ts +0 -1
- package/dist/engine/join-index.js +2 -2
- package/dist/engine/keyed-live.d.ts +57 -0
- package/dist/engine/keyed-live.js +226 -0
- package/dist/engine/live-api.d.ts +4 -0
- package/dist/engine/live-api.js +4 -0
- package/dist/engine/live.d.ts +43 -26
- package/dist/engine/live.js +499 -129
- package/dist/engine/memory.d.ts +2 -1
- package/dist/engine/memory.js +3 -2
- package/dist/engine/optimizer.d.ts +0 -1
- package/dist/engine/optimizer.js +4 -4
- package/dist/engine/query-api.d.ts +3 -0
- package/dist/engine/query-api.js +3 -0
- package/dist/engine/query-cache.d.ts +0 -1
- package/dist/engine/query-cache.js +4 -4
- package/dist/engine/query.d.ts +4 -7
- package/dist/engine/query.js +348 -155
- package/dist/engine/result-wire.d.ts +0 -1
- package/dist/engine/result-wire.js +2 -2
- package/dist/engine/schema-wire.d.ts +1 -2
- package/dist/engine/schema-wire.js +0 -1
- package/dist/engine/schema.d.ts +3 -8
- package/dist/engine/schema.js +41 -24
- package/dist/engine/sort-keys.d.ts +0 -1
- package/dist/engine/sort-keys.js +2 -2
- package/dist/engine/sql-domains.d.ts +6 -1
- package/dist/engine/sql-domains.js +209 -45
- package/dist/engine/sql-driver.d.ts +2 -2
- package/dist/engine/sql-driver.js +0 -1
- package/dist/engine/sql-json.d.ts +0 -1
- package/dist/engine/sql-json.js +53 -7
- package/dist/engine/sql-semantics.d.ts +8 -5
- package/dist/engine/sql-semantics.js +427 -65
- package/dist/engine/typed-live.d.ts +67 -0
- package/dist/engine/typed-live.js +349 -0
- package/dist/engine/vector.d.ts +7 -1
- package/dist/engine/vector.js +202 -58
- package/dist/engine/worker-host.d.ts +8 -2
- package/dist/engine/worker-host.js +616 -152
- package/dist/engine/worker.d.ts +0 -1
- package/dist/engine/worker.js +3 -3
- package/dist/engine/write-block-planner.d.ts +18 -0
- package/dist/engine/write-block-planner.js +112 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/plan/index.d.ts +0 -1
- package/dist/plan/index.js +0 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/storage/indexeddb.d.ts +74 -65
- package/dist/storage/indexeddb.js +12301 -2076
- package/dist/storage/memory.d.ts +56 -66
- package/dist/storage/memory.js +1004 -139
- package/dist/storage/opfs/files.d.ts +18 -7
- package/dist/storage/opfs/files.js +115 -28
- package/dist/storage/opfs/index.d.ts +1 -1
- package/dist/storage/opfs/index.js +1 -1
- package/dist/storage/opfs/leader.d.ts +403 -91
- package/dist/storage/opfs/leader.js +4306 -602
- package/dist/storage/opfs/rpc.d.ts +15 -3
- package/dist/storage/opfs/rpc.js +223 -2
- package/dist/storage/opfs/snapshot-ledger.d.ts +40 -0
- package/dist/storage/opfs/snapshot-ledger.js +281 -0
- package/dist/storage/opfs/store.d.ts +26 -121
- package/dist/storage/opfs/store.js +436 -388
- package/dist/storage/persistence.d.ts +37 -0
- package/dist/storage/persistence.js +78 -0
- package/dist/storage/snapshot-stream.d.ts +24 -0
- package/dist/storage/snapshot-stream.js +897 -0
- package/dist/storage/snapshot.d.ts +9 -99
- package/dist/storage/snapshot.js +33 -309
- package/dist/storage/toolkit/extents.d.ts +41 -7
- package/dist/storage/toolkit/extents.js +402 -39
- package/dist/storage/toolkit/index.d.ts +3 -4
- package/dist/storage/toolkit/index.js +27 -3
- package/dist/storage/toolkit/record-core.d.ts +174 -61
- package/dist/storage/toolkit/record-core.js +5401 -849
- package/dist/storage/toolkit/sync-file.d.ts +10 -1
- package/dist/storage/toolkit/sync-file.js +50 -2
- package/dist/storage/toolkit/wal.d.ts +23 -5
- package/dist/storage/toolkit/wal.js +89 -27
- package/dist/storage/toolkit/wire.d.ts +4 -6
- package/dist/storage/toolkit/wire.js +80 -25
- package/dist/storage/types.d.ts +1271 -218
- package/dist/storage/types.js +1471 -138
- package/dist/testing/block-store-conformance.d.ts +0 -1
- package/dist/testing/block-store-conformance.js +877 -138
- package/dist/testing/index.d.ts +42 -31
- package/dist/testing/index.js +100 -68
- package/dist/testing/opfs-shim.d.ts +13 -3
- package/dist/testing/opfs-shim.js +40 -6
- package/dist/testing/simulator.d.ts +0 -1
- package/dist/testing/simulator.js +43 -12
- package/dist/testing/sqllogictest.d.ts +0 -1
- package/dist/testing/sqllogictest.js +0 -1
- package/dist/transactions/index.d.ts +81 -20
- package/dist/transactions/index.js +1050 -268
- package/dist/worker-protocol/index.d.ts +3 -2
- package/dist/worker-protocol/index.js +2 -5
- package/package.json +49 -1
- package/dist/block-format/block.d.ts.map +0 -1
- package/dist/block-format/block.js.map +0 -1
- package/dist/block-format/checksum.d.ts.map +0 -1
- package/dist/block-format/checksum.js.map +0 -1
- package/dist/block-format/codecs.d.ts.map +0 -1
- package/dist/block-format/codecs.js.map +0 -1
- package/dist/block-format/column.d.ts.map +0 -1
- package/dist/block-format/column.js.map +0 -1
- package/dist/block-format/index.d.ts.map +0 -1
- package/dist/block-format/index.js.map +0 -1
- package/dist/block-format/physical.d.ts.map +0 -1
- package/dist/block-format/physical.js.map +0 -1
- package/dist/block-format/types.d.ts.map +0 -1
- package/dist/block-format/types.js.map +0 -1
- package/dist/engine/artifact-cache.d.ts.map +0 -1
- package/dist/engine/artifact-cache.js.map +0 -1
- package/dist/engine/batch.d.ts.map +0 -1
- package/dist/engine/batch.js.map +0 -1
- package/dist/engine/buffered-writer.d.ts.map +0 -1
- package/dist/engine/buffered-writer.js.map +0 -1
- package/dist/engine/catalog.d.ts.map +0 -1
- package/dist/engine/catalog.js.map +0 -1
- package/dist/engine/client.d.ts.map +0 -1
- package/dist/engine/client.js.map +0 -1
- package/dist/engine/coordinator.d.ts +0 -17
- package/dist/engine/coordinator.d.ts.map +0 -1
- package/dist/engine/coordinator.js +0 -60
- package/dist/engine/coordinator.js.map +0 -1
- package/dist/engine/database.d.ts.map +0 -1
- package/dist/engine/database.js.map +0 -1
- package/dist/engine/defaults.d.ts.map +0 -1
- package/dist/engine/defaults.js.map +0 -1
- package/dist/engine/errors.d.ts.map +0 -1
- package/dist/engine/errors.js.map +0 -1
- package/dist/engine/fts.d.ts.map +0 -1
- package/dist/engine/fts.js.map +0 -1
- package/dist/engine/group-index.d.ts.map +0 -1
- package/dist/engine/group-index.js.map +0 -1
- package/dist/engine/index.d.ts.map +0 -1
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/join-index.d.ts.map +0 -1
- package/dist/engine/join-index.js.map +0 -1
- package/dist/engine/live.d.ts.map +0 -1
- package/dist/engine/live.js.map +0 -1
- package/dist/engine/memory.d.ts.map +0 -1
- package/dist/engine/memory.js.map +0 -1
- package/dist/engine/optimizer.d.ts.map +0 -1
- package/dist/engine/optimizer.js.map +0 -1
- package/dist/engine/query-cache.d.ts.map +0 -1
- package/dist/engine/query-cache.js.map +0 -1
- package/dist/engine/query.d.ts.map +0 -1
- package/dist/engine/query.js.map +0 -1
- package/dist/engine/result-wire.d.ts.map +0 -1
- package/dist/engine/result-wire.js.map +0 -1
- package/dist/engine/schema-wire.d.ts.map +0 -1
- package/dist/engine/schema-wire.js.map +0 -1
- package/dist/engine/schema.d.ts.map +0 -1
- package/dist/engine/schema.js.map +0 -1
- package/dist/engine/sort-keys.d.ts.map +0 -1
- package/dist/engine/sort-keys.js.map +0 -1
- package/dist/engine/sql-domains.d.ts.map +0 -1
- package/dist/engine/sql-domains.js.map +0 -1
- package/dist/engine/sql-driver.d.ts.map +0 -1
- package/dist/engine/sql-driver.js.map +0 -1
- package/dist/engine/sql-json.d.ts.map +0 -1
- package/dist/engine/sql-json.js.map +0 -1
- package/dist/engine/sql-semantics.d.ts.map +0 -1
- package/dist/engine/sql-semantics.js.map +0 -1
- package/dist/engine/vector.d.ts.map +0 -1
- package/dist/engine/vector.js.map +0 -1
- package/dist/engine/worker-host.d.ts.map +0 -1
- package/dist/engine/worker-host.js.map +0 -1
- package/dist/engine/worker.d.ts.map +0 -1
- package/dist/engine/worker.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plan/index.d.ts.map +0 -1
- package/dist/plan/index.js.map +0 -1
- package/dist/storage/fixture-shape.d.ts +0 -42
- package/dist/storage/fixture-shape.d.ts.map +0 -1
- package/dist/storage/fixture-shape.js +0 -146
- package/dist/storage/fixture-shape.js.map +0 -1
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/indexeddb.d.ts.map +0 -1
- package/dist/storage/indexeddb.js.map +0 -1
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/opfs/files.d.ts.map +0 -1
- package/dist/storage/opfs/files.js.map +0 -1
- package/dist/storage/opfs/index.d.ts.map +0 -1
- package/dist/storage/opfs/index.js.map +0 -1
- package/dist/storage/opfs/leader.d.ts.map +0 -1
- package/dist/storage/opfs/leader.js.map +0 -1
- package/dist/storage/opfs/rpc.d.ts.map +0 -1
- package/dist/storage/opfs/rpc.js.map +0 -1
- package/dist/storage/opfs/store.d.ts.map +0 -1
- package/dist/storage/opfs/store.js.map +0 -1
- package/dist/storage/snapshot.d.ts.map +0 -1
- package/dist/storage/snapshot.js.map +0 -1
- package/dist/storage/toolkit/extents.d.ts.map +0 -1
- package/dist/storage/toolkit/extents.js.map +0 -1
- package/dist/storage/toolkit/index.d.ts.map +0 -1
- package/dist/storage/toolkit/index.js.map +0 -1
- package/dist/storage/toolkit/record-core.d.ts.map +0 -1
- package/dist/storage/toolkit/record-core.js.map +0 -1
- package/dist/storage/toolkit/sync-file.d.ts.map +0 -1
- package/dist/storage/toolkit/sync-file.js.map +0 -1
- package/dist/storage/toolkit/wal.d.ts.map +0 -1
- package/dist/storage/toolkit/wal.js.map +0 -1
- package/dist/storage/toolkit/wire.d.ts.map +0 -1
- package/dist/storage/toolkit/wire.js.map +0 -1
- package/dist/storage/types.d.ts.map +0 -1
- package/dist/storage/types.js.map +0 -1
- package/dist/testing/block-store-conformance.d.ts.map +0 -1
- package/dist/testing/block-store-conformance.js.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/opfs-shim.d.ts.map +0 -1
- package/dist/testing/opfs-shim.js.map +0 -1
- package/dist/testing/seeds.d.ts +0 -11
- package/dist/testing/seeds.d.ts.map +0 -1
- package/dist/testing/seeds.js +0 -50
- package/dist/testing/seeds.js.map +0 -1
- package/dist/testing/simulator.d.ts.map +0 -1
- package/dist/testing/simulator.js.map +0 -1
- package/dist/testing/sqllogictest.d.ts.map +0 -1
- package/dist/testing/sqllogictest.js.map +0 -1
- package/dist/transactions/index.d.ts.map +0 -1
- package/dist/transactions/index.js.map +0 -1
- package/dist/worker-protocol/index.d.ts.map +0 -1
- package/dist/worker-protocol/index.js.map +0 -1
package/dist/engine/vector.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { dateMilliseconds } from "../date-value.js";
|
|
2
|
+
import { MAX_TEMP_RUN_BATCH_BYTES, MAX_TEMP_RUN_PAGE_BYTES, MAX_TEMP_RUN_PAGES_PER_BATCH, } from "../storage/types.js";
|
|
1
3
|
import { cachedListMembership, childExpressions, distinctFromComparison, nullOrder, isScalarFunctionName, likeMatches, orderOutputName, parseQuantified, quantifiedComparison, scalarFunctionValue, } from "./query.js";
|
|
2
4
|
import { jsonValueOf } from "./sql-json.js";
|
|
3
5
|
import { bm25DocumentScore, cachedQueryTerms, FtsStatsAccumulator, fullTermsMask, renderDocumentValue, termFrequencies, termsMask, tokenize, } from "./fts.js";
|
|
@@ -27,7 +29,17 @@ const SPILL_PAGE_MAGIC = 0x5350494c;
|
|
|
27
29
|
const SPILL_PAGE_HEADER_BYTES = 8;
|
|
28
30
|
const vectorTextEncoder = new TextEncoder();
|
|
29
31
|
/** Pages per batched spill write: bounds the transient encoded copies a batch holds. */
|
|
30
|
-
const SPILL_WRITE_BATCH_PAGES = 8;
|
|
32
|
+
const SPILL_WRITE_BATCH_PAGES = Math.min(8, MAX_TEMP_RUN_PAGES_PER_BATCH);
|
|
33
|
+
function boundedSpillPageRows(value) {
|
|
34
|
+
const rows = value ?? DEFAULT_BATCH_ROWS;
|
|
35
|
+
if (!Number.isSafeInteger(rows) || rows <= 0) {
|
|
36
|
+
throw new RangeError("Query spill page rows must be a positive whole number");
|
|
37
|
+
}
|
|
38
|
+
// Page rows are a tuning target, not a request to buffer an unbounded number of rows. Larger
|
|
39
|
+
// pages do not improve the block-store round trip because byte-bounded batches provide that
|
|
40
|
+
// amortization independently.
|
|
41
|
+
return Math.min(rows, DEFAULT_BATCH_ROWS);
|
|
42
|
+
}
|
|
31
43
|
/** Writes already-materialized pages through the batch method when the store offers one. */
|
|
32
44
|
async function writeSpillPages(store, pages) {
|
|
33
45
|
const batched = store.putPages?.bind(store);
|
|
@@ -37,9 +49,43 @@ async function writeSpillPages(store, pages) {
|
|
|
37
49
|
}
|
|
38
50
|
return;
|
|
39
51
|
}
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
let batch = [];
|
|
53
|
+
let batchBytes = 0;
|
|
54
|
+
for (const page of pages) {
|
|
55
|
+
if (page.bytes.byteLength > MAX_TEMP_RUN_PAGE_BYTES) {
|
|
56
|
+
throw new RangeError("Query spill page exceeds the storage limit");
|
|
57
|
+
}
|
|
58
|
+
if (batch.length > 0 &&
|
|
59
|
+
(batch.length === SPILL_WRITE_BATCH_PAGES ||
|
|
60
|
+
batchBytes + page.bytes.byteLength > MAX_TEMP_RUN_BATCH_BYTES)) {
|
|
61
|
+
await batched(batch);
|
|
62
|
+
batch = [];
|
|
63
|
+
batchBytes = 0;
|
|
64
|
+
}
|
|
65
|
+
batch.push(page);
|
|
66
|
+
batchBytes += page.bytes.byteLength;
|
|
42
67
|
}
|
|
68
|
+
if (batch.length > 0)
|
|
69
|
+
await batched(batch);
|
|
70
|
+
}
|
|
71
|
+
async function writeSpillRowPages(store, ownerId, runId, startPageIndex, columns, rows, pageRows) {
|
|
72
|
+
let pending = [];
|
|
73
|
+
let pendingBytes = 0;
|
|
74
|
+
let pageCount = 0;
|
|
75
|
+
for (const bytes of encodeSpillRowPages(columns, rows, pageRows)) {
|
|
76
|
+
if (pending.length > 0 &&
|
|
77
|
+
(pending.length === SPILL_WRITE_BATCH_PAGES ||
|
|
78
|
+
pendingBytes + bytes.byteLength > MAX_TEMP_RUN_BATCH_BYTES)) {
|
|
79
|
+
await writeSpillPages(store, pending);
|
|
80
|
+
pending = [];
|
|
81
|
+
pendingBytes = 0;
|
|
82
|
+
}
|
|
83
|
+
pending.push({ ownerId, runId, pageIndex: startPageIndex + pageCount, bytes });
|
|
84
|
+
pendingBytes += bytes.byteLength;
|
|
85
|
+
pageCount += 1;
|
|
86
|
+
}
|
|
87
|
+
await writeSpillPages(store, pending);
|
|
88
|
+
return pageCount;
|
|
43
89
|
}
|
|
44
90
|
export function createColumnarTable(name, columns, uniqueKey) {
|
|
45
91
|
const first = columns.values().next().value;
|
|
@@ -135,6 +181,23 @@ export function prepareVectorQuery(plan, inputTables, options = {}) {
|
|
|
135
181
|
executionMemory.close();
|
|
136
182
|
}
|
|
137
183
|
},
|
|
184
|
+
async executeBatches(executionOptions, consume) {
|
|
185
|
+
if (closed)
|
|
186
|
+
throw new Error("Prepared vector query is closed");
|
|
187
|
+
if (bound.grouped || bound.orderBy.length > 0 || bound.joins.length > 0) {
|
|
188
|
+
throw new TypeError("Native query batching requires an ungrouped, unordered, single-source plan");
|
|
189
|
+
}
|
|
190
|
+
if (!Number.isSafeInteger(executionOptions.batchRows) || executionOptions.batchRows <= 0) {
|
|
191
|
+
throw new RangeError("Query batch rows must be a positive whole number");
|
|
192
|
+
}
|
|
193
|
+
const executionMemory = retainedMemory.createChild();
|
|
194
|
+
try {
|
|
195
|
+
return await executeBoundPlanBatches(bound, executionMemory, executionOptions, consume);
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
executionMemory.close();
|
|
199
|
+
}
|
|
200
|
+
},
|
|
138
201
|
close() {
|
|
139
202
|
if (closed)
|
|
140
203
|
return;
|
|
@@ -198,7 +261,7 @@ function createVector(input) {
|
|
|
198
261
|
continue;
|
|
199
262
|
const numericValue = input.type === "datetime"
|
|
200
263
|
? value instanceof Date
|
|
201
|
-
? value
|
|
264
|
+
? dateMilliseconds(value)
|
|
202
265
|
: Number.NaN
|
|
203
266
|
: typeof value === "number"
|
|
204
267
|
? value
|
|
@@ -1202,15 +1265,61 @@ async function executeBoundPlanAsync(plan, memory, options) {
|
|
|
1202
1265
|
const rows = plan.grouped ? finishGroups(plan, groups.values(), memory) : output.finish();
|
|
1203
1266
|
return finishResult(plan, rows, memory);
|
|
1204
1267
|
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Pull-driven scan execution for cursor-safe plans. A result page owns a child memory context
|
|
1270
|
+
* that closes after the consumer settles, so both modeled memory and live row objects are
|
|
1271
|
+
* bounded by one page. OFFSET/LIMIT are applied once across the whole scan, never per page.
|
|
1272
|
+
*/
|
|
1273
|
+
async function executeBoundPlanBatches(plan, memory, options, consume) {
|
|
1274
|
+
const columns = plan.wildcard ? wildcardColumnNames(plan) : plan.select.map((item) => item.alias);
|
|
1275
|
+
const { limit, offset, ...unbounded } = plan;
|
|
1276
|
+
const scanPlan = unbounded;
|
|
1277
|
+
let skipped = 0;
|
|
1278
|
+
let emitted = 0;
|
|
1279
|
+
const scanRows = scanPlan.sourceTables[scanPlan.scanSource]?.rowCount ?? 0;
|
|
1280
|
+
const step = Math.min(DEFAULT_BATCH_ROWS, options.batchRows);
|
|
1281
|
+
for (let start = 0; start < scanRows && (limit === undefined || emitted < limit);) {
|
|
1282
|
+
options.signal?.throwIfAborted();
|
|
1283
|
+
let length = Math.min(step, scanRows - start);
|
|
1284
|
+
const loaded = options.loadScanWindow?.(start, length);
|
|
1285
|
+
const residentEnd = typeof loaded === "number" || loaded === undefined ? loaded : await loaded;
|
|
1286
|
+
options.signal?.throwIfAborted();
|
|
1287
|
+
if (typeof residentEnd === "number" && residentEnd > start) {
|
|
1288
|
+
length = Math.min(length, residentEnd - start);
|
|
1289
|
+
}
|
|
1290
|
+
const pageMemory = memory.createChild();
|
|
1291
|
+
try {
|
|
1292
|
+
const groups = new GroupAccumulator(scanPlan, pageMemory);
|
|
1293
|
+
const output = new ResultSink(scanPlan, pageMemory, options.loadScanWindow === undefined);
|
|
1294
|
+
runScanBatch(scanPlan, start, length, groups, output, pageMemory);
|
|
1295
|
+
let rows = output.finish();
|
|
1296
|
+
const remainingOffset = Math.max(0, (offset ?? 0) - skipped);
|
|
1297
|
+
if (remainingOffset > 0) {
|
|
1298
|
+
const remove = Math.min(remainingOffset, rows.length);
|
|
1299
|
+
rows = rows.slice(remove);
|
|
1300
|
+
skipped += remove;
|
|
1301
|
+
}
|
|
1302
|
+
if (limit !== undefined && rows.length > limit - emitted) {
|
|
1303
|
+
rows = rows.slice(0, limit - emitted);
|
|
1304
|
+
}
|
|
1305
|
+
if (rows.length > 0) {
|
|
1306
|
+
emitted += rows.length;
|
|
1307
|
+
await consume({ columns: [...columns], rows });
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
finally {
|
|
1311
|
+
pageMemory.close();
|
|
1312
|
+
}
|
|
1313
|
+
start += length;
|
|
1314
|
+
}
|
|
1315
|
+
return columns;
|
|
1316
|
+
}
|
|
1205
1317
|
function createSpillOwnerId() {
|
|
1206
1318
|
return `query-${globalThis.crypto.randomUUID()}`;
|
|
1207
1319
|
}
|
|
1208
1320
|
async function executeBoundPlanWithSortSpill(plan, memory, options) {
|
|
1209
1321
|
const store = required(options.spillStore, "Query spill store is missing");
|
|
1210
|
-
const pageRows = options.spillPageRows
|
|
1211
|
-
if (!Number.isSafeInteger(pageRows) || pageRows <= 0) {
|
|
1212
|
-
throw new RangeError("Query spill page rows must be a positive whole number");
|
|
1213
|
-
}
|
|
1322
|
+
const pageRows = boundedSpillPageRows(options.spillPageRows);
|
|
1214
1323
|
const columns = plan.wildcard ? wildcardColumnNames(plan) : plan.select.map((item) => item.alias);
|
|
1215
1324
|
const ownerId = createSpillOwnerId();
|
|
1216
1325
|
const runs = [];
|
|
@@ -1251,8 +1360,8 @@ async function executeBoundPlanWithSortSpill(plan, memory, options) {
|
|
|
1251
1360
|
ordering.release();
|
|
1252
1361
|
}
|
|
1253
1362
|
const runId = `run-${String(runSequence++)}`;
|
|
1254
|
-
await store
|
|
1255
|
-
runs.push({ id: runId, pageCount
|
|
1363
|
+
const pageCount = await writeSpillRowPages(store, ownerId, runId, 0, columns, rows, pageRows);
|
|
1364
|
+
runs.push({ id: runId, pageCount });
|
|
1256
1365
|
}
|
|
1257
1366
|
finally {
|
|
1258
1367
|
outputMemory.close();
|
|
@@ -1307,10 +1416,7 @@ async function executeBoundPlanWithSortSpill(plan, memory, options) {
|
|
|
1307
1416
|
}
|
|
1308
1417
|
async function executeBoundPlanWithHashSpill(plan, memory, options) {
|
|
1309
1418
|
const store = required(options.spillStore, "Query spill store is missing");
|
|
1310
|
-
const pageRows = options.spillPageRows
|
|
1311
|
-
if (!Number.isSafeInteger(pageRows) || pageRows <= 0) {
|
|
1312
|
-
throw new RangeError("Query spill page rows must be a positive whole number");
|
|
1313
|
-
}
|
|
1419
|
+
const pageRows = boundedSpillPageRows(options.spillPageRows);
|
|
1314
1420
|
const partitionCount = 64;
|
|
1315
1421
|
const columns = plan.select.map((item) => item.alias);
|
|
1316
1422
|
const groupColumnNames = plan.groupBy.map((_, index) => `g${String(index)}`);
|
|
@@ -1382,15 +1488,26 @@ async function executeBoundPlanWithHashSpill(plan, memory, options) {
|
|
|
1382
1488
|
}
|
|
1383
1489
|
});
|
|
1384
1490
|
const flush = [];
|
|
1491
|
+
let flushBytes = 0;
|
|
1385
1492
|
for (const [partition, rows] of partitionBuffers) {
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1493
|
+
for (const bytes of encodeSpillRowPages(spillColumns, rows, pageRows)) {
|
|
1494
|
+
if (flush.length > 0 &&
|
|
1495
|
+
(flush.length === SPILL_WRITE_BATCH_PAGES ||
|
|
1496
|
+
flushBytes + bytes.byteLength > MAX_TEMP_RUN_BATCH_BYTES)) {
|
|
1497
|
+
await writeSpillPages(store, flush);
|
|
1498
|
+
flush.length = 0;
|
|
1499
|
+
flushBytes = 0;
|
|
1500
|
+
}
|
|
1501
|
+
const pageIndex = partitionPages[partition] ?? 0;
|
|
1502
|
+
flush.push({
|
|
1503
|
+
ownerId,
|
|
1504
|
+
runId: `partition-${String(partition)}`,
|
|
1505
|
+
pageIndex,
|
|
1506
|
+
bytes,
|
|
1507
|
+
});
|
|
1508
|
+
flushBytes += bytes.byteLength;
|
|
1509
|
+
partitionPages[partition] = pageIndex + 1;
|
|
1510
|
+
}
|
|
1394
1511
|
}
|
|
1395
1512
|
await writeSpillPages(store, flush);
|
|
1396
1513
|
}
|
|
@@ -1437,23 +1554,8 @@ async function executeBoundPlanWithHashSpill(plan, memory, options) {
|
|
|
1437
1554
|
}
|
|
1438
1555
|
}
|
|
1439
1556
|
const runId = `group-${String(runSequence++)}`;
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
for (let start = 0; start < rows.length; start += pageRows) {
|
|
1443
|
-
pending.push({
|
|
1444
|
-
ownerId,
|
|
1445
|
-
runId,
|
|
1446
|
-
pageIndex: outputPage,
|
|
1447
|
-
bytes: encodeSpillRows(columns, rows.slice(start, start + pageRows)),
|
|
1448
|
-
});
|
|
1449
|
-
outputPage += 1;
|
|
1450
|
-
if (pending.length >= SPILL_WRITE_BATCH_PAGES) {
|
|
1451
|
-
await writeSpillPages(store, pending);
|
|
1452
|
-
pending = [];
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
await writeSpillPages(store, pending);
|
|
1456
|
-
runs.push({ id: runId, pageCount: outputPage });
|
|
1557
|
+
const pageCount = await writeSpillRowPages(store, ownerId, runId, 0, columns, rows, pageRows);
|
|
1558
|
+
runs.push({ id: runId, pageCount });
|
|
1457
1559
|
}
|
|
1458
1560
|
finally {
|
|
1459
1561
|
partitionMemory.close();
|
|
@@ -1589,11 +1691,10 @@ async function mergeSpillRuns(store, ownerId, left, right, outputId, columns, or
|
|
|
1589
1691
|
const flush = async () => {
|
|
1590
1692
|
if (outputPage.length === 0)
|
|
1591
1693
|
return;
|
|
1592
|
-
await store
|
|
1694
|
+
pageIndex += await writeSpillRowPages(store, ownerId, outputId, pageIndex, columns, outputPage, pageRows);
|
|
1593
1695
|
outputPage = [];
|
|
1594
1696
|
outputMemory.close();
|
|
1595
1697
|
outputMemory = mergeMemory.createChild();
|
|
1596
|
-
pageIndex += 1;
|
|
1597
1698
|
};
|
|
1598
1699
|
try {
|
|
1599
1700
|
let leftRow = await leftReader.next();
|
|
@@ -1665,19 +1766,63 @@ function compareOrderedRows(left, right, orderBy) {
|
|
|
1665
1766
|
}
|
|
1666
1767
|
return 0;
|
|
1667
1768
|
}
|
|
1668
|
-
function
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1769
|
+
function encodeSpillRow(columns, row) {
|
|
1770
|
+
return {
|
|
1771
|
+
bytes: vectorTextEncoder.encode(JSON.stringify(columns.map((column) => encodeSpillValue(row[column] ?? null)))),
|
|
1772
|
+
modeledBytes: queryRowPayloadBytes(row),
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
function buildSpillPage(rows, byteLength, modeledBytes) {
|
|
1776
|
+
const bytes = new Uint8Array(byteLength);
|
|
1675
1777
|
const header = new DataView(bytes.buffer);
|
|
1676
1778
|
header.setUint32(0, SPILL_PAGE_MAGIC, true);
|
|
1677
1779
|
header.setUint32(4, modeledBytes, true);
|
|
1678
|
-
|
|
1780
|
+
let offset = SPILL_PAGE_HEADER_BYTES;
|
|
1781
|
+
bytes[offset++] = 0x5b;
|
|
1782
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
1783
|
+
if (index > 0)
|
|
1784
|
+
bytes[offset++] = 0x2c;
|
|
1785
|
+
const row = required(rows[index], "Encoded spill row is missing");
|
|
1786
|
+
bytes.set(row.bytes, offset);
|
|
1787
|
+
offset += row.bytes.byteLength;
|
|
1788
|
+
}
|
|
1789
|
+
bytes[offset] = 0x5d;
|
|
1679
1790
|
return bytes;
|
|
1680
1791
|
}
|
|
1792
|
+
/** Encodes pages incrementally and splits on both the requested row target and the hard byte cap. */
|
|
1793
|
+
function* encodeSpillRowPages(columns, rows, pageRows) {
|
|
1794
|
+
let pending = [];
|
|
1795
|
+
let byteLength = SPILL_PAGE_HEADER_BYTES + 2;
|
|
1796
|
+
let modeledBytes = 0;
|
|
1797
|
+
const flush = () => {
|
|
1798
|
+
const page = buildSpillPage(pending, byteLength, modeledBytes);
|
|
1799
|
+
pending = [];
|
|
1800
|
+
byteLength = SPILL_PAGE_HEADER_BYTES + 2;
|
|
1801
|
+
modeledBytes = 0;
|
|
1802
|
+
return page;
|
|
1803
|
+
};
|
|
1804
|
+
for (const row of rows) {
|
|
1805
|
+
const encoded = encodeSpillRow(columns, row);
|
|
1806
|
+
const separatorBytes = pending.length === 0 ? 0 : 1;
|
|
1807
|
+
const nextByteLength = byteLength + separatorBytes + encoded.bytes.byteLength;
|
|
1808
|
+
const nextModeledBytes = modeledBytes + encoded.modeledBytes;
|
|
1809
|
+
if (pending.length > 0 &&
|
|
1810
|
+
(pending.length === pageRows ||
|
|
1811
|
+
nextByteLength > MAX_TEMP_RUN_PAGE_BYTES ||
|
|
1812
|
+
nextModeledBytes > 0xffffffff)) {
|
|
1813
|
+
yield flush();
|
|
1814
|
+
}
|
|
1815
|
+
const addedSeparatorBytes = pending.length === 0 ? 0 : 1;
|
|
1816
|
+
byteLength += addedSeparatorBytes + encoded.bytes.byteLength;
|
|
1817
|
+
modeledBytes += encoded.modeledBytes;
|
|
1818
|
+
if (byteLength > MAX_TEMP_RUN_PAGE_BYTES || modeledBytes > 0xffffffff) {
|
|
1819
|
+
throw new RangeError("One query result row exceeds the spill page storage limit");
|
|
1820
|
+
}
|
|
1821
|
+
pending.push(encoded);
|
|
1822
|
+
}
|
|
1823
|
+
if (pending.length > 0)
|
|
1824
|
+
yield flush();
|
|
1825
|
+
}
|
|
1681
1826
|
function decodeSpillRows(columns, bytes) {
|
|
1682
1827
|
spillRowsModeledBytes(bytes);
|
|
1683
1828
|
const value = JSON.parse(new TextDecoder().decode(bytes.subarray(SPILL_PAGE_HEADER_BYTES)));
|
|
@@ -1708,7 +1853,7 @@ function encodeSpillValue(value) {
|
|
|
1708
1853
|
return [2, Object.is(value, -0) ? "-0" : String(value)];
|
|
1709
1854
|
if (typeof value === "string")
|
|
1710
1855
|
return [3, value];
|
|
1711
|
-
return [4, value
|
|
1856
|
+
return [4, dateMilliseconds(value)];
|
|
1712
1857
|
}
|
|
1713
1858
|
function decodeSpillValue(value) {
|
|
1714
1859
|
if (!Array.isArray(value))
|
|
@@ -2851,7 +2996,7 @@ class ResultSink {
|
|
|
2851
2996
|
: typeof first === "number"
|
|
2852
2997
|
? first
|
|
2853
2998
|
: first instanceof Date
|
|
2854
|
-
? first
|
|
2999
|
+
? dateMilliseconds(first)
|
|
2855
3000
|
: undefined;
|
|
2856
3001
|
}
|
|
2857
3002
|
/**
|
|
@@ -3404,7 +3549,7 @@ function createGroupState(groupValues, plan, memory) {
|
|
|
3404
3549
|
* string a row genuinely holds.
|
|
3405
3550
|
*/
|
|
3406
3551
|
function distinctKey(value) {
|
|
3407
|
-
return value instanceof Date ?
|
|
3552
|
+
return value instanceof Date ? `\0d${String(dateMilliseconds(value))}` : value;
|
|
3408
3553
|
}
|
|
3409
3554
|
/**
|
|
3410
3555
|
* Whether this value is the first of its kind for the slot, folding it into the set when it is.
|
|
@@ -3799,7 +3944,7 @@ function detectPrimitiveComparison(predicate) {
|
|
|
3799
3944
|
return { source: column.source, vector, operator, value };
|
|
3800
3945
|
}
|
|
3801
3946
|
if (vector.kind === "datetime" && value instanceof Date) {
|
|
3802
|
-
return { source: column.source, vector, operator, value: value
|
|
3947
|
+
return { source: column.source, vector, operator, value: dateMilliseconds(value) };
|
|
3803
3948
|
}
|
|
3804
3949
|
if (vector.kind === "boolean" &&
|
|
3805
3950
|
typeof value === "boolean" &&
|
|
@@ -3847,7 +3992,7 @@ function detectPrimitiveInList(predicate) {
|
|
|
3847
3992
|
else {
|
|
3848
3993
|
if (!(value instanceof Date))
|
|
3849
3994
|
return undefined;
|
|
3850
|
-
members.add(value
|
|
3995
|
+
members.add(dateMilliseconds(value));
|
|
3851
3996
|
}
|
|
3852
3997
|
}
|
|
3853
3998
|
if (members.size === 0)
|
|
@@ -4361,7 +4506,7 @@ function comparisonValue(operator, leftValue, rightValue) {
|
|
|
4361
4506
|
return comparison <= 0;
|
|
4362
4507
|
}
|
|
4363
4508
|
function comparable(value) {
|
|
4364
|
-
return value instanceof Date ? value
|
|
4509
|
+
return value instanceof Date ? dateMilliseconds(value) : value;
|
|
4365
4510
|
}
|
|
4366
4511
|
function groupKey(value) {
|
|
4367
4512
|
const comparableValue = comparable(value);
|
|
@@ -4411,8 +4556,8 @@ function compareValues(left, right) {
|
|
|
4411
4556
|
const exact = exactNumericCompare(left, right);
|
|
4412
4557
|
if (exact !== undefined)
|
|
4413
4558
|
return exact;
|
|
4414
|
-
const a = left instanceof Date ? left
|
|
4415
|
-
const b = right instanceof Date ? right
|
|
4559
|
+
const a = left instanceof Date ? dateMilliseconds(left) : left;
|
|
4560
|
+
const b = right instanceof Date ? dateMilliseconds(right) : right;
|
|
4416
4561
|
if (a === b)
|
|
4417
4562
|
return 0;
|
|
4418
4563
|
if (a === null || a === undefined)
|
|
@@ -4492,4 +4637,3 @@ function safeMemoryProduct(left, right, label) {
|
|
|
4492
4637
|
}
|
|
4493
4638
|
return product;
|
|
4494
4639
|
}
|
|
4495
|
-
//# sourceMappingURL=vector.js.map
|
|
@@ -21,7 +21,7 @@ export type StoreDescriptor = {
|
|
|
21
21
|
durability?: "relaxed" | "strict";
|
|
22
22
|
};
|
|
23
23
|
/** The cloneable subset of MinnowDatabaseOptions; function-valued seams stay worker-side. */
|
|
24
|
-
export type WireDatabaseOptions = Pick<MinnowDatabaseOptions, "compression" | "rowsPerBlock" | "maxCommitRetries" | "spillOwnerLeaseMs" | "bufferPoolBytes">;
|
|
24
|
+
export type WireDatabaseOptions = Pick<MinnowDatabaseOptions, "compression" | "targetBlockBytes" | "rowsPerBlock" | "maxCommitRetries" | "spillOwnerLeaseMs" | "transactionOwnerLeaseMs" | "transactionIdleTimeoutMs" | "bufferPoolBytes" | "executionMemoryBudgetBytes" | "autoCollectDebtLimitCommits" | "autoCollect" | "autoCompact">;
|
|
25
25
|
export interface DatabaseInitPayload {
|
|
26
26
|
store: StoreDescriptor;
|
|
27
27
|
options?: WireDatabaseOptions;
|
|
@@ -40,6 +40,11 @@ export interface RpcScope {
|
|
|
40
40
|
export interface ExposeDatabaseOptions {
|
|
41
41
|
/** Called when the client sends its dispose frame, after every handle has been closed. */
|
|
42
42
|
onDispose?: () => void | Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Rolls back a worker write handle after this long without a handle RPC. Match the constructed
|
|
45
|
+
* database's `transactionIdleTimeoutMs` when it is customized. Defaults to 30 seconds.
|
|
46
|
+
*/
|
|
47
|
+
writeHandleIdleTimeoutMs?: number;
|
|
43
48
|
/**
|
|
44
49
|
* Called when the main thread reports its page visibility. The stock entry forwards this to
|
|
45
50
|
* the store's `setForeground` when it has one — the OPFS store uses it to keep leadership
|
|
@@ -51,6 +56,8 @@ export interface AttachDatabaseWorkerOptions {
|
|
|
51
56
|
/** Test seam for environments without a global IndexedDB (e.g. fake-indexeddb). */
|
|
52
57
|
indexedDB?: IDBFactory;
|
|
53
58
|
}
|
|
59
|
+
/** Hard per-connection ceiling for resident worker resources abandoned by a client. */
|
|
60
|
+
export declare const MAX_WORKER_HANDLES_PER_CONNECTION = 256;
|
|
54
61
|
/**
|
|
55
62
|
* Answers client RPC frames against a database you constructed yourself. Use this in a custom
|
|
56
63
|
* worker entry when you need non-cloneable construction options (a custom store, `now`,
|
|
@@ -62,4 +69,3 @@ export declare function exposeDatabase(database: MinnowDatabase, scope: RpcScope
|
|
|
62
69
|
* constructs the database, and exposes it. The store is closed when the client disposes.
|
|
63
70
|
*/
|
|
64
71
|
export declare function attachDatabaseWorker(scope: RpcScope, options?: AttachDatabaseWorkerOptions): void;
|
|
65
|
-
//# sourceMappingURL=worker-host.d.ts.map
|