@rocicorp/zero 1.11.0-canary.15 → 1.11.0-canary.17

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 (111) hide show
  1. package/out/replicache/src/bg-interval.d.ts +2 -1
  2. package/out/replicache/src/bg-interval.d.ts.map +1 -1
  3. package/out/replicache/src/bg-interval.js +13 -4
  4. package/out/replicache/src/bg-interval.js.map +1 -1
  5. package/out/replicache/src/dag/lazy-store.d.ts +17 -4
  6. package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
  7. package/out/replicache/src/dag/lazy-store.js +35 -9
  8. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  9. package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
  10. package/out/replicache/src/dag/store-impl.js +7 -1
  11. package/out/replicache/src/dag/store-impl.js.map +1 -1
  12. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  13. package/out/replicache/src/kv/sqlite-store.js +4 -6
  14. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  15. package/out/replicache/src/persist/client-gc.d.ts +2 -1
  16. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  17. package/out/replicache/src/persist/client-gc.js +2 -2
  18. package/out/replicache/src/persist/client-gc.js.map +1 -1
  19. package/out/replicache/src/persist/client-group-gc.d.ts +2 -1
  20. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  21. package/out/replicache/src/persist/client-group-gc.js +2 -2
  22. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  23. package/out/replicache/src/persist/collect-idb-databases.d.ts +2 -1
  24. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  25. package/out/replicache/src/persist/collect-idb-databases.js +2 -2
  26. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  27. package/out/replicache/src/persist/heartbeat.d.ts +2 -1
  28. package/out/replicache/src/persist/heartbeat.d.ts.map +1 -1
  29. package/out/replicache/src/persist/heartbeat.js +2 -2
  30. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  31. package/out/replicache/src/replicache-impl.d.ts +34 -3
  32. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  33. package/out/replicache/src/replicache-impl.js +104 -27
  34. package/out/replicache/src/replicache-impl.js.map +1 -1
  35. package/out/zero/package.js +1 -1
  36. package/out/zero/package.js.map +1 -1
  37. package/out/zero-cache/src/config/zero-config.d.ts +23 -0
  38. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  39. package/out/zero-cache/src/config/zero-config.js +67 -16
  40. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  41. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -1
  42. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  43. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +4 -1
  44. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  45. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +5 -0
  46. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -1
  47. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +34 -5
  48. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -1
  49. package/out/zero-cache/src/services/plannerz.d.ts +5 -1
  50. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
  51. package/out/zero-cache/src/services/plannerz.js +8 -4
  52. package/out/zero-cache/src/services/plannerz.js.map +1 -1
  53. package/out/zero-cache/src/services/profz.d.ts +24 -1
  54. package/out/zero-cache/src/services/profz.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/profz.js +43 -3
  56. package/out/zero-cache/src/services/profz.js.map +1 -1
  57. package/out/zero-cache/src/services/statz.d.ts +4 -0
  58. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  59. package/out/zero-cache/src/services/statz.js +22 -5
  60. package/out/zero-cache/src/services/statz.js.map +1 -1
  61. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  62. package/out/zero-cache/src/services/view-syncer/snapshotter.js +21 -2
  63. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  64. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
  65. package/out/zero-client/src/client/mutator-proxy.js +3 -1
  66. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  67. package/out/zero-client/src/client/options.d.ts +2 -1
  68. package/out/zero-client/src/client/options.d.ts.map +1 -1
  69. package/out/zero-client/src/client/options.js.map +1 -1
  70. package/out/zero-client/src/client/version.js +1 -1
  71. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  72. package/out/zero-client/src/client/zero.js +2 -1
  73. package/out/zero-client/src/client/zero.js.map +1 -1
  74. package/out/zero-server/src/logging.d.ts +2 -2
  75. package/out/zero-server/src/logging.d.ts.map +1 -1
  76. package/out/zero-server/src/logging.js +2 -2
  77. package/out/zero-server/src/logging.js.map +1 -1
  78. package/out/zero-server/src/process-mutations.d.ts +12 -3
  79. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  80. package/out/zero-server/src/process-mutations.js +13 -8
  81. package/out/zero-server/src/process-mutations.js.map +1 -1
  82. package/out/zero-server/src/push-processor.d.ts +8 -2
  83. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  84. package/out/zero-server/src/push-processor.js +12 -4
  85. package/out/zero-server/src/push-processor.js.map +1 -1
  86. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  87. package/out/zql/src/ivm/cap.js +1 -0
  88. package/out/zql/src/ivm/cap.js.map +1 -1
  89. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  90. package/out/zql/src/ivm/flipped-join.js +1 -0
  91. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  92. package/out/zql/src/ivm/join-utils.d.ts +1 -0
  93. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  94. package/out/zql/src/ivm/join-utils.js.map +1 -1
  95. package/out/zql/src/ivm/join.d.ts.map +1 -1
  96. package/out/zql/src/ivm/join.js +1 -0
  97. package/out/zql/src/ivm/join.js.map +1 -1
  98. package/out/zql/src/ivm/memory-storage.d.ts +1 -0
  99. package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
  100. package/out/zql/src/ivm/memory-storage.js +1 -0
  101. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  102. package/out/zql/src/ivm/operator.d.ts +6 -0
  103. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  104. package/out/zql/src/ivm/operator.js.map +1 -1
  105. package/out/zql/src/ivm/take.d.ts.map +1 -1
  106. package/out/zql/src/ivm/take.js +1 -0
  107. package/out/zql/src/ivm/take.js.map +1 -1
  108. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  109. package/out/zqlite/src/database-storage.js +9 -1
  110. package/out/zqlite/src/database-storage.js.map +1 -1
  111. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
- export declare function initBgIntervalProcess(processName: string, process: () => Promise<unknown>, delayMs: () => number, lc: LogContext, signal: AbortSignal): void;
2
+ import { type StorageFailureError } from './storage-failure.ts';
3
+ export declare function initBgIntervalProcess(processName: string, process: () => Promise<unknown>, delayMs: () => number, lc: LogContext, signal: AbortSignal, onStorageFailure?: ((failure: StorageFailureError) => void) | undefined): void;
3
4
  //# sourceMappingURL=bg-interval.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bg-interval.d.ts","sourceRoot":"","sources":["../../../../replicache/src/bg-interval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,MAAM,EACrB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,GAClB,IAAI,CAEN"}
