From 62fef7c9a74179001f7af37bde22a7c1dc7fdb93 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Fri, 23 Dec 2022 17:12:04 -0500 Subject: [PATCH] fix(swing-store): move getAllState/setAllState onto a debug object `getAllState` and `setAllState` are swing-store helper functions which copy (or set) all the state of a store at once, used exclusively for testing. Previously, they were exported by swing-store, and applied to a `kernelStorage` object, but that depended upon a `streamStore.dumpStreams` method that we'd rather not expose to normal users. This commit adds a new `debug` object, next to `kernelStorage` and `hostStorage`, which holds `getAllState`, `setAllState`, and `dumpStreams`. The `kernelStorage.streamStore` object no longer has a `dumpStreams` method. This also updates all the swingset unit tests which were using the helper functions. --- .../test-change-parameters.js | 13 +- .../SwingSet/test/devices/test-devices.js | 6 +- .../promise-watcher/test-promise-watcher.js | 13 +- .../test/test-activityhash-vs-start.js | 18 +-- packages/SwingSet/test/test-state.js | 20 +-- .../SwingSet/test/test-transcript-light.js | 56 ++++---- packages/SwingSet/test/test-transcript.js | 26 ++-- .../test/upgrade/test-upgrade-replay.js | 10 +- .../SwingSet/test/upgrade/test-upgrade.js | 11 +- .../terminate/test-terminate-replay.js | 10 +- .../vat-admin/terminate/test-terminate.js | 10 +- .../SwingSet/test/vat-admin/test-replay.js | 10 +- packages/swing-store/src/swingStore.js | 121 +++++++++--------- packages/swing-store/test/test-state.js | 26 ++-- 14 files changed, 166 insertions(+), 184 deletions(-) diff --git a/packages/SwingSet/test/change-parameters/test-change-parameters.js b/packages/SwingSet/test/change-parameters/test-change-parameters.js index cfd32a59c21..b5f0bae078d 100644 --- a/packages/SwingSet/test/change-parameters/test-change-parameters.js +++ b/packages/SwingSet/test/change-parameters/test-change-parameters.js @@ -3,7 +3,7 @@ import { test } from '../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order import { assert } from '@agoric/assert'; -import { initSwingStore, getAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { initializeSwingset, makeSwingsetController } from '../../src/index.js'; import { kunser } from '../../src/lib/kmarshal.js'; @@ -11,17 +11,6 @@ function bfile(name) { return new URL(name, import.meta.url).pathname; } -// eslint-disable-next-line no-unused-vars -function dumpState(kernelStorage, vatID) { - const s = getAllState(kernelStorage).kvStuff; - const keys = Array.from(Object.keys(s)).sort(); - for (const k of keys) { - if (k.startsWith(`${vatID}.vs.`)) { - console.log(k, s[k]); - } - } -} - async function testChangeParameters(t) { const config = { bootstrap: 'bootstrap', diff --git a/packages/SwingSet/test/devices/test-devices.js b/packages/SwingSet/test/devices/test-devices.js index ca3fa38232d..e05a07abf7e 100644 --- a/packages/SwingSet/test/devices/test-devices.js +++ b/packages/SwingSet/test/devices/test-devices.js @@ -2,7 +2,7 @@ import { test } from '../../tools/prepare-test-env-ava.js'; import bundleSource from '@endo/bundle-source'; -import { initSwingStore, getAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { parse } from '@endo/marshal'; import { @@ -211,7 +211,7 @@ test.serial('d2.5', async t => { }); test.serial('device state', async t => { - const kernelStorage = initSwingStore().kernelStorage; + const { kernelStorage, debug } = initSwingStore(); const config = { bootstrap: 'bootstrap', vats: { @@ -236,7 +236,7 @@ test.serial('device state', async t => { const d3 = c1.deviceNameToID('d3'); await c1.run(); t.deepEqual(c1.dump().log, ['undefined', 'w+r', 'called', 'got {"s":"new"}']); - const s = getAllState(kernelStorage).kvStuff; + const s = debug.getAllState().kvStuff; t.deepEqual(JSON.parse(s[`${d3}.deviceState`]), kser({ s: 'new' })); t.deepEqual(JSON.parse(s[`${d3}.o.nextID`]), 10); }); diff --git a/packages/SwingSet/test/promise-watcher/test-promise-watcher.js b/packages/SwingSet/test/promise-watcher/test-promise-watcher.js index ed9b2bc2bb7..d4bbd070ac6 100644 --- a/packages/SwingSet/test/promise-watcher/test-promise-watcher.js +++ b/packages/SwingSet/test/promise-watcher/test-promise-watcher.js @@ -8,24 +8,13 @@ import { test } from '../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order import { assert } from '@agoric/assert'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { initializeSwingset, makeSwingsetController } from '../../src/index.js'; function bfile(name) { return new URL(name, import.meta.url).pathname; } -// eslint-disable-next-line no-unused-vars -function dumpState(kernelStorage, vatID) { - const s = getAllState(kernelStorage).kvStuff; - const keys = Array.from(Object.keys(s)).sort(); - for (const k of keys) { - if (k.startsWith(`${vatID}.vs.`)) { - console.log(k, s[k]); - } - } -} - async function testPromiseWatcher(t) { const config = { includeDevDependencies: true, // for vat-data diff --git a/packages/SwingSet/test/test-activityhash-vs-start.js b/packages/SwingSet/test/test-activityhash-vs-start.js index 31900b62e2a..08213e0c136 100644 --- a/packages/SwingSet/test/test-activityhash-vs-start.js +++ b/packages/SwingSet/test/test-activityhash-vs-start.js @@ -2,7 +2,7 @@ import { test } from '../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { initializeSwingset, makeSwingsetController } from '../src/index.js'; import { buildTimer } from '../src/devices/timer/timer.js'; @@ -38,7 +38,7 @@ test.serial('restarting kernel does not change activityhash', async t => { const deviceEndowments1 = { timer: { ...timer1.endowments }, }; - const ks1 = initSwingStore().kernelStorage; + const { kernelStorage: ks1, debug: debug1 } = initSwingStore(); // console.log(`--c1 build`); await initializeSwingset(config, [], ks1); const c1 = await makeSwingsetController(ks1, deviceEndowments1); @@ -49,7 +49,7 @@ test.serial('restarting kernel does not change activityhash', async t => { await c1.run(); // console.log(`--c1 getAllState`); - const state = getAllState(ks1); + const state = debug1.getAllState(); // console.log(`ah: ${c1.getActivityhash()}`); // console.log(`--c1 poll1`); @@ -70,8 +70,8 @@ test.serial('restarting kernel does not change activityhash', async t => { const deviceEndowments2 = { timer: { ...timer2.endowments }, }; - const ks2 = initSwingStore().kernelStorage; - setAllState(ks2, state); + const { kernelStorage: ks2, debug: debug2 } = initSwingStore(); + debug2.setAllState(state); // console.log(`--c2 build`); const c2 = await makeSwingsetController(ks2, deviceEndowments2); // console.log(`ah: ${c2.getActivityhash()}`); @@ -102,14 +102,14 @@ test.serial('comms initialize is deterministic', async t => { const config = {}; config.bootstrap = 'bootstrap'; config.vats = { bootstrap: { sourceSpec } }; - const ks1 = initSwingStore().kernelStorage; + const { kernelStorage: ks1, debug: debug1 } = initSwingStore(); await initializeSwingset(config, [], ks1); const c1 = await makeSwingsetController(ks1, {}); c1.pinVatRoot('bootstrap'); // the bootstrap message will cause comms to initialize itself await c1.run(); - const state = getAllState(ks1); + const state = debug1.getAllState(); // but the second message should not c1.queueToVatRoot('bootstrap', 'addRemote', ['remote2']); @@ -118,8 +118,8 @@ test.serial('comms initialize is deterministic', async t => { await c1.shutdown(); // a kernel restart is loading a new kernel from the same state - const ks2 = initSwingStore().kernelStorage; - setAllState(ks2, state); + const { kernelStorage: ks2, debug: debug2 } = initSwingStore(); + debug2.setAllState(state); const c2 = await makeSwingsetController(ks2, {}); // the "am I already initialized?" check must be identical to the diff --git a/packages/SwingSet/test/test-state.js b/packages/SwingSet/test/test-state.js index 5479bdda514..43d15965b39 100644 --- a/packages/SwingSet/test/test-state.js +++ b/packages/SwingSet/test/test-state.js @@ -3,7 +3,7 @@ import { test } from '../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order import { createHash } from 'crypto'; -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import makeKernelKeeper from '../src/kernel/state/kernelKeeper.js'; import { makeKernelStats } from '../src/kernel/state/stats.js'; import { KERNEL_STATS_METRICS } from '../src/kernel/metrics.js'; @@ -70,17 +70,17 @@ async function testStorage(t, s, getState, commit) { } test('storageInMemory', async t => { - const kernelStorage = initSwingStore(null).kernelStorage; + const { kernelStorage, debug } = initSwingStore(null); await testStorage( t, kernelStorage.kvStore, - () => getAllState(kernelStorage).kvStuff, + () => debug.getAllState().kvStuff, null, ); }); test('storage helpers', t => { - const kernelStorage = initSwingStore(null).kernelStorage; + const { kernelStorage, debug } = initSwingStore(null); const kv = kernelStorage.kvStore; kv.set('foo.0', 'f0'); @@ -89,7 +89,7 @@ test('storage helpers', t => { kv.set('foo.3', 'f3'); // omit foo.4 kv.set('foo.5', 'f5'); - checkState(t, () => getAllState(kernelStorage).kvStuff, [ + checkState(t, () => debug.getAllState().kvStuff, [ ['foo.0', 'f0'], ['foo.1', 'f1'], ['foo.2', 'f2'], @@ -114,20 +114,20 @@ test('storage helpers', t => { // zero, so if there is a gap in the key sequence (e.g., 'foo.4' in the // above), they stop counting when they hit it t.truthy(kv.has('foo.5')); - checkState(t, () => getAllState(kernelStorage).kvStuff, [['foo.5', 'f5']]); + checkState(t, () => debug.getAllState().kvStuff, [['foo.5', 'f5']]); }); function buildKeeperStorageInMemory() { - const kernelStorage = initSwingStore(null).kernelStorage; + const { kernelStorage, debug } = initSwingStore(null); return { - getState: () => getAllState(kernelStorage).kvStuff, + getState: () => debug.getAllState().kvStuff, ...kernelStorage, }; } function duplicateKeeper(getState) { - const kernelStorage = initSwingStore(null).kernelStorage; - setAllState(kernelStorage, { kvStuff: getState(), streamStuff: new Map() }); + const { kernelStorage, debug } = initSwingStore(null); + debug.setAllState({ kvStuff: getState(), streamStuff: new Map() }); const kernelKeeper = makeKernelKeeper(kernelStorage, null); kernelKeeper.loadStats(); return kernelKeeper; diff --git a/packages/SwingSet/test/test-transcript-light.js b/packages/SwingSet/test/test-transcript-light.js index 98e421486bb..e872540fba8 100644 --- a/packages/SwingSet/test/test-transcript-light.js +++ b/packages/SwingSet/test/test-transcript-light.js @@ -1,35 +1,35 @@ // eslint-disable-next-line import/order import { test } from '../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { buildVatController, loadBasedir } from '../src/index.js'; test('transcript-light load', async t => { const config = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage = initSwingStore().kernelStorage; + const { kernelStorage, debug } = initSwingStore(); const c = await buildVatController(config, ['one'], { kernelStorage }); t.teardown(c.shutdown); - const state0 = getAllState(kernelStorage); + const state0 = debug.getAllState(); t.is(state0.kvStuff.initialized, 'true'); t.is(state0.kvStuff.runQueue, '[1,1]'); t.not(state0.kvStuff.acceptanceQueue, '[]'); await c.step(); - const state1 = getAllState(kernelStorage); + const state1 = debug.getAllState(); await c.step(); - const state2 = getAllState(kernelStorage); + const state2 = debug.getAllState(); await c.step(); - const state3 = getAllState(kernelStorage); + const state3 = debug.getAllState(); await c.step(); - const state4 = getAllState(kernelStorage); + const state4 = debug.getAllState(); await c.step(); - const state5 = getAllState(kernelStorage); + const state5 = debug.getAllState(); // build from loaded state // Step 0 @@ -37,74 +37,74 @@ test('transcript-light load', async t => { const cfg0 = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage0 = initSwingStore().kernelStorage; - setAllState(kernelStorage0, state0); + const { kernelStorage: kernelStorage0, debug: debug0 } = initSwingStore(); + debug0.setAllState(state0); const c0 = await buildVatController(cfg0, ['one'], { kernelStorage: kernelStorage0, }); t.teardown(c0.shutdown); await c0.step(); - t.deepEqual(state1, getAllState(kernelStorage0), `p1`); + t.deepEqual(state1, debug0.getAllState(), `p1`); await c0.step(); - t.deepEqual(state2, getAllState(kernelStorage0), `p2`); + t.deepEqual(state2, debug0.getAllState(), `p2`); await c0.step(); - t.deepEqual(state3, getAllState(kernelStorage0), `p3`); + t.deepEqual(state3, debug0.getAllState(), `p3`); await c0.step(); - t.deepEqual(state4, getAllState(kernelStorage0), `p4`); + t.deepEqual(state4, debug0.getAllState(), `p4`); await c0.step(); - t.deepEqual(state5, getAllState(kernelStorage0), `p5`); + t.deepEqual(state5, debug0.getAllState(), `p5`); // Step 1 const cfg1 = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage1 = initSwingStore().kernelStorage; - setAllState(kernelStorage1, state1); + const { kernelStorage: kernelStorage1, debug: debug1 } = initSwingStore(); + debug1.setAllState(state1); const c1 = await buildVatController(cfg1, ['one'], { kernelStorage: kernelStorage1, }); t.teardown(c1.shutdown); - t.deepEqual(state1, getAllState(kernelStorage1), `p6`); // actual, expected + t.deepEqual(state1, debug1.getAllState(), `p6`); // actual, expected await c1.step(); - t.deepEqual(state2, getAllState(kernelStorage1), `p7`); + t.deepEqual(state2, debug1.getAllState(), `p7`); await c1.step(); - t.deepEqual(state3, getAllState(kernelStorage1), `p8`); + t.deepEqual(state3, debug1.getAllState(), `p8`); await c1.step(); - t.deepEqual(state4, getAllState(kernelStorage1), `p9`); + t.deepEqual(state4, debug1.getAllState(), `p9`); await c1.step(); - t.deepEqual(state5, getAllState(kernelStorage1), `p10`); + t.deepEqual(state5, debug1.getAllState(), `p10`); // Step 2 const cfg2 = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage2 = initSwingStore().kernelStorage; - setAllState(kernelStorage2, state2); + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); + debug2.setAllState(state2); const c2 = await buildVatController(cfg2, ['one'], { kernelStorage: kernelStorage2, }); t.teardown(c2.shutdown); - t.deepEqual(state2, getAllState(kernelStorage2), `p11`); + t.deepEqual(state2, debug2.getAllState(), `p11`); await c2.step(); - t.deepEqual(state3, getAllState(kernelStorage2), `p12`); + t.deepEqual(state3, debug2.getAllState(), `p12`); await c2.step(); - t.deepEqual(state4, getAllState(kernelStorage2), `p13`); + t.deepEqual(state4, debug2.getAllState(), `p13`); await c2.step(); - t.deepEqual(state5, getAllState(kernelStorage2), `p14`); + t.deepEqual(state5, debug2.getAllState(), `p14`); }); diff --git a/packages/SwingSet/test/test-transcript.js b/packages/SwingSet/test/test-transcript.js index 8583bd4cc64..30da829f59e 100644 --- a/packages/SwingSet/test/test-transcript.js +++ b/packages/SwingSet/test/test-transcript.js @@ -1,19 +1,19 @@ // eslint-disable-next-line import/order import { test } from '../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; // import fs from 'fs'; import { buildVatController, loadBasedir } from '../src/index.js'; -async function buildTrace(c, kernelStorage) { +async function buildTrace(c, getAllState) { const states = []; while (c.dump().runQueue.length && c.dump().gcActions.length) { - states.push(getAllState(kernelStorage)); + states.push(getAllState()); // eslint-disable-next-line no-await-in-loop await c.step(); } - states.push(getAllState(kernelStorage)); + states.push(getAllState()); await c.shutdown(); return states; } @@ -22,11 +22,11 @@ test('transcript-one save', async t => { const config = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage = initSwingStore().kernelStorage; + const { kernelStorage, debug } = initSwingStore(); const c1 = await buildVatController(config, ['one'], { kernelStorage, }); - const states1 = await buildTrace(c1, kernelStorage); + const states1 = await buildTrace(c1, debug.getAllState); /* states1.forEach( (s, i) => fs.writeFileSync(`kdata-${i}.json`, JSON.stringify(s)) @@ -35,11 +35,11 @@ test('transcript-one save', async t => { const config2 = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const kernelStorage2 = initSwingStore().kernelStorage; + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); const c2 = await buildVatController(config2, ['one'], { kernelStorage: kernelStorage2, }); - const states2 = await buildTrace(c2, kernelStorage2); + const states2 = await buildTrace(c2, debug2.getAllState); states1.forEach((s, i) => { // Too expensive! If there is a difference in the 3MB data, AVA will spin @@ -63,9 +63,9 @@ test('transcript-one load', async t => { const config = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const s0 = initSwingStore().kernelStorage; + const { kernelStorage: s0, debug: d0 } = initSwingStore(); const c0 = await buildVatController(config, ['one'], { kernelStorage: s0 }); - const states = await buildTrace(c0, s0); + const states = await buildTrace(c0, d0.getAllState); // states.forEach((s,j) => // fs.writeFileSync(`kdata-${j}.json`, // JSON.stringify(states[j]))); @@ -75,12 +75,12 @@ test('transcript-one load', async t => { const cfg = await loadBasedir( new URL('basedir-transcript', import.meta.url).pathname, ); - const s = initSwingStore().kernelStorage; - setAllState(s, states[i]); + const { kernelStorage: s, debug: d } = initSwingStore(); + d.setAllState(states[i]); // eslint-disable-next-line no-await-in-loop const c = await buildVatController(cfg, ['one'], { kernelStorage: s }); // eslint-disable-next-line no-await-in-loop - const newstates = await buildTrace(c, s); + const newstates = await buildTrace(c, d.getAllState); // newstates.forEach((s,j) => // fs.writeFileSync(`kdata-${i+j}-${i}+${j}.json`, // JSON.stringify(newstates[j]))); diff --git a/packages/SwingSet/test/upgrade/test-upgrade-replay.js b/packages/SwingSet/test/upgrade/test-upgrade-replay.js index ed5219521fd..f3727731136 100644 --- a/packages/SwingSet/test/upgrade/test-upgrade-replay.js +++ b/packages/SwingSet/test/upgrade/test-upgrade-replay.js @@ -2,7 +2,7 @@ import { test } from '../../tools/prepare-test-env-ava.js'; import { assert } from '@agoric/assert'; -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { buildKernelBundles, initializeSwingset, @@ -45,7 +45,7 @@ test('replay after upgrade', async t => { }; const { initOpts, runtimeOpts } = bundleOpts(t.context.data); - const kernelStorage1 = initSwingStore().kernelStorage; + const { kernelStorage: kernelStorage1, debug: debug1 } = initSwingStore(); { await initializeSwingset(copy(config), [], kernelStorage1, initOpts); const c1 = await makeSwingsetController(kernelStorage1, {}, runtimeOpts); @@ -66,9 +66,9 @@ test('replay after upgrade', async t => { } // copy the store just to be sure - const state1 = getAllState(kernelStorage1); - const kernelStorage2 = initSwingStore().kernelStorage; - setAllState(kernelStorage2, state1); + const state1 = debug1.getAllState(); + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); + debug2.setAllState(state1); { const c2 = await makeSwingsetController(kernelStorage2, {}, runtimeOpts); t.teardown(c2.shutdown); diff --git a/packages/SwingSet/test/upgrade/test-upgrade.js b/packages/SwingSet/test/upgrade/test-upgrade.js index d81af6231d5..07551ce502a 100644 --- a/packages/SwingSet/test/upgrade/test-upgrade.js +++ b/packages/SwingSet/test/upgrade/test-upgrade.js @@ -4,7 +4,7 @@ import { test } from '../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order import { assert } from '@agoric/assert'; import bundleSource from '@endo/bundle-source'; -import { initSwingStore, getAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { parseReachableAndVatSlot } from '../../src/kernel/state/reachable.js'; import { parseVatSlot } from '../../src/lib/parseVatSlots.js'; import { kunser, krefOf } from '../../src/lib/kmarshal.js'; @@ -24,8 +24,8 @@ test.before(async t => { }); // eslint-disable-next-line no-unused-vars -const dumpState = (kernelStorage, vatID) => { - const s = getAllState(kernelStorage).kvStuff; +const dumpState = (debug, vatID) => { + const s = debug.getAllState().kvStuff; const keys = Array.from(Object.keys(s)).sort(); for (const k of keys) { if (k.startsWith(`${vatID}.vs.`)) { @@ -130,6 +130,7 @@ const testUpgrade = async ( }, }; + // const { kernelStorage, debug } = initSwingStore(); const { kernelStorage } = initSwingStore(); const { kvStore } = kernelStorage; const { initOpts, runtimeOpts } = bundleOpts(t.context.data); @@ -195,7 +196,7 @@ const testUpgrade = async ( return kvStore.has(`${vatID}.vs.vom.${vref}`); }; - // dumpState(kernelStorage, vatID); + // dumpState(debug, vatID); // deduce exporter vrefs for all durable/virtual objects, and assert // that they're still in DB @@ -261,7 +262,7 @@ const testUpgrade = async ( t.is(c.kpStatus(v1p2Kref), 'rejected'); t.deepEqual(kunser(c.kpResolution(v1p2Kref)), vatUpgradedError); - // dumpState(kernelStorage, vatID); + // dumpState(debug, vatID); // all the merely-virtual exports should be gone // for (let i = 1; i < NUM_SENSORS + 1; i += 1) { diff --git a/packages/SwingSet/test/vat-admin/terminate/test-terminate-replay.js b/packages/SwingSet/test/vat-admin/terminate/test-terminate-replay.js index 00ddbd48738..e973f8f959d 100644 --- a/packages/SwingSet/test/vat-admin/terminate/test-terminate-replay.js +++ b/packages/SwingSet/test/vat-admin/terminate/test-terminate-replay.js @@ -1,7 +1,7 @@ // eslint-disable-next-line import/order import { test } from '../../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { buildVatController, @@ -20,7 +20,7 @@ test.serial('replay does not resurrect dead vat', async t => { .pathname; const config = await loadSwingsetConfigFile(configPath); - const kernelStorage1 = initSwingStore().kernelStorage; + const { kernelStorage: kernelStorage1, debug: debug1 } = initSwingStore(); { const c1 = await buildVatController(config, [], { kernelStorage: kernelStorage1, @@ -32,10 +32,10 @@ test.serial('replay does not resurrect dead vat', async t => { t.deepEqual(c1.dump().log, [`w: I ate'nt dead`]); } - const state1 = getAllState(kernelStorage1); - const kernelStorage2 = initSwingStore().kernelStorage; + const state1 = debug1.getAllState(); + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); // XXX TODO also copy transcripts - setAllState(kernelStorage2, state1); + debug2.setAllState(state1); { const c2 = await buildVatController(config, [], { kernelStorage: kernelStorage2, diff --git a/packages/SwingSet/test/vat-admin/terminate/test-terminate.js b/packages/SwingSet/test/vat-admin/terminate/test-terminate.js index 8e1f4068638..b936c017d34 100644 --- a/packages/SwingSet/test/vat-admin/terminate/test-terminate.js +++ b/packages/SwingSet/test/vat-admin/terminate/test-terminate.js @@ -1,7 +1,7 @@ // eslint-disable-next-line import/order import { test } from '../../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { buildVatController, @@ -389,7 +389,7 @@ test.serial('dispatches to the dead do not harm kernel', async t => { .pathname; const config = await loadSwingsetConfigFile(configPath); - const kernelStorage1 = initSwingStore().kernelStorage; + const { kernelStorage: kernelStorage1, debug: debug1 } = initSwingStore(); { const c1 = await buildVatController(config, [], { kernelStorage: kernelStorage1, @@ -407,10 +407,10 @@ test.serial('dispatches to the dead do not harm kernel', async t => { 'done: Error: arbitrary reason', ]); } - const state1 = getAllState(kernelStorage1); - const kernelStorage2 = initSwingStore().kernelStorage; + const state1 = debug1.getAllState(); + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); // XXX TODO also copy transcripts - setAllState(kernelStorage2, state1); + debug2.setAllState(state1); { const c2 = await buildVatController(config, [], { kernelStorage: kernelStorage2, diff --git a/packages/SwingSet/test/vat-admin/test-replay.js b/packages/SwingSet/test/vat-admin/test-replay.js index 05ea20f34cf..17b2565451d 100644 --- a/packages/SwingSet/test/vat-admin/test-replay.js +++ b/packages/SwingSet/test/vat-admin/test-replay.js @@ -1,7 +1,7 @@ // eslint-disable-next-line import/order import { test } from '../../tools/prepare-test-env-ava.js'; // eslint-disable-next-line import/order -import { initSwingStore, getAllState, setAllState } from '@agoric/swing-store'; +import { initSwingStore } from '@agoric/swing-store'; import { buildKernelBundles, buildVatController } from '../../src/index.js'; import { kser } from '../../src/lib/kmarshal.js'; @@ -31,7 +31,7 @@ test.serial('replay dynamic vat', async t => { }; // XXX TODO: also copy and check transcripts - const kernelStorage1 = initSwingStore().kernelStorage; + const { kernelStorage: kernelStorage1, debug: debug1 } = initSwingStore(); { const c1 = await buildVatController(copy(config), [], { kernelStorage: kernelStorage1, @@ -48,9 +48,9 @@ test.serial('replay dynamic vat', async t => { // we could re-use the Storage object, but I'll be paranoid and create a // new one. - const state1 = getAllState(kernelStorage1); - const kernelStorage2 = initSwingStore().kernelStorage; - setAllState(kernelStorage2, state1); + const state1 = debug1.getAllState(); + const { kernelStorage: kernelStorage2, debug: debug2 } = initSwingStore(); + debug2.setAllState(state1); { const c2 = await buildVatController(copy(config), [], { kernelStorage: kernelStorage2, diff --git a/packages/swing-store/src/swingStore.js b/packages/swing-store/src/swingStore.js index 3eb7432cac5..0d8b0d714ae 100644 --- a/packages/swing-store/src/swingStore.js +++ b/packages/swing-store/src/swingStore.js @@ -50,7 +50,6 @@ export function makeSnapStoreIO() { * writeStreamItem: (streamName: string, item: string, position: StreamPosition) => StreamPosition, * readStream: (streamName: string, startPosition: StreamPosition, endPosition: StreamPosition) => IterableIterator, * closeStream: (streamName: string) => void, - * dumpStreams: () => any, * STREAM_START: StreamPosition, * }} StreamStore * @@ -74,8 +73,15 @@ export function makeSnapStoreIO() { * }} SwingStoreHostStorage * * @typedef {{ + * dumpStreams: () => any, + * getAllState: () => { kvStuff: Record, streamStuff: Map> }, + * setAllState: (stuff: { kvStuff: Record, streamStuff: Map> }) => void, + * }} SwingStoreDebugTools + * + * @typedef {{ * kernelStorage: SwingStoreKernelStorage, * hostStorage: SwingStoreHostStorage, + * debug: SwingStoreDebugTools, * }} SwingStore */ @@ -427,7 +433,7 @@ function makeSwingStore(dirPath, forceReset, options) { }, }; - const streamStore = makeSQLStreamStore(db, ensureTxn); + const { dumpStreams, ...streamStore } = makeSQLStreamStore(db, ensureTxn); let snapStore; if (dirPath) { @@ -541,6 +547,56 @@ function makeSwingStore(dirPath, forceReset, options) { stopTrace(); } + /** + * Produce a representation of all the state found in a swing store. + * + * WARNING: This is a helper function intended for use in testing and debugging. + * It extracts *everything*, and does so in the simplest and stupidest possible + * way, hence it is likely to be a performance and memory hog if you attempt to + * use it on anything real. + * + * @returns {{ + * kvStuff: Record, + * streamStuff: Map>, + * }} A crude representation of all of the state of `kernelStorage` + */ + function getAllState() { + /** @type { Record } */ + const kvStuff = {}; + for (const key of Array.from(kernelKVStore.getKeys('', ''))) { + // @ts-expect-error get(key) of key from getKeys() is not undefined + kvStuff[key] = kernelKVStore.get(key); + } + const streamStuff = dumpStreams(); + return { kvStuff, streamStuff }; + } + + /** + * Stuff a bunch of state into a swing store. + * + * WARNING: This is intended to support testing and should not be used as a + * general store initialization mechanism. In particular, note that it does not + * bother to remove any pre-existing state from the store that it is given. + * + * @param {{ + * kvStuff: Record, + * streamStuff: Map>, + * }} stuff The state to stuff into `kernelStorage` + */ + function setAllState(stuff) { + const { kvStuff, streamStuff } = stuff; + for (const k of Object.getOwnPropertyNames(kvStuff)) { + kernelKVStore.set(k, kvStuff[k], true); + } + for (const [streamName, stream] of streamStuff.entries()) { + for (const [pos, item] of stream) { + const position = { itemCount: pos }; + streamStore.writeStreamItem(streamName, item, position); + } + streamStore.closeStream(streamName); + } + } + const kernelStorage = { kvStore: kernelKVStore, streamStore, @@ -558,10 +614,16 @@ function makeSwingStore(dirPath, forceReset, options) { close, diskUsage, }; + const debug = { + dumpStreams, + getAllState, + setAllState, + }; return harden({ kernelStorage, hostStorage, + debug, }); } @@ -626,58 +688,3 @@ export function isSwingStore(dirPath) { } return false; } - -/** - * Produce a representation of all the state found in a swing store. - * - * WARNING: This is a helper function intended for use in testing and debugging. - * It extracts *everything*, and does so in the simplest and stupidest possible - * way, hence it is likely to be a performance and memory hog if you attempt to - * use it on anything real. - * - * @param {SwingStoreKernelStorage} kernelStorage The swing store whose state is to be extracted. - * - * @returns {{ - * kvStuff: Record, - * streamStuff: Map>, - * }} A crude representation of all of the state of `kernelStorage` - */ -export function getAllState(kernelStorage) { - const { kvStore, streamStore } = kernelStorage; - /** @type { Record } */ - const kvStuff = {}; - for (const key of Array.from(kvStore.getKeys('', ''))) { - // @ts-expect-error get(key) of key from getKeys() is not undefined - kvStuff[key] = kvStore.get(key); - } - const streamStuff = streamStore.dumpStreams(); - return { kvStuff, streamStuff }; -} - -/** - * Stuff a bunch of state into a swing store. - * - * WARNING: This is intended to support testing and should not be used as a - * general store initialization mechanism. In particular, note that it does not - * bother to remove any pre-existing state from the store that it is given. - * - * @param {SwingStoreKernelStorage} kernelStorage The swing store whose state is to be set. - * @param {{ - * kvStuff: Record, - * streamStuff: Map>, - * }} stuff The state to stuff into `kernelStorage` - */ -export function setAllState(kernelStorage, stuff) { - const { kvStore, streamStore } = kernelStorage; - const { kvStuff, streamStuff } = stuff; - for (const k of Object.getOwnPropertyNames(kvStuff)) { - kvStore.set(k, kvStuff[k], true); - } - for (const [streamName, stream] of streamStuff.entries()) { - for (const [pos, item] of stream) { - const position = { itemCount: pos }; - streamStore.writeStreamItem(streamName, item, position); - } - streamStore.closeStream(streamName); - } -} diff --git a/packages/swing-store/test/test-state.js b/packages/swing-store/test/test-state.js index 4b890d91a10..608078ae4c5 100644 --- a/packages/swing-store/test/test-state.js +++ b/packages/swing-store/test/test-state.js @@ -8,7 +8,6 @@ import test from 'ava'; import { initSwingStore, openSwingStore, - getAllState, isSwingStore, } from '../src/swingStore.js'; @@ -27,8 +26,9 @@ const tmpDir = prefix => }); }); -function testKVStore(t, kernelStorage) { - const kvStore = kernelStorage.kvStore; +function testKVStore(t, storage) { + const { kernelStorage, debug } = storage; + const { kvStore } = kernelStorage; t.falsy(kvStore.has('missing')); t.is(kvStore.get('missing'), undefined); @@ -59,33 +59,29 @@ function testKVStore(t, kernelStorage) { }, streamStuff: new Map(), }; - t.deepEqual( - getAllState(kernelStorage), - reference, - 'check state after changes', - ); + t.deepEqual(debug.getAllState(), reference, 'check state after changes'); } test('in-memory kvStore read/write', t => { - testKVStore(t, initSwingStore(null).kernelStorage); + testKVStore(t, initSwingStore(null)); }); test('persistent kvStore read/write/re-open', async t => { const [dbDir, cleanup] = await tmpDir('testdb'); t.teardown(cleanup); t.is(isSwingStore(dbDir), false); - const { kernelStorage, hostStorage } = initSwingStore(dbDir); + const storage = initSwingStore(dbDir); + const { hostStorage, debug } = storage; const { commit, close } = hostStorage; - testKVStore(t, kernelStorage); + testKVStore(t, storage); await commit(); - const before = getAllState(kernelStorage); + const before = debug.getAllState(); await close(); t.is(isSwingStore(dbDir), true); - const { kernelStorage: kernelStorage2, hostStorage: hostStorage2 } = - openSwingStore(dbDir); + const { hostStorage: hostStorage2, debug: debug2 } = openSwingStore(dbDir); const { close: close2 } = hostStorage2; - t.deepEqual(getAllState(kernelStorage2), before, 'check state after reread'); + t.deepEqual(debug2.getAllState(), before, 'check state after reread'); t.is(isSwingStore(dbDir), true); await close2(); });