@agoric/swing-store 0.9.2-dev-3825031.0 → 0.9.2-dev-d1ef359.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/swing-store",
3
- "version": "0.9.2-dev-3825031.0+3825031",
3
+ "version": "0.9.2-dev-d1ef359.0+d1ef359",
4
4
  "description": "Persistent storage for SwingSet",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -21,7 +21,7 @@
21
21
  "lint:eslint": "eslint ."
22
22
  },
23
23
  "dependencies": {
24
- "@agoric/internal": "0.3.3-dev-3825031.0+3825031",
24
+ "@agoric/internal": "0.3.3-dev-d1ef359.0+d1ef359",
25
25
  "@endo/base64": "^1.0.9",
26
26
  "@endo/bundle-source": "^3.5.1",
27
27
  "@endo/check-bundle": "^1.0.13",
@@ -51,5 +51,5 @@
51
51
  "typeCoverage": {
52
52
  "atLeast": 79.04
53
53
  },
54
- "gitHead": "38250315cedf68dc801b75bee867818a3846fae7"
54
+ "gitHead": "d1ef35965047ef31f0fa5451d4cfb8bd06c59247"
55
55
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @param {import('./internal.js').SwingStoreInternal} internal
3
- * @param {Omit<import('./internal.js').ArtifactMode, 'debug'>} checkMode
2
+ * @param {Pick<import('./internal.js').SwingStoreInternal, 'bundleStore' | 'transcriptStore' | 'snapStore'>} internal
3
+ * @param {Exclude<import('./internal.js').ArtifactMode, 'debug'>} checkMode
4
4
  * @returns {void}
5
5
  */
6
6
  export function assertComplete(internal, checkMode) {
@@ -42,7 +42,7 @@ import { createSHA256 } from './hasher.js';
42
42
  *
43
43
  */
44
44
 
45
- function bundleIDFromName(name) {
45
+ export const bundleIDFromName = name => {
46
46
  typeof name === 'string' || Fail`artifact name must be a string`;
47
47
  const [tag, ...pieces] = name.split('.');
48
48
  if (tag !== 'bundle' || pieces.length !== 1) {
@@ -52,7 +52,8 @@ function bundleIDFromName(name) {
52
52
  }
53
53
  const bundleID = pieces[0];
54
54
  return bundleID;
55
- }
55
+ };
56
+ harden(bundleIDFromName);
56
57
 
57
58
  /**
58
59
  * @param {*} db
package/src/exporter.js CHANGED
@@ -15,10 +15,6 @@ import { validateArtifactMode } from './internal.js';
15
15
  * @template T
16
16
  * @typedef { Iterable<T> | AsyncIterable<T> } AnyIterable
17
17
  */
18
- /**
19
- * @template T
20
- * @typedef { IterableIterator<T> | AsyncIterableIterator<T> } AnyIterableIterator
21
- */
22
18
 
23
19
  /**
24
20
  *
@@ -41,7 +37,7 @@ import { validateArtifactMode } from './internal.js';
41
37
  * Retrieve a value from the "host" portion of the kvStore, just like
42
38
  * hostStorage.hostKVStore.get() would do.
43
39
  *
44
- * @property {() => AnyIterableIterator<KVPair>} getExportData
40
+ * @property {() => AnyIterable<KVPair>} getExportData
45
41
  *
46
42
  * Get a full copy of the first-stage export data (key-value pairs) from the
47
43
  * swingStore. This represents both the contents of the KVStore (excluding host
@@ -56,7 +52,7 @@ import { validateArtifactMode } from './internal.js';
56
52
  * - transcript.${vatID}.${startPos} = ${{ vatID, startPos, endPos, hash }}
57
53
  * - transcript.${vatID}.current = ${{ vatID, startPos, endPos, hash }}
58
54
  *
59
- * @property {() => AnyIterableIterator<string>} getArtifactNames
55
+ * @property {() => AnyIterable<string>} getArtifactNames
60
56
  *
61
57
  * Get a list of name of artifacts available from the swingStore. A name
62
58
  * returned by this method guarantees that a call to `getArtifact` on the same
@@ -69,7 +65,7 @@ import { validateArtifactMode } from './internal.js';
69
65
  * - snapshot.${vatID}.${snapPos}
70
66
  * - bundle.${bundleID}
71
67
  *
72
- * @property {(name: string) => AnyIterableIterator<Uint8Array>} getArtifact
68
+ * @property {(name: string) => AnyIterable<Uint8Array>} getArtifact
73
69
  *
74
70
  * Retrieve an artifact by name as a sequence of binary chunks. May throw if
75
71
  * the artifact is not available, which can occur if the artifact is historical
package/src/index.js CHANGED
@@ -4,10 +4,12 @@ export { importSwingStore } from './importer.js';
4
4
 
5
5
  export { makeArchiveSnapshot, makeArchiveTranscript } from './archiver.js';
6
6
 
7
- // temporary, for the benefit of SwingSet/misc-tools/replay-transcript.js
7
+ // for the benefit of tools like SwingSet/misc-tools/replay-transcript.js
8
+ export { makeKVStore, getKeyType } from './kvStore.js';
9
+ export { makeTranscriptStore } from './transcriptStore.js';
8
10
  export { makeSnapStore } from './snapStore.js';
9
- // and less temporary, for SwingSet/test/vat-warehouse/test-reload-snapshot.js
10
11
  export { makeSnapStoreIO } from './snapStoreIO.js';
12
+ export { makeBundleStore, bundleIDFromName } from './bundleStore.js';
11
13
 
12
14
  // eslint-disable-next-line import/export
13
15
  export * from './types-index.js';
package/src/internal.js CHANGED
@@ -7,6 +7,8 @@ import { Fail, q } from '@endo/errors';
7
7
  *
8
8
  * @typedef {{
9
9
  * dirPath: string | null,
10
+ * db: ReturnType<import('better-sqlite3')>,
11
+ * kvStore: import('./kvStore.js').KVStore,
10
12
  * transcriptStore: TranscriptStoreInternal,
11
13
  * snapStore: SnapStoreInternal,
12
14
  * bundleStore: BundleStoreInternal,
package/src/kvStore.js CHANGED
@@ -27,7 +27,7 @@ export function getKeyType(key) {
27
27
  /**
28
28
  * @param {object} db The SQLite database connection.
29
29
  * @param {() => void} ensureTxn Called before mutating methods to establish a DB transaction
30
- * @param {(...args: string[]) => void} trace Called after sets/gets to record a debug log
30
+ * @param {(...args: string[]) => void} trace Called after set/delete to record a debug log
31
31
  * @returns { KVStore }
32
32
  */
33
33
 
package/src/snapStore.js CHANGED
@@ -7,6 +7,11 @@ import { Fail, q } from '@endo/errors';
7
7
  import { withDeferredCleanup } from '@agoric/internal';
8
8
  import { buffer } from './util.js';
9
9
 
10
+ /**
11
+ * @import { AnyIterable, SwingStoreExporter } from './exporter.js';
12
+ * @import { ArtifactMode } from './internal.js';
13
+ */
14
+
10
15
  /**
11
16
  * @typedef {object} SnapshotResult
12
17
  * @property {string} hash sha256 hash of (uncompressed) snapshot
@@ -26,13 +31,6 @@ import { buffer } from './util.js';
26
31
  */
27
32
 
28
33
  /**
29
- * @import {AnyIterableIterator} from './exporter.js'
30
- */
31
-
32
- /**
33
- * @typedef { import('./exporter.js').SwingStoreExporter } SwingStoreExporter
34
- * @typedef { import('./internal.js').ArtifactMode } ArtifactMode
35
- *
36
34
  * @typedef {{
37
35
  * loadSnapshot: (vatID: string) => AsyncIterableIterator<Uint8Array>,
38
36
  * saveSnapshot: (vatID: string, snapPos: number, snapshotStream: AsyncIterable<Uint8Array>) => Promise<SnapshotResult>,
@@ -47,17 +45,23 @@ import { buffer } from './util.js';
47
45
  * getExportRecords: (includeHistorical: boolean) => IterableIterator<readonly [key: string, value: string]>,
48
46
  * getArtifactNames: (artifactMode: ArtifactMode) => AsyncIterableIterator<string>,
49
47
  * importSnapshotRecord: (key: string, value: string) => void,
50
- * populateSnapshot: (name: string, makeChunkIterator: () => AnyIterableIterator<Uint8Array>, options: { artifactMode: ArtifactMode }) => Promise<void>,
48
+ * populateSnapshot: (name: string, makeChunkIterator: () => AnyIterable<Uint8Array>, options: { artifactMode: ArtifactMode }) => Promise<void>,
51
49
  * assertComplete: (checkMode: Omit<ArtifactMode, 'debug'>) => void,
52
50
  * repairSnapshotRecord: (key: string, value: string) => void,
53
51
  * }} SnapStoreInternal
54
52
  *
55
53
  * @typedef {{
56
54
  * hasHash: (vatID: string, hash: string) => boolean,
57
- * dumpSnapshots: (includeHistorical?: boolean) => {},
55
+ * listAllSnapshots: () => Iterable<{}>,
56
+ * dumpSnapshots: (includeHistorical?: boolean) => Record<string, Array<{snapPos: number, hash: string, compressedSnapshot: Buffer, inUse: (null | 0 | 1)}>>,
58
57
  * deleteSnapshotByHash: (vatID: string, hash: string) => void,
59
58
  * }} SnapStoreDebug
60
59
  *
60
+ * @callback SnapshotCallback
61
+ * Called with the gzipped contents of a new heap snapshot.
62
+ * @param {string} name an export key, e.g. `snapshot.${vatID}.${deliveryCount}`
63
+ * @param {Parameters<import('stream').Readable.from>[0]} compressedData
64
+ * @returns {Promise<void>}
61
65
  */
62
66
 
63
67
  const finished = promisify(finishedCallback);
@@ -71,7 +75,7 @@ const finished = promisify(finishedCallback);
71
75
  * @param {(key: string, value: string | undefined) => void} noteExport
72
76
  * @param {object} [options]
73
77
  * @param {boolean | undefined} [options.keepSnapshots]
74
- * @param {(name: string, compressedData: Parameters<import('stream').Readable.from>[0]) => Promise<void>} [options.archiveSnapshot]
78
+ * @param {SnapshotCallback} [options.archiveSnapshot]
75
79
  * @returns {SnapStore & SnapStoreInternal & SnapStoreDebug}
76
80
  */
77
81
  export function makeSnapStore(
@@ -605,7 +609,7 @@ export function makeSnapStore(
605
609
 
606
610
  /**
607
611
  * @param {string} name Artifact name of the snapshot
608
- * @param {() => AnyIterableIterator<Uint8Array>} makeChunkIterator get an iterator of snapshot byte chunks
612
+ * @param {() => AnyIterable<Uint8Array>} makeChunkIterator get an iterator of snapshot byte chunks
609
613
  * @param {object} options
610
614
  * @param {ArtifactMode} options.artifactMode
611
615
  * @returns {Promise<void>}
@@ -677,7 +681,6 @@ export function makeSnapStore(
677
681
 
678
682
  /**
679
683
  * debug function to list all snapshots
680
- *
681
684
  */
682
685
  function* listAllSnapshots() {
683
686
  yield* sqlListAllSnapshots.iterate();
@@ -706,6 +709,7 @@ export function makeSnapStore(
706
709
  const sql = includeHistorical
707
710
  ? sqlDumpAllSnapshots
708
711
  : sqlDumpCurrentSnapshots;
712
+ /** @type {Record<string, Array<{snapPos: number, hash: string, compressedSnapshot: Buffer, inUse: (null | 0 | 1)}>>} */
709
713
  const dump = {};
710
714
  for (const row of sql.iterate()) {
711
715
  const { vatID, snapPos, hash, compressedSnapshot, inUse } = row;
package/src/swingStore.js CHANGED
@@ -1,12 +1,15 @@
1
1
  // @ts-check
2
2
  /* eslint-env node */
3
3
  import * as fs from 'fs';
4
- import * as path from 'path';
4
+ import * as pathlib from 'path';
5
5
 
6
6
  import sqlite3 from 'better-sqlite3';
7
7
 
8
8
  import { Fail, q } from '@endo/errors';
9
9
 
10
+ import { attenuate } from '@agoric/internal';
11
+ import { TRUE } from '@agoric/internal/src/js-utils.js';
12
+
10
13
  import { dbFileInDirectory } from './util.js';
11
14
  import { makeKVStore, getKeyType } from './kvStore.js';
12
15
  import { makeTranscriptStore } from './transcriptStore.js';
@@ -16,6 +19,14 @@ import { createSHA256 } from './hasher.js';
16
19
  import { makeSnapStoreIO } from './snapStoreIO.js';
17
20
  import { doRepairMetadata } from './repairMetadata.js';
18
21
 
22
+ // https://github.com/WiseLibs/better-sqlite3/blob/HEAD/docs/api.md#new-databasepath-options
23
+ const IN_MEMORY = ':memory:';
24
+
25
+ /**
26
+ * @template T
27
+ * @typedef {(input: T) => T} Replacer
28
+ */
29
+
19
30
  /**
20
31
  * @typedef { import('./kvStore.js').KVStore } KVStore
21
32
  *
@@ -119,24 +130,63 @@ import { doRepairMetadata } from './repairMetadata.js';
119
130
  * relative the relevant transactional unit.
120
131
  */
121
132
 
133
+ /**
134
+ * @typedef {object} SwingStoreOptions
135
+ * @property {boolean} [asFile] For testing, interpret path as a file rather than a swingstore.sqlite parent directory
136
+ * @property {Buffer} [serialized] Binary data to load in memory
137
+ * @property {boolean} [unsafeFastMode] Disable SQLite safeties for e.g. fast import
138
+ * @property {boolean} [readonly]
139
+ * @property {string} [traceFile] Path at which to record KVStore set/delete activity
140
+ * @property {boolean} [keepSnapshots] Retain old heap snapshots
141
+ * @property {boolean} [keepTranscripts] Retain old transcript span items
142
+ * @property {import('./snapStore.js').SnapshotCallback} [archiveSnapshot] Called after creation of a new heap snapshot
143
+ * @property {import('./transcriptStore.js').TranscriptCallback} [archiveTranscript] Called after a formerly-current transcript span is finalized
144
+ * @property {(pendingExports: Iterable<[key: string, value: string | null]>) => void} [exportCallback]
145
+ * @property {Replacer<ReturnType<makeKVStore>>} [wrapKvStore]
146
+ * @property {Replacer<ReturnType<makeTranscriptStore>>} [wrapTranscriptStore]
147
+ * @property {Replacer<ReturnType<makeSnapStore>>} [wrapSnapStore]
148
+ * @property {Replacer<ReturnType<makeBundleStore>>} [wrapBundleStore]
149
+ */
150
+
122
151
  /**
123
152
  * Do the work of `initSwingStore` and `openSwingStore`.
124
153
  *
125
- * @param {string|null} dirPath Path to a directory in which database files may
126
- * be kept. If this is null, the database will be an in-memory ephemeral
154
+ * @param {string|null} path Path to a directory in which database files may
155
+ * be kept (or when the `asFile` option is true, the path to such a database
156
+ * file). If this is null, the database will be an in-memory ephemeral
127
157
  * database that evaporates when the process exits, which is useful for testing.
128
158
  * @param {boolean} forceReset If true, initialize the database to an empty
129
159
  * state if it already exists
130
- * @param {object} options Configuration options
131
- *
160
+ * @param {SwingStoreOptions} [options]
132
161
  * @returns {SwingStore}
133
162
  */
134
- export function makeSwingStore(dirPath, forceReset, options = {}) {
135
- const { serialized } = options;
163
+ export function makeSwingStore(path, forceReset, options = {}) {
164
+ const {
165
+ asFile = false,
166
+ serialized,
167
+ unsafeFastMode,
168
+ readonly = false,
169
+
170
+ traceFile,
171
+ keepSnapshots,
172
+ keepTranscripts,
173
+ archiveSnapshot,
174
+ archiveTranscript,
175
+ exportCallback,
176
+ wrapKvStore = x => x,
177
+ wrapTranscriptStore = x => x,
178
+ wrapSnapStore = x => x,
179
+ wrapBundleStore = x => x,
180
+ } = options;
181
+
136
182
  if (serialized) {
137
183
  Buffer.isBuffer(serialized) || Fail`options.serialized must be Buffer`;
138
- dirPath === null || Fail`options.serialized makes :memory: DB`;
184
+ path === null || Fail`options.serialized makes :memory: DB`;
139
185
  }
186
+ exportCallback === undefined ||
187
+ typeof exportCallback === 'function' ||
188
+ Fail`export callback must be a function`;
189
+
140
190
  let crankhasher;
141
191
  function resetCrankhash() {
142
192
  crankhasher = createSHA256();
@@ -144,40 +194,22 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
144
194
  resetCrankhash();
145
195
 
146
196
  let filePath;
147
- if (dirPath) {
197
+ if (path) {
148
198
  if (forceReset) {
149
- try {
150
- // Node.js 16.8.0 warns:
151
- // In future versions of Node.js, fs.rmdir(path, { recursive: true }) will
152
- // be removed. Use fs.rm(path, { recursive: true }) instead
153
- if (fs.rmSync) {
154
- fs.rmSync(dirPath, { recursive: true });
155
- } else {
156
- fs.rmdirSync(dirPath, { recursive: true });
157
- }
158
- } catch (e) {
159
- // Attempting to delete a non-existent directory is allowed
160
- if (e.code !== 'ENOENT') {
161
- throw e;
162
- }
163
- }
199
+ fs.rmSync(path, { recursive: true, force: true });
200
+ }
201
+ if (asFile) {
202
+ filePath = path;
203
+ } else {
204
+ fs.mkdirSync(path, { recursive: true });
205
+ filePath = dbFileInDirectory(path);
164
206
  }
165
- fs.mkdirSync(dirPath, { recursive: true });
166
- filePath = dbFileInDirectory(dirPath);
167
207
  } else {
168
208
  filePath = ':memory:';
169
209
  }
170
210
 
171
- const {
172
- traceFile,
173
- keepSnapshots,
174
- keepTranscripts,
175
- archiveSnapshot,
176
- archiveTranscript,
177
- } = options;
178
-
179
211
  let traceOutput = traceFile
180
- ? fs.createWriteStream(path.resolve(traceFile), {
212
+ ? fs.createWriteStream(pathlib.resolve(traceFile), {
181
213
  flags: 'a',
182
214
  })
183
215
  : null;
@@ -194,10 +226,10 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
194
226
  }
195
227
 
196
228
  /** @type {*} */
197
- let db = sqlite3(
198
- serialized || filePath,
199
- // { verbose: console.log },
200
- );
229
+ let db = sqlite3(/** @type {string} */ (serialized || filePath), {
230
+ readonly,
231
+ // verbose: console.log,
232
+ });
201
233
 
202
234
  // We use WAL (write-ahead log) mode to allow a background export process to
203
235
  // keep reading from an earlier DB state, while allowing execution to proceed
@@ -230,7 +262,7 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
230
262
  }
231
263
 
232
264
  // PRAGMAs have to happen outside a transaction
233
- setUnsafeFastMode(options.unsafeFastMode);
265
+ if (!readonly) setUnsafeFastMode(unsafeFastMode);
234
266
 
235
267
  // We use IMMEDIATE because the kernel is supposed to be the sole writer of
236
268
  // the DB, and if some other process is holding a write lock, we want to find
@@ -273,11 +305,6 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
273
305
  )
274
306
  `);
275
307
 
276
- const { exportCallback } = options;
277
- exportCallback === undefined ||
278
- typeof exportCallback === 'function' ||
279
- Fail`export callback must be a function`;
280
-
281
308
  const sqlAddPendingExport = db.prepare(`
282
309
  INSERT INTO pendingExports (key, value)
283
310
  VALUES (?, ?)
@@ -290,31 +317,22 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
290
317
  }
291
318
  }
292
319
 
293
- const kvStore = makeKVStore(db, ensureTxn, trace);
320
+ const kvStore = wrapKvStore(makeKVStore(db, ensureTxn, trace));
294
321
 
295
- const { dumpTranscripts, ...transcriptStore } = makeTranscriptStore(
296
- db,
297
- ensureTxn,
298
- noteExport,
299
- {
322
+ const { dumpTranscripts, ...transcriptStoreInternal } = wrapTranscriptStore(
323
+ makeTranscriptStore(db, ensureTxn, noteExport, {
300
324
  keepTranscripts,
301
325
  archiveTranscript,
302
- },
326
+ }),
303
327
  );
304
- const { dumpSnapshots, ...snapStore } = makeSnapStore(
305
- db,
306
- ensureTxn,
307
- makeSnapStoreIO(),
308
- noteExport,
309
- {
328
+ const { dumpSnapshots, ...snapStoreInternal } = wrapSnapStore(
329
+ makeSnapStore(db, ensureTxn, makeSnapStoreIO(), noteExport, {
310
330
  keepSnapshots,
311
331
  archiveSnapshot,
312
- },
332
+ }),
313
333
  );
314
- const { dumpBundles, ...bundleStore } = makeBundleStore(
315
- db,
316
- ensureTxn,
317
- noteExport,
334
+ const { dumpBundles, ...bundleStoreInternal } = wrapBundleStore(
335
+ makeBundleStore(db, ensureTxn, noteExport),
318
336
  );
319
337
 
320
338
  const sqlCommit = db.prepare('COMMIT');
@@ -325,13 +343,9 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
325
343
  let inCrank = false;
326
344
 
327
345
  function diskUsage() {
328
- if (dirPath) {
329
- const dataFilePath = dbFileInDirectory(dirPath);
330
- const stat = fs.statSync(dataFilePath);
331
- return stat.size;
332
- } else {
333
- return 0;
334
- }
346
+ if (filePath === IN_MEMORY) return 0;
347
+ const stat = fs.statSync(filePath);
348
+ return stat.size;
335
349
  }
336
350
 
337
351
  const kernelKVStore = {
@@ -503,10 +517,13 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
503
517
 
504
518
  /** @type {import('./internal.js').SwingStoreInternal} */
505
519
  const internal = harden({
506
- dirPath,
507
- snapStore,
508
- transcriptStore,
509
- bundleStore,
520
+ dirPath: asFile ? null : path,
521
+ asFile,
522
+ db,
523
+ kvStore,
524
+ snapStore: snapStoreInternal,
525
+ transcriptStore: transcriptStoreInternal,
526
+ bundleStore: bundleStoreInternal,
510
527
  });
511
528
 
512
529
  async function repairMetadata(exporter) {
@@ -549,38 +566,38 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
549
566
  return db;
550
567
  }
551
568
 
552
- const transcriptStorePublic = {
553
- initTranscript: transcriptStore.initTranscript,
554
- rolloverSpan: transcriptStore.rolloverSpan,
555
- rolloverIncarnation: transcriptStore.rolloverIncarnation,
556
- getCurrentSpanBounds: transcriptStore.getCurrentSpanBounds,
557
- addItem: transcriptStore.addItem,
558
- readSpan: transcriptStore.readSpan,
559
- stopUsingTranscript: transcriptStore.stopUsingTranscript,
560
- deleteVatTranscripts: transcriptStore.deleteVatTranscripts,
561
- };
569
+ const transcriptStore = attenuate(transcriptStoreInternal, {
570
+ initTranscript: TRUE,
571
+ rolloverSpan: TRUE,
572
+ rolloverIncarnation: TRUE,
573
+ getCurrentSpanBounds: TRUE,
574
+ addItem: TRUE,
575
+ readSpan: TRUE,
576
+ stopUsingTranscript: TRUE,
577
+ deleteVatTranscripts: TRUE,
578
+ });
562
579
 
563
- const snapStorePublic = {
564
- loadSnapshot: snapStore.loadSnapshot,
565
- saveSnapshot: snapStore.saveSnapshot,
566
- deleteAllUnusedSnapshots: snapStore.deleteAllUnusedSnapshots,
567
- deleteVatSnapshots: snapStore.deleteVatSnapshots,
568
- stopUsingLastSnapshot: snapStore.stopUsingLastSnapshot,
569
- getSnapshotInfo: snapStore.getSnapshotInfo,
570
- };
580
+ const snapStore = attenuate(snapStoreInternal, {
581
+ loadSnapshot: TRUE,
582
+ saveSnapshot: TRUE,
583
+ deleteAllUnusedSnapshots: TRUE,
584
+ deleteVatSnapshots: TRUE,
585
+ stopUsingLastSnapshot: TRUE,
586
+ getSnapshotInfo: TRUE,
587
+ });
571
588
 
572
- const bundleStorePublic = {
573
- addBundle: bundleStore.addBundle,
574
- hasBundle: bundleStore.hasBundle,
575
- getBundle: bundleStore.getBundle,
576
- deleteBundle: bundleStore.deleteBundle,
577
- };
589
+ const bundleStore = attenuate(bundleStoreInternal, {
590
+ addBundle: TRUE,
591
+ hasBundle: TRUE,
592
+ getBundle: TRUE,
593
+ deleteBundle: TRUE,
594
+ });
578
595
 
579
596
  const kernelStorage = {
580
597
  kvStore: kernelKVStore,
581
- transcriptStore: transcriptStorePublic,
582
- snapStore: snapStorePublic,
583
- bundleStore: bundleStorePublic,
598
+ transcriptStore,
599
+ snapStore,
600
+ bundleStore,
584
601
  startCrank,
585
602
  establishCrankSavepoint,
586
603
  rollbackCrank,
@@ -610,43 +627,40 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
610
627
  }
611
628
 
612
629
  /**
613
- * Create a new swingset store. If given a directory path string, a persistent
614
- * store will be created in that directory; if there is already a store there,
615
- * it will be reinitialized to an empty state. If the path is null or
616
- * undefined, a memory-only ephemeral store will be created that will evaporate
617
- * on program exit.
618
- *
619
- * @param {string|null} dirPath Path to a directory in which database files may
620
- * be kept. This directory need not actually exist yet (if it doesn't it will
621
- * be created) but it is reserved (by the caller) for the exclusive use of
622
- * this swing store instance. If null, an ephemeral (memory only) store will
623
- * be created.
624
- * @param {object?} options Optional configuration options
630
+ * Create a new swingset store at the given `path`, overwriting any prior store
631
+ * there.
625
632
  *
633
+ * @param {string|null} [path] Path to a directory in which database files may
634
+ * be kept (or when the `asFile` option is true, the path to such a database
635
+ * file). This directory or file need not actually exist yet (if it doesn't
636
+ * it will be created) but it is reserved (by the caller) for the exclusive
637
+ * use of this swing store instance. If null, an ephemeral (memory only)
638
+ * store will be created.
639
+ * @param {SwingStoreOptions} [options]
626
640
  * @returns {SwingStore}
627
641
  */
628
- export function initSwingStore(dirPath = null, options = {}) {
629
- if (dirPath) {
630
- typeof dirPath === 'string' || Fail`dirPath must be a string`;
642
+ export function initSwingStore(path = null, options = {}) {
643
+ if (path) {
644
+ typeof path === 'string' || Fail`path must be a string`;
631
645
  }
632
- return makeSwingStore(dirPath, true, options);
646
+ return makeSwingStore(path, true, options);
633
647
  }
634
648
 
635
649
  /**
636
650
  * Open a persistent swingset store. If there is no existing store at the given
637
- * `dirPath`, a new, empty store will be created.
638
- *
639
- * @param {string} dirPath Path to a directory in which database files may be kept.
640
- * This directory need not actually exist yet (if it doesn't it will be
641
- * created) but it is reserved (by the caller) for the exclusive use of this
642
- * swing store instance.
643
- * @param {object?} options Optional configuration options
651
+ * `path`, a new, empty store will be created.
644
652
  *
653
+ * @param {string} path Path to a directory in which database files may be kept
654
+ * (or when the `asFile` option is true, the path to such a database file).
655
+ * This directory or file need not actually exist yet (if it doesn't it will
656
+ * be created) but it is reserved (by the caller) for the exclusive use of
657
+ * this swing store instance.
658
+ * @param {SwingStoreOptions} [options]
645
659
  * @returns {SwingStore}
646
660
  */
647
- export function openSwingStore(dirPath, options = {}) {
648
- typeof dirPath === 'string' || Fail`dirPath must be a string`;
649
- return makeSwingStore(dirPath, false, options);
661
+ export function openSwingStore(path, options = {}) {
662
+ typeof path === 'string' || Fail`path must be a string`;
663
+ return makeSwingStore(path, false, options);
650
664
  }
651
665
 
652
666
  /**
@@ -6,13 +6,11 @@ import BufferLineTransform from '@agoric/internal/src/node/buffer-line-transform
6
6
  import { createSHA256 } from './hasher.js';
7
7
 
8
8
  /**
9
- * @template T
10
- * @typedef { IterableIterator<T> | AsyncIterableIterator<T> } AnyIterableIterator<T>
9
+ * @import { AnyIterable } from './exporter.js';
10
+ * @import { ArtifactMode } from './internal.js';
11
11
  */
12
12
 
13
13
  /**
14
- * @typedef { import('./internal.js').ArtifactMode } ArtifactMode
15
- *
16
14
  * @typedef {{
17
15
  * initTranscript: (vatID: string) => void,
18
16
  * rolloverSpan: (vatID: string) => Promise<number>,
@@ -29,7 +27,7 @@ import { createSHA256 } from './hasher.js';
29
27
  * getExportRecords: (includeHistorical: boolean) => IterableIterator<readonly [key: string, value: string]>,
30
28
  * getArtifactNames: (artifactMode: ArtifactMode) => AsyncIterableIterator<string>,
31
29
  * importTranscriptSpanRecord: (key: string, value: string) => void,
32
- * populateTranscriptSpan: (name: string, makeChunkIterator: () => AnyIterableIterator<Uint8Array>, options: { artifactMode: ArtifactMode }) => Promise<void>,
30
+ * populateTranscriptSpan: (name: string, makeChunkIterator: () => AnyIterable<Uint8Array>, options: { artifactMode: ArtifactMode }) => Promise<void>,
33
31
  * assertComplete: (checkMode: Omit<ArtifactMode, 'debug'>) => void,
34
32
  * repairTranscriptSpanRecord: (key: string, value: string) => void,
35
33
  * readFullVatTranscript: (vatID: string) => Iterable<{position: number, item: string}>
@@ -39,6 +37,11 @@ import { createSHA256 } from './hasher.js';
39
37
  * dumpTranscripts: (includeHistorical?: boolean) => {[vatID: string]: {[position: number]: string}}
40
38
  * }} TranscriptStoreDebug
41
39
  *
40
+ * @callback TranscriptCallback
41
+ * Called with the entries of a newly-finalized transcript span.
42
+ * @param {string} spanName e.g., `transcript.${vatID}.${startPos}.${endPos}`
43
+ * @param {AnyIterable<Uint8Array>} entries as from `exportSpan`
44
+ * @returns {Promise<void>}
42
45
  */
43
46
 
44
47
  function* empty() {
@@ -62,7 +65,7 @@ function insistTranscriptPosition(position) {
62
65
  * @param {(key: string, value: string | undefined ) => void} noteExport
63
66
  * @param {object} [options]
64
67
  * @param {boolean} [options.keepTranscripts]
65
- * @param {(spanName: string, entries: ReturnType<exportSpan>) => Promise<void>} [options.archiveTranscript]
68
+ * @param {TranscriptCallback} [options.archiveTranscript]
66
69
  * @returns { TranscriptStore & TranscriptStoreInternal & TranscriptStoreDebug }
67
70
  */
68
71
  export function makeTranscriptStore(
@@ -775,7 +778,7 @@ export function makeTranscriptStore(
775
778
  * Import a transcript span from another store.
776
779
  *
777
780
  * @param {string} name Artifact Name of the transcript span
778
- * @param {() => AnyIterableIterator<Uint8Array>} makeChunkIterator get an iterator of transcript byte chunks
781
+ * @param {() => AnyIterable<Uint8Array>} makeChunkIterator get an iterator of transcript byte chunks
779
782
  * @param {object} options
780
783
  * @param {ArtifactMode} options.artifactMode
781
784
  *