@agoric/swing-store 0.9.2-dev-7bfadd3.0 → 0.9.2-dev-f2445bc.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/docs/data-export.md +20 -11
- package/package.json +4 -4
- package/src/assertComplete.js +5 -6
- package/src/bundleStore.js +4 -3
- package/src/exporter.js +18 -12
- package/src/importer.js +17 -13
- package/src/internal.js +10 -2
- package/src/repairMetadata.js +3 -1
- package/src/snapStore.js +11 -10
- package/src/transcriptStore.js +122 -57
- package/src/types.d.ts +10 -9
- package/test/test-export.js +78 -43
- package/test/test-exportImport.js +57 -16
- package/test/test-import.js +76 -47
- package/test/test-repair-metadata.js +10 -10
package/test/test-import.js
CHANGED
|
@@ -16,6 +16,13 @@ import { importSwingStore, makeSwingStoreExporter } from '../src/index.js';
|
|
|
16
16
|
|
|
17
17
|
import { tmpDir, makeB0ID } from './util.js';
|
|
18
18
|
|
|
19
|
+
const rank = {
|
|
20
|
+
operational: 1,
|
|
21
|
+
replay: 2,
|
|
22
|
+
archival: 3,
|
|
23
|
+
debug: 4,
|
|
24
|
+
};
|
|
25
|
+
|
|
19
26
|
const snapshotData = 'snapshot data';
|
|
20
27
|
// this snapHash was computed manually
|
|
21
28
|
const snapHash =
|
|
@@ -74,7 +81,7 @@ test('import empty', async t => {
|
|
|
74
81
|
t.teardown(cleanup);
|
|
75
82
|
const exporter = makeExporter(new Map(), new Map());
|
|
76
83
|
const ss = await importSwingStore(exporter, dbDir);
|
|
77
|
-
ss.hostStorage.commit();
|
|
84
|
+
await ss.hostStorage.commit();
|
|
78
85
|
const data = convert(ss.debug.dump());
|
|
79
86
|
t.deepEqual(data, {
|
|
80
87
|
kvEntries: {},
|
|
@@ -98,60 +105,66 @@ export function buildData() {
|
|
|
98
105
|
exportData.set(`bundle.${bundle0ID}`, bundle0ID);
|
|
99
106
|
|
|
100
107
|
const sbase = { vatID: 'v1', hash: snapHash, inUse: 0 };
|
|
101
|
-
const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation:
|
|
108
|
+
const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation: 1 };
|
|
102
109
|
const addTS = (key, obj) =>
|
|
103
110
|
exportData.set(key, JSON.stringify({ ...tbase, ...obj }));
|
|
104
111
|
const t0hash =
|
|
112
|
+
'5bee0f44eca02f23eab03703e84ed2647d5d117fed99e1c30a3b424b7f082ab9';
|
|
113
|
+
const t2hash =
|
|
105
114
|
'57152efdd7fdf75c03371d2b4f1088d5bf3eae7fe643babce527ff81df38998c';
|
|
106
|
-
const
|
|
115
|
+
const t5hash =
|
|
107
116
|
'1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
|
|
108
|
-
const
|
|
117
|
+
const t8hash =
|
|
109
118
|
'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
|
|
110
119
|
|
|
111
|
-
addTS(`transcript.v1.0`, { endPos:
|
|
120
|
+
addTS(`transcript.v1.0`, { incarnation: 0, endPos: 2, hash: t0hash });
|
|
121
|
+
artifacts.set(`transcript.v1.0.2`, 'start-worker\nshutdown-worker\n');
|
|
122
|
+
|
|
123
|
+
addTS(`transcript.v1.2`, { startPos: 2, endPos: 5, hash: t2hash });
|
|
112
124
|
artifacts.set(
|
|
113
|
-
`transcript.v1.
|
|
125
|
+
`transcript.v1.2.5`,
|
|
114
126
|
'start-worker\ndelivery1\nsave-snapshot\n',
|
|
115
127
|
);
|
|
116
|
-
exportData.set(`snapshot.v1.
|
|
117
|
-
artifacts.set(`snapshot.v1.
|
|
128
|
+
exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
|
|
129
|
+
artifacts.set(`snapshot.v1.4`, snapshotData);
|
|
118
130
|
|
|
119
|
-
addTS(`transcript.v1.
|
|
131
|
+
addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
|
|
120
132
|
artifacts.set(
|
|
121
|
-
'transcript.v1.
|
|
133
|
+
'transcript.v1.5.8',
|
|
122
134
|
'load-snapshot\ndelivery2\nsave-snapshot\n',
|
|
123
135
|
);
|
|
124
136
|
exportData.set(
|
|
125
|
-
`snapshot.v1.
|
|
126
|
-
JSON.stringify({ ...sbase, snapPos:
|
|
137
|
+
`snapshot.v1.7`,
|
|
138
|
+
JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
|
|
127
139
|
);
|
|
128
|
-
artifacts.set(`snapshot.v1.
|
|
140
|
+
artifacts.set(`snapshot.v1.7`, snapshotData);
|
|
129
141
|
|
|
130
|
-
artifacts.set('transcript.v1.
|
|
131
|
-
exportData.set(`snapshot.v1.current`, 'snapshot.v1.
|
|
142
|
+
artifacts.set('transcript.v1.8.10', 'load-snapshot\ndelivery3\n');
|
|
143
|
+
exportData.set(`snapshot.v1.current`, 'snapshot.v1.7');
|
|
132
144
|
addTS(`transcript.v1.current`, {
|
|
133
|
-
startPos:
|
|
134
|
-
endPos:
|
|
145
|
+
startPos: 8,
|
|
146
|
+
endPos: 10,
|
|
135
147
|
isCurrent: 1,
|
|
136
|
-
hash:
|
|
148
|
+
hash: t8hash,
|
|
137
149
|
});
|
|
138
150
|
|
|
139
|
-
return { exportData, artifacts, t0hash,
|
|
151
|
+
return { exportData, artifacts, t0hash, t2hash, t5hash, t8hash };
|
|
140
152
|
}
|
|
141
153
|
|
|
142
154
|
const importTest = test.macro(async (t, mode) => {
|
|
155
|
+
/** @typedef {import('../src/internal.js').ArtifactMode} ArtifactMode */
|
|
156
|
+
const artifactMode = /** @type {ArtifactMode} */ (mode);
|
|
157
|
+
|
|
143
158
|
const [dbDir, cleanup] = await tmpDir('testdb');
|
|
144
159
|
t.teardown(cleanup);
|
|
145
160
|
|
|
146
|
-
const { exportData, artifacts, t0hash,
|
|
161
|
+
const { exportData, artifacts, t0hash, t2hash, t5hash, t8hash } = buildData();
|
|
147
162
|
|
|
148
163
|
const exporter = makeExporter(exportData, artifacts);
|
|
149
164
|
|
|
150
165
|
// now import
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
const ss = await importSwingStore(exporter, dbDir, options);
|
|
154
|
-
ss.hostStorage.commit();
|
|
166
|
+
const ss = await importSwingStore(exporter, dbDir, { artifactMode });
|
|
167
|
+
await ss.hostStorage.commit();
|
|
155
168
|
const data = convert(ss.debug.dump());
|
|
156
169
|
|
|
157
170
|
const convertTranscript = (items, startPos = 0) => {
|
|
@@ -187,31 +200,43 @@ const importTest = test.macro(async (t, mode) => {
|
|
|
187
200
|
|
|
188
201
|
t.deepEqual(data.kvEntries, { key1: 'value1' });
|
|
189
202
|
let ts = [];
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
if (rank[artifactMode] >= rank.archival) {
|
|
204
|
+
// only 'archival' and 'debug' get the old incarnation's span
|
|
205
|
+
ts = ts.concat(['start-worker', 'shutdown-worker']); // 0,1
|
|
206
|
+
}
|
|
207
|
+
if (rank[artifactMode] >= rank.replay) {
|
|
208
|
+
// those, or 'replay', get the current incarnation's old spans
|
|
209
|
+
ts = ts.concat(['start-worker', 'delivery1', 'save-snapshot']); // 2,3,4
|
|
210
|
+
ts = ts.concat(['load-snapshot', 'delivery2', 'save-snapshot']); // 5,6,7
|
|
211
|
+
}
|
|
212
|
+
ts = ts.concat(['load-snapshot', 'delivery3']); // 8,9
|
|
213
|
+
|
|
214
|
+
let tsStart;
|
|
215
|
+
if (artifactMode === 'archival' || artifactMode === 'debug') {
|
|
216
|
+
tsStart = 0;
|
|
217
|
+
} else if (artifactMode === 'replay') {
|
|
218
|
+
tsStart = 2;
|
|
219
|
+
} else {
|
|
220
|
+
tsStart = 8;
|
|
195
221
|
}
|
|
196
|
-
ts = ts.concat(['load-snapshot', 'delivery3']); // 6,7
|
|
197
222
|
|
|
198
223
|
const expectedTranscript = convertTranscript(ts, tsStart);
|
|
199
224
|
t.deepEqual(data.transcripts, { v1: expectedTranscript });
|
|
200
225
|
const uncompressedSnapshot = Buffer.from(snapshotData);
|
|
201
226
|
const expectedSnapshots = [];
|
|
202
|
-
if (
|
|
227
|
+
if (artifactMode === 'debug') {
|
|
203
228
|
expectedSnapshots.push({
|
|
204
229
|
uncompressedSnapshot,
|
|
205
230
|
hash: snapHash,
|
|
206
231
|
inUse: 0,
|
|
207
|
-
snapPos:
|
|
232
|
+
snapPos: 4,
|
|
208
233
|
});
|
|
209
234
|
}
|
|
210
235
|
expectedSnapshots.push({
|
|
211
236
|
uncompressedSnapshot,
|
|
212
237
|
hash: snapHash,
|
|
213
238
|
inUse: 1,
|
|
214
|
-
snapPos:
|
|
239
|
+
snapPos: 7,
|
|
215
240
|
});
|
|
216
241
|
t.deepEqual(await convertSnapshots(data.snapshots), {
|
|
217
242
|
v1: expectedSnapshots,
|
|
@@ -225,12 +250,12 @@ const importTest = test.macro(async (t, mode) => {
|
|
|
225
250
|
];
|
|
226
251
|
t.deepEqual(
|
|
227
252
|
spanRows.map(sr => sr.startPos),
|
|
228
|
-
[0,
|
|
253
|
+
[0, 2, 5, 8],
|
|
229
254
|
);
|
|
230
255
|
|
|
231
256
|
// and a new export should include all metadata, regardless of import mode
|
|
232
257
|
|
|
233
|
-
const reExporter = makeSwingStoreExporter(dbDir
|
|
258
|
+
const reExporter = makeSwingStoreExporter(dbDir);
|
|
234
259
|
const reExportData = new Map();
|
|
235
260
|
for await (const [key, value] of reExporter.getExportData()) {
|
|
236
261
|
reExportData.set(key, value);
|
|
@@ -248,18 +273,20 @@ const importTest = test.macro(async (t, mode) => {
|
|
|
248
273
|
};
|
|
249
274
|
|
|
250
275
|
check('kv.key1', 'value1');
|
|
251
|
-
check('snapshot.v1.
|
|
252
|
-
check('snapshot.v1.
|
|
253
|
-
check('snapshot.v1.current', 'snapshot.v1.
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
check('transcript.v1.
|
|
276
|
+
check('snapshot.v1.4', { vatID: 'v1', snapPos: 4, inUse: 0, hash: snapHash });
|
|
277
|
+
check('snapshot.v1.7', { vatID: 'v1', snapPos: 7, inUse: 1, hash: snapHash });
|
|
278
|
+
check('snapshot.v1.current', 'snapshot.v1.7');
|
|
279
|
+
const base0 = { vatID: 'v1', incarnation: 0, isCurrent: 0 };
|
|
280
|
+
const base1 = { vatID: 'v1', incarnation: 1, isCurrent: 0 };
|
|
281
|
+
check('transcript.v1.0', { ...base0, startPos: 0, endPos: 2, hash: t0hash });
|
|
282
|
+
check('transcript.v1.2', { ...base1, startPos: 2, endPos: 5, hash: t2hash });
|
|
283
|
+
check('transcript.v1.5', { ...base1, startPos: 5, endPos: 8, hash: t5hash });
|
|
257
284
|
check('transcript.v1.current', {
|
|
258
|
-
...
|
|
259
|
-
startPos:
|
|
260
|
-
endPos:
|
|
285
|
+
...base1,
|
|
286
|
+
startPos: 8,
|
|
287
|
+
endPos: 10,
|
|
261
288
|
isCurrent: 1,
|
|
262
|
-
hash:
|
|
289
|
+
hash: t8hash,
|
|
263
290
|
});
|
|
264
291
|
check(`bundle.${bundle0ID}`, bundle0ID);
|
|
265
292
|
|
|
@@ -270,8 +297,10 @@ const importTest = test.macro(async (t, mode) => {
|
|
|
270
297
|
}
|
|
271
298
|
});
|
|
272
299
|
|
|
273
|
-
test('import
|
|
274
|
-
test('import
|
|
300
|
+
test('import operational', importTest, 'operational');
|
|
301
|
+
test('import replay', importTest, 'replay');
|
|
302
|
+
test('import archival', importTest, 'archival');
|
|
303
|
+
test('import debug', importTest, 'debug');
|
|
275
304
|
|
|
276
305
|
test('import is missing bundle', async t => {
|
|
277
306
|
const [dbDir, cleanup] = await tmpDir('testdb');
|
|
@@ -38,9 +38,9 @@ test('repair metadata', async t => {
|
|
|
38
38
|
|
|
39
39
|
// assert that all the metadata is there at first
|
|
40
40
|
const ts1 = getTS.all('v1');
|
|
41
|
-
t.deepEqual(ts1, [0,
|
|
41
|
+
t.deepEqual(ts1, [0, 2, 5, 8]); // four spans
|
|
42
42
|
const ss1 = getSS.all('v1');
|
|
43
|
-
t.deepEqual(ss1, [
|
|
43
|
+
t.deepEqual(ss1, [4, 7]); // two snapshots
|
|
44
44
|
|
|
45
45
|
// now clobber them to simulate #8025 (note: these auto-commit)
|
|
46
46
|
db.prepare('DELETE FROM transcriptSpans WHERE isCurrent IS NULL').run();
|
|
@@ -48,9 +48,9 @@ test('repair metadata', async t => {
|
|
|
48
48
|
|
|
49
49
|
// confirm that we clobbered them
|
|
50
50
|
const ts2 = getTS.all('v1');
|
|
51
|
-
t.deepEqual(ts2, [
|
|
51
|
+
t.deepEqual(ts2, [8]); // only the latest
|
|
52
52
|
const ss2 = getSS.all('v1');
|
|
53
|
-
t.deepEqual(ss2, [
|
|
53
|
+
t.deepEqual(ss2, [7]);
|
|
54
54
|
|
|
55
55
|
// now fix it
|
|
56
56
|
await ss.hostStorage.repairMetadata(exporter);
|
|
@@ -58,17 +58,17 @@ test('repair metadata', async t => {
|
|
|
58
58
|
|
|
59
59
|
// and check that the metadata is back
|
|
60
60
|
const ts3 = getTS.all('v1');
|
|
61
|
-
t.deepEqual(ts3, [0,
|
|
61
|
+
t.deepEqual(ts3, [0, 2, 5, 8]); // all four again
|
|
62
62
|
const ss3 = getSS.all('v1');
|
|
63
|
-
t.deepEqual(ss3, [
|
|
63
|
+
t.deepEqual(ss3, [4, 7]);
|
|
64
64
|
|
|
65
65
|
// repair should be idempotent
|
|
66
66
|
await ss.hostStorage.repairMetadata(exporter);
|
|
67
67
|
|
|
68
68
|
const ts4 = getTS.all('v1');
|
|
69
|
-
t.deepEqual(ts4, [0,
|
|
69
|
+
t.deepEqual(ts4, [0, 2, 5, 8]); // still there
|
|
70
70
|
const ss4 = getSS.all('v1');
|
|
71
|
-
t.deepEqual(ss4, [
|
|
71
|
+
t.deepEqual(ss4, [4, 7]);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
test('repair metadata ignores kvStore entries', async t => {
|
|
@@ -101,9 +101,9 @@ test('repair metadata rejects mismatched snapshot entries', async t => {
|
|
|
101
101
|
await ss.hostStorage.commit();
|
|
102
102
|
|
|
103
103
|
// perform the repair with mismatched snapshot entry
|
|
104
|
-
const old = JSON.parse(exportData.get('snapshot.v1.
|
|
104
|
+
const old = JSON.parse(exportData.get('snapshot.v1.4'));
|
|
105
105
|
const wrong = { ...old, hash: 'wrong' };
|
|
106
|
-
exportData.set('snapshot.v1.
|
|
106
|
+
exportData.set('snapshot.v1.4', JSON.stringify(wrong));
|
|
107
107
|
|
|
108
108
|
await t.throwsAsync(async () => ss.hostStorage.repairMetadata(exporter), {
|
|
109
109
|
message: /repairSnapshotRecord metadata mismatch/,
|