@opendatalabs/personal-server-ts-server 1.34.2 → 1.35.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/api-auth.d.ts +1 -0
- package/dist/api-auth.d.ts.map +1 -1
- package/dist/api-auth.js.map +1 -1
- package/dist/api.d.ts +3 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +3 -0
- package/dist/api.js.map +1 -1
- package/dist/app.d.ts +14 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +64 -8
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +19 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +87 -4
- package/dist/bootstrap.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -0
- package/dist/client.js.map +1 -1
- package/dist/enclave-main.d.ts.map +1 -1
- package/dist/enclave-main.js +0 -2
- package/dist/enclave-main.js.map +1 -1
- package/dist/mcp/durable-state.d.ts +2 -1
- package/dist/mcp/durable-state.d.ts.map +1 -1
- package/dist/mcp/durable-state.js +35 -1
- package/dist/mcp/durable-state.js.map +1 -1
- package/dist/pdpp/bootstrap.d.ts.map +1 -1
- package/dist/pdpp/bootstrap.js +1 -0
- package/dist/pdpp/bootstrap.js.map +1 -1
- package/dist/pdpp/records-bootstrap.d.ts +47 -1
- package/dist/pdpp/records-bootstrap.d.ts.map +1 -1
- package/dist/pdpp/records-bootstrap.js +78 -2
- package/dist/pdpp/records-bootstrap.js.map +1 -1
- package/dist/pdpp/replica-authorization.d.ts +35 -0
- package/dist/pdpp/replica-authorization.d.ts.map +1 -0
- package/dist/pdpp/replica-authorization.js +234 -0
- package/dist/pdpp/replica-authorization.js.map +1 -0
- package/dist/pending-blob-deletions.d.ts +1 -0
- package/dist/pending-blob-deletions.d.ts.map +1 -1
- package/dist/pending-blob-deletions.js +8 -4
- package/dist/pending-blob-deletions.js.map +1 -1
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +5 -0
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/mcp.d.ts +18 -2
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +111 -11
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/oura.d.ts +6 -0
- package/dist/routes/oura.d.ts.map +1 -0
- package/dist/routes/oura.js +272 -0
- package/dist/routes/oura.js.map +1 -0
- package/dist/routes/pdpp-auth-query-keys.d.ts +7 -0
- package/dist/routes/pdpp-auth-query-keys.d.ts.map +1 -0
- package/dist/routes/pdpp-auth-query-keys.js +25 -0
- package/dist/routes/pdpp-auth-query-keys.js.map +1 -0
- package/dist/routes/pdpp-auth.d.ts +3 -1
- package/dist/routes/pdpp-auth.d.ts.map +1 -1
- package/dist/routes/pdpp-auth.js +126 -45
- package/dist/routes/pdpp-auth.js.map +1 -1
- package/dist/routes/pdpp-blobs.d.ts +13 -1
- package/dist/routes/pdpp-blobs.d.ts.map +1 -1
- package/dist/routes/pdpp-blobs.js +100 -65
- package/dist/routes/pdpp-blobs.js.map +1 -1
- package/dist/routes/pdpp-connections.d.ts.map +1 -1
- package/dist/routes/pdpp-connections.js +24 -1
- package/dist/routes/pdpp-connections.js.map +1 -1
- package/dist/routes/pdpp-instance-bindings.d.ts +3 -0
- package/dist/routes/pdpp-instance-bindings.d.ts.map +1 -1
- package/dist/routes/pdpp-instance-bindings.js +63 -0
- package/dist/routes/pdpp-instance-bindings.js.map +1 -1
- package/dist/routes/pdpp-record-query.d.ts +19 -0
- package/dist/routes/pdpp-record-query.d.ts.map +1 -0
- package/dist/routes/pdpp-record-query.js +51 -0
- package/dist/routes/pdpp-record-query.js.map +1 -0
- package/dist/routes/pdpp-records.d.ts +12 -1
- package/dist/routes/pdpp-records.d.ts.map +1 -1
- package/dist/routes/pdpp-records.js +120 -233
- package/dist/routes/pdpp-records.js.map +1 -1
- package/dist/routes/pdpp-replica-quarantine-fixture.d.ts +65 -0
- package/dist/routes/pdpp-replica-quarantine-fixture.d.ts.map +1 -0
- package/dist/routes/pdpp-replica-quarantine-fixture.js +389 -0
- package/dist/routes/pdpp-replica-quarantine-fixture.js.map +1 -0
- package/dist/storage/claude-method-transition.d.ts +12 -0
- package/dist/storage/claude-method-transition.d.ts.map +1 -0
- package/dist/storage/claude-method-transition.js +139 -0
- package/dist/storage/claude-method-transition.js.map +1 -0
- package/dist/storage/import-operations.d.ts +16 -0
- package/dist/storage/import-operations.d.ts.map +1 -1
- package/dist/storage/import-operations.js +54 -1
- package/dist/storage/import-operations.js.map +1 -1
- package/dist/storage/index-schema.d.ts +1 -1
- package/dist/storage/index-schema.d.ts.map +1 -1
- package/dist/storage/index-schema.js +22 -5
- package/dist/storage/index-schema.js.map +1 -1
- package/dist/storage/legacy-scope-authority.d.ts.map +1 -1
- package/dist/storage/legacy-scope-authority.js +83 -11
- package/dist/storage/legacy-scope-authority.js.map +1 -1
- package/dist/storage/node-data-storage.d.ts.map +1 -1
- package/dist/storage/node-data-storage.js +58 -2
- package/dist/storage/node-data-storage.js.map +1 -1
- package/dist/storage/pdpp-binary-chunks.d.ts +120 -0
- package/dist/storage/pdpp-binary-chunks.d.ts.map +1 -0
- package/dist/storage/pdpp-binary-chunks.js +480 -0
- package/dist/storage/pdpp-binary-chunks.js.map +1 -0
- package/dist/storage/pdpp-records-sqlite-store.d.ts +96 -15
- package/dist/storage/pdpp-records-sqlite-store.d.ts.map +1 -1
- package/dist/storage/pdpp-records-sqlite-store.js +616 -211
- package/dist/storage/pdpp-records-sqlite-store.js.map +1 -1
- package/dist/storage/pdpp-replica-canonical-port.d.ts +202 -0
- package/dist/storage/pdpp-replica-canonical-port.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-canonical-port.js +451 -0
- package/dist/storage/pdpp-replica-canonical-port.js.map +1 -0
- package/dist/storage/pdpp-replica-coordinator-state.d.ts +16 -0
- package/dist/storage/pdpp-replica-coordinator-state.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-coordinator-state.js +25 -0
- package/dist/storage/pdpp-replica-coordinator-state.js.map +1 -0
- package/dist/storage/pdpp-replica-copies.d.ts +81 -0
- package/dist/storage/pdpp-replica-copies.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-copies.js +59 -0
- package/dist/storage/pdpp-replica-copies.js.map +1 -0
- package/dist/storage/pdpp-replica-reconciler.d.ts +96 -0
- package/dist/storage/pdpp-replica-reconciler.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-reconciler.js +710 -0
- package/dist/storage/pdpp-replica-reconciler.js.map +1 -0
- package/dist/storage/pdpp-replica-sql.d.ts +13 -0
- package/dist/storage/pdpp-replica-sql.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-sql.js +43 -0
- package/dist/storage/pdpp-replica-sql.js.map +1 -0
- package/dist/storage/pdpp-replica-staging.d.ts +36 -0
- package/dist/storage/pdpp-replica-staging.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-staging.js +202 -0
- package/dist/storage/pdpp-replica-staging.js.map +1 -0
- package/dist/storage/pdpp-replica-visibility-view.d.ts +64 -0
- package/dist/storage/pdpp-replica-visibility-view.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-visibility-view.js +1397 -0
- package/dist/storage/pdpp-replica-visibility-view.js.map +1 -0
- package/dist/storage/pdpp-replica-writer-identity.d.ts +64 -0
- package/dist/storage/pdpp-replica-writer-identity.d.ts.map +1 -0
- package/dist/storage/pdpp-replica-writer-identity.js +81 -0
- package/dist/storage/pdpp-replica-writer-identity.js.map +1 -0
- package/dist/storage/pdpp-replication-door.d.ts +60 -0
- package/dist/storage/pdpp-replication-door.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-door.js +203 -0
- package/dist/storage/pdpp-replication-door.js.map +1 -0
- package/dist/storage/pdpp-replication-host.d.ts +67 -0
- package/dist/storage/pdpp-replication-host.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-host.js +159 -0
- package/dist/storage/pdpp-replication-host.js.map +1 -0
- package/dist/storage/pdpp-replication-memory.fixture.d.ts +2 -0
- package/dist/storage/pdpp-replication-memory.fixture.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-memory.fixture.js +267 -0
- package/dist/storage/pdpp-replication-memory.fixture.js.map +1 -0
- package/dist/storage/pdpp-replication-preparation.d.ts +3 -0
- package/dist/storage/pdpp-replication-preparation.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-preparation.js +3 -0
- package/dist/storage/pdpp-replication-preparation.js.map +1 -0
- package/dist/storage/pdpp-replication-promotion-memory.fixture.d.ts +2 -0
- package/dist/storage/pdpp-replication-promotion-memory.fixture.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-promotion-memory.fixture.js +65 -0
- package/dist/storage/pdpp-replication-promotion-memory.fixture.js.map +1 -0
- package/dist/storage/pdpp-replication-receiver.d.ts +230 -0
- package/dist/storage/pdpp-replication-receiver.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-receiver.js +950 -0
- package/dist/storage/pdpp-replication-receiver.js.map +1 -0
- package/dist/storage/pdpp-replication-sqlite.d.ts +95 -0
- package/dist/storage/pdpp-replication-sqlite.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-sqlite.js +615 -0
- package/dist/storage/pdpp-replication-sqlite.js.map +1 -0
- package/dist/storage/pdpp-replication-transport.d.ts +39 -0
- package/dist/storage/pdpp-replication-transport.d.ts.map +1 -0
- package/dist/storage/pdpp-replication-transport.js +196 -0
- package/dist/storage/pdpp-replication-transport.js.map +1 -0
- package/dist/storage/schema-versions.d.ts +5 -0
- package/dist/storage/schema-versions.d.ts.map +1 -0
- package/dist/storage/schema-versions.js +26 -0
- package/dist/storage/schema-versions.js.map +1 -0
- package/dist/storage/strava-method-transition.d.ts +18 -0
- package/dist/storage/strava-method-transition.d.ts.map +1 -0
- package/dist/storage/strava-method-transition.js +209 -0
- package/dist/storage/strava-method-transition.js.map +1 -0
- package/dist/ui/ps-lite-debug.js +154947 -124896
- package/package.json +3 -3
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Database } from "better-sqlite3";
|
|
2
|
+
export declare const BINARY_CHUNK_BYTES: number;
|
|
3
|
+
/** Legacy whole-row reads: windows are at least this big and at most this many. */
|
|
4
|
+
export declare const LEGACY_MIN_WINDOW_BYTES: number;
|
|
5
|
+
export declare const LEGACY_WINDOWS = 16;
|
|
6
|
+
export declare const CANONICAL_INLINE_BYTES: number;
|
|
7
|
+
export declare const BINARY_CHUNKS_MIGRATION = "\nCREATE TABLE IF NOT EXISTS pdpp_binary_manifests (\n namespace TEXT NOT NULL, blob_id TEXT NOT NULL, size_bytes INTEGER NOT NULL,\n PRIMARY KEY(namespace,blob_id));\nCREATE TABLE IF NOT EXISTS pdpp_binary_chunks (\n namespace TEXT NOT NULL, blob_id TEXT NOT NULL, position INTEGER NOT NULL, bytes BLOB NOT NULL,\n PRIMARY KEY(namespace,blob_id,position));\n";
|
|
8
|
+
export type BinaryNamespace = "canonical" | "pinned" | "received" | "staging" | "payload" | "pending";
|
|
9
|
+
/**
|
|
10
|
+
* What each namespace's bytes are for. A "reader" namespace holds bytes a
|
|
11
|
+
* reader can be served. Each one MUST have manifest insert and delete
|
|
12
|
+
* triggers in the visibility view (pdpp-replica-visibility-view.ts), or
|
|
13
|
+
* records stay stale when its chunked bytes arrive or leave. Add a new
|
|
14
|
+
* namespace here first; pdpp-replica-invariants.test.ts guards the triggers.
|
|
15
|
+
*/
|
|
16
|
+
export declare const BINARY_NAMESPACE_ROLE: {
|
|
17
|
+
readonly canonical: "reader";
|
|
18
|
+
readonly received: "reader";
|
|
19
|
+
readonly pending: "reader";
|
|
20
|
+
readonly pinned: "export";
|
|
21
|
+
readonly staging: "scratch";
|
|
22
|
+
readonly payload: "scratch";
|
|
23
|
+
};
|
|
24
|
+
/** Read chunk copies when present; fall back to main's whole-value blob row. */
|
|
25
|
+
export declare function binaryLength(db: Database, namespace: BinaryNamespace, id: string): number | undefined;
|
|
26
|
+
export declare function readBinaryChunks(db: Database, namespace: BinaryNamespace, id: string): Generator<Uint8Array>;
|
|
27
|
+
/** Where a chunked read resumes: a chunk row and a byte offset inside it. */
|
|
28
|
+
export interface BinaryCursor {
|
|
29
|
+
position: number;
|
|
30
|
+
offset: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read exactly `length` bytes of chunked (manifest) bytes from `from`, and
|
|
34
|
+
* return them with the cursor after them. Rows may have any length, so a
|
|
35
|
+
* caller that reads a value in parts keeps the returned cursor; it never
|
|
36
|
+
* seeks by arithmetic. Memory is `length`. Legacy whole-row values are not
|
|
37
|
+
* supported: only namespaces without a legacy table use this.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readBinaryWindow(db: Database, namespace: BinaryNamespace, id: string, from: BinaryCursor, length: number): {
|
|
40
|
+
bytes: Uint8Array;
|
|
41
|
+
next: BinaryCursor;
|
|
42
|
+
};
|
|
43
|
+
export declare function verifyBinary(db: Database, namespace: BinaryNamespace, id: string, digest: string, size: number): boolean;
|
|
44
|
+
export declare function deleteBinary(db: Database, namespace: BinaryNamespace, id: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* A repair write is about to give `id` a verified copy in `namespace`.
|
|
47
|
+
* Remove a published manifest whose size is not a safe non-negative
|
|
48
|
+
* integer, with its chunks, in the caller's transaction. Readers veto a
|
|
49
|
+
* namespace on such a manifest even beside a legacy row, so without this a
|
|
50
|
+
* repair would never take effect.
|
|
51
|
+
*/
|
|
52
|
+
export declare function clearMalformedManifest(db: Database, namespace: BinaryNamespace, id: string): void;
|
|
53
|
+
/** Publish the manifest only after EOF. Callers own transaction/visibility and cleanup. */
|
|
54
|
+
export declare function binaryWriter(db: Database, namespace: BinaryNamespace, id: string): {
|
|
55
|
+
write(bytes: Uint8Array): void;
|
|
56
|
+
finish(): number;
|
|
57
|
+
};
|
|
58
|
+
export declare function copyBinary(db: Database, from: BinaryNamespace, sourceId: string, to: BinaryNamespace, targetId?: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Write canonical bytes the server holds as one value, in one form only. A
|
|
61
|
+
* value up to CANONICAL_INLINE_BYTES (one Lite fragment) is main's whole row.
|
|
62
|
+
* A larger one is chunks only: the transport and capture's pin read those
|
|
63
|
+
* chunks, and the flag-off boot that retires replication writes main's row
|
|
64
|
+
* (`materializeCanonicalBinaries`).
|
|
65
|
+
*/
|
|
66
|
+
export declare function writeCanonicalBinary(db: Database, id: string, bytes: Uint8Array): void;
|
|
67
|
+
/**
|
|
68
|
+
* Promote verified bytes to canonical in the caller's transaction. A value up
|
|
69
|
+
* to CANONICAL_INLINE_BYTES (one Lite fragment) becomes main's whole row. A
|
|
70
|
+
* larger one is copied chunk by chunk and is stored only in the chunk form:
|
|
71
|
+
* no whole value is assembled or stored twice. Canonical readers accept both
|
|
72
|
+
* forms; the flag-off boot that retires replication writes main's row for
|
|
73
|
+
* chunk-only blobs (`materializeCanonicalBinaries`).
|
|
74
|
+
*/
|
|
75
|
+
export declare function copyBinaryToCanonical(db: Database, from: BinaryNamespace, sourceId: string, targetId?: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Write main's whole row for each verified canonical blob that has only the
|
|
78
|
+
* chunk form, so a flag-off or plain main build can read it. One blob per
|
|
79
|
+
* transaction; each costs one whole value in memory. Run it only when
|
|
80
|
+
* replication is retired: an enabled store keeps large blobs chunk-only.
|
|
81
|
+
* A first enable that stopped after the door committed, before the replica
|
|
82
|
+
* schema, left no chunk store, so there is nothing to write.
|
|
83
|
+
*/
|
|
84
|
+
export declare function materializeCanonicalBinaries(db: Database): number;
|
|
85
|
+
/**
|
|
86
|
+
* Explicit whole-value read for HTTP consumers, rollback materialization and
|
|
87
|
+
* inline-size promotion. Replication never calls it on a value larger than
|
|
88
|
+
* CANONICAL_INLINE_BYTES.
|
|
89
|
+
*/
|
|
90
|
+
export declare function readBinary(db: Database, namespace: BinaryNamespace, id: string): Uint8Array<ArrayBuffer> | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Bring blobs an earlier build stored more than once down to one copy. The
|
|
93
|
+
* caller runs each `step` in its own write transaction. A
|
|
94
|
+
* copy goes only when canonical storage holds the blob and it verifies:
|
|
95
|
+
*
|
|
96
|
+
* - main's whole row of a large blob that also has the chunk form;
|
|
97
|
+
* - a capture pin's own copy, which becomes a pin row that references the
|
|
98
|
+
* canonical chunks (`captureBlob`).
|
|
99
|
+
*
|
|
100
|
+
* Verification reads a bounded number of chunks per call, so a large blob
|
|
101
|
+
* is verified across calls. The hash in progress lives in memory: after a
|
|
102
|
+
* restart that blob is verified again from its start. A canonical whole row
|
|
103
|
+
* up to 1 MiB verifies in one call; a larger one has no bounded read and is
|
|
104
|
+
* skipped, and so is canonical storage with a chunk past the blob's end. A
|
|
105
|
+
* candidate that fails verification is skipped for the compactor's life,
|
|
106
|
+
* and a step examines at most 8 candidates, so corrupt blobs cannot hold
|
|
107
|
+
* back the rest or stall a step. Once a
|
|
108
|
+
* search finds nothing, the compactor stops for good: current writes keep
|
|
109
|
+
* one copy, so only a database an earlier build wrote has work, and an idle
|
|
110
|
+
* step then reads none of these tables.
|
|
111
|
+
*/
|
|
112
|
+
export declare function createBinaryCompactor(db: Database): {
|
|
113
|
+
/**
|
|
114
|
+
* Spend up to about `bytes` of canonical reads, and at most
|
|
115
|
+
* `COMPACT_CANDIDATES_PER_STEP` new candidates, toward compaction. Call it
|
|
116
|
+
* in a write transaction.
|
|
117
|
+
*/
|
|
118
|
+
step(bytes: number): void;
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=pdpp-binary-chunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdpp-binary-chunks.d.ts","sourceRoot":"","sources":["../../src/storage/pdpp-binary-chunks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const BINARY_CHUNK_BYTES = 64 * 1024;
|
|
3
|
+
/** Legacy whole-row reads: windows are at least this big and at most this many. */
|
|
4
|
+
export const LEGACY_MIN_WINDOW_BYTES = 8 * 1024 * 1024;
|
|
5
|
+
export const LEGACY_WINDOWS = 16;
|
|
6
|
+
export const CANONICAL_INLINE_BYTES = 1024 * 1024;
|
|
7
|
+
/** Candidates one compaction step may examine, so skipped ones cannot stall it. */
|
|
8
|
+
const COMPACT_CANDIDATES_PER_STEP = 8;
|
|
9
|
+
export const BINARY_CHUNKS_MIGRATION = `
|
|
10
|
+
CREATE TABLE IF NOT EXISTS pdpp_binary_manifests (
|
|
11
|
+
namespace TEXT NOT NULL, blob_id TEXT NOT NULL, size_bytes INTEGER NOT NULL,
|
|
12
|
+
PRIMARY KEY(namespace,blob_id));
|
|
13
|
+
CREATE TABLE IF NOT EXISTS pdpp_binary_chunks (
|
|
14
|
+
namespace TEXT NOT NULL, blob_id TEXT NOT NULL, position INTEGER NOT NULL, bytes BLOB NOT NULL,
|
|
15
|
+
PRIMARY KEY(namespace,blob_id,position));
|
|
16
|
+
`;
|
|
17
|
+
/**
|
|
18
|
+
* What each namespace's bytes are for. A "reader" namespace holds bytes a
|
|
19
|
+
* reader can be served. Each one MUST have manifest insert and delete
|
|
20
|
+
* triggers in the visibility view (pdpp-replica-visibility-view.ts), or
|
|
21
|
+
* records stay stale when its chunked bytes arrive or leave. Add a new
|
|
22
|
+
* namespace here first; pdpp-replica-invariants.test.ts guards the triggers.
|
|
23
|
+
*/
|
|
24
|
+
export const BINARY_NAMESPACE_ROLE = {
|
|
25
|
+
canonical: "reader",
|
|
26
|
+
received: "reader",
|
|
27
|
+
pending: "reader",
|
|
28
|
+
pinned: "export",
|
|
29
|
+
staging: "scratch",
|
|
30
|
+
payload: "scratch",
|
|
31
|
+
};
|
|
32
|
+
const legacy = {
|
|
33
|
+
canonical: "pdpp_blob_bytes",
|
|
34
|
+
pinned: "pdpp_replica_blob_bytes",
|
|
35
|
+
received: "pdpp_replica_received_bytes",
|
|
36
|
+
staging: null,
|
|
37
|
+
payload: null,
|
|
38
|
+
pending: null,
|
|
39
|
+
};
|
|
40
|
+
/** Read chunk copies when present; fall back to main's whole-value blob row. */
|
|
41
|
+
export function binaryLength(db, namespace, id) {
|
|
42
|
+
const manifest = db
|
|
43
|
+
.prepare("SELECT size_bytes AS size FROM pdpp_binary_manifests WHERE namespace=? AND blob_id=?")
|
|
44
|
+
.get(namespace, id);
|
|
45
|
+
if (manifest)
|
|
46
|
+
return Number.isSafeInteger(manifest.size) && manifest.size >= 0
|
|
47
|
+
? manifest.size
|
|
48
|
+
: undefined;
|
|
49
|
+
const table = legacy[namespace];
|
|
50
|
+
if (table) {
|
|
51
|
+
const row = db
|
|
52
|
+
.prepare(`SELECT length(bytes) AS size FROM ${table} WHERE blob_id=?`)
|
|
53
|
+
.get(id);
|
|
54
|
+
if (row)
|
|
55
|
+
return row.size;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
export function* readBinaryChunks(db, namespace, id) {
|
|
60
|
+
const table = legacy[namespace];
|
|
61
|
+
const hasManifest = db
|
|
62
|
+
.prepare("SELECT 1 FROM pdpp_binary_manifests WHERE namespace=? AND blob_id=?")
|
|
63
|
+
.get(namespace, id) !== undefined;
|
|
64
|
+
if (table && !hasManifest) {
|
|
65
|
+
const row = db
|
|
66
|
+
.prepare(`SELECT length(bytes) AS size FROM ${table} WHERE blob_id=?`)
|
|
67
|
+
.get(id);
|
|
68
|
+
if (row) {
|
|
69
|
+
// SQLite reaches a BLOB offset by walking its overflow pages, so a read
|
|
70
|
+
// at offset N costs O(N). One read per 64 KiB chunk is quadratic (a
|
|
71
|
+
// 64 MiB row took 37 s). Reading windows of size/WINDOWS_PER_BLOB bounds
|
|
72
|
+
// the walk to a constant multiple of the blob and memory to a fraction.
|
|
73
|
+
const readWindow = db.prepare(`SELECT substr(bytes, ?, ?) AS bytes FROM ${table} WHERE blob_id=?`);
|
|
74
|
+
const window = Math.ceil(Math.max(LEGACY_MIN_WINDOW_BYTES, row.size / LEGACY_WINDOWS) /
|
|
75
|
+
BINARY_CHUNK_BYTES) * BINARY_CHUNK_BYTES;
|
|
76
|
+
for (let start = 0; start < row.size; start += window) {
|
|
77
|
+
const part = readWindow.get(start + 1, window, id);
|
|
78
|
+
if (!part?.bytes.length)
|
|
79
|
+
throw new Error("corrupt binary chunks");
|
|
80
|
+
for (let offset = 0; offset < part.bytes.length; offset += BINARY_CHUNK_BYTES)
|
|
81
|
+
yield part.bytes.subarray(offset, offset + BINARY_CHUNK_BYTES);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const size = binaryLength(db, namespace, id);
|
|
87
|
+
if (size === undefined)
|
|
88
|
+
throw new Error("missing binary bytes");
|
|
89
|
+
const read = db.prepare("SELECT bytes FROM pdpp_binary_chunks WHERE namespace=? AND blob_id=? AND position=?");
|
|
90
|
+
let offset = 0, position = 0;
|
|
91
|
+
while (offset < size) {
|
|
92
|
+
const row = read.get(namespace, id, position++);
|
|
93
|
+
if (!row ||
|
|
94
|
+
!row.bytes.length ||
|
|
95
|
+
row.bytes.length > BINARY_CHUNK_BYTES ||
|
|
96
|
+
offset + row.bytes.length > size)
|
|
97
|
+
throw new Error("corrupt binary chunks");
|
|
98
|
+
offset += row.bytes.length;
|
|
99
|
+
yield row.bytes;
|
|
100
|
+
}
|
|
101
|
+
if (db
|
|
102
|
+
.prepare("SELECT 1 FROM pdpp_binary_chunks WHERE namespace=? AND blob_id=? AND position>=? LIMIT 1")
|
|
103
|
+
.get(namespace, id, position))
|
|
104
|
+
throw new Error("excess binary chunks");
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Read exactly `length` bytes of chunked (manifest) bytes from `from`, and
|
|
108
|
+
* return them with the cursor after them. Rows may have any length, so a
|
|
109
|
+
* caller that reads a value in parts keeps the returned cursor; it never
|
|
110
|
+
* seeks by arithmetic. Memory is `length`. Legacy whole-row values are not
|
|
111
|
+
* supported: only namespaces without a legacy table use this.
|
|
112
|
+
*/
|
|
113
|
+
export function readBinaryWindow(db, namespace, id, from, length) {
|
|
114
|
+
if (legacy[namespace])
|
|
115
|
+
throw new Error("legacy binary windows unsupported");
|
|
116
|
+
const size = binaryLength(db, namespace, id);
|
|
117
|
+
if (size === undefined ||
|
|
118
|
+
!Number.isSafeInteger(length) ||
|
|
119
|
+
length < 1 ||
|
|
120
|
+
!Number.isSafeInteger(from.position) ||
|
|
121
|
+
from.position < 0 ||
|
|
122
|
+
!Number.isSafeInteger(from.offset) ||
|
|
123
|
+
from.offset < 0)
|
|
124
|
+
throw new Error("missing binary bytes");
|
|
125
|
+
const bytes = new Uint8Array(length);
|
|
126
|
+
const read = db.prepare("SELECT bytes FROM pdpp_binary_chunks WHERE namespace=? AND blob_id=? AND position=?");
|
|
127
|
+
let filled = 0;
|
|
128
|
+
let { position, offset } = from;
|
|
129
|
+
while (filled < length) {
|
|
130
|
+
const row = read.get(namespace, id, position);
|
|
131
|
+
if (!row ||
|
|
132
|
+
!row.bytes.length ||
|
|
133
|
+
row.bytes.length > BINARY_CHUNK_BYTES ||
|
|
134
|
+
offset >= row.bytes.length)
|
|
135
|
+
throw new Error("corrupt binary chunks");
|
|
136
|
+
const take = Math.min(row.bytes.length - offset, length - filled);
|
|
137
|
+
bytes.set(row.bytes.subarray(offset, offset + take), filled);
|
|
138
|
+
filled += take;
|
|
139
|
+
offset += take;
|
|
140
|
+
if (offset === row.bytes.length) {
|
|
141
|
+
position++;
|
|
142
|
+
offset = 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { bytes, next: { position, offset } };
|
|
146
|
+
}
|
|
147
|
+
export function verifyBinary(db, namespace, id, digest, size) {
|
|
148
|
+
if (binaryLength(db, namespace, id) !== size)
|
|
149
|
+
return false;
|
|
150
|
+
const hash = createHash("sha256");
|
|
151
|
+
try {
|
|
152
|
+
for (const bytes of readBinaryChunks(db, namespace, id))
|
|
153
|
+
hash.update(bytes);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return `sha256:${hash.digest("hex")}` === digest;
|
|
159
|
+
}
|
|
160
|
+
export function deleteBinary(db, namespace, id) {
|
|
161
|
+
db.prepare("DELETE FROM pdpp_binary_chunks WHERE namespace=? AND blob_id=?").run(namespace, id);
|
|
162
|
+
db.prepare("DELETE FROM pdpp_binary_manifests WHERE namespace=? AND blob_id=?").run(namespace, id);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A repair write is about to give `id` a verified copy in `namespace`.
|
|
166
|
+
* Remove a published manifest whose size is not a safe non-negative
|
|
167
|
+
* integer, with its chunks, in the caller's transaction. Readers veto a
|
|
168
|
+
* namespace on such a manifest even beside a legacy row, so without this a
|
|
169
|
+
* repair would never take effect.
|
|
170
|
+
*/
|
|
171
|
+
export function clearMalformedManifest(db, namespace, id) {
|
|
172
|
+
const row = db
|
|
173
|
+
.prepare("SELECT size_bytes AS size FROM pdpp_binary_manifests WHERE namespace=? AND blob_id=?")
|
|
174
|
+
.get(namespace, id);
|
|
175
|
+
if (row &&
|
|
176
|
+
!(typeof row.size === "number" &&
|
|
177
|
+
Number.isSafeInteger(row.size) &&
|
|
178
|
+
row.size >= 0))
|
|
179
|
+
deleteBinary(db, namespace, id);
|
|
180
|
+
}
|
|
181
|
+
/** Publish the manifest only after EOF. Callers own transaction/visibility and cleanup. */
|
|
182
|
+
export function binaryWriter(db, namespace, id) {
|
|
183
|
+
deleteBinary(db, namespace, id);
|
|
184
|
+
const insert = db.prepare("INSERT INTO pdpp_binary_chunks VALUES (?,?,?,?)");
|
|
185
|
+
let size = 0, position = 0;
|
|
186
|
+
return {
|
|
187
|
+
write(bytes) {
|
|
188
|
+
for (let offset = 0; offset < bytes.length; offset += BINARY_CHUNK_BYTES) {
|
|
189
|
+
const part = bytes.subarray(offset, offset + BINARY_CHUNK_BYTES);
|
|
190
|
+
insert.run(namespace, id, position++, part);
|
|
191
|
+
size += part.length;
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
finish() {
|
|
195
|
+
db.prepare("INSERT INTO pdpp_binary_manifests VALUES (?,?,?)").run(namespace, id, size);
|
|
196
|
+
return size;
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export function copyBinary(db, from, sourceId, to, targetId = sourceId) {
|
|
201
|
+
const writer = binaryWriter(db, to, targetId);
|
|
202
|
+
for (const chunk of readBinaryChunks(db, from, sourceId))
|
|
203
|
+
writer.write(chunk);
|
|
204
|
+
writer.finish();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Write canonical bytes the server holds as one value, in one form only. A
|
|
208
|
+
* value up to CANONICAL_INLINE_BYTES (one Lite fragment) is main's whole row.
|
|
209
|
+
* A larger one is chunks only: the transport and capture's pin read those
|
|
210
|
+
* chunks, and the flag-off boot that retires replication writes main's row
|
|
211
|
+
* (`materializeCanonicalBinaries`).
|
|
212
|
+
*/
|
|
213
|
+
export function writeCanonicalBinary(db, id, bytes) {
|
|
214
|
+
deleteBinary(db, "canonical", id);
|
|
215
|
+
if (bytes.length > CANONICAL_INLINE_BYTES) {
|
|
216
|
+
db.prepare(`DELETE FROM ${legacy.canonical} WHERE blob_id=?`).run(id);
|
|
217
|
+
const writer = binaryWriter(db, "canonical", id);
|
|
218
|
+
for (let offset = 0; offset < bytes.length; offset += BINARY_CHUNK_BYTES)
|
|
219
|
+
writer.write(bytes.subarray(offset, offset + BINARY_CHUNK_BYTES));
|
|
220
|
+
writer.finish();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const view = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
224
|
+
db.prepare(`INSERT INTO ${legacy.canonical} (blob_id, bytes) VALUES (?, ?)
|
|
225
|
+
ON CONFLICT(blob_id) DO UPDATE SET bytes = excluded.bytes`).run(id, view);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Promote verified bytes to canonical in the caller's transaction. A value up
|
|
229
|
+
* to CANONICAL_INLINE_BYTES (one Lite fragment) becomes main's whole row. A
|
|
230
|
+
* larger one is copied chunk by chunk and is stored only in the chunk form:
|
|
231
|
+
* no whole value is assembled or stored twice. Canonical readers accept both
|
|
232
|
+
* forms; the flag-off boot that retires replication writes main's row for
|
|
233
|
+
* chunk-only blobs (`materializeCanonicalBinaries`).
|
|
234
|
+
*/
|
|
235
|
+
export function copyBinaryToCanonical(db, from, sourceId, targetId = sourceId) {
|
|
236
|
+
const size = binaryLength(db, from, sourceId);
|
|
237
|
+
if (size === undefined)
|
|
238
|
+
throw new Error("missing binary bytes");
|
|
239
|
+
if (size > CANONICAL_INLINE_BYTES) {
|
|
240
|
+
db.prepare(`DELETE FROM ${legacy.canonical} WHERE blob_id=?`).run(targetId);
|
|
241
|
+
copyBinary(db, from, sourceId, "canonical", targetId);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const bytes = readBinary(db, from, sourceId);
|
|
245
|
+
if (!bytes)
|
|
246
|
+
throw new Error("missing binary bytes");
|
|
247
|
+
writeCanonicalBinary(db, targetId, bytes);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Write main's whole row for each verified canonical blob that has only the
|
|
251
|
+
* chunk form, so a flag-off or plain main build can read it. One blob per
|
|
252
|
+
* transaction; each costs one whole value in memory. Run it only when
|
|
253
|
+
* replication is retired: an enabled store keeps large blobs chunk-only.
|
|
254
|
+
* A first enable that stopped after the door committed, before the replica
|
|
255
|
+
* schema, left no chunk store, so there is nothing to write.
|
|
256
|
+
*/
|
|
257
|
+
export function materializeCanonicalBinaries(db) {
|
|
258
|
+
const chunkStore = db
|
|
259
|
+
.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'pdpp_binary_manifests'")
|
|
260
|
+
.get();
|
|
261
|
+
if (!chunkStore)
|
|
262
|
+
return 0;
|
|
263
|
+
const missing = db
|
|
264
|
+
.prepare(`SELECT m.blob_id, b.size_bytes, b.sha256
|
|
265
|
+
FROM pdpp_binary_manifests m
|
|
266
|
+
JOIN pdpp_blobs b ON b.blob_id = m.blob_id
|
|
267
|
+
LEFT JOIN ${legacy.canonical} c ON c.blob_id = m.blob_id
|
|
268
|
+
WHERE m.namespace = 'canonical' AND c.blob_id IS NULL`)
|
|
269
|
+
.all();
|
|
270
|
+
let written = 0;
|
|
271
|
+
for (const blob of missing)
|
|
272
|
+
db.transaction(() => {
|
|
273
|
+
if (!verifyBinary(db, "canonical", blob.blob_id, `sha256:${blob.sha256}`, blob.size_bytes))
|
|
274
|
+
return;
|
|
275
|
+
const bytes = readBinary(db, "canonical", blob.blob_id);
|
|
276
|
+
if (!bytes)
|
|
277
|
+
return;
|
|
278
|
+
// Main's row becomes the only copy.
|
|
279
|
+
db.prepare(`INSERT INTO ${legacy.canonical} (blob_id, bytes) VALUES (?, ?)`).run(blob.blob_id, Buffer.from(bytes.buffer, 0, bytes.byteLength));
|
|
280
|
+
deleteBinary(db, "canonical", blob.blob_id);
|
|
281
|
+
written++;
|
|
282
|
+
}).immediate();
|
|
283
|
+
return written;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Explicit whole-value read for HTTP consumers, rollback materialization and
|
|
287
|
+
* inline-size promotion. Replication never calls it on a value larger than
|
|
288
|
+
* CANONICAL_INLINE_BYTES.
|
|
289
|
+
*/
|
|
290
|
+
export function readBinary(db, namespace, id) {
|
|
291
|
+
const length = binaryLength(db, namespace, id);
|
|
292
|
+
if (length === undefined)
|
|
293
|
+
return undefined;
|
|
294
|
+
const result = new Uint8Array(length);
|
|
295
|
+
let offset = 0;
|
|
296
|
+
try {
|
|
297
|
+
for (const bytes of readBinaryChunks(db, namespace, id)) {
|
|
298
|
+
result.set(bytes, offset);
|
|
299
|
+
offset += bytes.length;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Bring blobs an earlier build stored more than once down to one copy. The
|
|
309
|
+
* caller runs each `step` in its own write transaction. A
|
|
310
|
+
* copy goes only when canonical storage holds the blob and it verifies:
|
|
311
|
+
*
|
|
312
|
+
* - main's whole row of a large blob that also has the chunk form;
|
|
313
|
+
* - a capture pin's own copy, which becomes a pin row that references the
|
|
314
|
+
* canonical chunks (`captureBlob`).
|
|
315
|
+
*
|
|
316
|
+
* Verification reads a bounded number of chunks per call, so a large blob
|
|
317
|
+
* is verified across calls. The hash in progress lives in memory: after a
|
|
318
|
+
* restart that blob is verified again from its start. A canonical whole row
|
|
319
|
+
* up to 1 MiB verifies in one call; a larger one has no bounded read and is
|
|
320
|
+
* skipped, and so is canonical storage with a chunk past the blob's end. A
|
|
321
|
+
* candidate that fails verification is skipped for the compactor's life,
|
|
322
|
+
* and a step examines at most 8 candidates, so corrupt blobs cannot hold
|
|
323
|
+
* back the rest or stall a step. Once a
|
|
324
|
+
* search finds nothing, the compactor stops for good: current writes keep
|
|
325
|
+
* one copy, so only a database an earlier build wrote has work, and an idle
|
|
326
|
+
* step then reads none of these tables.
|
|
327
|
+
*/
|
|
328
|
+
export function createBinaryCompactor(db) {
|
|
329
|
+
const known = "IN (SELECT blob_id FROM pdpp_blobs)";
|
|
330
|
+
/** Per kind: queries for its candidates after `@after`, first by blob id. */
|
|
331
|
+
const kinds = {
|
|
332
|
+
whole: {
|
|
333
|
+
arms: [
|
|
334
|
+
`SELECT c.blob_id FROM ${legacy.canonical} c
|
|
335
|
+
JOIN pdpp_binary_manifests m ON m.namespace='canonical' AND m.blob_id=c.blob_id
|
|
336
|
+
WHERE m.size_bytes > ${CANONICAL_INLINE_BYTES} AND c.blob_id>@after AND c.blob_id ${known}`,
|
|
337
|
+
],
|
|
338
|
+
compact(id) {
|
|
339
|
+
db.prepare(`DELETE FROM ${legacy.canonical} WHERE blob_id=?`).run(id);
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
pinned: {
|
|
343
|
+
arms: [
|
|
344
|
+
`SELECT p.blob_id FROM pdpp_binary_manifests p
|
|
345
|
+
JOIN pdpp_binary_manifests m ON m.namespace='canonical' AND m.blob_id=p.blob_id
|
|
346
|
+
WHERE p.namespace='pinned' AND p.blob_id>@after AND p.blob_id ${known}`,
|
|
347
|
+
],
|
|
348
|
+
compact(id) {
|
|
349
|
+
// Export may have released the pin since verification began.
|
|
350
|
+
if (binaryLength(db, "pinned", id) === undefined)
|
|
351
|
+
return;
|
|
352
|
+
db.prepare("INSERT OR IGNORE INTO pdpp_replica_blob_pins VALUES (?)").run(id);
|
|
353
|
+
deleteBinary(db, "pinned", id);
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
const order = Object.keys(kinds);
|
|
358
|
+
/**
|
|
359
|
+
* Keyset position: the kind being searched and the last blob examined in
|
|
360
|
+
* it. A candidate is examined once per process, so a skipped one costs no
|
|
361
|
+
* later search.
|
|
362
|
+
*/
|
|
363
|
+
let cursor = { kind: 0, after: "" };
|
|
364
|
+
let current;
|
|
365
|
+
/** The next candidate, or undefined when none is left. */
|
|
366
|
+
function next() {
|
|
367
|
+
while (cursor.kind < order.length) {
|
|
368
|
+
const kind = order[cursor.kind];
|
|
369
|
+
const row = db
|
|
370
|
+
.prepare(`SELECT min(blob_id) AS blob_id FROM (${kinds[kind].arms
|
|
371
|
+
.map((arm) => `SELECT * FROM (${arm} ORDER BY 1 LIMIT 1)`)
|
|
372
|
+
.join(" UNION ALL ")})`)
|
|
373
|
+
.get({ after: cursor.after });
|
|
374
|
+
if (row.blob_id !== null) {
|
|
375
|
+
cursor.after = row.blob_id;
|
|
376
|
+
return { kind, id: row.blob_id };
|
|
377
|
+
}
|
|
378
|
+
cursor = { kind: cursor.kind + 1, after: "" };
|
|
379
|
+
}
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Begin verifying a candidate. A canonical whole row up to 1 MiB verifies
|
|
384
|
+
* and compacts at once; a larger whole row has no bounded read and is
|
|
385
|
+
* skipped. Returns the bytes read.
|
|
386
|
+
*/
|
|
387
|
+
function begin(candidate) {
|
|
388
|
+
const meta = db
|
|
389
|
+
.prepare("SELECT size_bytes AS size, sha256 FROM pdpp_blobs WHERE blob_id=?")
|
|
390
|
+
.get(candidate.id);
|
|
391
|
+
const size = binaryLength(db, "canonical", candidate.id);
|
|
392
|
+
if (!meta || size !== meta.size)
|
|
393
|
+
return 0;
|
|
394
|
+
const digest = `sha256:${meta.sha256}`;
|
|
395
|
+
const chunked = db
|
|
396
|
+
.prepare("SELECT 1 FROM pdpp_binary_manifests WHERE namespace='canonical' AND blob_id=?")
|
|
397
|
+
.get(candidate.id);
|
|
398
|
+
if (!chunked) {
|
|
399
|
+
if (size > CANONICAL_INLINE_BYTES)
|
|
400
|
+
return 0;
|
|
401
|
+
if (verifyBinary(db, "canonical", candidate.id, digest, size))
|
|
402
|
+
kinds[candidate.kind].compact(candidate.id);
|
|
403
|
+
return size;
|
|
404
|
+
}
|
|
405
|
+
current = {
|
|
406
|
+
...candidate,
|
|
407
|
+
size,
|
|
408
|
+
digest,
|
|
409
|
+
hash: createHash("sha256"),
|
|
410
|
+
position: 0,
|
|
411
|
+
read: 0,
|
|
412
|
+
};
|
|
413
|
+
return 0;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Hash up to `bytes` more of the current blob, at least one chunk, and
|
|
417
|
+
* compact it once it verifies. Returns the bytes read.
|
|
418
|
+
*/
|
|
419
|
+
function advance(bytes) {
|
|
420
|
+
const blob = current;
|
|
421
|
+
const rows = db
|
|
422
|
+
.prepare("SELECT position, bytes FROM pdpp_binary_chunks WHERE namespace='canonical' AND blob_id=? AND position>=? ORDER BY position")
|
|
423
|
+
.iterate(blob.id, blob.position);
|
|
424
|
+
let read = 0;
|
|
425
|
+
let corrupt = true;
|
|
426
|
+
for (const row of rows) {
|
|
427
|
+
corrupt =
|
|
428
|
+
row.position !== blob.position ||
|
|
429
|
+
!row.bytes.length ||
|
|
430
|
+
row.bytes.length > BINARY_CHUNK_BYTES ||
|
|
431
|
+
blob.read + row.bytes.length > blob.size;
|
|
432
|
+
if (corrupt || (read && read + row.bytes.length > bytes))
|
|
433
|
+
break;
|
|
434
|
+
blob.hash.update(row.bytes);
|
|
435
|
+
blob.position++;
|
|
436
|
+
blob.read += row.bytes.length;
|
|
437
|
+
read += row.bytes.length;
|
|
438
|
+
if (blob.read === blob.size)
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
if (corrupt)
|
|
442
|
+
current = undefined;
|
|
443
|
+
else if (blob.read === blob.size) {
|
|
444
|
+
current = undefined;
|
|
445
|
+
// Readers reject a chunk past the blob's end, so verification does too.
|
|
446
|
+
const trailing = db
|
|
447
|
+
.prepare("SELECT 1 FROM pdpp_binary_chunks WHERE namespace='canonical' AND blob_id=? AND position>=?")
|
|
448
|
+
.get(blob.id, blob.position);
|
|
449
|
+
if (!trailing &&
|
|
450
|
+
`sha256:${blob.hash.digest("hex")}` === blob.digest &&
|
|
451
|
+
binaryLength(db, "canonical", blob.id) === blob.size)
|
|
452
|
+
kinds[blob.kind].compact(blob.id);
|
|
453
|
+
}
|
|
454
|
+
return Math.max(read, 1);
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
/**
|
|
458
|
+
* Spend up to about `bytes` of canonical reads, and at most
|
|
459
|
+
* `COMPACT_CANDIDATES_PER_STEP` new candidates, toward compaction. Call it
|
|
460
|
+
* in a write transaction.
|
|
461
|
+
*/
|
|
462
|
+
step(bytes) {
|
|
463
|
+
let started = 0;
|
|
464
|
+
while (bytes >= BINARY_CHUNK_BYTES) {
|
|
465
|
+
if (current) {
|
|
466
|
+
bytes -= advance(bytes);
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (started === COMPACT_CANDIDATES_PER_STEP)
|
|
470
|
+
return;
|
|
471
|
+
const candidate = next();
|
|
472
|
+
if (!candidate)
|
|
473
|
+
return;
|
|
474
|
+
started++;
|
|
475
|
+
bytes -= begin(candidate);
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
//# sourceMappingURL=pdpp-binary-chunks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdpp-binary-chunks.js","sourceRoot":"","sources":["../../src/storage/pdpp-binary-chunks.ts"],"names":[],"mappings":"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"}
|