@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 +3 -3
- package/src/assertComplete.js +2 -2
- package/src/bundleStore.js +3 -2
- package/src/exporter.js +3 -7
- package/src/index.js +4 -2
- package/src/internal.js +2 -0
- package/src/kvStore.js +1 -1
- package/src/snapStore.js +16 -12
- package/src/swingStore.js +141 -127
- package/src/transcriptStore.js +10 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swing-store",
|
|
3
|
-
"version": "0.9.2-dev-
|
|
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-
|
|
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": "
|
|
54
|
+
"gitHead": "d1ef35965047ef31f0fa5451d4cfb8bd06c59247"
|
|
55
55
|
}
|
package/src/assertComplete.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @param {import('./internal.js').SwingStoreInternal} internal
|
|
3
|
-
* @param {
|
|
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) {
|
package/src/bundleStore.js
CHANGED
|
@@ -42,7 +42,7 @@ import { createSHA256 } from './hasher.js';
|
|
|
42
42
|
*
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
|
|
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 {() =>
|
|
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 {() =>
|
|
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) =>
|
|
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
|
-
//
|
|
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
|
|
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: () =>
|
|
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
|
-
*
|
|
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 {
|
|
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 {() =>
|
|
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
|
|
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}
|
|
126
|
-
* be kept
|
|
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 {
|
|
131
|
-
*
|
|
160
|
+
* @param {SwingStoreOptions} [options]
|
|
132
161
|
* @returns {SwingStore}
|
|
133
162
|
*/
|
|
134
|
-
export function makeSwingStore(
|
|
135
|
-
const {
|
|
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
|
-
|
|
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 (
|
|
197
|
+
if (path) {
|
|
148
198
|
if (forceReset) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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(
|
|
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
|
-
|
|
199
|
-
//
|
|
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(
|
|
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, ...
|
|
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, ...
|
|
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, ...
|
|
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 (
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
|
553
|
-
initTranscript:
|
|
554
|
-
rolloverSpan:
|
|
555
|
-
rolloverIncarnation:
|
|
556
|
-
getCurrentSpanBounds:
|
|
557
|
-
addItem:
|
|
558
|
-
readSpan:
|
|
559
|
-
stopUsingTranscript:
|
|
560
|
-
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
|
|
564
|
-
loadSnapshot:
|
|
565
|
-
saveSnapshot:
|
|
566
|
-
deleteAllUnusedSnapshots:
|
|
567
|
-
deleteVatSnapshots:
|
|
568
|
-
stopUsingLastSnapshot:
|
|
569
|
-
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
|
|
573
|
-
addBundle:
|
|
574
|
-
hasBundle:
|
|
575
|
-
getBundle:
|
|
576
|
-
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
|
|
582
|
-
snapStore
|
|
583
|
-
bundleStore
|
|
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
|
|
614
|
-
*
|
|
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(
|
|
629
|
-
if (
|
|
630
|
-
typeof
|
|
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(
|
|
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
|
-
* `
|
|
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(
|
|
648
|
-
typeof
|
|
649
|
-
return makeSwingStore(
|
|
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
|
/**
|
package/src/transcriptStore.js
CHANGED
|
@@ -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
|
-
* @
|
|
10
|
-
*
|
|
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: () =>
|
|
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 {
|
|
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 {() =>
|
|
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
|
*
|