@optimystic/db-p2p-storage-fs 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +142 -33
  2. package/dist/src/file-batch-backend.d.ts +69 -0
  3. package/dist/src/file-batch-backend.d.ts.map +1 -0
  4. package/dist/src/file-batch-backend.js +400 -0
  5. package/dist/src/file-batch-backend.js.map +1 -0
  6. package/dist/src/file-kv-store.d.ts +37 -3
  7. package/dist/src/file-kv-store.d.ts.map +1 -1
  8. package/dist/src/file-kv-store.js +100 -34
  9. package/dist/src/file-kv-store.js.map +1 -1
  10. package/dist/src/file-storage.d.ts +20 -58
  11. package/dist/src/file-storage.d.ts.map +1 -1
  12. package/dist/src/file-storage.js +16 -430
  13. package/dist/src/file-storage.js.map +1 -1
  14. package/dist/src/file-write-log.d.ts +361 -0
  15. package/dist/src/file-write-log.d.ts.map +1 -0
  16. package/dist/src/file-write-log.js +848 -0
  17. package/dist/src/file-write-log.js.map +1 -0
  18. package/dist/src/index.d.ts +3 -0
  19. package/dist/src/index.d.ts.map +1 -1
  20. package/dist/src/index.js +3 -0
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/store-lock.d.ts +42 -0
  23. package/dist/src/store-lock.d.ts.map +1 -0
  24. package/dist/src/store-lock.js +116 -0
  25. package/dist/src/store-lock.js.map +1 -0
  26. package/package.json +3 -3
  27. package/src/file-batch-backend.ts +430 -0
  28. package/src/file-kv-store.ts +112 -32
  29. package/src/file-storage.ts +22 -468
  30. package/src/file-write-log.ts +906 -0
  31. package/src/index.ts +3 -0
  32. package/src/store-lock.ts +123 -0
  33. package/dist/src/atomic-write.d.ts +0 -22
  34. package/dist/src/atomic-write.d.ts.map +0 -1
  35. package/dist/src/atomic-write.js +0 -90
  36. package/dist/src/atomic-write.js.map +0 -1
  37. package/src/atomic-write.ts +0 -89