1
+ {"version":3,"file":"bg-interval.d.ts","sourceRoot":"","sources":["../../../../replicache/src/bg-interval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAE9B,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,MAAM,EACrB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,SAAS,GACtE,IAAI,CASN"}
@@ -1,11 +1,12 @@
1
+ import { getStorageFailure } from "./storage-failure.js";
1
2
  import { IDBNotFoundError } from "./kv/idb-store.js";
2
3
  import { AbortError } from "../../shared/src/abort-error.js";
3
4
  import { sleep } from "../../shared/src/sleep.js";
4
5
  //#region ../replicache/src/bg-interval.ts
5
- function initBgIntervalProcess(processName, process, delayMs, lc, signal) {
6
- runBgIntervalProcess(processName, process, delayMs, lc, signal);
6
+ function initBgIntervalProcess(processName, process, delayMs, lc, signal, onStorageFailure) {
7
+ runBgIntervalProcess(processName, process, delayMs, lc, signal, onStorageFailure);
7
8
  }
8
- async function runBgIntervalProcess(processName, process, delayMs, lc, signal) {
9
+ async function runBgIntervalProcess(processName, process, delayMs, lc, signal, onStorageFailure) {
9
10
  if (signal.aborted) return;
10
11
  lc = lc.withContext("bgIntervalProcess", processName);
11
12
  lc.debug?.("Starting");
@@ -22,7 +23,15 @@ async function runBgIntervalProcess(processName, process, delayMs, lc, signal) {
22
23
  } catch (e) {
23
24
  if (signal.aborted) lc.debug?.("Error running most likely due to close.", e);
24
25
  else if (e instanceof IDBNotFoundError) lc.info?.("IndexedDB was deleted externally.", e);
25
- else lc.error?.("Error running.", e);
26
+ else {
27
+ const failure = getStorageFailure(e);
28
+ if (failure === void 0) lc.error?.("Error running.", e);
29
+ else {
30
+ lc.warn?.("Storage failed; stopping.", e);
31
+ onStorageFailure?.(failure);
32
+ break;
33
+ }
34
+ }
26
35
  }
27
36
  }
28
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bg-interval.js","names":[],"sources":["../../../../replicache/src/bg-interval.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../shared/src/abort-error.ts';\nimport {sleep} from '../../shared/src/sleep.ts';\nimport {IDBNotFoundError} from './kv/idb-store.ts';\n\nexport function initBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): void {\n void runBgIntervalProcess(processName, process, delayMs, lc, signal);\n}\n\nasync function runBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): Promise<void> {\n if (signal.aborted) {\n return;\n }\n lc = lc.withContext('bgIntervalProcess', processName);\n lc.debug?.('Starting');\n while (!signal.aborted) {\n try {\n await sleep(delayMs(), signal);\n } catch (e) {\n if (!(e instanceof AbortError)) {\n throw e;\n }\n }\n if (!signal.aborted) {\n lc.debug?.('Running');\n try {\n await process();\n } catch (e) {\n if (signal.aborted) {\n lc.debug?.('Error running most likely due to close.', e);\n } else if (e instanceof IDBNotFoundError) {\n lc.info?.('IndexedDB was deleted externally.', e);\n } else {\n lc.error?.('Error running.', e);\n }\n }\n }\n }\n lc.debug?.('Stopping');\n}\n"],"mappings":";;;;AAKA,SAAgB,sBACd,aACA,SACA,SACA,IACA,QACM;CACN,qBAA0B,aAAa,SAAS,SAAS,IAAI,MAAM;AACrE;AAEA,eAAe,qBACb,aACA,SACA,SACA,IACA,QACe;CACf,IAAI,OAAO,SACT;CAEF,KAAK,GAAG,YAAY,qBAAqB,WAAW;CACpD,GAAG,QAAQ,UAAU;CACrB,OAAO,CAAC,OAAO,SAAS;EACtB,IAAI;GACF,MAAM,MAAM,QAAQ,GAAG,MAAM;EAC/B,SAAS,GAAG;GACV,IAAI,EAAE,aAAa,aACjB,MAAM;EAEV;EACA,IAAI,CAAC,OAAO,SAAS;GACnB,GAAG,QAAQ,SAAS;GACpB,IAAI;IACF,MAAM,QAAQ;GAChB,SAAS,GAAG;IACV,IAAI,OAAO,SACT,GAAG,QAAQ,2CAA2C,CAAC;SAClD,IAAI,aAAa,kBACtB,GAAG,OAAO,qCAAqC,CAAC;SAEhD,GAAG,QAAQ,kBAAkB,CAAC;GAElC;EACF;CACF;CACA,GAAG,QAAQ,UAAU;AACvB"}
1
+ {"version":3,"file":"bg-interval.js","names":[],"sources":["../../../../replicache/src/bg-interval.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../shared/src/abort-error.ts';\nimport {sleep} from '../../shared/src/sleep.ts';\nimport {IDBNotFoundError} from './kv/idb-store.ts';\nimport {\n getStorageFailure,\n type StorageFailureError,\n} from './storage-failure.ts';\n\nexport function initBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n): void {\n void runBgIntervalProcess(\n processName,\n process,\n delayMs,\n lc,\n signal,\n onStorageFailure,\n );\n}\n\nasync function runBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n): Promise<void> {\n if (signal.aborted) {\n return;\n }\n lc = lc.withContext('bgIntervalProcess', processName);\n lc.debug?.('Starting');\n while (!signal.aborted) {\n try {\n await sleep(delayMs(), signal);\n } catch (e) {\n if (!(e instanceof AbortError)) {\n throw e;\n }\n }\n if (!signal.aborted) {\n lc.debug?.('Running');\n try {\n await process();\n } catch (e) {\n if (signal.aborted) {\n lc.debug?.('Error running most likely due to close.', e);\n } else if (e instanceof IDBNotFoundError) {\n lc.info?.('IndexedDB was deleted externally.', e);\n } else {\n const failure = getStorageFailure(e);\n if (failure === undefined) {\n lc.error?.('Error running.', e);\n } else {\n // The store's storage failed, not this process: running it again\n // at the interval fails the same way (see `onStorageFailure`).\n // warn, not error: the instance reports it once through the\n // callback, and there is nothing for a developer to fix.\n lc.warn?.('Storage failed; stopping.', e);\n onStorageFailure?.(failure);\n break;\n }\n }\n }\n }\n }\n lc.debug?.('Stopping');\n}\n"],"mappings":";;;;;AASA,SAAgB,sBACd,aACA,SACA,SACA,IACA,QACA,kBACM;CACN,qBACE,aACA,SACA,SACA,IACA,QACA,gBACF;AACF;AAEA,eAAe,qBACb,aACA,SACA,SACA,IACA,QACA,kBACe;CACf,IAAI,OAAO,SACT;CAEF,KAAK,GAAG,YAAY,qBAAqB,WAAW;CACpD,GAAG,QAAQ,UAAU;CACrB,OAAO,CAAC,OAAO,SAAS;EACtB,IAAI;GACF,MAAM,MAAM,QAAQ,GAAG,MAAM;EAC/B,SAAS,GAAG;GACV,IAAI,EAAE,aAAa,aACjB,MAAM;EAEV;EACA,IAAI,CAAC,OAAO,SAAS;GACnB,GAAG,QAAQ,SAAS;GACpB,IAAI;IACF,MAAM,QAAQ;GAChB,SAAS,GAAG;IACV,IAAI,OAAO,SACT,GAAG,QAAQ,2CAA2C,CAAC;SAClD,IAAI,aAAa,kBACtB,GAAG,OAAO,qCAAqC,CAAC;SAC3C;KACL,MAAM,UAAU,kBAAkB,CAAC;KACnC,IAAI,YAAY,KAAA,GACd,GAAG,QAAQ,kBAAkB,CAAC;UACzB;MAKL,GAAG,OAAO,6BAA6B,CAAC;MACxC,mBAAmB,OAAO;MAC1B;KACF;IACF;GACF;EACF;CACF;CACA,GAAG,QAAQ,UAAU;AACvB"}
@@ -1,5 +1,6 @@
1
1
  import type { MaybePromise } from '../../../shared/src/types.ts';
2
2
  import type { Hash } from '../hash.ts';
3
+ import { type StorageFailureError } from '../storage-failure.ts';
3
4
  import type { Chunk } from './chunk.ts';
4
5
  import { type ChunkHasher, type Refs } from './chunk.ts';
5
6
  import { type HeadChange, type RefCountUpdatesDelegate } from './gc.ts';
@@ -106,7 +107,14 @@ export declare class LazyStore implements Store {
106
107
  */
107
108
  protected readonly _refCounts: Map<Hash, number>;
108
109
  protected readonly _refs: Map<Hash, readonly Hash[]>;
109
- constructor(sourceStore: Store, sourceCacheSizeLimit: number, chunkHasher: ChunkHasher, assertValidHash: (hash: Hash) => void, getSizeOfChunk?: (chunk: Chunk) => number);
110
+ /**
111
+ * @param onStorageFailure Called when a read of the source store fails on
112
+ * its storage (a {@link StorageFailureError}). Every read this store makes
113
+ * for a chunk it has not cached goes through here, whichever caller asked
114
+ * for it: a query, a mutation, a poke. The source store's own wrapper
115
+ * reports only the begin, commit and release of a transaction.
116
+ */
117
+ constructor(sourceStore: Store, sourceCacheSizeLimit: number, chunkHasher: ChunkHasher, assertValidHash: (hash: Hash) => void, getSizeOfChunk?: (chunk: Chunk) => number, onStorageFailure?: ((failure: StorageFailureError) => void) | undefined);
110
118
  read(sourceRead?: Read): Promise<LazyRead>;
111
119
  write(): Promise<LazyWrite>;
112
120
  close(): Promise<void>;
@@ -123,7 +131,13 @@ export declare class LazyRead implements Read {
123
131
  protected readonly _sourceChunksCache: ChunksCache;
124
132
  protected readonly _sourceStore: Store;
125
133
  readonly assertValidHash: (hash: Hash) => void;
126
- constructor(heads: Map<string, Hash>, memOnlyChunks: Map<Hash, Chunk>, sourceChunksCache: ChunksCache, sourceStore: Store, release: () => void, assertValidHash: (hash: Hash) => void, sourceRead?: Read);
134
+ constructor(heads: Map<string, Hash>, memOnlyChunks: Map<Hash, Chunk>, sourceChunksCache: ChunksCache, sourceStore: Store, release: () => void, assertValidHash: (hash: Hash) => void, sourceRead?: Read, onStorageFailure?: ((failure: StorageFailureError) => void) | undefined);
135
+ /**
136
+ * Reads `hash` from the source store. A storage failure on the read is
137
+ * reported before it propagates, so the instance hears of it whichever
138
+ * caller made the read.
139
+ */
140
+ protected _getSourceChunk(hash: Hash): Promise<Chunk | undefined>;
127
141
  isMemOnlyChunkHash(hash: Hash): boolean;
128
142
  hasChunk(hash: Hash): Promise<boolean>;
129
143
  getChunk(hash: Hash): Promise<Chunk | undefined>;
@@ -131,7 +145,6 @@ export declare class LazyRead implements Read {
131
145
  getHead(name: string): Promise<Hash | undefined>;
132
146
  release(): void;
133
147
  get closed(): boolean;
134
- protected _getSourceRead(): Promise<Read>;
135
148
  }
136
149
  export declare class LazyWrite extends LazyRead implements Write, RefCountUpdatesDelegate {
137
150
  #private;
@@ -141,7 +154,7 @@ export declare class LazyWrite extends LazyRead implements Write, RefCountUpdate
141
154
  chunk: Chunk;
142
155
  size: number;
143
156
  }>;
144
- constructor(heads: Map<string, Hash>, memOnlyChunks: Map<Hash, Chunk>, sourceChunksCache: ChunksCache, sourceStore: Store, refCounts: Map<Hash, number>, refs: Map<Hash, readonly Hash[]>, release: () => void, chunkHasher: ChunkHasher, assertValidHash: (hash: Hash) => void);
157
+ constructor(heads: Map<string, Hash>, memOnlyChunks: Map<Hash, Chunk>, sourceChunksCache: ChunksCache, sourceStore: Store, refCounts: Map<Hash, number>, refs: Map<Hash, readonly Hash[]>, release: () => void, chunkHasher: ChunkHasher, assertValidHash: (hash: Hash) => void, onStorageFailure?: ((failure: StorageFailureError) => void) | undefined);
145
158
  createChunk: <V>(data: V, refs: Refs) => Chunk<V>;
146
159
  putChunk<V>(c: Chunk<V>, size?: number): Promise<void>;
147
160
  setHead(name: string, hash: Hash): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/dag/lazy-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lazy-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/dag/lazy-store.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { promiseVoid } from "../../../shared/src/resolved-promises.js";
2
+ import { getStorageFailure } from "../storage-failure.js";
2
3
  import { createChunk } from "./chunk.js";
3
4
  import { computeRefCountUpdates } from "./gc.js";
4
5
  import { mustGetChunk } from "./store.js";
@@ -133,19 +134,28 @@ var LazyStore = class {
133
134
  */
134
135
  _refCounts = /* @__PURE__ */ new Map();
135
136
  _refs = /* @__PURE__ */ new Map();
136
- constructor(sourceStore, sourceCacheSizeLimit, chunkHasher, assertValidHash, getSizeOfChunk = getSizeOfValue) {
137
+ #onStorageFailure;
138
+ /**
139
+ * @param onStorageFailure Called when a read of the source store fails on
140
+ * its storage (a {@link StorageFailureError}). Every read this store makes
141
+ * for a chunk it has not cached goes through here, whichever caller asked
142
+ * for it: a query, a mutation, a poke. The source store's own wrapper
143
+ * reports only the begin, commit and release of a transaction.
144
+ */
145
+ constructor(sourceStore, sourceCacheSizeLimit, chunkHasher, assertValidHash, getSizeOfChunk = getSizeOfValue, onStorageFailure) {
137
146
  this._sourceChunksCache = new ChunksCache(sourceCacheSizeLimit, getSizeOfChunk, this._refCounts, this._refs);
138
147
  this.#sourceStore = sourceStore;
139
148
  this.#chunkHasher = chunkHasher;
140
149
  this.#assertValidHash = assertValidHash;
150
+ this.#onStorageFailure = onStorageFailure;
141
151
  }
142
152
  async read(sourceRead) {
143
153
  const release = await this.#rwLock.read();
144
- return new LazyRead(this.#heads, this._memOnlyChunks, this._sourceChunksCache, this.#sourceStore, release, this.#assertValidHash, sourceRead);
154
+ return new LazyRead(this.#heads, this._memOnlyChunks, this._sourceChunksCache, this.#sourceStore, release, this.#assertValidHash, sourceRead, this.#onStorageFailure);
145
155
  }
146
156
  async write() {
147
157
  const release = await this.#rwLock.write();
148
- return new LazyWrite(this.#heads, this._memOnlyChunks, this._sourceChunksCache, this.#sourceStore, this._refCounts, this._refs, release, this.#chunkHasher, this.#assertValidHash);
158
+ return new LazyWrite(this.#heads, this._memOnlyChunks, this._sourceChunksCache, this.#sourceStore, this._refCounts, this._refs, release, this.#chunkHasher, this.#assertValidHash, this.#onStorageFailure);
149
159
  }
150
160
  close() {
151
161
  return promiseVoid;
@@ -170,7 +180,8 @@ var LazyRead = class {
170
180
  #closed = false;
171
181
  assertValidHash;
172
182
  #sourceReadOwnedByCaller;
173
- constructor(heads, memOnlyChunks, sourceChunksCache, sourceStore, release, assertValidHash, sourceRead) {
183
+ #onStorageFailure;
184
+ constructor(heads, memOnlyChunks, sourceChunksCache, sourceStore, release, assertValidHash, sourceRead, onStorageFailure) {
174
185
  this._heads = heads;
175
186
  this._memOnlyChunks = memOnlyChunks;
176
187
  this._sourceChunksCache = sourceChunksCache;
@@ -179,6 +190,21 @@ var LazyRead = class {
179
190
  this.assertValidHash = assertValidHash;
180
191
  this.#sourceRead = sourceRead !== void 0 ? Promise.resolve(sourceRead) : void 0;
181
192
  this.#sourceReadOwnedByCaller = sourceRead !== void 0;
193
+ this.#onStorageFailure = onStorageFailure;
194
+ }
195
+ /**
196
+ * Reads `hash` from the source store. A storage failure on the read is
197
+ * reported before it propagates, so the instance hears of it whichever
198
+ * caller made the read.
199
+ */
200
+ async _getSourceChunk(hash) {
201
+ try {
202
+ return await (await this.#getSourceRead()).getChunk(hash);
203
+ } catch (e) {
204
+ const failure = getStorageFailure(e);
205
+ if (failure !== void 0) this.#onStorageFailure?.(failure);
206
+ throw e;
207
+ }
182
208
  }
183
209
  isMemOnlyChunkHash(hash) {
184
210
  return this._memOnlyChunks.has(hash);
@@ -191,7 +217,7 @@ var LazyRead = class {
191
217
  if (memOnlyChunk !== void 0) return memOnlyChunk;
192
218
  let chunk = this._sourceChunksCache.get(hash);
193
219
  if (chunk === void 0) {
194
- chunk = await (await this._getSourceRead()).getChunk(hash);
220
+ chunk = await this._getSourceChunk(hash);
195
221
  if (chunk !== void 0) this._sourceChunksCache.put(chunk);
196
222
  }
197
223
  return chunk;
@@ -212,7 +238,7 @@ var LazyRead = class {
212
238
  get closed() {
213
239
  return this.#closed;
214
240
  }
215
- _getSourceRead() {
241
+ #getSourceRead() {
216
242
  if (!this.#sourceRead) this.#sourceRead = this._sourceStore.read();
217
243
  return this.#sourceRead;
218
244
  }
@@ -225,8 +251,8 @@ var LazyWrite = class extends LazyRead {
225
251
  _pendingMemOnlyChunks = /* @__PURE__ */ new Map();
226
252
  _pendingCachedChunks = /* @__PURE__ */ new Map();
227
253
  #createdChunks = /* @__PURE__ */ new Set();
228
- constructor(heads, memOnlyChunks, sourceChunksCache, sourceStore, refCounts, refs, release, chunkHasher, assertValidHash) {
229
- super(heads, memOnlyChunks, sourceChunksCache, sourceStore, release, assertValidHash);
254
+ constructor(heads, memOnlyChunks, sourceChunksCache, sourceStore, refCounts, refs, release, chunkHasher, assertValidHash, onStorageFailure) {
255
+ super(heads, memOnlyChunks, sourceChunksCache, sourceStore, release, assertValidHash, void 0, onStorageFailure);
230
256
  this.#refCounts = refCounts;
231
257
  this.#refs = refs;
232
258
  this.#chunkHasher = chunkHasher;
@@ -274,7 +300,7 @@ var LazyWrite = class extends LazyRead {
274
300
  if (pendingCachedChunk !== void 0) return pendingCachedChunk.chunk;
275
301
  let chunk = this._sourceChunksCache.get(hash);
276
302
  if (chunk === void 0) {
277
- chunk = await (await this._getSourceRead()).getChunk(hash);
303
+ chunk = await this._getSourceChunk(hash);
278
304
  if (chunk !== void 0) this._pendingCachedChunks.set(chunk.hash, {
279
305
  chunk,
280
306
  size: -1
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-store.js","names":["#rwLock","#heads","#sourceStore","#chunkHasher","#assertValidHash","#release","#sourceReadOwnedByCaller","#sourceRead","#closed","#refCounts","#refs","#createdChunks","#setHead","#cacheSizeLimit","#getSizeOfChunk","#suspendedDeletes","#cacheChunk","#ensureCacheSizeLimit","#evictsAndDeletesSuspended","#size","#evict","#deleteEntryByHash"],"sources":["../../../../../replicache/src/dag/lazy-store.ts"],"sourcesContent":["import {RWLock} from '@rocicorp/lock';\nimport {joinIterables} from '../../../shared/src/iterables.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport {getSizeOfValue} from '../../../shared/src/size-of-value.ts';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport type {Hash} from '../hash.ts';\nimport type {Chunk} from './chunk.ts';\nimport {type ChunkHasher, type Refs, createChunk} from './chunk.ts';\nimport {\n type HeadChange,\n type RefCountUpdatesDelegate,\n computeRefCountUpdates,\n} from './gc.ts';\nimport {type Read, type Store, type Write, mustGetChunk} from './store.ts';\n\n/**\n * Dag Store which lazily loads values from a source store and then caches\n * them in an LRU cache. The memory cache for chunks from the source store\n * size is limited to `sourceCacheSizeLimit` bytes, and values are evicted in an\n * LRU fashion. The purpose of this store is to avoid holding the entire client\n * view (i.e. the source store's content) in each tab's JavaScript heap.\n *\n * This store's heads are independent from the heads of source store, and are\n * only stored in memory.\n *\n * Chunks which are created via this store's {@link Write} transaction's\n * {@link createChunk} method are assumed to not be persisted to the source\n * store and thus are cached separately from the source store chunks. These\n * memory-only chunks will not be evicted, and their sizes are not counted\n * towards the source chunk cache size. A memory-only chunk will be deleted if\n * it is no longer reachable from one of this store's heads.\n *\n * Writes only manipulate the in memory state of this store and do not alter the\n * source store. Thus values must be written to the source store through a\n * separate process (see {@link persist}).\n *\n * Intended use:\n * 1. source store is the 'perdag', a slower persistent store (i.e.\n * dag.StoreImpl using a kv.IDBStore)\n * 2. this store's 'main' head is initialized to the hash of a chunk containing\n * a commit in the source store\n * 3. reads lazily read chunks from the source store and cache them\n * 3. writes are initially made to this store with memory-only chunks\n * 4. writes are asynchronously persisted to the source store through a separate\n * process (see {@link persist}}. This process gathers memory-only chunks\n * from this store and then writes them to the source store. It then informs\n * this store that these chunks are no longer memory-only by calling\n * {@link chunksPersisted}, which move these chunks\n * to this store's LRU cache of source chunks (making them eligible for\n * eviction).\n *\n * @param sourceStore Store to lazy load and cache values from.\n * @param sourceCacheSizeLimit Size limit in bytes for cache of chunks loaded\n * from `sourceStore`. This size of a value is determined using\n * `getSizeOfValue`. Keys do not count towards cache size. Memory-only chunks\n * do not count towards cache size.\n * @param getSizeOfValue Function for measuring the size in bytes of a value.\n */\nexport class LazyStore implements Store {\n /**\n * This lock is used to ensure correct isolation of Reads and Writes.\n * Multiple Reads are allowed in parallel but only a single Write. Reads and\n * Writes see an isolated view of the store (corresponding to the Serializable\n * level of transaction isolation defined in the SQL standard).\n *\n * To ensure these semantics the read lock must be acquired when a Read is\n * created and held til it is closed, and a Write lock must be acquired when a\n * Write is created and held til it is committed or closed.\n *\n * Code must have a read or write lock to\n * - read `_heads`\n * - read `_memOnlyChunks`\n * - read `_sourceStore`\n * - read and write `_sourceChunksCache`\n * - read and write `_refCounts`\n * - read and write `_refs`\n * and must have a write lock to\n * - write `_heads`\n * - write `_memOnlyChunks`\n */\n readonly #rwLock = new RWLock();\n readonly #heads = new Map<string, Hash>();\n readonly #sourceStore: Store;\n readonly #chunkHasher: ChunkHasher;\n readonly #assertValidHash: (hash: Hash) => void;\n\n /** The following are protected so testing subclass can access. */\n protected readonly _memOnlyChunks = new Map<Hash, Chunk>();\n protected readonly _sourceChunksCache: ChunksCache;\n /**\n * Ref counts are maintained so that chunks which are unreachable\n * from this stores heads can be eagerly and deterministically deleted from\n * `this._memOnlyChunks` and `this._sourceChunksCache`.\n *\n * These ref counts are independent from `this._sourceStore`'s ref counts.\n * These ref counts are based on reachability from `this._heads`.\n * A chunk is deleted from `this._memOnlyChunks` or\n * `this._sourceChunksCache` (which ever it is in) when its ref count becomes\n * zero.\n * These ref counts count the refs in `this._heads` and `this._refs`.\n *\n * Not all reachable chunk's refs are included in `this._refs`, because this\n * would require loading all chunks reachable in the source store in a\n * non-lazy manner. `this._refs` contains the refs of all currently reachable\n * chunks that were ever in `this._memOnlyChunks` or\n * `this._sourceChunksCache` (even if they have been evicted). A\n * chunk's ref information is lazily discovered and stored in `this._refs` and\n * counted in `this._refCounts`. A chunk's entries in `this._refs` and\n * `this._refCounts` are only deleted when a chunk is deleted due to it\n * becoming unreachable (it is not deleted if the chunk is evicted from the\n * source-store cache).\n *\n * The major implication of this lazy discovery of source store refs, is that\n * a reachable source store chunk may not be cached when loaded, because it is\n * not known to be reachable because some of the pertinent refs have not been\n * discovered. However, in practice chunks are read by traversing the graph\n * starting from a head, and all pertinent refs are discovered as part of the\n * traversal.\n *\n * These ref counts can be changed in two ways:\n * 1. A LazyRead has a cache miss and loads a chunk from the source store that\n * is reachable from this._heads. If this chunk's refs are not currently\n * counted, it will not have an entry in `this._refs`. In this case, the\n * chunks refs will be put in `this._refs` and `this._refCounts` will be\n * updated to count them.\n * 2. A LazyWrite commit updates a head (which can result in increasing or\n * decreasing ref count) or puts a reachable chunk (either a `memory-only` or\n * `source` chunk) that references this hash (increasing ref count). The\n * computation of these ref count changes is delegated to the\n * `computeRefCountUpdates` shared with dag.StoreImpl. In order to\n * delegate determining reachability to `computeRefCountUpdates` and defer\n * this determination until commit time, LazyWrite treats cache misses\n * as a 'put' of the lazily-loaded chunk.\n *\n * A chunk's hash may have an entry in `this._refCounts` without that\n * chunk have ever been in `this._memOnlyChunks` or `this._sourceChunksCache`.\n * This is the case when a head or a reachable chunk that was ever in\n * `this._memOnlyChunks` or `this._sourceChunksCache` references a chunk\n * which is not currently cached (either because it has not been read, or\n * because it has been evicted).\n */\n protected readonly _refCounts = new Map<Hash, number>();\n protected readonly _refs = new Map<Hash, readonly Hash[]>();\n\n constructor(\n sourceStore: Store,\n sourceCacheSizeLimit: number,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n getSizeOfChunk: (chunk: Chunk) => number = getSizeOfValue,\n ) {\n this._sourceChunksCache = new ChunksCache(\n sourceCacheSizeLimit,\n getSizeOfChunk,\n this._refCounts,\n this._refs,\n );\n this.#sourceStore = sourceStore;\n this.#chunkHasher = chunkHasher;\n this.#assertValidHash = assertValidHash;\n }\n\n async read(sourceRead?: Read): Promise<LazyRead> {\n const release = await this.#rwLock.read();\n return new LazyRead(\n this.#heads,\n this._memOnlyChunks,\n this._sourceChunksCache,\n this.#sourceStore,\n release,\n this.#assertValidHash,\n sourceRead,\n );\n }\n\n async write(): Promise<LazyWrite> {\n const release = await this.#rwLock.write();\n return new LazyWrite(\n this.#heads,\n this._memOnlyChunks,\n this._sourceChunksCache,\n this.#sourceStore,\n this._refCounts,\n this._refs,\n release,\n this.#chunkHasher,\n this.#assertValidHash,\n );\n }\n\n close(): Promise<void> {\n return promiseVoid;\n }\n\n /**\n * Does not acquire any lock on the store.\n */\n isCached(chunkHash: Hash): boolean {\n return (\n this._sourceChunksCache.getWithoutUpdatingLRU(chunkHash) !== undefined\n );\n }\n\n withSuspendedSourceCacheEvictsAndDeletes<T>(\n fn: () => MaybePromise<T>,\n ): Promise<T> {\n return this._sourceChunksCache.withSuspendedEvictsAndDeletes(fn);\n }\n}\n\nexport class LazyRead implements Read {\n protected readonly _heads: Map<string, Hash>;\n protected readonly _memOnlyChunks: Map<Hash, Chunk>;\n protected readonly _sourceChunksCache: ChunksCache;\n protected readonly _sourceStore: Store;\n #sourceRead: Promise<Read> | undefined = undefined;\n readonly #release: () => void;\n #closed = false;\n readonly assertValidHash: (hash: Hash) => void;\n readonly #sourceReadOwnedByCaller: boolean;\n\n constructor(\n heads: Map<string, Hash>,\n memOnlyChunks: Map<Hash, Chunk>,\n sourceChunksCache: ChunksCache,\n sourceStore: Store,\n release: () => void,\n assertValidHash: (hash: Hash) => void,\n // If the lazyRead is being run in the context of an existing\n // read, or write, from the perdag then we must use _that_\n // transaction's read. Trying to open our own `sourceRead` will\n // cause the outer transaction to auto-commit.\n sourceRead?: Read,\n ) {\n this._heads = heads;\n this._memOnlyChunks = memOnlyChunks;\n this._sourceChunksCache = sourceChunksCache;\n this._sourceStore = sourceStore;\n this.#release = release;\n this.assertValidHash = assertValidHash;\n this.#sourceRead =\n sourceRead !== undefined ? Promise.resolve(sourceRead) : undefined;\n this.#sourceReadOwnedByCaller = sourceRead !== undefined;\n }\n\n isMemOnlyChunkHash(hash: Hash): boolean {\n return this._memOnlyChunks.has(hash);\n }\n\n async hasChunk(hash: Hash): Promise<boolean> {\n return (await this.getChunk(hash)) !== undefined;\n }\n\n async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk !== undefined) {\n return memOnlyChunk;\n }\n let chunk = this._sourceChunksCache.get(hash);\n if (chunk === undefined) {\n chunk = await (await this._getSourceRead()).getChunk(hash);\n if (chunk !== undefined) {\n this._sourceChunksCache.put(chunk);\n }\n }\n return chunk;\n }\n\n mustGetChunk(hash: Hash): Promise<Chunk> {\n return mustGetChunk(this, hash);\n }\n\n getHead(name: string): Promise<Hash | undefined> {\n return Promise.resolve(this._heads.get(name));\n }\n\n release(): void {\n if (!this.#closed) {\n this.#release();\n if (!this.#sourceReadOwnedByCaller) {\n this.#sourceRead\n ?.then(read => read.release())\n // If creation of the read failed there is nothing to release.\n // Catch to avoid `Uncaught (in promise)` errors being reported.\n .catch(_ => {});\n }\n this.#closed = true;\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n protected _getSourceRead(): Promise<Read> {\n if (!this.#sourceRead) {\n this.#sourceRead = this._sourceStore.read();\n }\n return this.#sourceRead;\n }\n}\n\nexport class LazyWrite\n extends LazyRead\n implements Write, RefCountUpdatesDelegate\n{\n readonly #refCounts: Map<Hash, number>;\n readonly #refs: Map<Hash, readonly Hash[]>;\n readonly #chunkHasher: ChunkHasher;\n protected readonly _pendingHeadChanges = new Map<string, HeadChange>();\n protected readonly _pendingMemOnlyChunks = new Map<Hash, Chunk>();\n protected readonly _pendingCachedChunks = new Map<\n Hash,\n {chunk: Chunk; size: number}\n >();\n readonly #createdChunks = new Set<Hash>();\n\n constructor(\n heads: Map<string, Hash>,\n memOnlyChunks: Map<Hash, Chunk>,\n sourceChunksCache: ChunksCache,\n sourceStore: Store,\n refCounts: Map<Hash, number>,\n refs: Map<Hash, readonly Hash[]>,\n release: () => void,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n ) {\n super(\n heads,\n memOnlyChunks,\n sourceChunksCache,\n sourceStore,\n release,\n assertValidHash,\n );\n this.#refCounts = refCounts;\n this.#refs = refs;\n this.#chunkHasher = chunkHasher;\n }\n\n createChunk = <V>(data: V, refs: Refs): Chunk<V> => {\n const chunk = createChunk(data, refs, this.#chunkHasher);\n this.#createdChunks.add(chunk.hash);\n return chunk;\n };\n\n putChunk<V>(c: Chunk<V>, size?: number): Promise<void> {\n const {hash, meta} = c;\n this.assertValidHash(hash);\n if (meta.length > 0) {\n for (const h of meta) {\n this.assertValidHash(h);\n }\n }\n if (this.#createdChunks.has(hash) || this.isMemOnlyChunkHash(hash)) {\n this._pendingMemOnlyChunks.set(hash, c);\n } else {\n this._pendingCachedChunks.set(hash, {chunk: c, size: size ?? -1});\n }\n return promiseVoid;\n }\n\n async setHead(name: string, hash: Hash): Promise<void> {\n await this.#setHead(name, hash);\n }\n\n async removeHead(name: string): Promise<void> {\n await this.#setHead(name, undefined);\n }\n\n async #setHead(name: string, hash: Hash | undefined): Promise<void> {\n const oldHash = await this.getHead(name);\n const v = this._pendingHeadChanges.get(name);\n if (v === undefined) {\n this._pendingHeadChanges.set(name, {new: hash, old: oldHash});\n } else {\n // Keep old if existing\n v.new = hash;\n }\n }\n\n override isMemOnlyChunkHash(hash: Hash): boolean {\n return (\n this._pendingMemOnlyChunks.has(hash) || super.isMemOnlyChunkHash(hash)\n );\n }\n\n override async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const pendingMemOnlyChunk = this._pendingMemOnlyChunks.get(hash);\n if (pendingMemOnlyChunk !== undefined) {\n return pendingMemOnlyChunk;\n }\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk !== undefined) {\n return memOnlyChunk;\n }\n // In order to delegate determining reachability to `computeRefCountUpdates`\n // and defer this determination until commit time, treat cache misses\n // as a 'put' of the lazily-loaded chunk.\n const pendingCachedChunk = this._pendingCachedChunks.get(hash);\n if (pendingCachedChunk !== undefined) {\n return pendingCachedChunk.chunk;\n }\n let chunk = this._sourceChunksCache.get(hash);\n if (chunk === undefined) {\n chunk = await (await this._getSourceRead()).getChunk(hash);\n if (chunk !== undefined) {\n this._pendingCachedChunks.set(chunk.hash, {chunk, size: -1});\n }\n }\n return chunk;\n }\n\n override getHead(name: string): Promise<Hash | undefined> {\n const headChange = this._pendingHeadChanges.get(name);\n if (headChange) {\n return Promise.resolve(headChange.new);\n }\n return super.getHead(name);\n }\n\n async commit(): Promise<void> {\n const pendingChunks = new Set(\n joinIterables(\n this._pendingMemOnlyChunks.keys(),\n this._pendingCachedChunks.keys(),\n ),\n );\n const refCountUpdates = await computeRefCountUpdates(\n this._pendingHeadChanges.values(),\n pendingChunks,\n this,\n );\n\n for (const [hash, count] of refCountUpdates) {\n if (this.isMemOnlyChunkHash(hash)) {\n if (count === 0) {\n this.#refCounts.delete(hash);\n this._memOnlyChunks.delete(hash);\n this.#refs.delete(hash);\n } else {\n this.#refCounts.set(hash, count);\n const chunk = this._pendingMemOnlyChunks.get(hash);\n if (chunk) {\n this.#refs.set(hash, chunk.meta);\n this._memOnlyChunks.set(hash, chunk);\n }\n }\n refCountUpdates.delete(hash);\n }\n }\n\n this._sourceChunksCache.updateForCommit(\n this._pendingCachedChunks,\n refCountUpdates,\n );\n\n for (const [name, headChange] of this._pendingHeadChanges) {\n if (headChange.new) {\n this._heads.set(name, headChange.new);\n } else {\n this._heads.delete(name);\n }\n }\n\n this._pendingMemOnlyChunks.clear();\n this._pendingCachedChunks.clear();\n this._pendingHeadChanges.clear();\n this.release();\n }\n\n getRefCount(hash: Hash): number | undefined {\n return this.#refCounts.get(hash);\n }\n\n getRefs(hash: Hash): readonly Hash[] | undefined {\n const pendingMemOnlyChunk = this._pendingMemOnlyChunks.get(hash);\n if (pendingMemOnlyChunk) {\n return pendingMemOnlyChunk.meta;\n }\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk) {\n return memOnlyChunk.meta;\n }\n const pendingCachedChunk = this._pendingCachedChunks.get(hash);\n if (pendingCachedChunk !== undefined) {\n return pendingCachedChunk.chunk.meta;\n }\n return this.#refs.get(hash);\n }\n\n areRefsCounted(hash: Hash): boolean {\n return this.#refs.has(hash);\n }\n\n chunksPersisted(chunkHashes: readonly Hash[]): void {\n const chunksToCache = [];\n for (const chunkHash of chunkHashes) {\n const chunk = this._memOnlyChunks.get(chunkHash);\n if (chunk) {\n this._memOnlyChunks.delete(chunkHash);\n chunksToCache.push(chunk);\n }\n }\n this._sourceChunksCache.persisted(chunksToCache);\n }\n}\n\ntype CacheEntry = {\n chunk: Chunk;\n size: number;\n};\n\nclass ChunksCache {\n readonly #cacheSizeLimit: number;\n readonly #getSizeOfChunk: (chunk: Chunk) => number;\n readonly #refCounts: Map<Hash, number>;\n readonly #refs: Map<Hash, readonly Hash[]>;\n #size = 0;\n #evictsAndDeletesSuspended = false;\n readonly #suspendedDeletes: Hash[] = [];\n\n /**\n * Iteration order is from least to most recently used.\n *\n * Public so that testing subclass can access.\n */\n readonly cacheEntries = new Map<Hash, CacheEntry>();\n\n constructor(\n cacheSizeLimit: number,\n getSizeOfChunk: (v: Chunk) => number,\n refCounts: Map<Hash, number>,\n refs: Map<Hash, readonly Hash[]>,\n ) {\n this.#cacheSizeLimit = cacheSizeLimit;\n this.#getSizeOfChunk = getSizeOfChunk;\n this.#refCounts = refCounts;\n this.#refs = refs;\n }\n\n get(hash: Hash): Chunk | undefined {\n const cacheEntry = this.cacheEntries.get(hash);\n if (cacheEntry) {\n // Update order in map for LRU tracking.\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, cacheEntry);\n }\n return cacheEntry?.chunk;\n }\n\n getWithoutUpdatingLRU(hash: Hash): Chunk | undefined {\n return this.cacheEntries.get(hash)?.chunk;\n }\n\n put(chunk: Chunk): void {\n const {hash} = chunk;\n // If there is an existing cache entry then the cached value must be\n // equivalent. Update order in map for LRU tracking and early return.\n const oldCacheEntry = this.cacheEntries.get(hash);\n if (oldCacheEntry) {\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, oldCacheEntry);\n return;\n }\n\n // Only cache if there is a ref from a head to this chunk\n const refCount = this.#refCounts.get(hash);\n if (refCount === undefined || refCount < 1) {\n return;\n }\n if (!this.#cacheChunk(chunk)) {\n return;\n }\n if (!this.#refs.has(hash)) {\n for (const refHash of chunk.meta) {\n this.#refCounts.set(refHash, (this.#refCounts.get(refHash) || 0) + 1);\n }\n this.#refs.set(hash, chunk.meta);\n }\n\n this.#ensureCacheSizeLimit();\n }\n\n #ensureCacheSizeLimit() {\n if (this.#evictsAndDeletesSuspended) {\n return;\n }\n for (const entry of this.cacheEntries.values()) {\n if (this.#size <= this.#cacheSizeLimit) {\n break;\n }\n this.#evict(entry);\n }\n }\n\n #cacheChunk(chunk: Chunk, size?: number): boolean {\n const chunkSize = size ?? this.#getSizeOfChunk(chunk);\n if (chunkSize > this.#cacheSizeLimit) {\n // This value cannot be cached due to its size exceeding the\n // cache size limit, don't evict other entries to try to make\n // room for it.\n return false;\n }\n this.#size += chunkSize;\n this.cacheEntries.set(chunk.hash, {chunk, size: chunkSize});\n return true;\n }\n\n #evict(cacheEntry: CacheEntry): void {\n const {hash} = cacheEntry.chunk;\n this.#size -= cacheEntry.size;\n this.cacheEntries.delete(hash);\n }\n\n #deleteEntryByHash(hash: Hash): void {\n this.#refCounts.delete(hash);\n this.#refs.delete(hash);\n const cacheEntry = this.cacheEntries.get(hash);\n if (cacheEntry) {\n this.#size -= cacheEntry.size;\n this.cacheEntries.delete(hash);\n }\n }\n\n updateForCommit(\n chunksToPut: Map<Hash, {chunk: Chunk; size: number}>,\n refCountUpdates: Map<Hash, number>,\n ): void {\n for (const [hash, count] of refCountUpdates) {\n if (count === 0) {\n if (!this.#evictsAndDeletesSuspended) {\n this.#deleteEntryByHash(hash);\n } else {\n this.#refCounts.set(hash, 0);\n this.#suspendedDeletes.push(hash);\n }\n } else {\n this.#refCounts.set(hash, count);\n const chunkAndSize = chunksToPut.get(hash);\n if (chunkAndSize) {\n const {chunk, size} = chunkAndSize;\n const oldCacheEntry = this.cacheEntries.get(hash);\n if (oldCacheEntry) {\n // If there is an existing cache entry then the cached value must be\n // equivalent. Update order in map for LRU tracking but avoid\n // recomputing size and creating a new cache entry.\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, oldCacheEntry);\n } else {\n this.#cacheChunk(chunk, size !== -1 ? size : undefined);\n this.#refs.set(hash, chunk.meta);\n }\n }\n }\n }\n this.#ensureCacheSizeLimit();\n }\n\n persisted(chunks: Iterable<Chunk>) {\n for (const chunk of chunks) {\n this.#cacheChunk(chunk);\n }\n this.#ensureCacheSizeLimit();\n }\n\n async withSuspendedEvictsAndDeletes<T>(\n fn: () => MaybePromise<T>,\n ): Promise<T> {\n this.#evictsAndDeletesSuspended = true;\n try {\n return await fn();\n } finally {\n this.#evictsAndDeletesSuspended = false;\n for (const hash of this.#suspendedDeletes) {\n if (this.#refCounts.get(hash) === 0) {\n this.#deleteEntryByHash(hash);\n }\n }\n this.#ensureCacheSizeLimit();\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lazy-store.js","names":["#rwLock","#heads","#sourceStore","#chunkHasher","#assertValidHash","#onStorageFailure","#release","#sourceReadOwnedByCaller","#sourceRead","#getSourceRead","#closed","#refCounts","#refs","#createdChunks","#setHead","#cacheSizeLimit","#getSizeOfChunk","#suspendedDeletes","#cacheChunk","#ensureCacheSizeLimit","#evictsAndDeletesSuspended","#size","#evict","#deleteEntryByHash"],"sources":["../../../../../replicache/src/dag/lazy-store.ts"],"sourcesContent":["import {RWLock} from '@rocicorp/lock';\nimport {joinIterables} from '../../../shared/src/iterables.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport {getSizeOfValue} from '../../../shared/src/size-of-value.ts';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport type {Hash} from '../hash.ts';\nimport {\n getStorageFailure,\n type StorageFailureError,\n} from '../storage-failure.ts';\nimport type {Chunk} from './chunk.ts';\nimport {type ChunkHasher, type Refs, createChunk} from './chunk.ts';\nimport {\n type HeadChange,\n type RefCountUpdatesDelegate,\n computeRefCountUpdates,\n} from './gc.ts';\nimport {type Read, type Store, type Write, mustGetChunk} from './store.ts';\n\n/**\n * Dag Store which lazily loads values from a source store and then caches\n * them in an LRU cache. The memory cache for chunks from the source store\n * size is limited to `sourceCacheSizeLimit` bytes, and values are evicted in an\n * LRU fashion. The purpose of this store is to avoid holding the entire client\n * view (i.e. the source store's content) in each tab's JavaScript heap.\n *\n * This store's heads are independent from the heads of source store, and are\n * only stored in memory.\n *\n * Chunks which are created via this store's {@link Write} transaction's\n * {@link createChunk} method are assumed to not be persisted to the source\n * store and thus are cached separately from the source store chunks. These\n * memory-only chunks will not be evicted, and their sizes are not counted\n * towards the source chunk cache size. A memory-only chunk will be deleted if\n * it is no longer reachable from one of this store's heads.\n *\n * Writes only manipulate the in memory state of this store and do not alter the\n * source store. Thus values must be written to the source store through a\n * separate process (see {@link persist}).\n *\n * Intended use:\n * 1. source store is the 'perdag', a slower persistent store (i.e.\n * dag.StoreImpl using a kv.IDBStore)\n * 2. this store's 'main' head is initialized to the hash of a chunk containing\n * a commit in the source store\n * 3. reads lazily read chunks from the source store and cache them\n * 3. writes are initially made to this store with memory-only chunks\n * 4. writes are asynchronously persisted to the source store through a separate\n * process (see {@link persist}}. This process gathers memory-only chunks\n * from this store and then writes them to the source store. It then informs\n * this store that these chunks are no longer memory-only by calling\n * {@link chunksPersisted}, which move these chunks\n * to this store's LRU cache of source chunks (making them eligible for\n * eviction).\n *\n * @param sourceStore Store to lazy load and cache values from.\n * @param sourceCacheSizeLimit Size limit in bytes for cache of chunks loaded\n * from `sourceStore`. This size of a value is determined using\n * `getSizeOfValue`. Keys do not count towards cache size. Memory-only chunks\n * do not count towards cache size.\n * @param getSizeOfValue Function for measuring the size in bytes of a value.\n */\nexport class LazyStore implements Store {\n /**\n * This lock is used to ensure correct isolation of Reads and Writes.\n * Multiple Reads are allowed in parallel but only a single Write. Reads and\n * Writes see an isolated view of the store (corresponding to the Serializable\n * level of transaction isolation defined in the SQL standard).\n *\n * To ensure these semantics the read lock must be acquired when a Read is\n * created and held til it is closed, and a Write lock must be acquired when a\n * Write is created and held til it is committed or closed.\n *\n * Code must have a read or write lock to\n * - read `_heads`\n * - read `_memOnlyChunks`\n * - read `_sourceStore`\n * - read and write `_sourceChunksCache`\n * - read and write `_refCounts`\n * - read and write `_refs`\n * and must have a write lock to\n * - write `_heads`\n * - write `_memOnlyChunks`\n */\n readonly #rwLock = new RWLock();\n readonly #heads = new Map<string, Hash>();\n readonly #sourceStore: Store;\n readonly #chunkHasher: ChunkHasher;\n readonly #assertValidHash: (hash: Hash) => void;\n\n /** The following are protected so testing subclass can access. */\n protected readonly _memOnlyChunks = new Map<Hash, Chunk>();\n protected readonly _sourceChunksCache: ChunksCache;\n /**\n * Ref counts are maintained so that chunks which are unreachable\n * from this stores heads can be eagerly and deterministically deleted from\n * `this._memOnlyChunks` and `this._sourceChunksCache`.\n *\n * These ref counts are independent from `this._sourceStore`'s ref counts.\n * These ref counts are based on reachability from `this._heads`.\n * A chunk is deleted from `this._memOnlyChunks` or\n * `this._sourceChunksCache` (which ever it is in) when its ref count becomes\n * zero.\n * These ref counts count the refs in `this._heads` and `this._refs`.\n *\n * Not all reachable chunk's refs are included in `this._refs`, because this\n * would require loading all chunks reachable in the source store in a\n * non-lazy manner. `this._refs` contains the refs of all currently reachable\n * chunks that were ever in `this._memOnlyChunks` or\n * `this._sourceChunksCache` (even if they have been evicted). A\n * chunk's ref information is lazily discovered and stored in `this._refs` and\n * counted in `this._refCounts`. A chunk's entries in `this._refs` and\n * `this._refCounts` are only deleted when a chunk is deleted due to it\n * becoming unreachable (it is not deleted if the chunk is evicted from the\n * source-store cache).\n *\n * The major implication of this lazy discovery of source store refs, is that\n * a reachable source store chunk may not be cached when loaded, because it is\n * not known to be reachable because some of the pertinent refs have not been\n * discovered. However, in practice chunks are read by traversing the graph\n * starting from a head, and all pertinent refs are discovered as part of the\n * traversal.\n *\n * These ref counts can be changed in two ways:\n * 1. A LazyRead has a cache miss and loads a chunk from the source store that\n * is reachable from this._heads. If this chunk's refs are not currently\n * counted, it will not have an entry in `this._refs`. In this case, the\n * chunks refs will be put in `this._refs` and `this._refCounts` will be\n * updated to count them.\n * 2. A LazyWrite commit updates a head (which can result in increasing or\n * decreasing ref count) or puts a reachable chunk (either a `memory-only` or\n * `source` chunk) that references this hash (increasing ref count). The\n * computation of these ref count changes is delegated to the\n * `computeRefCountUpdates` shared with dag.StoreImpl. In order to\n * delegate determining reachability to `computeRefCountUpdates` and defer\n * this determination until commit time, LazyWrite treats cache misses\n * as a 'put' of the lazily-loaded chunk.\n *\n * A chunk's hash may have an entry in `this._refCounts` without that\n * chunk have ever been in `this._memOnlyChunks` or `this._sourceChunksCache`.\n * This is the case when a head or a reachable chunk that was ever in\n * `this._memOnlyChunks` or `this._sourceChunksCache` references a chunk\n * which is not currently cached (either because it has not been read, or\n * because it has been evicted).\n */\n protected readonly _refCounts = new Map<Hash, number>();\n protected readonly _refs = new Map<Hash, readonly Hash[]>();\n\n readonly #onStorageFailure:\n | ((failure: StorageFailureError) => void)\n | undefined;\n\n /**\n * @param onStorageFailure Called when a read of the source store fails on\n * its storage (a {@link StorageFailureError}). Every read this store makes\n * for a chunk it has not cached goes through here, whichever caller asked\n * for it: a query, a mutation, a poke. The source store's own wrapper\n * reports only the begin, commit and release of a transaction.\n */\n constructor(\n sourceStore: Store,\n sourceCacheSizeLimit: number,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n getSizeOfChunk: (chunk: Chunk) => number = getSizeOfValue,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n ) {\n this._sourceChunksCache = new ChunksCache(\n sourceCacheSizeLimit,\n getSizeOfChunk,\n this._refCounts,\n this._refs,\n );\n this.#sourceStore = sourceStore;\n this.#chunkHasher = chunkHasher;\n this.#assertValidHash = assertValidHash;\n this.#onStorageFailure = onStorageFailure;\n }\n\n async read(sourceRead?: Read): Promise<LazyRead> {\n const release = await this.#rwLock.read();\n return new LazyRead(\n this.#heads,\n this._memOnlyChunks,\n this._sourceChunksCache,\n this.#sourceStore,\n release,\n this.#assertValidHash,\n sourceRead,\n this.#onStorageFailure,\n );\n }\n\n async write(): Promise<LazyWrite> {\n const release = await this.#rwLock.write();\n return new LazyWrite(\n this.#heads,\n this._memOnlyChunks,\n this._sourceChunksCache,\n this.#sourceStore,\n this._refCounts,\n this._refs,\n release,\n this.#chunkHasher,\n this.#assertValidHash,\n this.#onStorageFailure,\n );\n }\n\n close(): Promise<void> {\n return promiseVoid;\n }\n\n /**\n * Does not acquire any lock on the store.\n */\n isCached(chunkHash: Hash): boolean {\n return (\n this._sourceChunksCache.getWithoutUpdatingLRU(chunkHash) !== undefined\n );\n }\n\n withSuspendedSourceCacheEvictsAndDeletes<T>(\n fn: () => MaybePromise<T>,\n ): Promise<T> {\n return this._sourceChunksCache.withSuspendedEvictsAndDeletes(fn);\n }\n}\n\nexport class LazyRead implements Read {\n protected readonly _heads: Map<string, Hash>;\n protected readonly _memOnlyChunks: Map<Hash, Chunk>;\n protected readonly _sourceChunksCache: ChunksCache;\n protected readonly _sourceStore: Store;\n #sourceRead: Promise<Read> | undefined = undefined;\n readonly #release: () => void;\n #closed = false;\n readonly assertValidHash: (hash: Hash) => void;\n readonly #sourceReadOwnedByCaller: boolean;\n readonly #onStorageFailure:\n | ((failure: StorageFailureError) => void)\n | undefined;\n\n constructor(\n heads: Map<string, Hash>,\n memOnlyChunks: Map<Hash, Chunk>,\n sourceChunksCache: ChunksCache,\n sourceStore: Store,\n release: () => void,\n assertValidHash: (hash: Hash) => void,\n // If the lazyRead is being run in the context of an existing\n // read, or write, from the perdag then we must use _that_\n // transaction's read. Trying to open our own `sourceRead` will\n // cause the outer transaction to auto-commit.\n sourceRead?: Read,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n ) {\n this._heads = heads;\n this._memOnlyChunks = memOnlyChunks;\n this._sourceChunksCache = sourceChunksCache;\n this._sourceStore = sourceStore;\n this.#release = release;\n this.assertValidHash = assertValidHash;\n this.#sourceRead =\n sourceRead !== undefined ? Promise.resolve(sourceRead) : undefined;\n this.#sourceReadOwnedByCaller = sourceRead !== undefined;\n this.#onStorageFailure = onStorageFailure;\n }\n\n /**\n * Reads `hash` from the source store. A storage failure on the read is\n * reported before it propagates, so the instance hears of it whichever\n * caller made the read.\n */\n protected async _getSourceChunk(hash: Hash): Promise<Chunk | undefined> {\n try {\n return await (await this.#getSourceRead()).getChunk(hash);\n } catch (e) {\n const failure = getStorageFailure(e);\n if (failure !== undefined) {\n this.#onStorageFailure?.(failure);\n }\n throw e;\n }\n }\n\n isMemOnlyChunkHash(hash: Hash): boolean {\n return this._memOnlyChunks.has(hash);\n }\n\n async hasChunk(hash: Hash): Promise<boolean> {\n return (await this.getChunk(hash)) !== undefined;\n }\n\n async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk !== undefined) {\n return memOnlyChunk;\n }\n let chunk = this._sourceChunksCache.get(hash);\n if (chunk === undefined) {\n chunk = await this._getSourceChunk(hash);\n if (chunk !== undefined) {\n this._sourceChunksCache.put(chunk);\n }\n }\n return chunk;\n }\n\n mustGetChunk(hash: Hash): Promise<Chunk> {\n return mustGetChunk(this, hash);\n }\n\n getHead(name: string): Promise<Hash | undefined> {\n return Promise.resolve(this._heads.get(name));\n }\n\n release(): void {\n if (!this.#closed) {\n this.#release();\n if (!this.#sourceReadOwnedByCaller) {\n this.#sourceRead\n ?.then(read => read.release())\n // If creation of the read failed there is nothing to release.\n // Catch to avoid `Uncaught (in promise)` errors being reported.\n .catch(_ => {});\n }\n this.#closed = true;\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n #getSourceRead(): Promise<Read> {\n if (!this.#sourceRead) {\n this.#sourceRead = this._sourceStore.read();\n }\n return this.#sourceRead;\n }\n}\n\nexport class LazyWrite\n extends LazyRead\n implements Write, RefCountUpdatesDelegate\n{\n readonly #refCounts: Map<Hash, number>;\n readonly #refs: Map<Hash, readonly Hash[]>;\n readonly #chunkHasher: ChunkHasher;\n protected readonly _pendingHeadChanges = new Map<string, HeadChange>();\n protected readonly _pendingMemOnlyChunks = new Map<Hash, Chunk>();\n protected readonly _pendingCachedChunks = new Map<\n Hash,\n {chunk: Chunk; size: number}\n >();\n readonly #createdChunks = new Set<Hash>();\n\n constructor(\n heads: Map<string, Hash>,\n memOnlyChunks: Map<Hash, Chunk>,\n sourceChunksCache: ChunksCache,\n sourceStore: Store,\n refCounts: Map<Hash, number>,\n refs: Map<Hash, readonly Hash[]>,\n release: () => void,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n ) {\n super(\n heads,\n memOnlyChunks,\n sourceChunksCache,\n sourceStore,\n release,\n assertValidHash,\n undefined,\n onStorageFailure,\n );\n this.#refCounts = refCounts;\n this.#refs = refs;\n this.#chunkHasher = chunkHasher;\n }\n\n createChunk = <V>(data: V, refs: Refs): Chunk<V> => {\n const chunk = createChunk(data, refs, this.#chunkHasher);\n this.#createdChunks.add(chunk.hash);\n return chunk;\n };\n\n putChunk<V>(c: Chunk<V>, size?: number): Promise<void> {\n const {hash, meta} = c;\n this.assertValidHash(hash);\n if (meta.length > 0) {\n for (const h of meta) {\n this.assertValidHash(h);\n }\n }\n if (this.#createdChunks.has(hash) || this.isMemOnlyChunkHash(hash)) {\n this._pendingMemOnlyChunks.set(hash, c);\n } else {\n this._pendingCachedChunks.set(hash, {chunk: c, size: size ?? -1});\n }\n return promiseVoid;\n }\n\n async setHead(name: string, hash: Hash): Promise<void> {\n await this.#setHead(name, hash);\n }\n\n async removeHead(name: string): Promise<void> {\n await this.#setHead(name, undefined);\n }\n\n async #setHead(name: string, hash: Hash | undefined): Promise<void> {\n const oldHash = await this.getHead(name);\n const v = this._pendingHeadChanges.get(name);\n if (v === undefined) {\n this._pendingHeadChanges.set(name, {new: hash, old: oldHash});\n } else {\n // Keep old if existing\n v.new = hash;\n }\n }\n\n override isMemOnlyChunkHash(hash: Hash): boolean {\n return (\n this._pendingMemOnlyChunks.has(hash) || super.isMemOnlyChunkHash(hash)\n );\n }\n\n override async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const pendingMemOnlyChunk = this._pendingMemOnlyChunks.get(hash);\n if (pendingMemOnlyChunk !== undefined) {\n return pendingMemOnlyChunk;\n }\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk !== undefined) {\n return memOnlyChunk;\n }\n // In order to delegate determining reachability to `computeRefCountUpdates`\n // and defer this determination until commit time, treat cache misses\n // as a 'put' of the lazily-loaded chunk.\n const pendingCachedChunk = this._pendingCachedChunks.get(hash);\n if (pendingCachedChunk !== undefined) {\n return pendingCachedChunk.chunk;\n }\n let chunk = this._sourceChunksCache.get(hash);\n if (chunk === undefined) {\n chunk = await this._getSourceChunk(hash);\n if (chunk !== undefined) {\n this._pendingCachedChunks.set(chunk.hash, {chunk, size: -1});\n }\n }\n return chunk;\n }\n\n override getHead(name: string): Promise<Hash | undefined> {\n const headChange = this._pendingHeadChanges.get(name);\n if (headChange) {\n return Promise.resolve(headChange.new);\n }\n return super.getHead(name);\n }\n\n async commit(): Promise<void> {\n const pendingChunks = new Set(\n joinIterables(\n this._pendingMemOnlyChunks.keys(),\n this._pendingCachedChunks.keys(),\n ),\n );\n const refCountUpdates = await computeRefCountUpdates(\n this._pendingHeadChanges.values(),\n pendingChunks,\n this,\n );\n\n for (const [hash, count] of refCountUpdates) {\n if (this.isMemOnlyChunkHash(hash)) {\n if (count === 0) {\n this.#refCounts.delete(hash);\n this._memOnlyChunks.delete(hash);\n this.#refs.delete(hash);\n } else {\n this.#refCounts.set(hash, count);\n const chunk = this._pendingMemOnlyChunks.get(hash);\n if (chunk) {\n this.#refs.set(hash, chunk.meta);\n this._memOnlyChunks.set(hash, chunk);\n }\n }\n refCountUpdates.delete(hash);\n }\n }\n\n this._sourceChunksCache.updateForCommit(\n this._pendingCachedChunks,\n refCountUpdates,\n );\n\n for (const [name, headChange] of this._pendingHeadChanges) {\n if (headChange.new) {\n this._heads.set(name, headChange.new);\n } else {\n this._heads.delete(name);\n }\n }\n\n this._pendingMemOnlyChunks.clear();\n this._pendingCachedChunks.clear();\n this._pendingHeadChanges.clear();\n this.release();\n }\n\n getRefCount(hash: Hash): number | undefined {\n return this.#refCounts.get(hash);\n }\n\n getRefs(hash: Hash): readonly Hash[] | undefined {\n const pendingMemOnlyChunk = this._pendingMemOnlyChunks.get(hash);\n if (pendingMemOnlyChunk) {\n return pendingMemOnlyChunk.meta;\n }\n const memOnlyChunk = this._memOnlyChunks.get(hash);\n if (memOnlyChunk) {\n return memOnlyChunk.meta;\n }\n const pendingCachedChunk = this._pendingCachedChunks.get(hash);\n if (pendingCachedChunk !== undefined) {\n return pendingCachedChunk.chunk.meta;\n }\n return this.#refs.get(hash);\n }\n\n areRefsCounted(hash: Hash): boolean {\n return this.#refs.has(hash);\n }\n\n chunksPersisted(chunkHashes: readonly Hash[]): void {\n const chunksToCache = [];\n for (const chunkHash of chunkHashes) {\n const chunk = this._memOnlyChunks.get(chunkHash);\n if (chunk) {\n this._memOnlyChunks.delete(chunkHash);\n chunksToCache.push(chunk);\n }\n }\n this._sourceChunksCache.persisted(chunksToCache);\n }\n}\n\ntype CacheEntry = {\n chunk: Chunk;\n size: number;\n};\n\nclass ChunksCache {\n readonly #cacheSizeLimit: number;\n readonly #getSizeOfChunk: (chunk: Chunk) => number;\n readonly #refCounts: Map<Hash, number>;\n readonly #refs: Map<Hash, readonly Hash[]>;\n #size = 0;\n #evictsAndDeletesSuspended = false;\n readonly #suspendedDeletes: Hash[] = [];\n\n /**\n * Iteration order is from least to most recently used.\n *\n * Public so that testing subclass can access.\n */\n readonly cacheEntries = new Map<Hash, CacheEntry>();\n\n constructor(\n cacheSizeLimit: number,\n getSizeOfChunk: (v: Chunk) => number,\n refCounts: Map<Hash, number>,\n refs: Map<Hash, readonly Hash[]>,\n ) {\n this.#cacheSizeLimit = cacheSizeLimit;\n this.#getSizeOfChunk = getSizeOfChunk;\n this.#refCounts = refCounts;\n this.#refs = refs;\n }\n\n get(hash: Hash): Chunk | undefined {\n const cacheEntry = this.cacheEntries.get(hash);\n if (cacheEntry) {\n // Update order in map for LRU tracking.\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, cacheEntry);\n }\n return cacheEntry?.chunk;\n }\n\n getWithoutUpdatingLRU(hash: Hash): Chunk | undefined {\n return this.cacheEntries.get(hash)?.chunk;\n }\n\n put(chunk: Chunk): void {\n const {hash} = chunk;\n // If there is an existing cache entry then the cached value must be\n // equivalent. Update order in map for LRU tracking and early return.\n const oldCacheEntry = this.cacheEntries.get(hash);\n if (oldCacheEntry) {\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, oldCacheEntry);\n return;\n }\n\n // Only cache if there is a ref from a head to this chunk\n const refCount = this.#refCounts.get(hash);\n if (refCount === undefined || refCount < 1) {\n return;\n }\n if (!this.#cacheChunk(chunk)) {\n return;\n }\n if (!this.#refs.has(hash)) {\n for (const refHash of chunk.meta) {\n this.#refCounts.set(refHash, (this.#refCounts.get(refHash) || 0) + 1);\n }\n this.#refs.set(hash, chunk.meta);\n }\n\n this.#ensureCacheSizeLimit();\n }\n\n #ensureCacheSizeLimit() {\n if (this.#evictsAndDeletesSuspended) {\n return;\n }\n for (const entry of this.cacheEntries.values()) {\n if (this.#size <= this.#cacheSizeLimit) {\n break;\n }\n this.#evict(entry);\n }\n }\n\n #cacheChunk(chunk: Chunk, size?: number): boolean {\n const chunkSize = size ?? this.#getSizeOfChunk(chunk);\n if (chunkSize > this.#cacheSizeLimit) {\n // This value cannot be cached due to its size exceeding the\n // cache size limit, don't evict other entries to try to make\n // room for it.\n return false;\n }\n this.#size += chunkSize;\n this.cacheEntries.set(chunk.hash, {chunk, size: chunkSize});\n return true;\n }\n\n #evict(cacheEntry: CacheEntry): void {\n const {hash} = cacheEntry.chunk;\n this.#size -= cacheEntry.size;\n this.cacheEntries.delete(hash);\n }\n\n #deleteEntryByHash(hash: Hash): void {\n this.#refCounts.delete(hash);\n this.#refs.delete(hash);\n const cacheEntry = this.cacheEntries.get(hash);\n if (cacheEntry) {\n this.#size -= cacheEntry.size;\n this.cacheEntries.delete(hash);\n }\n }\n\n updateForCommit(\n chunksToPut: Map<Hash, {chunk: Chunk; size: number}>,\n refCountUpdates: Map<Hash, number>,\n ): void {\n for (const [hash, count] of refCountUpdates) {\n if (count === 0) {\n if (!this.#evictsAndDeletesSuspended) {\n this.#deleteEntryByHash(hash);\n } else {\n this.#refCounts.set(hash, 0);\n this.#suspendedDeletes.push(hash);\n }\n } else {\n this.#refCounts.set(hash, count);\n const chunkAndSize = chunksToPut.get(hash);\n if (chunkAndSize) {\n const {chunk, size} = chunkAndSize;\n const oldCacheEntry = this.cacheEntries.get(hash);\n if (oldCacheEntry) {\n // If there is an existing cache entry then the cached value must be\n // equivalent. Update order in map for LRU tracking but avoid\n // recomputing size and creating a new cache entry.\n this.cacheEntries.delete(hash);\n this.cacheEntries.set(hash, oldCacheEntry);\n } else {\n this.#cacheChunk(chunk, size !== -1 ? size : undefined);\n this.#refs.set(hash, chunk.meta);\n }\n }\n }\n }\n this.#ensureCacheSizeLimit();\n }\n\n persisted(chunks: Iterable<Chunk>) {\n for (const chunk of chunks) {\n this.#cacheChunk(chunk);\n }\n this.#ensureCacheSizeLimit();\n }\n\n async withSuspendedEvictsAndDeletes<T>(\n fn: () => MaybePromise<T>,\n ): Promise<T> {\n this.#evictsAndDeletesSuspended = true;\n try {\n return await fn();\n } finally {\n this.#evictsAndDeletesSuspended = false;\n for (const hash of this.#suspendedDeletes) {\n if (this.#refCounts.get(hash) === 0) {\n this.#deleteEntryByHash(hash);\n }\n }\n this.#ensureCacheSizeLimit();\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"store-impl.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/dag/store-impl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store-impl.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/dag/store-impl.ts"],"names":[],"mappings":"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"}
@@ -39,7 +39,13 @@ var ReadImpl = class {
39
39
  async getChunk(hash) {
40
40
  const dataPromise = this._tx.get(chunkDataKey(hash));
41
41
  const refsPromise = this._tx.get(chunkMetaKey(hash));
42
- const data = await dataPromise;
42
+ let data;
43
+ try {
44
+ data = await dataPromise;
45
+ } catch (e) {
46
+ refsPromise.catch(() => {});
47
+ throw e;
48
+ }
43
49
  if (data === void 0) {
44
50
  refsPromise.catch(() => {});
45
51
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"store-impl.js","names":["#kv","#chunkHasher","#assertValidHash","#onInvalidRefCount","#putChunks","#changedHeads","#setHead","#invalidRefCountError","#applyRefCountUpdates","#removeAllRelatedKeys"],"sources":["../../../../../replicache/src/dag/store-impl.ts"],"sourcesContent":["import type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {type Hash, assertHash} from '../hash.ts';\nimport type {\n Read as KVRead,\n Store as KVStore,\n Write as KVWrite,\n} from '../kv/store.ts';\nimport {\n Chunk,\n type ChunkHasher,\n type Refs,\n assertRefs,\n createChunk,\n} from './chunk.ts';\nimport {type RefCountUpdatesDelegate, computeRefCountUpdates} from './gc.ts';\nimport {InvalidRefCountError} from './invalid-ref-count-error.ts';\nimport {chunkDataKey, chunkMetaKey, chunkRefCountKey, headKey} from './key.ts';\nimport {type Read, type Store, type Write, mustGetChunk} from './store.ts';\n\n/**\n * Called when a write found an invalid ref count in the store. This is the\n * single place where store corruption is detected, so the owner of the store\n * can start recovery no matter which code path performed the write.\n *\n * The callback runs after the write transaction has been released, so it is\n * safe for it to close or drop the underlying kv store.\n */\nexport type OnInvalidRefCount = (e: InvalidRefCountError) => void;\n\nexport class StoreImpl implements Store {\n readonly #kv: KVStore;\n readonly #chunkHasher: ChunkHasher;\n readonly #assertValidHash: (hash: Hash) => void;\n readonly #onInvalidRefCount: OnInvalidRefCount | undefined;\n\n constructor(\n kv: KVStore,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n onInvalidRefCount?: OnInvalidRefCount | undefined,\n ) {\n this.#kv = kv;\n this.#chunkHasher = chunkHasher;\n this.#assertValidHash = assertValidHash;\n this.#onInvalidRefCount = onInvalidRefCount;\n }\n\n async read(): Promise<Read> {\n return new ReadImpl(await this.#kv.read(), this.#assertValidHash);\n }\n\n async write(): Promise<Write> {\n return new WriteImpl(\n await this.#kv.write(),\n this.#chunkHasher,\n this.#assertValidHash,\n this.#onInvalidRefCount,\n );\n }\n\n close(): Promise<void> {\n return this.#kv.close();\n }\n}\n\nexport class ReadImpl implements Read {\n protected readonly _tx: KVRead;\n readonly assertValidHash: (hash: Hash) => void;\n\n constructor(kv: KVRead, assertValidHash: (hash: Hash) => void) {\n this._tx = kv;\n this.assertValidHash = assertValidHash;\n }\n\n hasChunk(hash: Hash): Promise<boolean> {\n return this._tx.has(chunkDataKey(hash));\n }\n\n async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const dataPromise = this._tx.get(chunkDataKey(hash));\n const refsPromise = this._tx.get(chunkMetaKey(hash));\n const data = await dataPromise;\n if (data === undefined) {\n refsPromise.catch(() => {\n // Ignore error since we will return undefined anyway.\n });\n return undefined;\n }\n\n const refsVal = await refsPromise;\n let refs: Refs;\n if (refsVal !== undefined) {\n assertRefs(refsVal);\n refs = refsVal;\n } else {\n refs = [];\n }\n return new Chunk(hash, data, refs);\n }\n\n mustGetChunk(hash: Hash): Promise<Chunk> {\n return mustGetChunk(this, hash);\n }\n\n async getHead(name: string): Promise<Hash | undefined> {\n const data = await this._tx.get(headKey(name));\n if (data === undefined) {\n return undefined;\n }\n assertHash(data);\n return data;\n }\n\n release(): void {\n this._tx.release();\n }\n\n get closed(): boolean {\n return this._tx.closed;\n }\n}\n\ntype HeadChange = {\n new: Hash | undefined;\n old: Hash | undefined;\n};\n\nexport class WriteImpl\n extends ReadImpl\n implements Write, RefCountUpdatesDelegate\n{\n declare protected readonly _tx: KVWrite;\n readonly #chunkHasher: ChunkHasher;\n readonly #onInvalidRefCount: OnInvalidRefCount | undefined;\n #invalidRefCountError: InvalidRefCountError | undefined;\n\n readonly #putChunks = new Set<Hash>();\n readonly #changedHeads = new Map<string, HeadChange>();\n\n constructor(\n kvw: KVWrite,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n onInvalidRefCount?: OnInvalidRefCount | undefined,\n ) {\n super(kvw, assertValidHash);\n this.#chunkHasher = chunkHasher;\n this.#onInvalidRefCount = onInvalidRefCount;\n }\n\n createChunk = <V>(data: V, refs: Refs): Chunk<V> =>\n createChunk(data, refs, this.#chunkHasher);\n\n get kvWrite(): KVWrite {\n return this._tx;\n }\n\n async putChunk(c: Chunk): Promise<void> {\n const {hash, data, meta} = c;\n // We never want to write temp hashes to the underlying store.\n this.assertValidHash(hash);\n const key = chunkDataKey(hash);\n // Commit contains InternalValue and Hash which are opaque types.\n const p1 = this._tx.put(key, data as ReadonlyJSONValue);\n let p2;\n if (meta.length > 0) {\n for (const h of meta) {\n this.assertValidHash(h);\n }\n p2 = this._tx.put(chunkMetaKey(hash), meta);\n }\n this.#putChunks.add(hash);\n await p1;\n await p2;\n }\n\n setHead(name: string, hash: Hash): Promise<void> {\n return this.#setHead(name, hash);\n }\n\n removeHead(name: string): Promise<void> {\n return this.#setHead(name, undefined);\n }\n\n async #setHead(name: string, hash: Hash | undefined): Promise<void> {\n const oldHash = await this.getHead(name);\n const hk = headKey(name);\n\n let p1: Promise<void>;\n if (hash === undefined) {\n p1 = this._tx.del(hk);\n } else {\n p1 = this._tx.put(hk, hash);\n }\n\n const v = this.#changedHeads.get(name);\n if (v === undefined) {\n this.#changedHeads.set(name, {new: hash, old: oldHash});\n } else {\n // Keep old if existing\n v.new = hash;\n }\n\n await p1;\n }\n\n async commit(): Promise<void> {\n let refCountUpdates: Map<Hash, number>;\n try {\n refCountUpdates = await computeRefCountUpdates(\n this.#changedHeads.values(),\n this.#putChunks,\n this,\n );\n } catch (e) {\n if (e instanceof InvalidRefCountError) {\n // Reported from release() rather than here: the owner may drop the\n // store in response and the kv transaction still needs to roll back.\n this.#invalidRefCountError = e;\n }\n throw e;\n }\n await this.#applyRefCountUpdates(refCountUpdates);\n await this._tx.commit();\n }\n\n async getRefCount(hash: Hash): Promise<number | undefined> {\n const value = await this._tx.get(chunkRefCountKey(hash));\n if (value === undefined) {\n return undefined;\n }\n if (\n typeof value !== 'number' ||\n value < 0 ||\n value > 0xffff ||\n value !== (value | 0)\n ) {\n throw new InvalidRefCountError(hash, value);\n }\n return value;\n }\n\n async getRefs(hash: Hash): Promise<readonly Hash[]> {\n const meta = await this._tx.get(chunkMetaKey(hash));\n if (meta === undefined) {\n return [];\n }\n assertRefs(meta);\n return meta;\n }\n\n async #applyRefCountUpdates(refCountCache: Map<Hash, number>): Promise<void> {\n const ps: Promise<void>[] = [];\n for (const [hash, count] of refCountCache) {\n if (count === 0) {\n ps.push(this.#removeAllRelatedKeys(hash));\n } else {\n const refCountKey = chunkRefCountKey(hash);\n ps.push(this._tx.put(refCountKey, count));\n }\n }\n await Promise.all(ps);\n }\n\n async #removeAllRelatedKeys(hash: Hash): Promise<void> {\n await Promise.all([\n this._tx.del(chunkDataKey(hash)),\n this._tx.del(chunkMetaKey(hash)),\n this._tx.del(chunkRefCountKey(hash)),\n ]);\n\n this.#putChunks.delete(hash);\n }\n\n release(): void {\n try {\n this._tx.release();\n } finally {\n // Report even if the kv release threw (for example a failed SQLite\n // ROLLBACK): the store is corrupt either way and the owner must still\n // recover. The release error keeps propagating to the caller.\n if (this.#invalidRefCountError) {\n this.#onInvalidRefCount?.(this.#invalidRefCountError);\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"store-impl.js","names":["#kv","#chunkHasher","#assertValidHash","#onInvalidRefCount","#putChunks","#changedHeads","#setHead","#invalidRefCountError","#applyRefCountUpdates","#removeAllRelatedKeys"],"sources":["../../../../../replicache/src/dag/store-impl.ts"],"sourcesContent":["import type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {type Hash, assertHash} from '../hash.ts';\nimport type {\n Read as KVRead,\n Store as KVStore,\n Write as KVWrite,\n} from '../kv/store.ts';\nimport {\n Chunk,\n type ChunkHasher,\n type Refs,\n assertRefs,\n createChunk,\n} from './chunk.ts';\nimport {type RefCountUpdatesDelegate, computeRefCountUpdates} from './gc.ts';\nimport {InvalidRefCountError} from './invalid-ref-count-error.ts';\nimport {chunkDataKey, chunkMetaKey, chunkRefCountKey, headKey} from './key.ts';\nimport {type Read, type Store, type Write, mustGetChunk} from './store.ts';\n\n/**\n * Called when a write found an invalid ref count in the store. This is the\n * single place where store corruption is detected, so the owner of the store\n * can start recovery no matter which code path performed the write.\n *\n * The callback runs after the write transaction has been released, so it is\n * safe for it to close or drop the underlying kv store.\n */\nexport type OnInvalidRefCount = (e: InvalidRefCountError) => void;\n\nexport class StoreImpl implements Store {\n readonly #kv: KVStore;\n readonly #chunkHasher: ChunkHasher;\n readonly #assertValidHash: (hash: Hash) => void;\n readonly #onInvalidRefCount: OnInvalidRefCount | undefined;\n\n constructor(\n kv: KVStore,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n onInvalidRefCount?: OnInvalidRefCount | undefined,\n ) {\n this.#kv = kv;\n this.#chunkHasher = chunkHasher;\n this.#assertValidHash = assertValidHash;\n this.#onInvalidRefCount = onInvalidRefCount;\n }\n\n async read(): Promise<Read> {\n return new ReadImpl(await this.#kv.read(), this.#assertValidHash);\n }\n\n async write(): Promise<Write> {\n return new WriteImpl(\n await this.#kv.write(),\n this.#chunkHasher,\n this.#assertValidHash,\n this.#onInvalidRefCount,\n );\n }\n\n close(): Promise<void> {\n return this.#kv.close();\n }\n}\n\nexport class ReadImpl implements Read {\n protected readonly _tx: KVRead;\n readonly assertValidHash: (hash: Hash) => void;\n\n constructor(kv: KVRead, assertValidHash: (hash: Hash) => void) {\n this._tx = kv;\n this.assertValidHash = assertValidHash;\n }\n\n hasChunk(hash: Hash): Promise<boolean> {\n return this._tx.has(chunkDataKey(hash));\n }\n\n async getChunk(hash: Hash): Promise<Chunk | undefined> {\n const dataPromise = this._tx.get(chunkDataKey(hash));\n const refsPromise = this._tx.get(chunkMetaKey(hash));\n let data: ReadonlyJSONValue | undefined;\n try {\n data = await dataPromise;\n } catch (e) {\n // The two reads fail together on a storage failure; the second\n // rejection has no one to await it and must not surface as unhandled.\n refsPromise.catch(() => {});\n throw e;\n }\n if (data === undefined) {\n refsPromise.catch(() => {\n // Ignore error since we will return undefined anyway.\n });\n return undefined;\n }\n\n const refsVal = await refsPromise;\n let refs: Refs;\n if (refsVal !== undefined) {\n assertRefs(refsVal);\n refs = refsVal;\n } else {\n refs = [];\n }\n return new Chunk(hash, data, refs);\n }\n\n mustGetChunk(hash: Hash): Promise<Chunk> {\n return mustGetChunk(this, hash);\n }\n\n async getHead(name: string): Promise<Hash | undefined> {\n const data = await this._tx.get(headKey(name));\n if (data === undefined) {\n return undefined;\n }\n assertHash(data);\n return data;\n }\n\n release(): void {\n this._tx.release();\n }\n\n get closed(): boolean {\n return this._tx.closed;\n }\n}\n\ntype HeadChange = {\n new: Hash | undefined;\n old: Hash | undefined;\n};\n\nexport class WriteImpl\n extends ReadImpl\n implements Write, RefCountUpdatesDelegate\n{\n declare protected readonly _tx: KVWrite;\n readonly #chunkHasher: ChunkHasher;\n readonly #onInvalidRefCount: OnInvalidRefCount | undefined;\n #invalidRefCountError: InvalidRefCountError | undefined;\n\n readonly #putChunks = new Set<Hash>();\n readonly #changedHeads = new Map<string, HeadChange>();\n\n constructor(\n kvw: KVWrite,\n chunkHasher: ChunkHasher,\n assertValidHash: (hash: Hash) => void,\n onInvalidRefCount?: OnInvalidRefCount | undefined,\n ) {\n super(kvw, assertValidHash);\n this.#chunkHasher = chunkHasher;\n this.#onInvalidRefCount = onInvalidRefCount;\n }\n\n createChunk = <V>(data: V, refs: Refs): Chunk<V> =>\n createChunk(data, refs, this.#chunkHasher);\n\n get kvWrite(): KVWrite {\n return this._tx;\n }\n\n async putChunk(c: Chunk): Promise<void> {\n const {hash, data, meta} = c;\n // We never want to write temp hashes to the underlying store.\n this.assertValidHash(hash);\n const key = chunkDataKey(hash);\n // Commit contains InternalValue and Hash which are opaque types.\n const p1 = this._tx.put(key, data as ReadonlyJSONValue);\n let p2;\n if (meta.length > 0) {\n for (const h of meta) {\n this.assertValidHash(h);\n }\n p2 = this._tx.put(chunkMetaKey(hash), meta);\n }\n this.#putChunks.add(hash);\n await p1;\n await p2;\n }\n\n setHead(name: string, hash: Hash): Promise<void> {\n return this.#setHead(name, hash);\n }\n\n removeHead(name: string): Promise<void> {\n return this.#setHead(name, undefined);\n }\n\n async #setHead(name: string, hash: Hash | undefined): Promise<void> {\n const oldHash = await this.getHead(name);\n const hk = headKey(name);\n\n let p1: Promise<void>;\n if (hash === undefined) {\n p1 = this._tx.del(hk);\n } else {\n p1 = this._tx.put(hk, hash);\n }\n\n const v = this.#changedHeads.get(name);\n if (v === undefined) {\n this.#changedHeads.set(name, {new: hash, old: oldHash});\n } else {\n // Keep old if existing\n v.new = hash;\n }\n\n await p1;\n }\n\n async commit(): Promise<void> {\n let refCountUpdates: Map<Hash, number>;\n try {\n refCountUpdates = await computeRefCountUpdates(\n this.#changedHeads.values(),\n this.#putChunks,\n this,\n );\n } catch (e) {\n if (e instanceof InvalidRefCountError) {\n // Reported from release() rather than here: the owner may drop the\n // store in response and the kv transaction still needs to roll back.\n this.#invalidRefCountError = e;\n }\n throw e;\n }\n await this.#applyRefCountUpdates(refCountUpdates);\n await this._tx.commit();\n }\n\n async getRefCount(hash: Hash): Promise<number | undefined> {\n const value = await this._tx.get(chunkRefCountKey(hash));\n if (value === undefined) {\n return undefined;\n }\n if (\n typeof value !== 'number' ||\n value < 0 ||\n value > 0xffff ||\n value !== (value | 0)\n ) {\n throw new InvalidRefCountError(hash, value);\n }\n return value;\n }\n\n async getRefs(hash: Hash): Promise<readonly Hash[]> {\n const meta = await this._tx.get(chunkMetaKey(hash));\n if (meta === undefined) {\n return [];\n }\n assertRefs(meta);\n return meta;\n }\n\n async #applyRefCountUpdates(refCountCache: Map<Hash, number>): Promise<void> {\n const ps: Promise<void>[] = [];\n for (const [hash, count] of refCountCache) {\n if (count === 0) {\n ps.push(this.#removeAllRelatedKeys(hash));\n } else {\n const refCountKey = chunkRefCountKey(hash);\n ps.push(this._tx.put(refCountKey, count));\n }\n }\n await Promise.all(ps);\n }\n\n async #removeAllRelatedKeys(hash: Hash): Promise<void> {\n await Promise.all([\n this._tx.del(chunkDataKey(hash)),\n this._tx.del(chunkMetaKey(hash)),\n this._tx.del(chunkRefCountKey(hash)),\n ]);\n\n this.#putChunks.delete(hash);\n }\n\n release(): void {\n try {\n this._tx.release();\n } finally {\n // Report even if the kv release threw (for example a failed SQLite\n // ROLLBACK): the store is corrupt either way and the owner must still\n // recover. The release error keeps propagating to the caller.\n if (this.#invalidRefCountError) {\n this.#onInvalidRefCount?.(this.#invalidRefCountError);\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"names":[],"mappings":"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"}
@@ -286,14 +286,12 @@ var SQLiteWrite = class extends WriteImplBase {
286
286
  deleteKeys.push(entry[0]);
287
287
  this._pending.delete(entry[0]);
288
288
  }
289
- const putP = this._pending.size > 0 ? execInBatches([...this._pending], this.#preparedStatements.putN, ([key, value], out) => {
289
+ if (this._pending.size > 0) await execInBatches([...this._pending], this.#preparedStatements.putN, ([key, value], out) => {
290
290
  out.push(key, JSON.stringify(value));
291
- }) : void 0;
292
- const delP = deleteKeys.length > 0 ? execInBatches(deleteKeys, this.#preparedStatements.delN, (key, out) => {
291
+ });
292
+ if (deleteKeys.length > 0) await execInBatches(deleteKeys, this.#preparedStatements.delN, (key, out) => {
293
293
  out.push(key);
294
- }) : void 0;
295
- if (putP) await putP;
296
- if (delP) await delP;
294
+ });
297
295
  this.#dbDelegate.execSync("COMMIT");
298
296
  this._pending.clear();
299
297
  this.#committed = true;