@minnowdb/core 0.7.0 → 0.7.1
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/block-format/block.js +254 -325
- package/dist/block-format/checksum.js +30 -52
- package/dist/block-format/codecs.js +112 -125
- package/dist/block-format/column.js +187 -205
- package/dist/block-format/index.js +5 -1
- package/dist/block-format/physical.js +371 -387
- package/dist/block-format/types.js +4 -1
- package/dist/block-format/unicode.js +30 -39
- package/dist/date-value.js +67 -78
- package/dist/engine/artifact-cache.js +106 -116
- package/dist/engine/batch.js +36 -44
- package/dist/engine/buffered-writer.js +156 -158
- package/dist/engine/byte-estimates.js +20 -22
- package/dist/engine/cache-limits.js +24 -25
- package/dist/engine/cancellation.js +5 -3
- package/dist/engine/catalog.js +64 -73
- package/dist/engine/client.js +715 -780
- package/dist/engine/database.js +15941 -19313
- package/dist/engine/defaults.js +104 -111
- package/dist/engine/errors.js +113 -128
- package/dist/engine/fts.js +233 -280
- package/dist/engine/group-index.js +287 -321
- package/dist/engine/index.js +23 -12
- package/dist/engine/join-index.js +177 -186
- package/dist/engine/keyed-live.js +168 -173
- package/dist/engine/live-api.js +0 -1
- package/dist/engine/live-equal.js +32 -37
- package/dist/engine/live.js +603 -647
- package/dist/engine/memory.js +109 -111
- package/dist/engine/optimizer.d.ts +19 -1
- package/dist/engine/optimizer.js +2633 -2934
- package/dist/engine/point-read.js +122 -182
- package/dist/engine/query-api.js +12 -3
- package/dist/engine/query-cache.js +61 -69
- package/dist/engine/query.d.ts +6 -0
- package/dist/engine/query.js +8503 -9980
- package/dist/engine/result-wire.js +221 -252
- package/dist/engine/schema-wire.js +97 -112
- package/dist/engine/schema.js +1099 -1254
- package/dist/engine/sort-keys.js +315 -389
- package/dist/engine/sql-domains.js +646 -769
- package/dist/engine/sql-driver.js +0 -1
- package/dist/engine/sql-functions.js +1031 -1125
- package/dist/engine/sql-json.js +199 -218
- package/dist/engine/sql-semantics.js +572 -639
- package/dist/engine/typed-live.js +271 -293
- package/dist/engine/vector.js +4484 -5145
- package/dist/engine/worker-host.d.ts +8 -63
- package/dist/engine/worker-host.js +28 -1130
- package/dist/engine/worker-indexeddb.d.ts +1 -0
- package/dist/engine/worker-indexeddb.js +3 -0
- package/dist/engine/worker-memory.d.ts +1 -0
- package/dist/engine/worker-memory.js +3 -0
- package/dist/engine/worker-opfs.d.ts +1 -0
- package/dist/engine/worker-opfs.js +3 -0
- package/dist/engine/worker-server.d.ts +93 -0
- package/dist/engine/worker-server.js +999 -0
- package/dist/engine/worker-store-indexeddb.d.ts +2 -0
- package/dist/engine/worker-store-indexeddb.js +11 -0
- package/dist/engine/worker-store-memory.d.ts +2 -0
- package/dist/engine/worker-store-memory.js +6 -0
- package/dist/engine/worker-store-opfs.d.ts +2 -0
- package/dist/engine/worker-store-opfs.js +9 -0
- package/dist/engine/worker.js +0 -12
- package/dist/engine/write-block-planner.js +93 -100
- package/dist/plan/index.js +15 -16
- package/dist/plan/model.d.ts +6 -0
- package/dist/plan/model.js +20 -27
- package/dist/storage/index.js +0 -12
- package/dist/storage/indexeddb.js +11776 -13171
- package/dist/storage/memory.js +1198 -1241
- package/dist/storage/opfs/files.js +238 -295
- package/dist/storage/opfs/index.js +9 -3
- package/dist/storage/opfs/leader.js +4386 -4856
- package/dist/storage/opfs/rpc.js +223 -259
- package/dist/storage/opfs/snapshot-ledger.js +219 -260
- package/dist/storage/opfs/store.js +884 -1003
- package/dist/storage/persistence.js +59 -74
- package/dist/storage/snapshot-stream.js +788 -826
- package/dist/storage/snapshot.js +36 -37
- package/dist/storage/toolkit/extents.js +444 -520
- package/dist/storage/toolkit/index.js +28 -29
- package/dist/storage/toolkit/record-core.js +5792 -6377
- package/dist/storage/toolkit/sync-file.js +34 -42
- package/dist/storage/toolkit/wal.js +92 -127
- package/dist/storage/toolkit/wire.js +232 -256
- package/dist/storage/types.js +2948 -3250
- package/dist/testing/block-store-conformance.js +1556 -1629
- package/dist/testing/index.js +310 -291
- package/dist/testing/opfs-shim.js +280 -312
- package/dist/testing/simulator.js +496 -534
- package/dist/testing/sqllogictest.js +425 -365
- package/dist/transactions/index.js +1464 -1712
- package/dist/worker-protocol/index.js +70 -69
- package/package.json +20 -2
|
@@ -1,281 +1,240 @@
|
|
|
1
1
|
import { crc32 } from "../../block-format/checksum.js";
|
|
2
2
|
import { MAX_STORED_BLOCK_BYTE_LENGTH } from "../../block-format/index.js";
|
|
3
|
-
import { MAX_SNAPSHOT_FRAME_ITEMS, MAX_SNAPSHOT_METADATA_FRAME_BYTES, SNAPSHOT_FRAME_KINDS, validateStorageId
|
|
3
|
+
import { MAX_SNAPSHOT_FRAME_ITEMS, MAX_SNAPSHOT_METADATA_FRAME_BYTES, SNAPSHOT_FRAME_KINDS, validateStorageId } from "../types.js";
|
|
4
4
|
import { assertValidPlacement } from "../toolkit/extents.js";
|
|
5
5
|
import { readFully, writeFully } from "../toolkit/sync-file.js";
|
|
6
6
|
import { encodeSegment } from "./files.js";
|
|
7
|
-
const LEDGER_MAGIC =
|
|
7
|
+
const LEDGER_MAGIC = 1397507889;
|
|
8
8
|
const LEDGER_PREFIX_BYTES = 80;
|
|
9
9
|
const MODE_INLINE = 0;
|
|
10
10
|
const MODE_PLACEMENT = 1;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
function snapshotLedgerPath(kind, id) {
|
|
12
|
+
validateStorageId(id);
|
|
13
|
+
return ["snapshots-v1", kind, encodeSegment(id)];
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
committedLength > this.#length ||
|
|
62
|
-
committedLength - offset < LEDGER_PREFIX_BYTES) {
|
|
63
|
-
throw new RangeError("Snapshot ledger read offset is invalid");
|
|
64
|
-
}
|
|
65
|
-
const prefix = new Uint8Array(LEDGER_PREFIX_BYTES);
|
|
66
|
-
readFully(this.#handle, prefix, offset, "reading snapshot frame ledger prefix");
|
|
67
|
-
const view = new DataView(prefix.buffer);
|
|
68
|
-
if (view.getUint32(0, true) !== LEDGER_MAGIC) {
|
|
69
|
-
throw new Error("Snapshot ledger record marker mismatch");
|
|
70
|
-
}
|
|
71
|
-
const recordLength = view.getUint32(4, true);
|
|
72
|
-
if (recordLength < LEDGER_PREFIX_BYTES ||
|
|
73
|
-
recordLength > MAX_SNAPSHOT_METADATA_FRAME_BYTES + LEDGER_PREFIX_BYTES + 3_072 ||
|
|
74
|
-
recordLength > committedLength - offset) {
|
|
75
|
-
throw new Error("Snapshot ledger record length is invalid");
|
|
76
|
-
}
|
|
77
|
-
const encoded = new Uint8Array(recordLength);
|
|
78
|
-
readFully(this.#handle, encoded, offset, "reading snapshot frame ledger record");
|
|
79
|
-
const expectedRecordChecksum = new DataView(encoded.buffer).getUint32(76, true);
|
|
80
|
-
new DataView(encoded.buffer).setUint32(76, 0, true);
|
|
81
|
-
if (crc32(encoded) !== expectedRecordChecksum) {
|
|
82
|
-
throw new Error("Snapshot ledger record checksum mismatch");
|
|
83
|
-
}
|
|
84
|
-
new DataView(encoded.buffer).setUint32(76, expectedRecordChecksum, true);
|
|
85
|
-
const record = decodeLedgerRecord(encoded);
|
|
86
|
-
return {
|
|
87
|
-
record,
|
|
88
|
-
offset,
|
|
89
|
-
nextOffset: safeLedgerSum(offset, recordLength, "Snapshot ledger read offset"),
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
*records(committedLength = this.#length) {
|
|
93
|
-
let offset = 0;
|
|
94
|
-
while (offset < committedLength) {
|
|
95
|
-
const read = this.read(offset, committedLength);
|
|
96
|
-
yield read;
|
|
97
|
-
offset = read.nextOffset;
|
|
98
|
-
}
|
|
99
|
-
if (offset !== committedLength)
|
|
100
|
-
throw new Error("Snapshot ledger prefix ends mid-record");
|
|
101
|
-
}
|
|
102
|
-
flush() {
|
|
103
|
-
this.#assertOpen();
|
|
104
|
-
this.#handle.flush();
|
|
105
|
-
}
|
|
106
|
-
truncate(length) {
|
|
107
|
-
this.#assertOpen();
|
|
108
|
-
if (!Number.isSafeInteger(length) || length < 0 || length > this.#length) {
|
|
109
|
-
throw new RangeError("Snapshot ledger truncation is invalid");
|
|
110
|
-
}
|
|
111
|
-
this.#handle.truncate(length);
|
|
112
|
-
this.#length = length;
|
|
113
|
-
}
|
|
114
|
-
/** Recovery adopts the next WAL-published prefix without copying or re-appending its bytes. */
|
|
115
|
-
adoptLength(length) {
|
|
116
|
-
this.#assertOpen();
|
|
117
|
-
if (!Number.isSafeInteger(length) || length < this.#length || length > this.#handle.getSize()) {
|
|
118
|
-
throw new RangeError("Snapshot ledger recovery length is invalid");
|
|
119
|
-
}
|
|
120
|
-
this.#length = length;
|
|
121
|
-
}
|
|
122
|
-
close() {
|
|
123
|
-
if (this.#closed)
|
|
124
|
-
return;
|
|
125
|
-
this.#closed = true;
|
|
126
|
-
this.#handle.close();
|
|
127
|
-
}
|
|
128
|
-
#assertOpen() {
|
|
129
|
-
if (this.#closed)
|
|
130
|
-
throw new Error("Snapshot ledger is closed");
|
|
15
|
+
class SnapshotFrameLedger {
|
|
16
|
+
#handle;
|
|
17
|
+
#length;
|
|
18
|
+
#closed = false;
|
|
19
|
+
constructor(handle, length) {
|
|
20
|
+
this.#handle = handle;
|
|
21
|
+
this.#length = length;
|
|
22
|
+
}
|
|
23
|
+
static async open(tree, kind, id, committedLength, create) {
|
|
24
|
+
if (!Number.isSafeInteger(committedLength) || committedLength < 0) {
|
|
25
|
+
throw new RangeError("Snapshot ledger length is invalid");
|
|
26
|
+
}
|
|
27
|
+
const handle = await tree.openHandle(snapshotLedgerPath(kind, id), { create });
|
|
28
|
+
const size = handle.getSize();
|
|
29
|
+
if (size < committedLength) {
|
|
30
|
+
handle.close();
|
|
31
|
+
throw new Error(`Snapshot ledger is shorter than its committed prefix: ${String(size)} < ` + String(committedLength));
|
|
32
|
+
}
|
|
33
|
+
return new SnapshotFrameLedger(handle, committedLength);
|
|
34
|
+
}
|
|
35
|
+
get byteLength() {
|
|
36
|
+
return this.#length;
|
|
37
|
+
}
|
|
38
|
+
append(frame, placement) {
|
|
39
|
+
this.#assertOpen();
|
|
40
|
+
const encoded = encodeLedgerRecord(frame, placement);
|
|
41
|
+
const offset = this.#length;
|
|
42
|
+
const nextOffset = safeLedgerSum(offset, encoded.byteLength, "Snapshot ledger length");
|
|
43
|
+
writeFully(this.#handle, encoded, offset, "appending snapshot frame ledger");
|
|
44
|
+
this.#length = nextOffset;
|
|
45
|
+
return { record: ledgerRecordFromFrame(frame, placement), offset, nextOffset };
|
|
46
|
+
}
|
|
47
|
+
read(offset, committedLength = this.#length) {
|
|
48
|
+
this.#assertOpen();
|
|
49
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(committedLength) || committedLength < offset || committedLength > this.#length || committedLength - offset < LEDGER_PREFIX_BYTES) {
|
|
50
|
+
throw new RangeError("Snapshot ledger read offset is invalid");
|
|
51
|
+
}
|
|
52
|
+
const prefix = new Uint8Array(LEDGER_PREFIX_BYTES);
|
|
53
|
+
readFully(this.#handle, prefix, offset, "reading snapshot frame ledger prefix");
|
|
54
|
+
const view = new DataView(prefix.buffer);
|
|
55
|
+
if (view.getUint32(0, true) !== LEDGER_MAGIC) {
|
|
56
|
+
throw new Error("Snapshot ledger record marker mismatch");
|
|
57
|
+
}
|
|
58
|
+
const recordLength = view.getUint32(4, true);
|
|
59
|
+
if (recordLength < LEDGER_PREFIX_BYTES || recordLength > MAX_SNAPSHOT_METADATA_FRAME_BYTES + LEDGER_PREFIX_BYTES + 3072 || recordLength > committedLength - offset) {
|
|
60
|
+
throw new Error("Snapshot ledger record length is invalid");
|
|
131
61
|
}
|
|
62
|
+
const encoded = new Uint8Array(recordLength);
|
|
63
|
+
readFully(this.#handle, encoded, offset, "reading snapshot frame ledger record");
|
|
64
|
+
const expectedRecordChecksum = new DataView(encoded.buffer).getUint32(76, true);
|
|
65
|
+
new DataView(encoded.buffer).setUint32(76, 0, true);
|
|
66
|
+
if (crc32(encoded) !== expectedRecordChecksum) {
|
|
67
|
+
throw new Error("Snapshot ledger record checksum mismatch");
|
|
68
|
+
}
|
|
69
|
+
new DataView(encoded.buffer).setUint32(76, expectedRecordChecksum, true);
|
|
70
|
+
const record = decodeLedgerRecord(encoded);
|
|
71
|
+
return {
|
|
72
|
+
record,
|
|
73
|
+
offset,
|
|
74
|
+
nextOffset: safeLedgerSum(offset, recordLength, "Snapshot ledger read offset")
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
*records(committedLength = this.#length) {
|
|
78
|
+
let offset = 0;
|
|
79
|
+
while (offset < committedLength) {
|
|
80
|
+
const read = this.read(offset, committedLength);
|
|
81
|
+
yield read;
|
|
82
|
+
offset = read.nextOffset;
|
|
83
|
+
}
|
|
84
|
+
if (offset !== committedLength)
|
|
85
|
+
throw new Error("Snapshot ledger prefix ends mid-record");
|
|
86
|
+
}
|
|
87
|
+
flush() {
|
|
88
|
+
this.#assertOpen();
|
|
89
|
+
this.#handle.flush();
|
|
90
|
+
}
|
|
91
|
+
truncate(length) {
|
|
92
|
+
this.#assertOpen();
|
|
93
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > this.#length) {
|
|
94
|
+
throw new RangeError("Snapshot ledger truncation is invalid");
|
|
95
|
+
}
|
|
96
|
+
this.#handle.truncate(length);
|
|
97
|
+
this.#length = length;
|
|
98
|
+
}
|
|
99
|
+
adoptLength(length) {
|
|
100
|
+
this.#assertOpen();
|
|
101
|
+
if (!Number.isSafeInteger(length) || length < this.#length || length > this.#handle.getSize()) {
|
|
102
|
+
throw new RangeError("Snapshot ledger recovery length is invalid");
|
|
103
|
+
}
|
|
104
|
+
this.#length = length;
|
|
105
|
+
}
|
|
106
|
+
close() {
|
|
107
|
+
if (this.#closed)
|
|
108
|
+
return;
|
|
109
|
+
this.#closed = true;
|
|
110
|
+
this.#handle.close();
|
|
111
|
+
}
|
|
112
|
+
#assertOpen() {
|
|
113
|
+
if (this.#closed)
|
|
114
|
+
throw new Error("Snapshot ledger is closed");
|
|
115
|
+
}
|
|
132
116
|
}
|
|
133
117
|
function encodeLedgerRecord(frame, placement) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return encoded;
|
|
118
|
+
validateFrameScalars(frame);
|
|
119
|
+
const isBlock = frame.kind === "block";
|
|
120
|
+
if (isBlock !== (placement !== void 0)) {
|
|
121
|
+
throw new TypeError("Snapshot ledger block placement is inconsistent");
|
|
122
|
+
}
|
|
123
|
+
if (placement !== void 0) {
|
|
124
|
+
assertValidPlacement(placement);
|
|
125
|
+
if (placement.length !== frame.payload.byteLength || placement.checksum !== frame.checksum) {
|
|
126
|
+
throw new Error("Snapshot block placement disagrees with its frame");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const keyBytes = frame.key === null ? new Uint8Array() : new TextEncoder().encode(frame.key);
|
|
130
|
+
const inlineLength = placement === void 0 ? frame.payload.byteLength : 0;
|
|
131
|
+
const recordLength = safeLedgerSum(LEDGER_PREFIX_BYTES + keyBytes.byteLength, inlineLength, "Snapshot ledger record length");
|
|
132
|
+
const encoded = new Uint8Array(recordLength);
|
|
133
|
+
const view = new DataView(encoded.buffer);
|
|
134
|
+
view.setUint32(0, LEDGER_MAGIC, true);
|
|
135
|
+
view.setUint32(4, recordLength, true);
|
|
136
|
+
view.setBigUint64(8, BigInt(frame.sequence), true);
|
|
137
|
+
view.setUint32(16, SNAPSHOT_FRAME_KINDS.indexOf(frame.kind), true);
|
|
138
|
+
view.setUint32(20, frame.itemCount, true);
|
|
139
|
+
view.setUint32(24, keyBytes.byteLength, true);
|
|
140
|
+
view.setUint32(28, placement === void 0 ? MODE_INLINE : MODE_PLACEMENT, true);
|
|
141
|
+
view.setBigUint64(32, BigInt(frame.payload.byteLength), true);
|
|
142
|
+
view.setUint32(40, frame.checksum, true);
|
|
143
|
+
if (placement !== void 0) {
|
|
144
|
+
view.setBigUint64(44, BigInt(placement.extent), true);
|
|
145
|
+
view.setBigUint64(52, BigInt(placement.offset), true);
|
|
146
|
+
view.setBigUint64(60, BigInt(placement.length), true);
|
|
147
|
+
view.setUint32(68, placement.checksum, true);
|
|
148
|
+
}
|
|
149
|
+
encoded.set(keyBytes, LEDGER_PREFIX_BYTES);
|
|
150
|
+
if (placement === void 0)
|
|
151
|
+
encoded.set(frame.payload, LEDGER_PREFIX_BYTES + keyBytes.byteLength);
|
|
152
|
+
view.setUint32(76, 0, true);
|
|
153
|
+
view.setUint32(76, crc32(encoded), true);
|
|
154
|
+
return encoded;
|
|
172
155
|
}
|
|
173
156
|
function decodeLedgerRecord(encoded) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
const placement = {
|
|
219
|
-
extent: Number(view.getBigUint64(44, true)),
|
|
220
|
-
offset: Number(view.getBigUint64(52, true)),
|
|
221
|
-
length: Number(view.getBigUint64(60, true)),
|
|
222
|
-
checksum: view.getUint32(68, true),
|
|
223
|
-
};
|
|
224
|
-
assertValidPlacement(placement);
|
|
225
|
-
if (placement.length !== payloadLength || placement.checksum !== checksum) {
|
|
226
|
-
throw new Error("Snapshot ledger placement disagrees with its frame");
|
|
227
|
-
}
|
|
228
|
-
return { sequence, kind, itemCount, key, payloadLength, checksum, placement };
|
|
157
|
+
const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.byteLength);
|
|
158
|
+
const sequence = Number(view.getBigUint64(8, true));
|
|
159
|
+
const kind = SNAPSHOT_FRAME_KINDS[view.getUint32(16, true)];
|
|
160
|
+
const itemCount = view.getUint32(20, true);
|
|
161
|
+
const keyLength = view.getUint32(24, true);
|
|
162
|
+
const mode = view.getUint32(28, true);
|
|
163
|
+
const payloadLength = Number(view.getBigUint64(32, true));
|
|
164
|
+
const checksum = view.getUint32(40, true);
|
|
165
|
+
if (kind === void 0 || !Number.isSafeInteger(sequence) || sequence < 0 || itemCount < 1 || itemCount > MAX_SNAPSHOT_FRAME_ITEMS || !Number.isSafeInteger(payloadLength) || payloadLength < 1 || (kind === "block" ? payloadLength > MAX_STORED_BLOCK_BYTE_LENGTH : payloadLength > MAX_SNAPSHOT_METADATA_FRAME_BYTES) || mode !== MODE_INLINE && mode !== MODE_PLACEMENT || encoded.subarray(72, 76).some((byte) => byte !== 0)) {
|
|
166
|
+
throw new TypeError("Snapshot ledger record header is invalid");
|
|
167
|
+
}
|
|
168
|
+
const inlineLength = mode === MODE_INLINE ? payloadLength : 0;
|
|
169
|
+
if (LEDGER_PREFIX_BYTES + keyLength + inlineLength !== encoded.byteLength) {
|
|
170
|
+
throw new Error("Snapshot ledger record body length is invalid");
|
|
171
|
+
}
|
|
172
|
+
let key = null;
|
|
173
|
+
if (keyLength > 0) {
|
|
174
|
+
try {
|
|
175
|
+
key = validateStorageId(new TextDecoder("utf-8", { fatal: true }).decode(encoded.subarray(LEDGER_PREFIX_BYTES, LEDGER_PREFIX_BYTES + keyLength)));
|
|
176
|
+
} catch {
|
|
177
|
+
throw new TypeError("Snapshot ledger key is not canonical UTF-8");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (kind === "block" !== (key !== null) || kind === "block" !== (mode === MODE_PLACEMENT)) {
|
|
181
|
+
throw new TypeError("Snapshot ledger frame identity is inconsistent");
|
|
182
|
+
}
|
|
183
|
+
if (mode === MODE_INLINE) {
|
|
184
|
+
const payload = encoded.slice(LEDGER_PREFIX_BYTES + keyLength);
|
|
185
|
+
if (crc32(payload) !== checksum)
|
|
186
|
+
throw new Error("Snapshot ledger payload checksum mismatch");
|
|
187
|
+
return { sequence, kind, itemCount, key, payloadLength, checksum, payload };
|
|
188
|
+
}
|
|
189
|
+
const placement = {
|
|
190
|
+
extent: Number(view.getBigUint64(44, true)),
|
|
191
|
+
offset: Number(view.getBigUint64(52, true)),
|
|
192
|
+
length: Number(view.getBigUint64(60, true)),
|
|
193
|
+
checksum: view.getUint32(68, true)
|
|
194
|
+
};
|
|
195
|
+
assertValidPlacement(placement);
|
|
196
|
+
if (placement.length !== payloadLength || placement.checksum !== checksum) {
|
|
197
|
+
throw new Error("Snapshot ledger placement disagrees with its frame");
|
|
198
|
+
}
|
|
199
|
+
return { sequence, kind, itemCount, key, payloadLength, checksum, placement };
|
|
229
200
|
}
|
|
230
201
|
function ledgerRecordFromFrame(frame, placement) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
202
|
+
return {
|
|
203
|
+
sequence: frame.sequence,
|
|
204
|
+
kind: frame.kind,
|
|
205
|
+
itemCount: frame.itemCount,
|
|
206
|
+
key: frame.key,
|
|
207
|
+
payloadLength: frame.payload.byteLength,
|
|
208
|
+
checksum: frame.checksum,
|
|
209
|
+
...placement === void 0 ? { payload: frame.payload } : { placement }
|
|
210
|
+
};
|
|
240
211
|
}
|
|
241
212
|
function validateFrameScalars(frame) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
throw new TypeError("Snapshot block frame identity is invalid");
|
|
260
|
-
}
|
|
261
|
-
validateStorageId(frame.key);
|
|
262
|
-
if (frame.payload.byteLength < 1 || frame.payload.byteLength > MAX_STORED_BLOCK_BYTE_LENGTH) {
|
|
263
|
-
throw new RangeError("Snapshot block frame is too large");
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
else if (frame.key !== null ||
|
|
267
|
-
frame.payload.byteLength < 1 ||
|
|
268
|
-
frame.payload.byteLength > MAX_SNAPSHOT_METADATA_FRAME_BYTES) {
|
|
269
|
-
throw new TypeError("Snapshot metadata frame identity is invalid");
|
|
270
|
-
}
|
|
213
|
+
if (!Number.isSafeInteger(frame.sequence) || frame.sequence < 0 || !SNAPSHOT_FRAME_KINDS.includes(frame.kind) || !Number.isSafeInteger(frame.itemCount) || frame.itemCount < 1 || frame.itemCount > MAX_SNAPSHOT_FRAME_ITEMS || !(frame.payload instanceof Uint8Array) || !Number.isSafeInteger(frame.checksum) || frame.checksum < 0 || frame.checksum > 4294967295) {
|
|
214
|
+
throw new TypeError("Snapshot frame is invalid");
|
|
215
|
+
}
|
|
216
|
+
if (crc32(frame.payload) !== frame.checksum) {
|
|
217
|
+
throw new Error("Snapshot frame checksum mismatch");
|
|
218
|
+
}
|
|
219
|
+
if (frame.kind === "block") {
|
|
220
|
+
if (frame.key === null || frame.itemCount !== 1) {
|
|
221
|
+
throw new TypeError("Snapshot block frame identity is invalid");
|
|
222
|
+
}
|
|
223
|
+
validateStorageId(frame.key);
|
|
224
|
+
if (frame.payload.byteLength < 1 || frame.payload.byteLength > MAX_STORED_BLOCK_BYTE_LENGTH) {
|
|
225
|
+
throw new RangeError("Snapshot block frame is too large");
|
|
226
|
+
}
|
|
227
|
+
} else if (frame.key !== null || frame.payload.byteLength < 1 || frame.payload.byteLength > MAX_SNAPSHOT_METADATA_FRAME_BYTES) {
|
|
228
|
+
throw new TypeError("Snapshot metadata frame identity is invalid");
|
|
229
|
+
}
|
|
271
230
|
}
|
|
272
231
|
function safeLedgerSum(left, right, label) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
left > Number.MAX_SAFE_INTEGER - right) {
|
|
278
|
-
throw new RangeError(`${label} exceeds the safe integer range`);
|
|
279
|
-
}
|
|
280
|
-
return left + right;
|
|
232
|
+
if (!Number.isSafeInteger(left) || left < 0 || !Number.isSafeInteger(right) || right < 0 || left > Number.MAX_SAFE_INTEGER - right) {
|
|
233
|
+
throw new RangeError(`${label} exceeds the safe integer range`);
|
|
234
|
+
}
|
|
235
|
+
return left + right;
|
|
281
236
|
}
|
|
237
|
+
export {
|
|
238
|
+
SnapshotFrameLedger,
|
|
239
|
+
snapshotLedgerPath
|
|
240
|
+
};
|