@@ -1 +1 @@
1
- {"version":3,"file":"file-kv-store.js","sourceRoot":"","sources":["../../src/file-kv-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-kv-store.js","sourceRoot":"","sources":["../../src/file-kv-store.ts"],"names":[],"mappings":"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"}
@@ -1,69 +1,31 @@
1
- import type { BlockId, ActionId } from "@optimystic/db-core";
2
- import { KvRawStorage, type RawStoreDriver, type StoreIdentity } from "@optimystic/db-p2p";
1
+ import type { BlockId } from "@optimystic/db-core";
2
+ import { KvRawStorage, type StoreIdentity, type WriteGroupOptions } from "@optimystic/db-p2p";
3
+ import type { FileWriteLogOptions } from './file-write-log.js';
3
4
  /**
4
- * Filesystem {@link RawStoreDriver}: the six logical block-storage stores mapped
5
- * to six paths under `basePath/<blockId>/`
6
- * (`{meta.json,revs/,pend/,actions/,proofs/,blocks/}`). The directory tree is a
7
- * deliberate, human-inspectable/debuggable layout — it is NOT flattened into
8
- * encoded-filename KV keys.
9
- *
10
- * `KvRawStorage` now owns all JSON serialization, so this driver reads/writes raw
11
- * `Uint8Array` bytes and never does `JSON.stringify/parse` on values. Everything
12
- * else fs-specific lives here: atomic (temp-file + rename) writes, the
13
- * corrupt-content-as-missing read guard, colon-encoded action-id filenames with
14
- * the legacy raw-colon read fallback + win32 guards, and rename-based promote.
5
+ * The write group's `idleFlushMs` and the directory log's `checkpointBytes` and `checkpointIdleMs`
6
+ * (see `WriteGroupOptions` and `FileWriteLogOptions`); the test-only `setTimer` arms both.
15
7
  */
16
- export declare class FileStoreDriver implements RawStoreDriver {
17
- private readonly basePath;
18
- private readonly identity;
19
- constructor(basePath: string);
20
- storeIdentity(): StoreIdentity;
21
- getMetadata(blockId: BlockId): Promise<Uint8Array | undefined>;
22
- putMetadata(blockId: BlockId, value: Uint8Array): Promise<void>;
23
- getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
24
- putRevision(blockId: BlockId, rev: number, value: Uint8Array): Promise<void>;
25
- rangeRevisions(blockId: BlockId, lo: number, hi: number, reverse: boolean): AsyncIterable<[number, Uint8Array]>;
26
- getPending(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
27
- putPending(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
28
- deletePending(blockId: BlockId, actionId: ActionId): Promise<void>;
29
- listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId>;
30
- getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
31
- putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
32
- getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
33
- putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void>;
34
- getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
35
- putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
36
- deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void>;
37
- promote(blockId: BlockId, actionId: ActionId): Promise<void>;
38
- listBlockIds(): AsyncIterable<BlockId>;
39
- approximateBytesUsed(): Promise<number>;
40
- private directoryByteSize;
41
- private getBlockPath;
42
- private getMetadataPath;
43
- private getRevisionPath;
44
- private getProofPath;
45
- private getPendingActionPath;
46
- private getActionPath;
47
- private getMaterializedPath;
48
- private unlinkRawColon;
49
- private readActionScopedBytes;
50
- private readBytesIfExists;
51
- }
8
+ export type FileRawStorageOptions = WriteGroupOptions & FileWriteLogOptions;
52
9
  /**
53
- * Filesystem-backed {@link IRawStorage}, now a thin shell over the shared
54
- * {@link KvRawStorage} kernel driven by a {@link FileStoreDriver}. The public
55
- * name/constructor (`new FileRawStorage(basePath)`) is unchanged so existing
56
- * imports keep resolving; the kernel supplies the `IRawStorage` surface and the
57
- * driver supplies fs behavior.
10
+ * Filesystem-backed {@link IRawStorage}: the shared {@link KvRawStorage} kernel over a
11
+ * {@link WriteGroupDriver} over a {@link FileBatchBackend}. Every write resolves into the driver's
12
+ * in-memory overlay; `flush()` hands the group to the backend as one batch, which appends it to
13
+ * `<basePath>/write-ahead.log` with one sync and then writes the tree. The public constructor
14
+ * (`new FileRawStorage(basePath, options?)`) is synchronous: the lock is taken and the log replayed
15
+ * on the first operation.
58
16
  *
59
- * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity` are re-declared here as
60
- * always-present (the fs driver always implements them, so the kernel constructor always
61
- * wires them) — the base declares them optional, but every fs consumer relies on them.
17
+ * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity`/`close` are re-declared here as
18
+ * always-present (the fs backend always implements the first three, so the driver and kernel always
19
+ * wire them, and the driver always has a `close`) — the base declares them optional, but every fs
20
+ * consumer relies on them. `close()` flushes what is still held, releases this store's reference to
21
+ * the directory's shared log, and — for the last store over the directory — checkpoints the log,
22
+ * closes it and removes the lock.
62
23
  */
63
24
  export declare class FileRawStorage extends KvRawStorage {
64
25
  listBlockIds: () => AsyncIterable<BlockId>;
65
26
  getApproximateBytesUsed: () => Promise<number>;
66
27
  getStoreIdentity: () => StoreIdentity;
67
- constructor(basePath: string);
28
+ close: () => Promise<void>;
29
+ constructor(basePath: string, options?: FileRawStorageOptions);
68
30
  }
69
31
  //# sourceMappingURL=file-storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA0C3F;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,YAAW,cAAc;IAGzC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAEZ,QAAQ,EAAE,MAAM;IAkC7C,aAAa,IAAI,aAAa;IAMxB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI9D,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/D,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI3E,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAuBhH,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOjF,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IASjE,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC;IA8ChE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOrF,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtF,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAIxE,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzE,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOtF,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvF,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB3D,YAAY,IAAI,aAAa,CAAC,OAAO,CAAC;IAgDvC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;YAI/B,iBAAiB;IA6B/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,mBAAmB;YASb,cAAc;YAsBd,qBAAqB;YAcrB,iBAAiB;CAc/B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,YAAY;IACvC,YAAY,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3C,uBAAuB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,gBAAgB,EAAE,MAAM,aAAa,CAAC;gBAElC,QAAQ,EAAE,MAAM;CAG5B"}
1
+ {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAoB,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEhH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAE5E;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,SAAQ,YAAY;IACvC,YAAY,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3C,uBAAuB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBAEvB,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B;CAGjE"}
@@ -1,437 +1,23 @@
1
- import { promises as fs } from 'fs';
2
- import * as path from 'path';
3
- import { KvRawStorage } from "@optimystic/db-p2p";
4
- import { createLogger } from './logger.js';
5
- import { atomicWriteFile } from './atomic-write.js';
6
- const log = createLogger('storage:file');
7
- // Built on first use rather than at module load, like every other `TextDecoder` in library source
8
- // (see NO_MODULE_SCOPE_TEXT_DECODER in eslint.config.js). Harmless on Node; kept uniform so the lint
9
- // rule needs no per-package exemption.
10
- let decoderInstance;
11
- const decoder = () => decoderInstance ??= new TextDecoder();
12
- // Colons are illegal in Windows filenames; encode them so action ids like
13
- // `tx:<hash>` and `stamp:<hash>` round-trip safely on all platforms.
14
- function encodeActionIdForFilename(actionId) {
15
- return actionId.replace(/:/g, '%3A');
16
- }
17
- function decodeFilenameToActionId(filename) {
18
- return filename.replace(/%3A/g, ':');
19
- }
20
- // A torn write leaves valid-prefix JSON cut off mid-token — JSON.parse throws
21
- // SyntaxError. Used as the "corrupt content → treat as missing" guard so a
22
- // crash-truncated file reads as absent (letting recover() make progress) instead
23
- // of surfacing a parse error forever. Only the JSON-valued stores use this; the
24
- // revisions store holds a bare ActionId string (not JSON) and is never guarded.
25
- // NOTE: every guarded read parses the JSON here (validate, discard) and the kernel's
26
- // decodeJson parses the same bytes AGAIN to build the value — 2× parse per get. The
27
- // guard is intrinsic to the driver's "corrupt→missing" contract (the kernel can't
28
- // express it), so it can't simply be dropped. Fine at current read volumes; if a read
29
- // path ever shows up hot, parse once and thread the parsed value through the driver.
30
- function isParseableJson(bytes) {
31
- try {
32
- JSON.parse(decoder().decode(bytes));
33
- return true;
34
- }
35
- catch (err) {
36
- if (err instanceof SyntaxError)
37
- return false;
38
- throw err;
39
- }
40
- }
41
- /**
42
- * Filesystem {@link RawStoreDriver}: the six logical block-storage stores mapped
43
- * to six paths under `basePath/<blockId>/`
44
- * (`{meta.json,revs/,pend/,actions/,proofs/,blocks/}`). The directory tree is a
45
- * deliberate, human-inspectable/debuggable layout — it is NOT flattened into
46
- * encoded-filename KV keys.
47
- *
48
- * `KvRawStorage` now owns all JSON serialization, so this driver reads/writes raw
49
- * `Uint8Array` bytes and never does `JSON.stringify/parse` on values. Everything
50
- * else fs-specific lives here: atomic (temp-file + rename) writes, the
51
- * corrupt-content-as-missing read guard, colon-encoded action-id filenames with
52
- * the legacy raw-colon read fallback + win32 guards, and rename-based promote.
53
- */
54
- export class FileStoreDriver {
55
- basePath;
56
- identity;
57
- constructor(basePath) {
58
- this.basePath = basePath;
59
- // TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
60
- // The directory this driver is backed by, resolved once here: `path.resolve` is
61
- // cwd-dependent, and capturing it at construction is the correct reading — two drivers
62
- // built from the same RELATIVE path under different cwds genuinely address different
63
- // directories and must not compare equal. An empty basePath resolves to the cwd;
64
- // nothing special-cases it. (A whitespace-only basePath is NOT the cwd — `path.resolve`
65
- // is pure string work, so `' '` names a child directory called `' '`.)
66
- // Lowercased on win32 because Windows paths are case-insensitive: `C:\Foo` and `C:\foo`
67
- // are one directory and must produce one identity.
68
- // NOTE: aliases of one directory that this does NOT collapse, and so read as two
69
- // identities: symlinks, junctions, UNC-versus-mapped-drive spellings, and case-differing
70
- // spellings on a case-INSENSITIVE non-Windows volume (the default on macOS) — platform is
71
- // the only signal available synchronously, and case-folding every darwin path would be
72
- // wrong on a case-sensitive volume. `fs.realpath` resolves all of these, but it is async
73
- // (this constructor is not) and requires the directory to already exist. Revisit if an
74
- // alias ever bites. All of these fail in the SAFE direction: a missed alias reports two
75
- // identities for one directory, so an identity-keyed consumer declines to merge and gets
76
- // today's behavior.
77
- // NOTE: the win32 fold is the one branch that can err in the UNSAFE direction — Windows
78
- // 10+ supports per-directory case sensitivity (`fsutil file setCaseSensitiveInfo`), and
79
- // on such a directory `X:\p\Foo` and `X:\p\foo` are two directories folded onto ONE
80
- // identity. That merging consumer now exists — `withReadCache` (db-p2p) shares ONE read
81
- // cache per identity — so on such a directory the two stores would read through one cache
82
- // and see each other's blocks, and if the second cache is built directly rather than
83
- // through that helper, `SharedCachePool.registerStore` refuses it outright (one cache per
84
- // backing store) and construction throws. Not addressable synchronously either (the flag is a
85
- // per-directory filesystem query). Revisit if Optimystic ever targets a
86
- // case-sensitive-enabled Windows directory; until then the fold is right for every
87
- // ordinary Windows volume.
88
- const resolved = path.resolve(basePath);
89
- this.identity = `file:${process.platform === 'win32' ? resolved.toLowerCase() : resolved}`;
90
- }
91
- storeIdentity() {
92
- return this.identity;
93
- }
94
- // --- metadata ---
95
- async getMetadata(blockId) {
96
- return this.readBytesIfExists(this.getMetadataPath(blockId), true);
97
- }
98
- async putMetadata(blockId, value) {
99
- await atomicWriteFile(this.getMetadataPath(blockId), value);
100
- }
101
- // --- revisions ---
102
- // The revisions store value is a bare ActionId string (kernel `encodeActionId`,
103
- // NOT JSON), so it is read WITHOUT the JSON guard — any bytes are a valid string
104
- // and `decodeActionId` never throws.
105
- // NOTE: because there is no guard here, a *torn* revision file reads back as a wrong
106
- // (truncated) ActionId rather than as missing — unlike the JSON stores, which torn-read
107
- // as undefined. Atomic writes (temp+rename) make a new torn revision impossible; only a
108
- // legacy pre-atomic-write torn rev could hit this, and recover() re-derives revisions
109
- // from the actions store anyway. If revisions ever move to a non-atomic writer, add a
110
- // checksum/length guard here.
111
- async getRevision(blockId, rev) {
112
- return this.readBytesIfExists(this.getRevisionPath(blockId, rev), false);
113
- }
114
- async putRevision(blockId, rev, value) {
115
- await atomicWriteFile(this.getRevisionPath(blockId, rev), value);
116
- }
117
- async *rangeRevisions(blockId, lo, hi, reverse) {
118
- // The fs backend has no cursor: walk the bounded [lo, hi] range rev-by-rev,
119
- // reading each present rev. The range is caller-bounded, so this avoids
120
- // listing an unbounded revs/ directory. Drain into an array BEFORE yielding
121
- // (drain-before-yield contract) — matches the memory/native drivers and keeps
122
- // the consumer's interleaved awaits from straddling any in-flight read.
123
- const results = [];
124
- for (let rev = lo; rev <= hi; rev++) {
125
- const value = await this.readBytesIfExists(this.getRevisionPath(blockId, rev), false);
126
- if (value !== undefined) {
127
- results.push([rev, value]);
128
- }
129
- }
130
- if (reverse) {
131
- results.reverse();
132
- }
133
- for (const result of results) {
134
- yield result;
135
- }
136
- }
137
- // --- pending ---
138
- async getPending(blockId, actionId) {
139
- return this.readActionScopedBytes(this.getPendingActionPath(blockId, actionId), this.getPendingActionPath(blockId, actionId, false));
140
- }
141
- async putPending(blockId, actionId, value) {
142
- await atomicWriteFile(this.getPendingActionPath(blockId, actionId), value);
143
- }
144
- async deletePending(blockId, actionId) {
145
- const pendingPath = this.getPendingActionPath(blockId, actionId);
146
- await fs.unlink(pendingPath)
147
- .catch((err) => {
148
- if (err?.code !== 'ENOENT')
149
- log('deletePending unlink failed for %s/%s - %o', blockId, actionId, err);
150
- });
151
- await this.unlinkRawColon(pendingPath, this.getPendingActionPath(blockId, actionId, false));
152
- }
153
- async *listPendingActionIds(blockId) {
154
- const pendingPath = path.join(this.getBlockPath(blockId), 'pend');
155
- // Only a genuinely-absent directory (ENOENT) maps to "no pendings". Any other error
156
- // (EACCES, EIO, ENOTDIR, ...) must surface — swallowing it here would make
157
- // listPendingActionIds silently report an empty directory, so pend's conflict
158
- // detection would be skipped. Mirrors directoryByteSize's ENOENT-vs-other discrimination.
159
- const files = await fs.readdir(pendingPath).catch((err) => {
160
- if (err?.code === 'ENOENT')
161
- return [];
162
- log('listPendingActionIds readdir failed for %s - %o', blockId, err);
163
- throw err;
164
- });
165
- // Drain into an array before yielding (drain-before-yield): readdir has already
166
- // resolved the full listing, so this just decodes/filters up front.
167
- const ids = [];
168
- for (const file of files) {
169
- if (!file.endsWith('.json'))
170
- continue;
171
- const actionId = decodeFilenameToActionId(file.slice(0, -5));
172
- // Accept every realistic action id: legacy UUIDs (`[0-9a-f-]`), consensus
173
- // tx:/stamp: ids (base64url-encoded SHA-256, alphabet `[A-Za-z0-9_-]` — see
174
- // db-core hashString, NOT lowercase hex), AND the bare-alphanumeric ids the
175
- // cross-backend conformance suite uses (`a1`, `b1`, ...). This is deliberately
176
- // broad-but-not-total: an id is any `[A-Za-z0-9_-]` string, optionally prefixed
177
- // with `tx:`/`stamp:`. It is NOT a total accept — a file whose decoded name
178
- // carries other punctuation (a dot, a space) is genuine junk in pend/ and is
179
- // logged-and-skipped rather than surfaced as a phantom pending. The memory/db
180
- // reference drivers key on the raw id and never see a filesystem name, so this
181
- // filter is fs-only; it must not drop an id those backends would list, hence the
182
- // widened class (an earlier hex-only class silently dropped real consensus ids —
183
- // see `optimystic-filestorage-colon-actionid-windows`).
184
- if (!/^(?:tx:|stamp:)?[A-Za-z0-9_-]+$/.test(actionId)) {
185
- // Leave a breadcrumb rather than silently dropping: the .json + decode guard
186
- // already excludes *.tmp orphans, so anything reaching here is an unexpected
187
- // filename a maintainer should see.
188
- log('listPendingActionIds skipping unrecognized action-id file %s for %s', file, blockId);
189
- continue;
190
- }
191
- ids.push(actionId);
192
- }
193
- for (const id of ids) {
194
- yield id;
195
- }
196
- }
197
- // --- transactions ---
198
- async getTransaction(blockId, actionId) {
199
- return this.readActionScopedBytes(this.getActionPath(blockId, actionId), this.getActionPath(blockId, actionId, false));
200
- }
201
- async putTransaction(blockId, actionId, value) {
202
- await atomicWriteFile(this.getActionPath(blockId, actionId), value);
203
- }
204
- // --- proofs ---
205
- // Keyed by (blockId, rev) like the revisions store, but JSON-valued like the action
206
- // stores — so it takes the corrupt-content-as-missing guard the revisions store does
207
- // not, and the filename carries no colon to encode. Deliberately no delete: a proof
208
- // lives and dies with its revision record (see RawStoreDriver.getProof).
209
- async getProof(blockId, rev) {
210
- return this.readBytesIfExists(this.getProofPath(blockId, rev), true);
211
- }
212
- async putProof(blockId, rev, value) {
213
- await atomicWriteFile(this.getProofPath(blockId, rev), value);
214
- }
215
- // --- materialized ---
216
- async getMaterialized(blockId, actionId) {
217
- return this.readActionScopedBytes(this.getMaterializedPath(blockId, actionId), this.getMaterializedPath(blockId, actionId, false));
218
- }
219
- async putMaterialized(blockId, actionId, value) {
220
- await atomicWriteFile(this.getMaterializedPath(blockId, actionId), value);
221
- }
222
- // The kernel owns the put-or-delete branch of `saveMaterializedBlock`, so the
223
- // driver exposes delete as a separate op.
224
- async deleteMaterialized(blockId, actionId) {
225
- const matPath = this.getMaterializedPath(blockId, actionId);
226
- await fs.unlink(matPath)
227
- .catch((err) => {
228
- if (err?.code !== 'ENOENT')
229
- log('deleteMaterialized unlink failed for %s/%s - %o', blockId, actionId, err);
230
- });
231
- await this.unlinkRawColon(matPath, this.getMaterializedPath(blockId, actionId, false));
232
- }
233
- // --- promote (the only cross-key atomic op) ---
234
- async promote(blockId, actionId) {
235
- const pendingPath = this.getPendingActionPath(blockId, actionId);
236
- const actionPath = this.getActionPath(blockId, actionId);
237
- await fs.mkdir(path.dirname(actionPath), { recursive: true });
238
- // This single rename IS the atomic move — it is why fs honors the kernel's
239
- // promote contract without a WAL. A crash leaves either the pending or the
240
- // committed file, never both/neither. Do NOT replace with read-write-delete.
241
- return fs.rename(pendingPath, actionPath)
242
- .catch(err => {
243
- if (err.code === 'ENOENT') {
244
- throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
245
- }
246
- log('promote rename failed for %s/%s - %o', blockId, actionId, err);
247
- throw err;
248
- });
249
- }
250
- // --- optional passthroughs ---
251
- async *listBlockIds() {
252
- // The block layout is `basePath/<blockId>/{meta.json,revs/,pend/,actions/,proofs/,blocks/}`
253
- // (see getBlockPath), so the direct children of basePath are the per-block directories
254
- // and each directory NAME is the blockId (used raw, no encoding). Filter to directories
255
- // so a stray file can't be mistaken for a block; `*.tmp` atomic-write orphans live inside
256
- // block subdirs, never at basePath root, so the root is clean.
257
- //
258
- // A directory alone is NOT sufficient: pending a transform straight through this driver
259
- // creates `<blockId>/pend/` — hence a root directory entry — via atomicWriteFile's
260
- // recursive mkdir, without writing meta.json. So we gate on meta.json existence:
261
- // `meta.json` IS this backend's metadata store, so gating on it enumerates exactly the
262
- // same population the metadata-keyed backends (sqlite/leveldb/indexeddb) get for free.
263
- // That population is every block with ANY durable metadata — which on the node path
264
- // INCLUDES a pend-only block, because `BlockStorage.savePendingTransaction` seeds
265
- // metadata for a block that has none before storing the transform. Do not "improve" this
266
- // into a committed-revision filter: reading and parsing every meta.json would turn a
267
- // cheap access() sweep into a per-block read at startup (see the `listBlockIds` contract
268
- // in i-raw-storage.ts). Existence (fs.access), not parse, matches key-existence
269
- // semantics: a torn/corrupt meta.json still counts as a key, exactly as a corrupt value
270
- // would in the other backends.
271
- //
272
- // ENOENT (basePath not created yet, or a dir without meta.json) maps to "not owned" —
273
- // same discrimination as directoryByteSize. Any OTHER readdir/access error must surface:
274
- // swallowing it would make the seed falsely report an empty store and under-protect data
275
- // already on disk.
276
- // NOTE: reads the whole root listing up front + one meta.json stat per block dir; if a
277
- // store ever grows to millions of block subdirs and this becomes a startup-latency
278
- // problem, page it (e.g. opendir cursor) — fine at current scale.
279
- const entries = await fs.readdir(this.basePath, { withFileTypes: true })
280
- .catch((err) => {
281
- if (err?.code === 'ENOENT')
282
- return [];
283
- log('listBlockIds readdir failed for %s - %o', this.basePath, err);
284
- throw err;
285
- });
286
- for (const entry of entries) {
287
- if (!entry.isDirectory())
288
- continue;
289
- const blockId = entry.name;
290
- const hasMeta = await fs.access(this.getMetadataPath(blockId))
291
- .then(() => true)
292
- .catch((err) => {
293
- if (err?.code === 'ENOENT')
294
- return false;
295
- log('listBlockIds access failed for %s - %o', blockId, err);
296
- throw err;
297
- });
298
- if (hasMeta)
299
- yield blockId;
300
- }
301
- }
302
- async approximateBytesUsed() {
303
- return this.directoryByteSize(this.basePath);
304
- }
305
- async directoryByteSize(dir) {
306
- const entries = await fs.readdir(dir, { withFileTypes: true })
307
- .catch((err) => {
308
- if (err?.code === 'ENOENT')
309
- return [];
310
- log('directoryByteSize readdir failed for %s - %o', dir, err);
311
- return [];
312
- });
313
- let total = 0;
314
- for (const entry of entries) {
315
- const entryPath = path.join(dir, entry.name);
316
- if (entry.isDirectory()) {
317
- total += await this.directoryByteSize(entryPath);
318
- }
319
- else if (entry.isFile()) {
320
- const size = await fs.stat(entryPath)
321
- .then(st => st.size)
322
- .catch((err) => {
323
- if (err?.code === 'ENOENT')
324
- return 0;
325
- log('directoryByteSize stat failed for %s - %o', entryPath, err);
326
- return 0;
327
- });
328
- total += size;
329
- }
330
- }
331
- return total;
332
- }
333
- // --- paths ---
334
- getBlockPath(blockId) {
335
- return path.join(this.basePath, blockId);
336
- }
337
- getMetadataPath(blockId) {
338
- return path.join(this.getBlockPath(blockId), 'meta.json');
339
- }
340
- getRevisionPath(blockId, rev) {
341
- return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
342
- }
343
- getProofPath(blockId, rev) {
344
- return path.join(this.getBlockPath(blockId), 'proofs', `${rev}.json`);
345
- }
346
- // `encoded` controls colon handling: writes and canonical reads use the
347
- // percent-encoded filename (encoded = true); the legacy raw-colon fallback
348
- // (see readActionScopedBytes) passes encoded = false to reach pre-encode
349
- // POSIX files like `actions/tx:<hash>.json`.
350
- getPendingActionPath(blockId, actionId, encoded = true) {
351
- const filename = encoded ? encodeActionIdForFilename(actionId) : actionId;
352
- return path.join(this.getBlockPath(blockId), 'pend', `${filename}.json`);
353
- }
354
- getActionPath(blockId, actionId, encoded = true) {
355
- const filename = encoded ? encodeActionIdForFilename(actionId) : actionId;
356
- return path.join(this.getBlockPath(blockId), 'actions', `${filename}.json`);
357
- }
358
- getMaterializedPath(blockId, actionId, encoded = true) {
359
- const filename = encoded ? encodeActionIdForFilename(actionId) : actionId;
360
- return path.join(this.getBlockPath(blockId), 'blocks', `${filename}.json`);
361
- }
362
- // Best-effort removal of a pre-encode raw-colon file after the encoded delete,
363
- // so a deleted item cannot resurface via the read fallback in readActionScopedBytes.
364
- // Skipped on win32 (raw-colon files cannot exist there) and when paths are identical
365
- // (action id contains no colon — only one syscall needed). ENOENT is silently ignored.
366
- async unlinkRawColon(encodedPath, rawPath) {
367
- if (process.platform === 'win32' || rawPath === encodedPath)
368
- return;
369
- await fs.unlink(rawPath).catch((err) => {
370
- if (err?.code !== 'ENOENT')
371
- log('unlinkRawColon failed for %s - %o', rawPath, err);
372
- });
373
- }
374
- // Reads an action-id-keyed file (JSON-valued) by its canonical (percent-encoded)
375
- // path, falling back on a miss to the legacy raw-colon path written by pre-encode
376
- // nodes (e.g. POSIX files literally named `actions/tx:<hash>.json`).
377
- //
378
- // Tradeoff: this reads legacy files in place and never renames them, so a
379
- // store upgraded from a pre-encode node keeps mixed naming on disk. That is
380
- // acceptable pre-1.0; a future migration sweep can normalize if desired. We
381
- // deliberately do NOT migrate-on-read here — reads stay side-effect-free.
382
- //
383
- // win32 guard: a raw-colon path is not a benign miss on Windows — the colon
384
- // is parsed as an NTFS alternate-data-stream separator and a read there can
385
- // throw a non-ENOENT error rather than cleanly missing. Raw-colon files
386
- // cannot have been written on win32 anyway, so we skip the fallback there
387
- // (losing nothing) and swallow ALL fallback errors elsewhere, guaranteeing
388
- // the fallback never surfaces a new throw to callers.
389
- async readActionScopedBytes(encodedPath, rawPath) {
390
- const hit = await this.readBytesIfExists(encodedPath, true);
391
- if (hit !== undefined)
392
- return hit;
393
- if (process.platform === 'win32' || rawPath === encodedPath)
394
- return undefined;
395
- return fs.readFile(rawPath)
396
- .then(bytes => (isParseableJson(bytes) ? bytes : undefined))
397
- .catch(() => undefined);
398
- }
399
- // Reads a file's raw bytes. ENOENT → undefined. When `jsonGuard` is set, a
400
- // present-but-corrupt file (JSON.parse fails — most likely a torn write from a
401
- // crash before atomic writes existed) is treated as "missing" so recover() and
402
- // normal reads make progress instead of rethrowing forever. A real I/O error
403
- // (permissions, EIO, EISDIR, ...) still throws — it must not be masked.
404
- async readBytesIfExists(filePath, jsonGuard) {
405
- let bytes;
406
- try {
407
- bytes = await fs.readFile(filePath);
408
- }
409
- catch (err) {
410
- if (err?.code === 'ENOENT')
411
- return undefined;
412
- throw err;
413
- }
414
- if (jsonGuard && !isParseableJson(bytes)) {
415
- log('readBytesIfExists: corrupt JSON at %s, treating as missing', filePath);
416
- return undefined;
417
- }
418
- return bytes;
419
- }
420
- }
1
+ import { KvRawStorage, WriteGroupDriver } from "@optimystic/db-p2p";
2
+ import { FileBatchBackend } from './file-batch-backend.js';
421
3
  /**
422
- * Filesystem-backed {@link IRawStorage}, now a thin shell over the shared
423
- * {@link KvRawStorage} kernel driven by a {@link FileStoreDriver}. The public
424
- * name/constructor (`new FileRawStorage(basePath)`) is unchanged so existing
425
- * imports keep resolving; the kernel supplies the `IRawStorage` surface and the
426
- * driver supplies fs behavior.
4
+ * Filesystem-backed {@link IRawStorage}: the shared {@link KvRawStorage} kernel over a
5
+ * {@link WriteGroupDriver} over a {@link FileBatchBackend}. Every write resolves into the driver's
6
+ * in-memory overlay; `flush()` hands the group to the backend as one batch, which appends it to
7
+ * `<basePath>/write-ahead.log` with one sync and then writes the tree. The public constructor
8
+ * (`new FileRawStorage(basePath, options?)`) is synchronous: the lock is taken and the log replayed
9
+ * on the first operation.
427
10
  *
428
- * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity` are re-declared here as
429
- * always-present (the fs driver always implements them, so the kernel constructor always
430
- * wires them) — the base declares them optional, but every fs consumer relies on them.
11
+ * `listBlockIds`/`getApproximateBytesUsed`/`getStoreIdentity`/`close` are re-declared here as
12
+ * always-present (the fs backend always implements the first three, so the driver and kernel always
13
+ * wire them, and the driver always has a `close`) — the base declares them optional, but every fs
14
+ * consumer relies on them. `close()` flushes what is still held, releases this store's reference to
15
+ * the directory's shared log, and — for the last store over the directory — checkpoints the log,
16
+ * closes it and removes the lock.
431
17
  */
432
18
  export class FileRawStorage extends KvRawStorage {
433
- constructor(basePath) {
434
- super(new FileStoreDriver(basePath));
19
+ constructor(basePath, options = {}) {
20
+ super(new WriteGroupDriver(new FileBatchBackend(basePath, options), options));
435
21
  }
436
22
  }
437
23
  //# sourceMappingURL=file-storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/file-storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAA8C,MAAM,oBAAoB,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAS3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,cAAe,SAAQ,YAAY;IAM/C,YAAY,QAAgB,EAAE,UAAiC,EAAE;QAChE,KAAK,CAAC,IAAI,gBAAgB,CAAC,IAAI,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/E,CAAC;CACD"}