@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.
@@ -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: 0 };
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 t3hash =
115
+ const t5hash =
107
116
  '1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
108
- const t6hash =
117
+ const t8hash =
109
118
  'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
110
119
 
111
- addTS(`transcript.v1.0`, { endPos: 3, hash: t0hash });
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.0.3`,
125
+ `transcript.v1.2.5`,
114
126
  'start-worker\ndelivery1\nsave-snapshot\n',
115
127
  );
116
- exportData.set(`snapshot.v1.2`, JSON.stringify({ ...sbase, snapPos: 2 }));
117
- artifacts.set(`snapshot.v1.2`, snapshotData);
128
+ exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
129
+ artifacts.set(`snapshot.v1.4`, snapshotData);
118
130
 
119
- addTS(`transcript.v1.3`, { startPos: 3, endPos: 6, hash: t3hash });
131
+ addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
120
132
  artifacts.set(
121
- 'transcript.v1.3.6',
133
+ 'transcript.v1.5.8',
122
134
  'load-snapshot\ndelivery2\nsave-snapshot\n',
123
135
  );
124
136
  exportData.set(
125
- `snapshot.v1.5`,
126
- JSON.stringify({ ...sbase, snapPos: 5, inUse: 1 }),
137
+ `snapshot.v1.7`,
138
+ JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
127
139
  );
128
- artifacts.set(`snapshot.v1.5`, snapshotData);
140
+ artifacts.set(`snapshot.v1.7`, snapshotData);
129
141
 
130
- artifacts.set('transcript.v1.6.8', 'load-snapshot\ndelivery3\n');
131
- exportData.set(`snapshot.v1.current`, 'snapshot.v1.5');
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: 6,
134
- endPos: 8,
145
+ startPos: 8,
146
+ endPos: 10,
135
147
  isCurrent: 1,
136
- hash: t6hash,
148
+ hash: t8hash,
137
149
  });
138
150
 
139
- return { exportData, artifacts, t0hash, t3hash, t6hash };
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, t3hash, t6hash } = buildData();
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 includeHistorical = mode === 'historical';
152
- const options = { includeHistorical };
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
- let tsStart = 6; // start of current span
191
- if (mode === 'historical') {
192
- tsStart = 0; // historical means we get all spans
193
- ts = ts.concat(['start-worker', 'delivery1', 'save-snapshot']); // 0,1,2
194
- ts = ts.concat(['load-snapshot', 'delivery2', 'save-snapshot']); // 3,4,5
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 (mode === 'historical') {
227
+ if (artifactMode === 'debug') {
203
228
  expectedSnapshots.push({
204
229
  uncompressedSnapshot,
205
230
  hash: snapHash,
206
231
  inUse: 0,
207
- snapPos: 2,
232
+ snapPos: 4,
208
233
  });
209
234
  }
210
235
  expectedSnapshots.push({
211
236
  uncompressedSnapshot,
212
237
  hash: snapHash,
213
238
  inUse: 1,
214
- snapPos: 5,
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, 3, 6],
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, 'current');
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.2', { vatID: 'v1', snapPos: 2, inUse: 0, hash: snapHash });
252
- check('snapshot.v1.5', { vatID: 'v1', snapPos: 5, inUse: 1, hash: snapHash });
253
- check('snapshot.v1.current', 'snapshot.v1.5');
254
- const base = { vatID: 'v1', incarnation: 0, isCurrent: 0 };
255
- check('transcript.v1.0', { ...base, startPos: 0, endPos: 3, hash: t0hash });
256
- check('transcript.v1.3', { ...base, startPos: 3, endPos: 6, hash: t3hash });
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
- ...base,
259
- startPos: 6,
260
- endPos: 8,
285
+ ...base1,
286
+ startPos: 8,
287
+ endPos: 10,
261
288
  isCurrent: 1,
262
- hash: t6hash,
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 current', importTest, 'current');
274
- test('import historical', importTest, 'historical');
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, 3, 6]); // three spans
41
+ t.deepEqual(ts1, [0, 2, 5, 8]); // four spans
42
42
  const ss1 = getSS.all('v1');
43
- t.deepEqual(ss1, [2, 5]); // two snapshots
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, [6]); // only the latest
51
+ t.deepEqual(ts2, [8]); // only the latest
52
52
  const ss2 = getSS.all('v1');
53
- t.deepEqual(ss2, [5]);
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, 3, 6]); // all three again
61
+ t.deepEqual(ts3, [0, 2, 5, 8]); // all four again
62
62
  const ss3 = getSS.all('v1');
63
- t.deepEqual(ss3, [2, 5]);
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, 3, 6]); // still there
69
+ t.deepEqual(ts4, [0, 2, 5, 8]); // still there
70
70
  const ss4 = getSS.all('v1');
71
- t.deepEqual(ss4, [2, 5]);
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.2'));
104
+ const old = JSON.parse(exportData.get('snapshot.v1.4'));
105
105
  const wrong = { ...old, hash: 'wrong' };
106
- exportData.set('snapshot.v1.2', JSON.stringify(wrong));
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/,