@statewalker/cellb 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +323 -2
- package/dist/adapters/files-backup.d.ts +16 -0
- package/dist/adapters/files-backup.js +32 -0
- package/dist/adapters/files-backup.js.map +1 -0
- package/dist/adapters/files-changelog.d.ts +33 -0
- package/dist/adapters/files-changelog.js +96 -0
- package/dist/adapters/files-changelog.js.map +1 -0
- package/dist/adapters/files-ltx.d.ts +35 -0
- package/dist/adapters/files-ltx.js +9 -0
- package/dist/adapters/files-ltx.js.map +1 -0
- package/dist/adapters/ltx-vfs.d.ts +21 -0
- package/dist/adapters/ltx-vfs.js +286 -0
- package/dist/adapters/ltx-vfs.js.map +1 -0
- package/dist/adapters/node-sqlite.d.ts +45 -0
- package/dist/adapters/node-sqlite.js +254 -0
- package/dist/adapters/node-sqlite.js.map +1 -0
- package/dist/adapters/wasm-page-hook.d.ts +26 -0
- package/dist/adapters/wasm-page-hook.js +55 -0
- package/dist/adapters/wasm-page-hook.js.map +1 -0
- package/dist/adapters/wasm-session.d.ts +11 -0
- package/dist/adapters/wasm-session.js +76 -0
- package/dist/adapters/wasm-session.js.map +1 -0
- package/dist/adapters/wasm-sqlite.d.ts +89 -0
- package/dist/adapters/wasm-sqlite.js +258 -0
- package/dist/adapters/wasm-sqlite.js.map +1 -0
- package/dist/bindings/assets.d.ts +26 -0
- package/dist/bindings/assets.js +260 -0
- package/dist/bindings/assets.js.map +1 -0
- package/dist/bindings/cache.d.ts +16 -0
- package/dist/bindings/cache.js +34 -0
- package/dist/bindings/cache.js.map +1 -0
- package/dist/bindings/celld-kv.d.ts +26 -0
- package/dist/bindings/celld-kv.js +81 -0
- package/dist/bindings/celld-kv.js.map +1 -0
- package/dist/bindings/celld-queues.d.ts +56 -0
- package/dist/bindings/celld-queues.js +223 -0
- package/dist/bindings/celld-queues.js.map +1 -0
- package/dist/bindings/celld-workflows.d.ts +22 -0
- package/dist/bindings/celld-workflows.js +54 -0
- package/dist/bindings/celld-workflows.js.map +1 -0
- package/dist/bindings/cron.d.ts +27 -0
- package/dist/bindings/cron.js +232 -0
- package/dist/bindings/cron.js.map +1 -0
- package/dist/bindings/d1-migrations.d.ts +22 -0
- package/dist/bindings/d1-migrations.js +32 -0
- package/dist/bindings/d1-migrations.js.map +1 -0
- package/dist/bindings/html-rewriter.d.ts +8 -0
- package/dist/bindings/html-rewriter.js +75 -0
- package/dist/bindings/html-rewriter.js.map +1 -0
- package/dist/bindings/r2-celld.d.ts +3 -0
- package/dist/bindings/r2-celld.js +113 -0
- package/dist/bindings/r2-celld.js.map +1 -0
- package/dist/bindings/r2.d.ts +236 -0
- package/dist/bindings/r2.js +419 -0
- package/dist/bindings/r2.js.map +1 -0
- package/dist/bindings/worker-loader.d.ts +83 -0
- package/dist/bindings/worker-loader.js +183 -0
- package/dist/bindings/worker-loader.js.map +1 -0
- package/dist/bindings/workers-ai.d.ts +39 -0
- package/dist/bindings/workers-ai.js +175 -0
- package/dist/bindings/workers-ai.js.map +1 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +8 -0
- package/dist/browser.js.map +1 -0
- package/dist/bucket/celld-cells.d.ts +86 -0
- package/dist/bucket/celld-cells.js +273 -0
- package/dist/bucket/celld-cells.js.map +1 -0
- package/dist/bucket/celld-format.d.ts +10 -0
- package/dist/bucket/celld-format.js +27 -0
- package/dist/bucket/celld-format.js.map +1 -0
- package/dist/bucket/idb-object-store.d.ts +9 -0
- package/dist/bucket/idb-object-store.js +73 -0
- package/dist/bucket/idb-object-store.js.map +1 -0
- package/dist/bucket/ltx-log.d.ts +34 -0
- package/dist/bucket/ltx-log.js +289 -0
- package/dist/bucket/ltx-log.js.map +1 -0
- package/dist/bucket/object-store.d.ts +51 -0
- package/dist/bucket/object-store.js +114 -0
- package/dist/bucket/object-store.js.map +1 -0
- package/dist/bucket/s3-object-store.d.ts +25 -0
- package/dist/bucket/s3-object-store.js +151 -0
- package/dist/bucket/s3-object-store.js.map +1 -0
- package/dist/bucket/sqlite-object-store.d.ts +10 -0
- package/dist/bucket/sqlite-object-store.js +107 -0
- package/dist/bucket/sqlite-object-store.js.map +1 -0
- package/dist/core/alarms.d.ts +27 -0
- package/dist/core/alarms.js +88 -0
- package/dist/core/alarms.js.map +1 -0
- package/dist/core/async-context.d.ts +34 -0
- package/dist/core/async-context.js +50 -0
- package/dist/core/async-context.js.map +1 -0
- package/dist/core/celld-schema.d.ts +14 -0
- package/dist/core/celld-schema.js +34 -0
- package/dist/core/celld-schema.js.map +1 -0
- package/dist/core/durable-object.d.ts +28 -0
- package/dist/core/durable-object.js +31 -0
- package/dist/core/durable-object.js.map +1 -0
- package/dist/core/gates.d.ts +33 -0
- package/dist/core/gates.js +89 -0
- package/dist/core/gates.js.map +1 -0
- package/dist/core/handles.d.ts +90 -0
- package/dist/core/handles.js +224 -0
- package/dist/core/handles.js.map +1 -0
- package/dist/core/id.d.ts +19 -0
- package/dist/core/id.js +64 -0
- package/dist/core/id.js.map +1 -0
- package/dist/core/namespace.d.ts +38 -0
- package/dist/core/namespace.js +141 -0
- package/dist/core/namespace.js.map +1 -0
- package/dist/core/object-host.d.ts +91 -0
- package/dist/core/object-host.js +616 -0
- package/dist/core/object-host.js.map +1 -0
- package/dist/core/request-body.d.ts +9 -0
- package/dist/core/request-body.js +55 -0
- package/dist/core/request-body.js.map +1 -0
- package/dist/core/runtime.d.ts +121 -0
- package/dist/core/runtime.js +366 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/shard.d.ts +7 -0
- package/dist/core/shard.js +10 -0
- package/dist/core/shard.js.map +1 -0
- package/dist/core/sql-split.d.ts +15 -0
- package/dist/core/sql-split.js +101 -0
- package/dist/core/sql-split.js.map +1 -0
- package/dist/core/sql-storage.d.ts +53 -0
- package/dist/core/sql-storage.js +407 -0
- package/dist/core/sql-storage.js.map +1 -0
- package/dist/core/state.d.ts +44 -0
- package/dist/core/state.js +93 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/storage.d.ts +103 -0
- package/dist/core/storage.js +351 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/worker-rejections.d.ts +21 -0
- package/dist/core/worker-rejections.js +55 -0
- package/dist/core/worker-rejections.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/isolate/browser.d.ts +16 -0
- package/dist/isolate/browser.js +37 -0
- package/dist/isolate/browser.js.map +1 -0
- package/dist/isolate/host.d.ts +24 -0
- package/dist/isolate/host.js +74 -0
- package/dist/isolate/host.js.map +1 -0
- package/dist/isolate/isolate-worker.d.ts +1 -0
- package/dist/isolate/isolate-worker.js +53 -0
- package/dist/isolate/isolate-worker.js.map +1 -0
- package/dist/isolate/isolate.d.ts +10 -0
- package/dist/isolate/isolate.js +169 -0
- package/dist/isolate/isolate.js.map +1 -0
- package/dist/isolate/node-entry.d.ts +1 -0
- package/dist/isolate/node-entry.js +12 -0
- package/dist/isolate/node-entry.js.map +1 -0
- package/dist/isolate/protocol.d.ts +66 -0
- package/dist/isolate/protocol.js +205 -0
- package/dist/isolate/protocol.js.map +1 -0
- package/dist/ltx/crc64.d.ts +6 -0
- package/dist/ltx/crc64.js +46 -0
- package/dist/ltx/crc64.js.map +1 -0
- package/dist/ltx/ltx-page-server.d.ts +65 -0
- package/dist/ltx/ltx-page-server.js +309 -0
- package/dist/ltx/ltx-page-server.js.map +1 -0
- package/dist/ltx/ltx-pages.d.ts +81 -0
- package/dist/ltx/ltx-pages.js +315 -0
- package/dist/ltx/ltx-pages.js.map +1 -0
- package/dist/ltx/ltx-store-worker.d.ts +1 -0
- package/dist/ltx/ltx-store-worker.js +38 -0
- package/dist/ltx/ltx-store-worker.js.map +1 -0
- package/dist/ltx/ltx.d.ts +45 -0
- package/dist/ltx/ltx.js +203 -0
- package/dist/ltx/ltx.js.map +1 -0
- package/dist/ltx/lz4.d.ts +9 -0
- package/dist/ltx/lz4.js +156 -0
- package/dist/ltx/lz4.js.map +1 -0
- package/dist/ltx/opfs-sync-files.d.ts +23 -0
- package/dist/ltx/opfs-sync-files.js +191 -0
- package/dist/ltx/opfs-sync-files.js.map +1 -0
- package/dist/ltx/xxh32.d.ts +1 -0
- package/dist/ltx/xxh32.js +43 -0
- package/dist/ltx/xxh32.js.map +1 -0
- package/dist/miniflare-compat/blob-service.d.ts +13 -0
- package/dist/miniflare-compat/blob-service.js +66 -0
- package/dist/miniflare-compat/blob-service.js.map +1 -0
- package/dist/miniflare-compat/kv-binding.d.ts +44 -0
- package/dist/miniflare-compat/kv-binding.js +99 -0
- package/dist/miniflare-compat/kv-binding.js.map +1 -0
- package/dist/miniflare-compat/shims/assert.d.ts +15 -0
- package/dist/miniflare-compat/shims/assert.js +24 -0
- package/dist/miniflare-compat/shims/assert.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.d.ts +7 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.js +6 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-globals.d.ts +1 -0
- package/dist/miniflare-compat/shims/workerd-globals.js +30 -0
- package/dist/miniflare-compat/shims/workerd-globals.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-internal.d.ts +20 -0
- package/dist/miniflare-compat/shims/workerd-internal.js +23 -0
- package/dist/miniflare-compat/shims/workerd-internal.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-performance.d.ts +4 -0
- package/dist/miniflare-compat/shims/workerd-performance.js +17 -0
- package/dist/miniflare-compat/shims/workerd-performance.js.map +1 -0
- package/dist/miniflare-compat/simulator-fetcher.d.ts +9 -0
- package/dist/miniflare-compat/simulator-fetcher.js +14 -0
- package/dist/miniflare-compat/simulator-fetcher.js.map +1 -0
- package/dist/miniflare-compat/vendored.d.ts +15 -0
- package/dist/miniflare-compat/vendored.js +27 -0
- package/dist/miniflare-compat/vendored.js.map +1 -0
- package/dist/node-compat/async_hooks.d.ts +22 -0
- package/dist/node-compat/async_hooks.js +176 -0
- package/dist/node-compat/async_hooks.js.map +1 -0
- package/dist/node-compat/browser-registry.d.ts +3 -0
- package/dist/node-compat/browser-registry.js +39 -0
- package/dist/node-compat/browser-registry.js.map +1 -0
- package/dist/node-compat/crypto.d.ts +60 -0
- package/dist/node-compat/crypto.js +143 -0
- package/dist/node-compat/crypto.js.map +1 -0
- package/dist/node-compat/diagnostics_channel.d.ts +27 -0
- package/dist/node-compat/diagnostics_channel.js +46 -0
- package/dist/node-compat/diagnostics_channel.js.map +1 -0
- package/dist/node-compat/fs.d.ts +35 -0
- package/dist/node-compat/fs.js +40 -0
- package/dist/node-compat/fs.js.map +1 -0
- package/dist/node-compat/globals.d.ts +3 -0
- package/dist/node-compat/globals.js +4 -0
- package/dist/node-compat/globals.js.map +1 -0
- package/dist/node-compat/install.d.ts +5 -0
- package/dist/node-compat/install.js +12 -0
- package/dist/node-compat/install.js.map +1 -0
- package/dist/node-compat/module.d.ts +12 -0
- package/dist/node-compat/module.js +36 -0
- package/dist/node-compat/module.js.map +1 -0
- package/dist/node-compat/modules.d.ts +8 -0
- package/dist/node-compat/modules.js +23 -0
- package/dist/node-compat/modules.js.map +1 -0
- package/dist/node-compat/os.d.ts +36 -0
- package/dist/node-compat/os.js +36 -0
- package/dist/node-compat/os.js.map +1 -0
- package/dist/node-compat/process.d.ts +14 -0
- package/dist/node-compat/process.js +16 -0
- package/dist/node-compat/process.js.map +1 -0
- package/dist/node-compat/shims.d.ts +4 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.js +6 -0
- package/dist/node.js.map +1 -0
- package/dist/peer/celld-peer.d.ts +53 -0
- package/dist/peer/celld-peer.js +555 -0
- package/dist/peer/celld-peer.js.map +1 -0
- package/dist/ports.d.ts +183 -0
- package/dist/ports.js +10 -0
- package/dist/ports.js.map +1 -0
- package/dist/project/browser-bundle.d.ts +17 -0
- package/dist/project/browser-bundle.js +125 -0
- package/dist/project/browser-bundle.js.map +1 -0
- package/dist/project/browser-cookies.d.ts +12 -0
- package/dist/project/browser-cookies.js +90 -0
- package/dist/project/browser-cookies.js.map +1 -0
- package/dist/project/browser-host.d.ts +173 -0
- package/dist/project/browser-host.js +200 -0
- package/dist/project/browser-host.js.map +1 -0
- package/dist/project/browser-modules.d.ts +17 -0
- package/dist/project/browser-modules.js +89 -0
- package/dist/project/browser-modules.js.map +1 -0
- package/dist/project/browser-shards.d.ts +62 -0
- package/dist/project/browser-shards.js +210 -0
- package/dist/project/browser-shards.js.map +1 -0
- package/dist/project/browser-tabs.d.ts +103 -0
- package/dist/project/browser-tabs.js +418 -0
- package/dist/project/browser-tabs.js.map +1 -0
- package/dist/project/cloudflare-email.d.ts +8 -0
- package/dist/project/cloudflare-email.js +11 -0
- package/dist/project/cloudflare-email.js.map +1 -0
- package/dist/project/cloudflare-workers.d.ts +12 -0
- package/dist/project/cloudflare-workers.js +16 -0
- package/dist/project/cloudflare-workers.js.map +1 -0
- package/dist/project/host-modules.d.ts +4 -0
- package/dist/project/host-modules.js +40 -0
- package/dist/project/host-modules.js.map +1 -0
- package/dist/project/jsonc.d.ts +2 -0
- package/dist/project/jsonc.js +27 -0
- package/dist/project/jsonc.js.map +1 -0
- package/dist/project/lower-await.d.ts +2 -0
- package/dist/project/lower-await.js +151 -0
- package/dist/project/lower-await.js.map +1 -0
- package/dist/project/node-project.d.ts +38 -0
- package/dist/project/node-project.js +373 -0
- package/dist/project/node-project.js.map +1 -0
- package/dist/project/own-module.d.ts +6 -0
- package/dist/project/own-module.js +13 -0
- package/dist/project/own-module.js.map +1 -0
- package/dist/project/scheduler.d.ts +2 -0
- package/dist/project/scheduler.js +3 -0
- package/dist/project/scheduler.js.map +1 -0
- package/dist/project/site.d.ts +74 -0
- package/dist/project/site.js +206 -0
- package/dist/project/site.js.map +1 -0
- package/dist/project/virtual-modules.d.ts +3 -0
- package/dist/project/worker-scope.d.ts +27 -0
- package/dist/project/worker-scope.js +46 -0
- package/dist/project/worker-scope.js.map +1 -0
- package/dist/project/workerd-message-channel.d.ts +13 -0
- package/dist/project/workerd-message-channel.js +137 -0
- package/dist/project/workerd-message-channel.js.map +1 -0
- package/dist/project/workers-global-names.d.ts +6 -0
- package/dist/project/workers-global-names.js +15 -0
- package/dist/project/workers-global-names.js.map +1 -0
- package/dist/project/workers-globals-module.d.ts +8 -0
- package/dist/project/workers-globals-module.js +9 -0
- package/dist/project/workers-globals-module.js.map +1 -0
- package/dist/project/workers-globals.d.ts +9 -0
- package/dist/project/workers-globals.js +19 -0
- package/dist/project/workers-globals.js.map +1 -0
- package/dist/project/wrangler.d.ts +116 -0
- package/dist/project/wrangler.js +342 -0
- package/dist/project/wrangler.js.map +1 -0
- package/dist/router/cell-router.d.ts +72 -0
- package/dist/router/cell-router.js +247 -0
- package/dist/router/cell-router.js.map +1 -0
- package/dist/router/shard-worker.d.ts +44 -0
- package/dist/router/shard-worker.js +163 -0
- package/dist/router/shard-worker.js.map +1 -0
- package/dist/transport/cells-http.d.ts +25 -0
- package/dist/transport/cells-http.js +141 -0
- package/dist/transport/cells-http.js.map +1 -0
- package/dist/transport/cells-link.d.ts +27 -0
- package/dist/transport/cells-link.js +71 -0
- package/dist/transport/cells-link.js.map +1 -0
- package/dist/transport/port.d.ts +26 -0
- package/dist/transport/port.js +100 -0
- package/dist/transport/port.js.map +1 -0
- package/dist/v8/codec.d.ts +6 -0
- package/dist/v8/codec.js +9 -0
- package/dist/v8/codec.js.map +1 -0
- package/dist/v8/serialize.d.ts +10 -0
- package/dist/v8/serialize.js +601 -0
- package/dist/v8/serialize.js.map +1 -0
- package/dist/ws/client.d.ts +25 -0
- package/dist/ws/client.js +203 -0
- package/dist/ws/client.js.map +1 -0
- package/dist/ws/control.d.ts +48 -0
- package/dist/ws/control.js +44 -0
- package/dist/ws/control.js.map +1 -0
- package/dist/ws/frames.d.ts +38 -0
- package/dist/ws/frames.js +39 -0
- package/dist/ws/frames.js.map +1 -0
- package/dist/ws/server.d.ts +99 -0
- package/dist/ws/server.js +295 -0
- package/dist/ws/server.js.map +1 -0
- package/dist/ws/sw-connector.d.ts +10 -0
- package/dist/ws/sw-connector.js +25 -0
- package/dist/ws/sw-connector.js.map +1 -0
- package/dist/ws/upgrade.d.ts +28 -0
- package/dist/ws/upgrade.js +75 -0
- package/dist/ws/upgrade.js.map +1 -0
- package/package.json +111 -3
- package/vendor/celld/LICENSE +202 -0
- package/vendor/celld/kv.js +1131 -0
- package/vendor/celld/queues.js +1656 -0
- package/vendor/celld/workflows.js +1610 -0
- package/vendor/html-rewriter-wasm/html_rewriter.js +925 -0
- package/vendor/html-rewriter-wasm/html_rewriter_bg.wasm +0 -0
- package/vendor/miniflare/d1-api.js +738 -0
- package/vendor/miniflare/d1-database.js +6978 -0
- package/vendor/miniflare/kv-namespace.js +3061 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { Crc64 } from "./crc64.js";
|
|
2
|
+
import { CHECKSUM_FLAG, lockPgno } from "./ltx.js";
|
|
3
|
+
import { lz4Compress, lz4Decompress, lz4FrameDecompress } from "./lz4.js";
|
|
4
|
+
const HEADER_SIZE = 100;
|
|
5
|
+
const PAGE_HEADER_FLAG_SIZE = 1;
|
|
6
|
+
async function readRange(files, path, start, length) {
|
|
7
|
+
const chunks = [];
|
|
8
|
+
for await (const c of files.read(path, { start, length }))
|
|
9
|
+
chunks.push(c);
|
|
10
|
+
const got = chunks.reduce((n, c) => n + c.length, 0);
|
|
11
|
+
// A short read is a file that changed or went away under its reader: say which, rather than
|
|
12
|
+
// decode past its end ("Offset is outside the bounds of the DataView").
|
|
13
|
+
if (got !== length) {
|
|
14
|
+
const st = await files.stats(path).catch(() => undefined);
|
|
15
|
+
throw new LtxShortReadError(`ltx: short read of ${path}: ${got} of ${length} bytes at ${start} (file ${st?.kind === "file" ? `${st.size} bytes` : "missing"})`);
|
|
16
|
+
}
|
|
17
|
+
if (chunks.length === 1)
|
|
18
|
+
return chunks[0];
|
|
19
|
+
const out = new Uint8Array(got);
|
|
20
|
+
let o = 0;
|
|
21
|
+
for (const c of chunks)
|
|
22
|
+
out.set(c, o), (o += c.length);
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
/** A range read that got fewer bytes than asked: the file changed or was removed meanwhile. */
|
|
26
|
+
export class LtxShortReadError extends Error {
|
|
27
|
+
name = "LtxShortReadError";
|
|
28
|
+
}
|
|
29
|
+
/** Opens an LTX file for page reads: reads its header and its page index only. */
|
|
30
|
+
export async function openLtxPages(files, path,
|
|
31
|
+
/** The header and index of a file this process just wrote: nothing is read back. */
|
|
32
|
+
known) {
|
|
33
|
+
if (known)
|
|
34
|
+
return pagesOf(files, path, known.header, known.index);
|
|
35
|
+
const size = (await files.stats(path))?.kind === "file"
|
|
36
|
+
? (await files.stats(path)).size
|
|
37
|
+
: 0;
|
|
38
|
+
if (size < HEADER_SIZE + 6 + 24)
|
|
39
|
+
throw new Error(`ltx: ${path} is too small`);
|
|
40
|
+
const head = await readRange(files, path, 0, HEADER_SIZE);
|
|
41
|
+
const hv = new DataView(head.buffer, head.byteOffset, head.byteLength);
|
|
42
|
+
if (new TextDecoder().decode(head.subarray(0, 4)) !== "LTX1")
|
|
43
|
+
throw new Error(`ltx: ${path}: bad magic`);
|
|
44
|
+
const header = {
|
|
45
|
+
flags: hv.getUint32(4),
|
|
46
|
+
pageSize: hv.getUint32(8),
|
|
47
|
+
commit: hv.getUint32(12),
|
|
48
|
+
minTXID: hv.getBigUint64(16),
|
|
49
|
+
maxTXID: hv.getBigUint64(24),
|
|
50
|
+
timestamp: Number(hv.getBigInt64(32)),
|
|
51
|
+
preApplyChecksum: hv.getBigUint64(40),
|
|
52
|
+
};
|
|
53
|
+
// Trailer: … index | u64 index length | u64 post-apply checksum | u64 file checksum.
|
|
54
|
+
const tail = await readRange(files, path, size - 24, 24);
|
|
55
|
+
const idxLen = Number(new DataView(tail.buffer, tail.byteOffset, 24).getBigUint64(0));
|
|
56
|
+
const idx = await readRange(files, path, size - 24 - idxLen, idxLen);
|
|
57
|
+
const index = new Map();
|
|
58
|
+
let o = 0;
|
|
59
|
+
const varint = () => {
|
|
60
|
+
let x = 0;
|
|
61
|
+
let shift = 0;
|
|
62
|
+
let b;
|
|
63
|
+
do {
|
|
64
|
+
b = idx[o++];
|
|
65
|
+
x += (b & 0x7f) * 2 ** shift;
|
|
66
|
+
shift += 7;
|
|
67
|
+
} while (b & 0x80);
|
|
68
|
+
return x;
|
|
69
|
+
};
|
|
70
|
+
for (;;) {
|
|
71
|
+
const pgno = varint();
|
|
72
|
+
if (pgno === 0)
|
|
73
|
+
break;
|
|
74
|
+
const offset = varint();
|
|
75
|
+
index.set(pgno, [offset, varint()]);
|
|
76
|
+
}
|
|
77
|
+
return pagesOf(files, path, header, index);
|
|
78
|
+
}
|
|
79
|
+
function pagesOf(files, path, header, index) {
|
|
80
|
+
const decodePage = (b) => {
|
|
81
|
+
const v = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
|
82
|
+
if (v.getUint16(4) & PAGE_HEADER_FLAG_SIZE)
|
|
83
|
+
return lz4Decompress(b.subarray(10, 10 + v.getUint32(6)), header.pageSize);
|
|
84
|
+
return lz4FrameDecompress(b.subarray(6), header.pageSize);
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
path,
|
|
88
|
+
header,
|
|
89
|
+
index,
|
|
90
|
+
async readPage(pgno) {
|
|
91
|
+
const at = index.get(pgno);
|
|
92
|
+
if (!at)
|
|
93
|
+
return undefined;
|
|
94
|
+
return decodePage(await readRange(files, path, at[0], at[1]));
|
|
95
|
+
},
|
|
96
|
+
async readPages(pgnos) {
|
|
97
|
+
const out = new Map();
|
|
98
|
+
const wanted = pgnos.filter((p) => index.has(p));
|
|
99
|
+
if (!wanted.length)
|
|
100
|
+
return out;
|
|
101
|
+
const spans = wanted.map((p) => index.get(p));
|
|
102
|
+
const start = Math.min(...spans.map((s) => s[0]));
|
|
103
|
+
const end = Math.max(...spans.map((s) => s[0] + s[1]));
|
|
104
|
+
const b = await readRange(files, path, start, end - start);
|
|
105
|
+
for (const [i, p] of wanted.entries())
|
|
106
|
+
out.set(p, decodePage(b.subarray(spans[i][0] - start, spans[i][0] - start + spans[i][1])));
|
|
107
|
+
return out;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A cell's pages over its LTX files: the newest snapshot (min TXID 1) and the files after it,
|
|
113
|
+
* in TXID order. Only headers and page indexes are read.
|
|
114
|
+
*/
|
|
115
|
+
export async function openPagedCell(files, paths) {
|
|
116
|
+
const opened = await Promise.all(paths.map((p) => openLtxPages(files, p)));
|
|
117
|
+
opened.sort((a, b) => a.header.maxTXID < b.header.maxTXID ? -1 : a.header.maxTXID > b.header.maxTXID ? 1 : 0);
|
|
118
|
+
let snapshotAt = -1;
|
|
119
|
+
opened.forEach((f, i) => {
|
|
120
|
+
if (f.header.minTXID === 1n)
|
|
121
|
+
snapshotAt = i;
|
|
122
|
+
});
|
|
123
|
+
if (snapshotAt < 0)
|
|
124
|
+
throw new Error("ltx: no snapshot among the cell's files");
|
|
125
|
+
const chain = opened.slice(snapshotAt);
|
|
126
|
+
for (let i = 1; i < chain.length; i++)
|
|
127
|
+
if (chain[i].header.minTXID !== chain[i - 1].header.maxTXID + 1n)
|
|
128
|
+
throw new Error(`ltx: gap before ${chain[i].path}`);
|
|
129
|
+
let newest = chain[chain.length - 1].header;
|
|
130
|
+
const owner = new Map();
|
|
131
|
+
for (const f of chain)
|
|
132
|
+
for (const pgno of f.index.keys())
|
|
133
|
+
owner.set(pgno, f);
|
|
134
|
+
const cell = {
|
|
135
|
+
pageSize: newest.pageSize,
|
|
136
|
+
pageCount: newest.commit,
|
|
137
|
+
maxTXID: newest.maxTXID,
|
|
138
|
+
files: chain,
|
|
139
|
+
source: (pgno) => owner.get(pgno)?.path,
|
|
140
|
+
async readPage(pgno) {
|
|
141
|
+
const page = pgno <= cell.pageCount ? await owner.get(pgno)?.readPage(pgno) : undefined;
|
|
142
|
+
return page ?? new Uint8Array(cell.pageSize);
|
|
143
|
+
},
|
|
144
|
+
async readRun(from, count) {
|
|
145
|
+
const byFile = new Map();
|
|
146
|
+
const out = new Map();
|
|
147
|
+
for (let p = from; p < from + count && p <= cell.pageCount; p++) {
|
|
148
|
+
const f = owner.get(p);
|
|
149
|
+
if (!f)
|
|
150
|
+
out.set(p, new Uint8Array(cell.pageSize));
|
|
151
|
+
else
|
|
152
|
+
byFile.set(f, [...(byFile.get(f) ?? []), p]);
|
|
153
|
+
}
|
|
154
|
+
for (const [f, pgnos] of byFile)
|
|
155
|
+
for (const [p, d] of await f.readPages(pgnos))
|
|
156
|
+
out.set(p, d);
|
|
157
|
+
return out;
|
|
158
|
+
},
|
|
159
|
+
async append(path, known) {
|
|
160
|
+
const f = await openLtxPages(files, path, known);
|
|
161
|
+
if (f.header.minTXID !== cell.maxTXID + 1n)
|
|
162
|
+
throw new Error(`ltx: ${path} does not follow TXID ${cell.maxTXID}`);
|
|
163
|
+
chain.push(f);
|
|
164
|
+
for (const pgno of f.index.keys())
|
|
165
|
+
owner.set(pgno, f);
|
|
166
|
+
newest = f.header;
|
|
167
|
+
cell.pageCount = newest.commit;
|
|
168
|
+
cell.maxTXID = newest.maxTXID;
|
|
169
|
+
for (const [pgno] of owner)
|
|
170
|
+
if (pgno > cell.pageCount)
|
|
171
|
+
owner.delete(pgno);
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
return cell;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* An LTX file produced page by page, as celld writes it (block format: size-prefixed LZ4 page
|
|
178
|
+
* blocks, page index, trailer, CRC-64/ISO over the uncompressed pages): the bytes come out as an
|
|
179
|
+
* async stream while `pages` is consumed, so a writer holds one page at a time plus the index
|
|
180
|
+
* (a few bytes per page), never the database.
|
|
181
|
+
*/
|
|
182
|
+
export async function* encodeLtxStream(header, pages, postApplyChecksum = 0n,
|
|
183
|
+
/** Filled while encoding: the file's page index (what `openLtxPages` would read back). */
|
|
184
|
+
written) {
|
|
185
|
+
// Coalesced into 256 KiB chunks: a writer pays per call (an OPFS SyncAccessHandle write, a
|
|
186
|
+
// stream write), and a page makes three small pieces.
|
|
187
|
+
yield* coalesce(encodePieces(header, pages, postApplyChecksum, written), 256 * 1024);
|
|
188
|
+
}
|
|
189
|
+
async function* coalesce(src, size) {
|
|
190
|
+
let buf = new Uint8Array(size);
|
|
191
|
+
let n = 0;
|
|
192
|
+
for await (const piece of src) {
|
|
193
|
+
if (piece.length >= size) {
|
|
194
|
+
if (n)
|
|
195
|
+
yield buf.slice(0, n), (n = 0);
|
|
196
|
+
yield piece;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (n + piece.length > size) {
|
|
200
|
+
yield buf.slice(0, n);
|
|
201
|
+
buf = new Uint8Array(size);
|
|
202
|
+
n = 0;
|
|
203
|
+
}
|
|
204
|
+
buf.set(piece, n);
|
|
205
|
+
n += piece.length;
|
|
206
|
+
}
|
|
207
|
+
if (n)
|
|
208
|
+
yield buf.slice(0, n);
|
|
209
|
+
}
|
|
210
|
+
async function* encodePieces(header, pages, postApplyChecksum, written) {
|
|
211
|
+
const crc = new Crc64();
|
|
212
|
+
const head = new Uint8Array(HEADER_SIZE);
|
|
213
|
+
const v = new DataView(head.buffer);
|
|
214
|
+
head.set(new TextEncoder().encode("LTX1"), 0);
|
|
215
|
+
const flags = header.flags ?? (header.preApplyChecksum === 0n && postApplyChecksum === 0n ? 2 : 0);
|
|
216
|
+
v.setUint32(4, flags);
|
|
217
|
+
v.setUint32(8, header.pageSize);
|
|
218
|
+
v.setUint32(12, header.commit);
|
|
219
|
+
v.setBigUint64(16, header.minTXID);
|
|
220
|
+
v.setBigUint64(24, header.maxTXID);
|
|
221
|
+
v.setBigInt64(32, BigInt(header.timestamp));
|
|
222
|
+
v.setBigUint64(40, header.preApplyChecksum);
|
|
223
|
+
v.setBigUint64(72, header.nodeID ?? 0n);
|
|
224
|
+
crc.update(head);
|
|
225
|
+
yield head;
|
|
226
|
+
const index = [];
|
|
227
|
+
const uvarint = (n) => {
|
|
228
|
+
while (n >= 0x80)
|
|
229
|
+
index.push((n & 0x7f) | 0x80), (n = Math.floor(n / 128));
|
|
230
|
+
index.push(n);
|
|
231
|
+
};
|
|
232
|
+
let offset = HEADER_SIZE;
|
|
233
|
+
const lock = lockPgno(header.pageSize);
|
|
234
|
+
let last = 0;
|
|
235
|
+
for await (const [pgno, data] of pages) {
|
|
236
|
+
if (pgno === lock)
|
|
237
|
+
continue;
|
|
238
|
+
if (pgno <= last)
|
|
239
|
+
throw new Error("ltx: pages must come in ascending order");
|
|
240
|
+
last = pgno;
|
|
241
|
+
const compressed = lz4Compress(data);
|
|
242
|
+
const ph = new Uint8Array(10);
|
|
243
|
+
const pv = new DataView(ph.buffer);
|
|
244
|
+
pv.setUint32(0, pgno);
|
|
245
|
+
pv.setUint16(4, PAGE_HEADER_FLAG_SIZE);
|
|
246
|
+
pv.setUint32(6, compressed.length);
|
|
247
|
+
crc.update(ph).update(data); // the checksum covers uncompressed pages (encodeLtx's `feed`)
|
|
248
|
+
uvarint(pgno), uvarint(offset), uvarint(10 + compressed.length);
|
|
249
|
+
written?.index.set(pgno, [offset, 10 + compressed.length]);
|
|
250
|
+
offset += 10 + compressed.length;
|
|
251
|
+
yield ph;
|
|
252
|
+
yield compressed;
|
|
253
|
+
}
|
|
254
|
+
const end = new Uint8Array(6);
|
|
255
|
+
uvarint(0);
|
|
256
|
+
const idx = Uint8Array.from(index);
|
|
257
|
+
const tail = new Uint8Array(16);
|
|
258
|
+
const tv = new DataView(tail.buffer);
|
|
259
|
+
tv.setBigUint64(0, BigInt(idx.length));
|
|
260
|
+
tv.setBigUint64(8, postApplyChecksum);
|
|
261
|
+
crc.update(end).update(idx).update(tail);
|
|
262
|
+
const sum = new Uint8Array(8);
|
|
263
|
+
new DataView(sum.buffer).setBigUint64(0, CHECKSUM_FLAG | crc.digest());
|
|
264
|
+
yield end;
|
|
265
|
+
yield idx;
|
|
266
|
+
yield tail;
|
|
267
|
+
yield sum;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Folds a cell's files into one snapshot (TXID 1..maxTXID) written to `files` at `path`, page by
|
|
271
|
+
* page: each page is read by range from the file that holds it and streamed into the new file,
|
|
272
|
+
* so memory stays at one page (plus the index), whatever the database size. The caller removes
|
|
273
|
+
* the files it replaces once this resolves.
|
|
274
|
+
*/
|
|
275
|
+
export async function compactPagedCellTo(cell, files, path, timestamp = Date.now()) {
|
|
276
|
+
// In runs of 256 pages: one range read per file a run touches (not one read per page).
|
|
277
|
+
async function* pages() {
|
|
278
|
+
for (let from = 1; from <= cell.pageCount; from += 256) {
|
|
279
|
+
const run = await cell.readRun(from, 256);
|
|
280
|
+
for (let pgno = from; pgno < from + 256 && pgno <= cell.pageCount; pgno++)
|
|
281
|
+
yield [pgno, run.get(pgno) ?? new Uint8Array(cell.pageSize)];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
await files.write(path, encodeLtxStream({
|
|
285
|
+
pageSize: cell.pageSize,
|
|
286
|
+
commit: cell.pageCount,
|
|
287
|
+
minTXID: 1n,
|
|
288
|
+
maxTXID: cell.maxTXID,
|
|
289
|
+
timestamp,
|
|
290
|
+
preApplyChecksum: 0n,
|
|
291
|
+
}, pages()));
|
|
292
|
+
}
|
|
293
|
+
/** The compacted snapshot as bytes (small cells, tests); compactPagedCellTo streams it. */
|
|
294
|
+
export async function compactPagedCell(cell, timestamp = Date.now()) {
|
|
295
|
+
const chunks = [];
|
|
296
|
+
async function* pages() {
|
|
297
|
+
for (let pgno = 1; pgno <= cell.pageCount; pgno++)
|
|
298
|
+
yield [pgno, await cell.readPage(pgno)];
|
|
299
|
+
}
|
|
300
|
+
for await (const c of encodeLtxStream({
|
|
301
|
+
pageSize: cell.pageSize,
|
|
302
|
+
commit: cell.pageCount,
|
|
303
|
+
minTXID: 1n,
|
|
304
|
+
maxTXID: cell.maxTXID,
|
|
305
|
+
timestamp,
|
|
306
|
+
preApplyChecksum: 0n,
|
|
307
|
+
}, pages()))
|
|
308
|
+
chunks.push(c);
|
|
309
|
+
const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
|
|
310
|
+
let o = 0;
|
|
311
|
+
for (const c of chunks)
|
|
312
|
+
out.set(c, o), (o += c.length);
|
|
313
|
+
return out;
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=ltx-pages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ltx-pages.js","sourceRoot":"","sources":["../../src/ltx/ltx-pages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Page-level random access to a cell kept as celld keeps it: LTX files in a bucket\n * (`…/ltx/e<epoch>/<level>/<min>-<max>.ltx`), a snapshot (TXID 1..N) and the incremental files\n * after it. Nothing is read whole: an LTX file ends with a page index (pgno → offset, size), so\n * opening a file reads its 100-byte header and its index, and a page is ONE range read plus an\n * LZ4 decode. The newest file holding a page wins; `compact` folds them into a new snapshot.\n *\n * This is the read side a SQLite VFS needs to serve a database from any FilesApi (OPFS, File\n * System Access, IndexedDB, S3…) without loading it: xRead → `readPage` (through a page cache);\n * the write side is the existing LTX log (one incremental file per commit).\n */\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { Crc64 } from \"./crc64.js\";\nimport { CHECKSUM_FLAG, type LtxHeader, lockPgno } from \"./ltx.js\";\nimport { lz4Compress, lz4Decompress, lz4FrameDecompress } from \"./lz4.js\";\n\nconst HEADER_SIZE = 100;\nconst PAGE_HEADER_FLAG_SIZE = 1;\n\nasync function readRange(\n files: FilesApi,\n path: string,\n start: number,\n length: number,\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n for await (const c of files.read(path, { start, length })) chunks.push(c);\n const got = chunks.reduce((n, c) => n + c.length, 0);\n // A short read is a file that changed or went away under its reader: say which, rather than\n // decode past its end (\"Offset is outside the bounds of the DataView\").\n if (got !== length) {\n const st = await files.stats(path).catch(() => undefined);\n throw new LtxShortReadError(\n `ltx: short read of ${path}: ${got} of ${length} bytes at ${start} (file ${st?.kind === \"file\" ? `${(st as { size: number }).size} bytes` : \"missing\"})`,\n );\n }\n if (chunks.length === 1) return chunks[0];\n const out = new Uint8Array(got);\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n\n/** A range read that got fewer bytes than asked: the file changed or was removed meanwhile. */\nexport class LtxShortReadError extends Error {\n name = \"LtxShortReadError\";\n}\n\nexport interface LtxPages {\n path: string;\n header: LtxHeader;\n /** pgno → [offset of the page's 6-byte header, size including it]. */\n index: Map<number, [number, number]>;\n /** One range read and an LZ4 decode. */\n readPage(pgno: number): Promise<Uint8Array | undefined>;\n /** Several pages of this file with ONE range read (they are stored in pgno order). */\n readPages(pgnos: number[]): Promise<Map<number, Uint8Array>>;\n}\n\n/** Opens an LTX file for page reads: reads its header and its page index only. */\nexport async function openLtxPages(\n files: FilesApi,\n path: string,\n /** The header and index of a file this process just wrote: nothing is read back. */\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n): Promise<LtxPages> {\n if (known) return pagesOf(files, path, known.header, known.index);\n const size =\n (await files.stats(path))?.kind === \"file\"\n ? ((await files.stats(path)) as { size: number }).size\n : 0;\n if (size < HEADER_SIZE + 6 + 24) throw new Error(`ltx: ${path} is too small`);\n const head = await readRange(files, path, 0, HEADER_SIZE);\n const hv = new DataView(head.buffer, head.byteOffset, head.byteLength);\n if (new TextDecoder().decode(head.subarray(0, 4)) !== \"LTX1\")\n throw new Error(`ltx: ${path}: bad magic`);\n const header: LtxHeader = {\n flags: hv.getUint32(4),\n pageSize: hv.getUint32(8),\n commit: hv.getUint32(12),\n minTXID: hv.getBigUint64(16),\n maxTXID: hv.getBigUint64(24),\n timestamp: Number(hv.getBigInt64(32)),\n preApplyChecksum: hv.getBigUint64(40),\n };\n // Trailer: … index | u64 index length | u64 post-apply checksum | u64 file checksum.\n const tail = await readRange(files, path, size - 24, 24);\n const idxLen = Number(new DataView(tail.buffer, tail.byteOffset, 24).getBigUint64(0));\n const idx = await readRange(files, path, size - 24 - idxLen, idxLen);\n const index = new Map<number, [number, number]>();\n let o = 0;\n const varint = () => {\n let x = 0;\n let shift = 0;\n let b: number;\n do {\n b = idx[o++];\n x += (b & 0x7f) * 2 ** shift;\n shift += 7;\n } while (b & 0x80);\n return x;\n };\n for (;;) {\n const pgno = varint();\n if (pgno === 0) break;\n const offset = varint();\n index.set(pgno, [offset, varint()]);\n }\n return pagesOf(files, path, header, index);\n}\n\nfunction pagesOf(\n files: FilesApi,\n path: string,\n header: LtxHeader,\n index: Map<number, [number, number]>,\n): LtxPages {\n const decodePage = (b: Uint8Array) => {\n const v = new DataView(b.buffer, b.byteOffset, b.byteLength);\n if (v.getUint16(4) & PAGE_HEADER_FLAG_SIZE)\n return lz4Decompress(b.subarray(10, 10 + v.getUint32(6)), header.pageSize);\n return lz4FrameDecompress(b.subarray(6), header.pageSize);\n };\n return {\n path,\n header,\n index,\n async readPage(pgno) {\n const at = index.get(pgno);\n if (!at) return undefined;\n return decodePage(await readRange(files, path, at[0], at[1]));\n },\n async readPages(pgnos) {\n const out = new Map<number, Uint8Array>();\n const wanted = pgnos.filter((p) => index.has(p));\n if (!wanted.length) return out;\n const spans = wanted.map((p) => index.get(p) as [number, number]);\n const start = Math.min(...spans.map((s) => s[0]));\n const end = Math.max(...spans.map((s) => s[0] + s[1]));\n const b = await readRange(files, path, start, end - start);\n for (const [i, p] of wanted.entries())\n out.set(p, decodePage(b.subarray(spans[i][0] - start, spans[i][0] - start + spans[i][1])));\n return out;\n },\n };\n}\n\nexport interface PagedCell {\n pageSize: number;\n /** Database size in pages, after the newest file. */\n pageCount: number;\n maxTXID: bigint;\n /** The files, oldest first (the snapshot, then the incremental ones). */\n files: LtxPages[];\n /** The page as of the newest file holding it (zeros past the database end). */\n readPage(pgno: number): Promise<Uint8Array>;\n /** Pages `from`..`from+count-1` (within the database), one range read per file they live in. */\n readRun(from: number, count: number): Promise<Map<number, Uint8Array>>;\n /** Which file serves each page (for tests and traces). */\n source(pgno: number): string | undefined;\n /**\n * Adds the cell's next file (the one just written after `maxTXID`): reads its header and index\n * only, so a commit costs one file whatever the number of files before it.\n */\n append(\n path: string,\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n ): Promise<void>;\n}\n\n/**\n * A cell's pages over its LTX files: the newest snapshot (min TXID 1) and the files after it,\n * in TXID order. Only headers and page indexes are read.\n */\nexport async function openPagedCell(files: FilesApi, paths: string[]): Promise<PagedCell> {\n const opened = await Promise.all(paths.map((p) => openLtxPages(files, p)));\n opened.sort((a, b) =>\n a.header.maxTXID < b.header.maxTXID ? -1 : a.header.maxTXID > b.header.maxTXID ? 1 : 0,\n );\n let snapshotAt = -1;\n opened.forEach((f, i) => {\n if (f.header.minTXID === 1n) snapshotAt = i;\n });\n if (snapshotAt < 0) throw new Error(\"ltx: no snapshot among the cell's files\");\n const chain = opened.slice(snapshotAt);\n for (let i = 1; i < chain.length; i++)\n if (chain[i].header.minTXID !== chain[i - 1].header.maxTXID + 1n)\n throw new Error(`ltx: gap before ${chain[i].path}`);\n let newest = chain[chain.length - 1].header;\n const owner = new Map<number, LtxPages>();\n for (const f of chain) for (const pgno of f.index.keys()) owner.set(pgno, f);\n const cell: PagedCell = {\n pageSize: newest.pageSize,\n pageCount: newest.commit,\n maxTXID: newest.maxTXID,\n files: chain,\n source: (pgno) => owner.get(pgno)?.path,\n async readPage(pgno) {\n const page = pgno <= cell.pageCount ? await owner.get(pgno)?.readPage(pgno) : undefined;\n return page ?? new Uint8Array(cell.pageSize);\n },\n async readRun(from, count) {\n const byFile = new Map<LtxPages, number[]>();\n const out = new Map<number, Uint8Array>();\n for (let p = from; p < from + count && p <= cell.pageCount; p++) {\n const f = owner.get(p);\n if (!f) out.set(p, new Uint8Array(cell.pageSize));\n else byFile.set(f, [...(byFile.get(f) ?? []), p]);\n }\n for (const [f, pgnos] of byFile) for (const [p, d] of await f.readPages(pgnos)) out.set(p, d);\n return out;\n },\n async append(path, known) {\n const f = await openLtxPages(files, path, known);\n if (f.header.minTXID !== cell.maxTXID + 1n)\n throw new Error(`ltx: ${path} does not follow TXID ${cell.maxTXID}`);\n chain.push(f);\n for (const pgno of f.index.keys()) owner.set(pgno, f);\n newest = f.header;\n cell.pageCount = newest.commit;\n cell.maxTXID = newest.maxTXID;\n for (const [pgno] of owner) if (pgno > cell.pageCount) owner.delete(pgno);\n },\n };\n return cell;\n}\n\n/**\n * An LTX file produced page by page, as celld writes it (block format: size-prefixed LZ4 page\n * blocks, page index, trailer, CRC-64/ISO over the uncompressed pages): the bytes come out as an\n * async stream while `pages` is consumed, so a writer holds one page at a time plus the index\n * (a few bytes per page), never the database.\n */\nexport async function* encodeLtxStream(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum = 0n,\n /** Filled while encoding: the file's page index (what `openLtxPages` would read back). */\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n // Coalesced into 256 KiB chunks: a writer pays per call (an OPFS SyncAccessHandle write, a\n // stream write), and a page makes three small pieces.\n yield* coalesce(encodePieces(header, pages, postApplyChecksum, written), 256 * 1024);\n}\n\nasync function* coalesce(src: AsyncIterable<Uint8Array>, size: number): AsyncGenerator<Uint8Array> {\n let buf = new Uint8Array(size);\n let n = 0;\n for await (const piece of src) {\n if (piece.length >= size) {\n if (n) yield buf.slice(0, n), (n = 0);\n yield piece;\n continue;\n }\n if (n + piece.length > size) {\n yield buf.slice(0, n);\n buf = new Uint8Array(size);\n n = 0;\n }\n buf.set(piece, n);\n n += piece.length;\n }\n if (n) yield buf.slice(0, n);\n}\n\nasync function* encodePieces(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum: bigint,\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n const crc = new Crc64();\n const head = new Uint8Array(HEADER_SIZE);\n const v = new DataView(head.buffer);\n head.set(new TextEncoder().encode(\"LTX1\"), 0);\n const flags =\n header.flags ?? (header.preApplyChecksum === 0n && postApplyChecksum === 0n ? 2 : 0);\n v.setUint32(4, flags);\n v.setUint32(8, header.pageSize);\n v.setUint32(12, header.commit);\n v.setBigUint64(16, header.minTXID);\n v.setBigUint64(24, header.maxTXID);\n v.setBigInt64(32, BigInt(header.timestamp));\n v.setBigUint64(40, header.preApplyChecksum);\n v.setBigUint64(72, header.nodeID ?? 0n);\n crc.update(head);\n yield head;\n const index: number[] = [];\n const uvarint = (n: number) => {\n while (n >= 0x80) index.push((n & 0x7f) | 0x80), (n = Math.floor(n / 128));\n index.push(n);\n };\n let offset = HEADER_SIZE;\n const lock = lockPgno(header.pageSize);\n let last = 0;\n for await (const [pgno, data] of pages) {\n if (pgno === lock) continue;\n if (pgno <= last) throw new Error(\"ltx: pages must come in ascending order\");\n last = pgno;\n const compressed = lz4Compress(data);\n const ph = new Uint8Array(10);\n const pv = new DataView(ph.buffer);\n pv.setUint32(0, pgno);\n pv.setUint16(4, PAGE_HEADER_FLAG_SIZE);\n pv.setUint32(6, compressed.length);\n crc.update(ph).update(data); // the checksum covers uncompressed pages (encodeLtx's `feed`)\n uvarint(pgno), uvarint(offset), uvarint(10 + compressed.length);\n written?.index.set(pgno, [offset, 10 + compressed.length]);\n offset += 10 + compressed.length;\n yield ph;\n yield compressed;\n }\n const end = new Uint8Array(6);\n uvarint(0);\n const idx = Uint8Array.from(index);\n const tail = new Uint8Array(16);\n const tv = new DataView(tail.buffer);\n tv.setBigUint64(0, BigInt(idx.length));\n tv.setBigUint64(8, postApplyChecksum);\n crc.update(end).update(idx).update(tail);\n const sum = new Uint8Array(8);\n new DataView(sum.buffer).setBigUint64(0, CHECKSUM_FLAG | crc.digest());\n yield end;\n yield idx;\n yield tail;\n yield sum;\n}\n\n/**\n * Folds a cell's files into one snapshot (TXID 1..maxTXID) written to `files` at `path`, page by\n * page: each page is read by range from the file that holds it and streamed into the new file,\n * so memory stays at one page (plus the index), whatever the database size. The caller removes\n * the files it replaces once this resolves.\n */\nexport async function compactPagedCellTo(\n cell: PagedCell,\n files: FilesApi,\n path: string,\n timestamp = Date.now(),\n): Promise<void> {\n // In runs of 256 pages: one range read per file a run touches (not one read per page).\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let from = 1; from <= cell.pageCount; from += 256) {\n const run = await cell.readRun(from, 256);\n for (let pgno = from; pgno < from + 256 && pgno <= cell.pageCount; pgno++)\n yield [pgno, run.get(pgno) ?? new Uint8Array(cell.pageSize)];\n }\n }\n await files.write(\n path,\n encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ),\n );\n}\n\n/** The compacted snapshot as bytes (small cells, tests); compactPagedCellTo streams it. */\nexport async function compactPagedCell(\n cell: PagedCell,\n timestamp = Date.now(),\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let pgno = 1; pgno <= cell.pageCount; pgno++) yield [pgno, await cell.readPage(pgno)];\n }\n for await (const c of encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ))\n chunks.push(c);\n const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/// <reference lib="webworker" />
|
|
2
|
+
/**
|
|
3
|
+
* The LTX store as a worker of its own (spawned by a shard worker that runs cells on the LTX
|
|
4
|
+
* VFS): cells' LTX files in an OPFS directory, in celld's layout. The shard connects with
|
|
5
|
+
* `{ op: "init", sab, dir, compactAfter }`, then sends the VFS's requests; answers go into
|
|
6
|
+
* the shared buffer.
|
|
7
|
+
*/
|
|
8
|
+
import { BrowserFilesApi } from "@statewalker/webrun-files-browser";
|
|
9
|
+
import { MemFilesApi } from "@statewalker/webrun-files-mem";
|
|
10
|
+
import { ltxCellStore } from "./ltx-page-server.js";
|
|
11
|
+
import { opfsSyncFiles } from "./opfs-sync-files.js";
|
|
12
|
+
let store;
|
|
13
|
+
let ready;
|
|
14
|
+
self.onmessage = (e) => {
|
|
15
|
+
const m = e.data;
|
|
16
|
+
if (m?.op === "init") {
|
|
17
|
+
ready = (async () => {
|
|
18
|
+
// The cells' FilesApi, by name (an instance cannot cross to this worker): "opfs-sync"
|
|
19
|
+
// (default: synchronous handles; each file written under a temporary name and moved into
|
|
20
|
+
// place, so a file being written is never read), "opfs" (OPFS's asynchronous API),
|
|
21
|
+
// "memory" (nothing kept).
|
|
22
|
+
const files = m.files === "memory"
|
|
23
|
+
? new MemFilesApi()
|
|
24
|
+
: await (async () => {
|
|
25
|
+
const root = await navigator.storage.getDirectory();
|
|
26
|
+
const dir = await root.getDirectoryHandle(m.dir, { create: true });
|
|
27
|
+
return m.files === "opfs"
|
|
28
|
+
? new BrowserFilesApi({ rootHandle: dir })
|
|
29
|
+
: opfsSyncFiles(dir);
|
|
30
|
+
})();
|
|
31
|
+
store = ltxCellStore(files, m.sab, { compactAfter: m.compactAfter, lockScope: m.dir });
|
|
32
|
+
postMessage({ op: "ready" });
|
|
33
|
+
})();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
void ready?.then(() => store?.handle(m));
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=ltx-store-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ltx-store-worker.js","sourceRoot":"","sources":["../../src/ltx/ltx-store-worker.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,IAAI,KAAkD,CAAC;AACvD,IAAI,KAAgC,CAAC;AACrC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAe,EAAE,EAAE;IACnC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QACrB,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE;YAClB,sFAAsF;YACtF,yFAAyF;YACzF,mFAAmF;YACnF,2BAA2B;YAC3B,MAAM,KAAK,GACT,CAAC,CAAC,KAAK,KAAK,QAAQ;gBAClB,CAAC,CAAC,IAAI,WAAW,EAAE;gBACnB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;oBAChB,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;oBACpD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnE,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM;wBACvB,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;wBAC1C,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC;YACX,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACvF,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,EAAE,CAAC;QACL,OAAO;IACT,CAAC;IACD,KAAK,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC","sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * The LTX store as a worker of its own (spawned by a shard worker that runs cells on the LTX\n * VFS): cells' LTX files in an OPFS directory, in celld's layout. The shard connects with\n * `{ op: \"init\", sab, dir, compactAfter }`, then sends the VFS's requests; answers go into\n * the shared buffer.\n */\nimport { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { MemFilesApi } from \"@statewalker/webrun-files-mem\";\nimport { ltxCellStore } from \"./ltx-page-server.js\";\nimport { opfsSyncFiles } from \"./opfs-sync-files.js\";\n\nlet store: ReturnType<typeof ltxCellStore> | undefined;\nlet ready: Promise<void> | undefined;\nself.onmessage = (e: MessageEvent) => {\n const m = e.data;\n if (m?.op === \"init\") {\n ready = (async () => {\n // The cells' FilesApi, by name (an instance cannot cross to this worker): \"opfs-sync\"\n // (default: synchronous handles; each file written under a temporary name and moved into\n // place, so a file being written is never read), \"opfs\" (OPFS's asynchronous API),\n // \"memory\" (nothing kept).\n const files =\n m.files === \"memory\"\n ? new MemFilesApi()\n : await (async () => {\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(m.dir, { create: true });\n return m.files === \"opfs\"\n ? new BrowserFilesApi({ rootHandle: dir })\n : opfsSyncFiles(dir);\n })();\n store = ltxCellStore(files, m.sab, { compactAfter: m.compactAfter, lockScope: m.dir });\n postMessage({ op: \"ready\" });\n })();\n return;\n }\n void ready?.then(() => store?.handle(m));\n};\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LTX v3 (superfly/ltx v0.5.2), byte for byte as celld writes it — see
|
|
3
|
+
* crates/ltx/reference/ltx-format.md in denoland/celld. Big-endian integers, 100-byte
|
|
4
|
+
* header, size-prefixed LZ4 page blocks, page index, 16-byte trailer, CRC-64/ISO checksums
|
|
5
|
+
* with the top bit always set.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CHECKSUM_FLAG: bigint;
|
|
8
|
+
/** Header flag: the file carries no rolling database checksums (what celld 0.6.2 writes). */
|
|
9
|
+
export declare const HEADER_FLAG_NO_CHECKSUM: number;
|
|
10
|
+
export interface LtxHeader {
|
|
11
|
+
/** Header flags; defaults to NO_CHECKSUM when both rolling checksums are 0 (celld's files). */
|
|
12
|
+
flags?: number;
|
|
13
|
+
/** WAL position the file was cut from (litestream WAL mode; 0 in journal mode). */
|
|
14
|
+
walOffset?: bigint;
|
|
15
|
+
walSize?: bigint;
|
|
16
|
+
walSalt1?: number;
|
|
17
|
+
walSalt2?: number;
|
|
18
|
+
pageSize: number;
|
|
19
|
+
/** Database size after the transaction, in pages. */
|
|
20
|
+
commit: number;
|
|
21
|
+
minTXID: bigint;
|
|
22
|
+
maxTXID: bigint;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
preApplyChecksum: bigint;
|
|
25
|
+
nodeID?: bigint;
|
|
26
|
+
}
|
|
27
|
+
export interface LtxFile {
|
|
28
|
+
header: LtxHeader;
|
|
29
|
+
/** pgno → page bytes, ascending. */
|
|
30
|
+
pages: Map<number, Uint8Array>;
|
|
31
|
+
postApplyChecksum: bigint;
|
|
32
|
+
}
|
|
33
|
+
/** The SQLite lock page (never stored, excluded from checksums). */
|
|
34
|
+
export declare const lockPgno: (pageSize: number) => number;
|
|
35
|
+
export declare const checksumPage: (pgno: number, data: Uint8Array) => bigint;
|
|
36
|
+
/** Rolling database checksum over pages 1..n (lock page excluded). */
|
|
37
|
+
export declare function databaseChecksum(pageSize: number, pageAt: (pgno: number) => Uint8Array, n: number): bigint;
|
|
38
|
+
/**
|
|
39
|
+
* `format: "legacy"` (default) writes one LZ4 frame per page, as celld 0.6.2 does; `"block"`
|
|
40
|
+
* writes v0.5.2's size-prefixed blocks (celld's decoder accepts both).
|
|
41
|
+
*/
|
|
42
|
+
export declare function encodeLtx(file: LtxFile, format?: "legacy" | "block"): Uint8Array;
|
|
43
|
+
export declare function decodeLtx(bytes: Uint8Array): LtxFile;
|
|
44
|
+
/** `<minTXID:016x>-<maxTXID:016x>.ltx` */
|
|
45
|
+
export declare const ltxFileName: (min: bigint, max: bigint) => string;
|