@agoric/swing-store 0.9.2-other-dev-3eb1a1d.0 → 0.9.2-other-dev-d15096d.0.d15096d
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 +22 -17
- package/src/archiver.js +24 -12
- package/src/assertComplete.js +7 -2
- package/src/bundleStore.js +5 -4
- package/src/exporter.js +7 -7
- package/src/importer.js +9 -3
- package/src/index.js +4 -2
- package/src/internal.js +9 -3
- package/src/kvStore.js +1 -1
- package/src/repairMetadata.js +9 -3
- package/src/snapStore.js +27 -13
- package/src/swingStore.js +159 -138
- package/src/transcriptStore.js +46 -15
- package/src/types-index.d.ts +6 -1
- package/src/util.js +5 -1
- package/test/bundles.test.js +12 -16
- package/test/deletion.test.js +12 -6
- package/test/export.test.js +14 -5
- package/test/exportImport.test.js +6 -17
- package/test/exports.js +7 -2
- package/test/import.test.js +17 -13
- package/test/repair-metadata.test.js +9 -5
- package/test/snapstore.test.js +5 -4
- package/test/state.test.js +13 -24
- package/test/transcriptStore.test.js +178 -0
- package/test/util.js +0 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swing-store",
|
|
3
|
-
"version": "0.9.2-other-dev-
|
|
3
|
+
"version": "0.9.2-other-dev-d15096d.0.d15096d",
|
|
4
4
|
"description": "Persistent storage for SwingSet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -13,27 +13,29 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "exit 0",
|
|
15
15
|
"test": "ava",
|
|
16
|
-
"test:c8": "c8 --all $C8_OPTIONS ava",
|
|
16
|
+
"test:c8": "c8 --all ${C8_OPTIONS:-} ava",
|
|
17
17
|
"test:xs": "exit 0",
|
|
18
18
|
"lint-fix": "yarn lint:eslint --fix",
|
|
19
|
-
"lint": "run-s --continue-on-error lint:*",
|
|
20
|
-
"lint:types": "tsc",
|
|
21
|
-
"lint:eslint": "eslint ."
|
|
19
|
+
"lint": "yarn run -T run-s --continue-on-error 'lint:*'",
|
|
20
|
+
"lint:types": "yarn run -T tsc",
|
|
21
|
+
"lint:eslint": "yarn run -T eslint ."
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@agoric/internal": "0.3.3-other-dev-
|
|
25
|
-
"@endo/base64": "^1.0.
|
|
26
|
-
"@endo/bundle-source": "^
|
|
27
|
-
"@endo/check-bundle": "^1.0.
|
|
28
|
-
"@endo/errors": "^1.2.
|
|
29
|
-
"@endo/nat": "^5.
|
|
30
|
-
"better-sqlite3": "^
|
|
24
|
+
"@agoric/internal": "0.3.3-other-dev-d15096d.0.d15096d",
|
|
25
|
+
"@endo/base64": "^1.0.12",
|
|
26
|
+
"@endo/bundle-source": "^4.1.2",
|
|
27
|
+
"@endo/check-bundle": "^1.0.17",
|
|
28
|
+
"@endo/errors": "^1.2.13",
|
|
29
|
+
"@endo/nat": "^5.1.3",
|
|
30
|
+
"better-sqlite3": "^10.1.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@endo/init": "^1.1.
|
|
34
|
-
"@
|
|
33
|
+
"@endo/init": "^1.1.12",
|
|
34
|
+
"@endo/promise-kit": "^1.1.13",
|
|
35
|
+
"@endo/stream": "^1.2.13",
|
|
36
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
35
37
|
"ava": "^5.3.0",
|
|
36
|
-
"c8": "^10.1.
|
|
38
|
+
"c8": "^10.1.3",
|
|
37
39
|
"tmp": "^0.2.1"
|
|
38
40
|
},
|
|
39
41
|
"publishConfig": {
|
|
@@ -49,7 +51,10 @@
|
|
|
49
51
|
"timeout": "2m"
|
|
50
52
|
},
|
|
51
53
|
"typeCoverage": {
|
|
52
|
-
"atLeast":
|
|
54
|
+
"atLeast": 80.49
|
|
53
55
|
},
|
|
54
|
-
"
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": "^20.9 || ^22.11"
|
|
58
|
+
},
|
|
59
|
+
"gitHead": "d15096dc4ff8b96e9b6cd11954c20d3a9efbb393"
|
|
55
60
|
}
|
package/src/archiver.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { finished as streamFinishedCallback, Readable } from 'node:stream';
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
2
3
|
import { promisify } from 'node:util';
|
|
3
4
|
import { createGzip } from 'node:zlib';
|
|
4
5
|
import { withDeferredCleanup } from '@agoric/internal';
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @import {AnyIterable} from './exporter.js';
|
|
9
|
+
*/
|
|
10
|
+
|
|
6
11
|
const streamFinished = promisify(streamFinishedCallback);
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
/**
|
|
9
14
|
* @param {string} dirPath
|
|
10
15
|
* @param {object} powers
|
|
11
16
|
* @param {Pick<import('fs'), 'createWriteStream' | 'mkdirSync' | 'renameSync'>} powers.fs
|
|
@@ -15,6 +20,11 @@ const streamFinished = promisify(streamFinishedCallback);
|
|
|
15
20
|
export const makeArchiveSnapshot = (dirPath, powers) => {
|
|
16
21
|
const { fs, path, tmp } = powers;
|
|
17
22
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} name
|
|
25
|
+
* @param {AnyIterable<Uint8Array>} gzData
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
18
28
|
const archiveSnapshot = (name, gzData) => {
|
|
19
29
|
const destPath = path.join(dirPath, `${name}.gz`);
|
|
20
30
|
return withDeferredCleanup(async addCleanup => {
|
|
@@ -28,7 +38,7 @@ export const makeArchiveSnapshot = (dirPath, powers) => {
|
|
|
28
38
|
postfix: '.gz.tmp',
|
|
29
39
|
detachDescriptor: true,
|
|
30
40
|
});
|
|
31
|
-
addCleanup(() => removeCallback());
|
|
41
|
+
addCleanup(async () => removeCallback());
|
|
32
42
|
const writer = fs.createWriteStream('', { fd, flush: true });
|
|
33
43
|
const reader = Readable.from(gzData);
|
|
34
44
|
const destroyReader = promisify(reader.destroy.bind(reader));
|
|
@@ -42,7 +52,7 @@ export const makeArchiveSnapshot = (dirPath, powers) => {
|
|
|
42
52
|
};
|
|
43
53
|
harden(makeArchiveSnapshot);
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
/**
|
|
46
56
|
* @param {string} dirPath
|
|
47
57
|
* @param {object} powers
|
|
48
58
|
* @param {Pick<import('fs'), 'createWriteStream' | 'mkdirSync' | 'renameSync'>} powers.fs
|
|
@@ -52,6 +62,11 @@ harden(makeArchiveSnapshot);
|
|
|
52
62
|
export const makeArchiveTranscript = (dirPath, powers) => {
|
|
53
63
|
const { fs, path, tmp } = powers;
|
|
54
64
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
65
|
+
/**
|
|
66
|
+
* @param {string} spanName
|
|
67
|
+
* @param {AnyIterable<Uint8Array>} entries
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
55
70
|
const archiveTranscript = (spanName, entries) => {
|
|
56
71
|
const destPath = path.join(dirPath, `${spanName}.gz`);
|
|
57
72
|
return withDeferredCleanup(async addCleanup => {
|
|
@@ -65,15 +80,12 @@ export const makeArchiveTranscript = (dirPath, powers) => {
|
|
|
65
80
|
postfix: '.gz.tmp',
|
|
66
81
|
detachDescriptor: true,
|
|
67
82
|
});
|
|
68
|
-
addCleanup(() => removeCallback());
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
addCleanup(() => destroyReader(null));
|
|
75
|
-
reader.pipe(gzip);
|
|
76
|
-
await streamFinished(gzip);
|
|
83
|
+
addCleanup(async () => removeCallback());
|
|
84
|
+
await pipeline(
|
|
85
|
+
entries,
|
|
86
|
+
createGzip(),
|
|
87
|
+
fs.createWriteStream('', { fd, flush: true }),
|
|
88
|
+
);
|
|
77
89
|
fs.renameSync(tmpName, destPath);
|
|
78
90
|
});
|
|
79
91
|
};
|
package/src/assertComplete.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @param {
|
|
3
|
-
* @param {
|
|
2
|
+
* @param {Pick<SwingStoreInternal, 'bundleStore' | 'transcriptStore' | 'snapStore'>} internal
|
|
3
|
+
* @param {Exclude<ArtifactMode, 'debug'>} checkMode
|
|
4
4
|
* @returns {void}
|
|
5
5
|
*/
|
|
6
6
|
export function assertComplete(internal, checkMode) {
|
|
7
7
|
// every bundle must be populated
|
|
8
8
|
internal.bundleStore.assertComplete(checkMode);
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @import {SwingStoreInternal} from './internal.js';
|
|
12
|
+
* @import {ArtifactMode} from './internal.js';
|
|
13
|
+
*/
|
|
14
|
+
|
|
10
15
|
// every 'isCurrent' transcript span must have all items
|
|
11
16
|
// TODO: every vat with any data must have a isCurrent transcript
|
|
12
17
|
// span
|
package/src/bundleStore.js
CHANGED
|
@@ -15,8 +15,8 @@ import { createSHA256 } from './hasher.js';
|
|
|
15
15
|
* @typedef { EndoZipBase64Bundle | GetExportBundle | NestedEvaluateBundle } Bundle
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
|
-
* @
|
|
19
|
-
* @
|
|
18
|
+
* @import {SwingStoreExporter} from './exporter.js';
|
|
19
|
+
* @import {ArtifactMode} from './internal.js';
|
|
20
20
|
*
|
|
21
21
|
* @typedef {{
|
|
22
22
|
* addBundle: (bundleID: string, bundle: Bundle) => void;
|
|
@@ -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
|
@@ -12,12 +12,12 @@ import { assertComplete } from './assertComplete.js';
|
|
|
12
12
|
import { validateArtifactMode } from './internal.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @
|
|
16
|
-
* @typedef { Iterable<T> | AsyncIterable<T> } AnyIterable
|
|
15
|
+
* @import {ArtifactMode} from './internal.js';
|
|
17
16
|
*/
|
|
17
|
+
|
|
18
18
|
/**
|
|
19
19
|
* @template T
|
|
20
|
-
* @typedef {
|
|
20
|
+
* @typedef { Iterable<T> | AsyncIterable<T> } AnyIterable
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -41,7 +41,7 @@ import { validateArtifactMode } from './internal.js';
|
|
|
41
41
|
* Retrieve a value from the "host" portion of the kvStore, just like
|
|
42
42
|
* hostStorage.hostKVStore.get() would do.
|
|
43
43
|
*
|
|
44
|
-
* @property {() =>
|
|
44
|
+
* @property {() => AnyIterable<KVPair>} getExportData
|
|
45
45
|
*
|
|
46
46
|
* Get a full copy of the first-stage export data (key-value pairs) from the
|
|
47
47
|
* swingStore. This represents both the contents of the KVStore (excluding host
|
|
@@ -56,7 +56,7 @@ import { validateArtifactMode } from './internal.js';
|
|
|
56
56
|
* - transcript.${vatID}.${startPos} = ${{ vatID, startPos, endPos, hash }}
|
|
57
57
|
* - transcript.${vatID}.current = ${{ vatID, startPos, endPos, hash }}
|
|
58
58
|
*
|
|
59
|
-
* @property {() =>
|
|
59
|
+
* @property {() => AnyIterable<string>} getArtifactNames
|
|
60
60
|
*
|
|
61
61
|
* Get a list of name of artifacts available from the swingStore. A name
|
|
62
62
|
* returned by this method guarantees that a call to `getArtifact` on the same
|
|
@@ -69,7 +69,7 @@ import { validateArtifactMode } from './internal.js';
|
|
|
69
69
|
* - snapshot.${vatID}.${snapPos}
|
|
70
70
|
* - bundle.${bundleID}
|
|
71
71
|
*
|
|
72
|
-
* @property {(name: string) =>
|
|
72
|
+
* @property {(name: string) => AnyIterable<Uint8Array>} getArtifact
|
|
73
73
|
*
|
|
74
74
|
* Retrieve an artifact by name as a sequence of binary chunks. May throw if
|
|
75
75
|
* the artifact is not available, which can occur if the artifact is historical
|
|
@@ -83,7 +83,7 @@ import { validateArtifactMode } from './internal.js';
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* @typedef { object } ExportSwingStoreOptions
|
|
86
|
-
* @property {
|
|
86
|
+
* @property { ArtifactMode } [artifactMode] What artifacts should/must the exporter provide?
|
|
87
87
|
*/
|
|
88
88
|
|
|
89
89
|
/**
|
package/src/importer.js
CHANGED
|
@@ -5,9 +5,15 @@ import { buffer } from './util.js';
|
|
|
5
5
|
import { validateArtifactMode } from './internal.js';
|
|
6
6
|
import { assertComplete } from './assertComplete.js';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @import {ArtifactMode} from './internal.js';
|
|
10
|
+
* @import {SwingStoreExporter} from './exporter.js';
|
|
11
|
+
* @import {SwingStore} from './swingStore.js';
|
|
12
|
+
*/
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* @typedef { object } ImportSwingStoreOptions
|
|
10
|
-
* @property {
|
|
16
|
+
* @property { ArtifactMode } [artifactMode] What artifacts should the importer use and require?
|
|
11
17
|
*/
|
|
12
18
|
|
|
13
19
|
/**
|
|
@@ -17,10 +23,10 @@ import { assertComplete } from './assertComplete.js';
|
|
|
17
23
|
* returned swingStore is not suitable for execution, and thus only contains
|
|
18
24
|
* the host facet for committing the populated swingStore.
|
|
19
25
|
*
|
|
20
|
-
* @param {
|
|
26
|
+
* @param {SwingStoreExporter} exporter
|
|
21
27
|
* @param {string | null} [dirPath]
|
|
22
28
|
* @param {ImportSwingStoreOptions} [options]
|
|
23
|
-
* @returns {Promise<Pick<
|
|
29
|
+
* @returns {Promise<Pick<SwingStore, 'hostStorage' | 'debug'>>}
|
|
24
30
|
*/
|
|
25
31
|
export async function importSwingStore(exporter, dirPath = null, options = {}) {
|
|
26
32
|
if (dirPath && typeof dirPath !== 'string') {
|
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
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { Fail, q } from '@endo/errors';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
* @import {KVStore} from './kvStore.js';
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @import {SnapStoreInternal} from './snapStore.js';
|
|
9
|
+
* @import {TranscriptStoreInternal} from './transcriptStore.js';
|
|
10
|
+
* @import {BundleStoreInternal} from './bundleStore.js';
|
|
7
11
|
*
|
|
8
12
|
* @typedef {{
|
|
9
13
|
* dirPath: string | null,
|
|
14
|
+
* db: ReturnType<import('better-sqlite3')>,
|
|
15
|
+
* kvStore: KVStore,
|
|
10
16
|
* transcriptStore: TranscriptStoreInternal,
|
|
11
17
|
* snapStore: SnapStoreInternal,
|
|
12
18
|
* 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/repairMetadata.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { Fail, q } from '@endo/errors';
|
|
2
2
|
import { assertComplete } from './assertComplete.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @import {SwingStoreInternal} from './internal.js';
|
|
6
|
+
* @import {SwingStoreExporter} from './exporter.js';
|
|
7
|
+
* @import {ArtifactMode} from './internal.js';
|
|
8
|
+
*/
|
|
9
|
+
|
|
4
10
|
/**
|
|
5
11
|
* Given a pre-existing swingstore and a SwingStoreExporter, read in
|
|
6
12
|
* all the metadata from the exporter and use it to regenerate any
|
|
@@ -24,8 +30,8 @@ import { assertComplete } from './assertComplete.js';
|
|
|
24
30
|
* an open transaction. The caller is responsible for calling
|
|
25
31
|
* `hostStorage.commit()` when they are ready.
|
|
26
32
|
*
|
|
27
|
-
* @param {
|
|
28
|
-
* @param {
|
|
33
|
+
* @param {SwingStoreInternal} internal
|
|
34
|
+
* @param {SwingStoreExporter} exporter
|
|
29
35
|
* @returns {Promise<void>}
|
|
30
36
|
*/
|
|
31
37
|
export async function doRepairMetadata(internal, exporter) {
|
|
@@ -60,7 +66,7 @@ export async function doRepairMetadata(internal, exporter) {
|
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
// and do a completeness check
|
|
63
|
-
/** @type {
|
|
69
|
+
/** @type { ArtifactMode } */
|
|
64
70
|
const artifactMode = 'operational';
|
|
65
71
|
assertComplete(internal, artifactMode);
|
|
66
72
|
await exporter.close();
|
package/src/snapStore.js
CHANGED
|
@@ -7,6 +7,12 @@ 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
|
+
* @import {makeMeasureSeconds} from '@agoric/internal';
|
|
14
|
+
*/
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* @typedef {object} SnapshotResult
|
|
12
18
|
* @property {string} hash sha256 hash of (uncompressed) snapshot
|
|
@@ -26,13 +32,6 @@ import { buffer } from './util.js';
|
|
|
26
32
|
*/
|
|
27
33
|
|
|
28
34
|
/**
|
|
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
35
|
* @typedef {{
|
|
37
36
|
* loadSnapshot: (vatID: string) => AsyncIterableIterator<Uint8Array>,
|
|
38
37
|
* saveSnapshot: (vatID: string, snapPos: number, snapshotStream: AsyncIterable<Uint8Array>) => Promise<SnapshotResult>,
|
|
@@ -47,17 +46,31 @@ import { buffer } from './util.js';
|
|
|
47
46
|
* getExportRecords: (includeHistorical: boolean) => IterableIterator<readonly [key: string, value: string]>,
|
|
48
47
|
* getArtifactNames: (artifactMode: ArtifactMode) => AsyncIterableIterator<string>,
|
|
49
48
|
* importSnapshotRecord: (key: string, value: string) => void,
|
|
50
|
-
* populateSnapshot: (name: string, makeChunkIterator: () =>
|
|
49
|
+
* populateSnapshot: (name: string, makeChunkIterator: () => AnyIterable<Uint8Array>, options: { artifactMode: ArtifactMode }) => Promise<void>,
|
|
51
50
|
* assertComplete: (checkMode: Omit<ArtifactMode, 'debug'>) => void,
|
|
52
51
|
* repairSnapshotRecord: (key: string, value: string) => void,
|
|
53
52
|
* }} SnapStoreInternal
|
|
54
53
|
*
|
|
54
|
+
* @typedef {object} SnapshotRow
|
|
55
|
+
* @property {string} vatID
|
|
56
|
+
* @property {number} snapPos
|
|
57
|
+
* @property {string} [hash]
|
|
58
|
+
* @property {number | null} [inUse]
|
|
59
|
+
* @property {number} uncompressedSize
|
|
60
|
+
* @property {number} compressedSize
|
|
61
|
+
*
|
|
55
62
|
* @typedef {{
|
|
56
63
|
* hasHash: (vatID: string, hash: string) => boolean,
|
|
57
|
-
*
|
|
64
|
+
* listAllSnapshots: () => Iterable<SnapshotRow>,
|
|
65
|
+
* dumpSnapshots: (includeHistorical?: boolean) => Record<string, Array<{snapPos: number, hash: string, compressedSnapshot: Buffer, inUse: (null | 0 | 1)}>>,
|
|
58
66
|
* deleteSnapshotByHash: (vatID: string, hash: string) => void,
|
|
59
67
|
* }} SnapStoreDebug
|
|
60
68
|
*
|
|
69
|
+
* @callback SnapshotCallback
|
|
70
|
+
* Called with the gzipped contents of a new heap snapshot.
|
|
71
|
+
* @param {string} name an export key, e.g. `snapshot.${vatID}.${deliveryCount}`
|
|
72
|
+
* @param {Parameters<typeof Readable.from>[0]} compressedData
|
|
73
|
+
* @returns {Promise<void>}
|
|
61
74
|
*/
|
|
62
75
|
|
|
63
76
|
const finished = promisify(finishedCallback);
|
|
@@ -66,12 +79,12 @@ const finished = promisify(finishedCallback);
|
|
|
66
79
|
* @param {*} db
|
|
67
80
|
* @param {() => void} ensureTxn
|
|
68
81
|
* @param {{
|
|
69
|
-
* measureSeconds: ReturnType<typeof
|
|
82
|
+
* measureSeconds: ReturnType<typeof makeMeasureSeconds>,
|
|
70
83
|
* }} io
|
|
71
84
|
* @param {(key: string, value: string | undefined) => void} noteExport
|
|
72
85
|
* @param {object} [options]
|
|
73
86
|
* @param {boolean | undefined} [options.keepSnapshots]
|
|
74
|
-
* @param {
|
|
87
|
+
* @param {SnapshotCallback} [options.archiveSnapshot]
|
|
75
88
|
* @returns {SnapStore & SnapStoreInternal & SnapStoreDebug}
|
|
76
89
|
*/
|
|
77
90
|
export function makeSnapStore(
|
|
@@ -605,7 +618,7 @@ export function makeSnapStore(
|
|
|
605
618
|
|
|
606
619
|
/**
|
|
607
620
|
* @param {string} name Artifact name of the snapshot
|
|
608
|
-
* @param {() =>
|
|
621
|
+
* @param {() => AnyIterable<Uint8Array>} makeChunkIterator get an iterator of snapshot byte chunks
|
|
609
622
|
* @param {object} options
|
|
610
623
|
* @param {ArtifactMode} options.artifactMode
|
|
611
624
|
* @returns {Promise<void>}
|
|
@@ -677,7 +690,7 @@ export function makeSnapStore(
|
|
|
677
690
|
|
|
678
691
|
/**
|
|
679
692
|
* debug function to list all snapshots
|
|
680
|
-
*
|
|
693
|
+
* @returns {Iterable<SnapshotRow>}
|
|
681
694
|
*/
|
|
682
695
|
function* listAllSnapshots() {
|
|
683
696
|
yield* sqlListAllSnapshots.iterate();
|
|
@@ -706,6 +719,7 @@ export function makeSnapStore(
|
|
|
706
719
|
const sql = includeHistorical
|
|
707
720
|
? sqlDumpAllSnapshots
|
|
708
721
|
: sqlDumpCurrentSnapshots;
|
|
722
|
+
/** @type {Record<string, Array<{snapPos: number, hash: string, compressedSnapshot: Buffer, inUse: (null | 0 | 1)}>>} */
|
|
709
723
|
const dump = {};
|
|
710
724
|
for (const row of sql.iterate()) {
|
|
711
725
|
const { vatID, snapPos, hash, compressedSnapshot, inUse } = row;
|