From 3b860fabc0784b2e32512b31b457fe8406a21772 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Sun, 8 Aug 2021 16:40:55 -0700 Subject: [PATCH] refactor(swingset): move crankbuffer/commit/abort inside kernelKeeper The host application (which uses swingset as a library) is obligated to provide a "hostStorage" object, which is a trio of kvStore, streamStore, and snapStore. The host typically uses openLMDBSwingStore() to create this, and holds onto the "commit block" facet. Previously the kernelKeeper was built on top of the streamStore, the snapStore, and an "enhancedCrankBuffer", which was the host-provided key-value store plus an abortable/committable "crank buffer", plus some extra convenience methods. The kernel held the abort/commit facet. The kernel was responsible for extracting the raw kvStore from `hostStorage`, wrapping it, and passing the enhanced version into `makeKernelKeeper` along with the other two values. Instead, we now give the entire "hostStorage" object to `makeKernelKeeper`, and give the kernel keeper responsibility for doing the wrapping. When the kernel wants to commit or abort, it calls `kernelKeeper.abortCrank()` or `commitCrank()`. This simplifies the `makeKernelKeeper` construction and will provide a place for `commitCrank` to store a hash of kernel activity. refs #3442 --- .../SwingSet/src/kernel/initializeKernel.js | 12 +- packages/SwingSet/src/kernel/kernel.js | 23 +--- packages/SwingSet/src/kernel/kernelSyscall.js | 3 +- .../SwingSet/src/kernel/state/kernelKeeper.js | 29 +++-- packages/SwingSet/test/test-clist.js | 9 +- packages/SwingSet/test/test-state.js | 114 ++++++------------ 6 files changed, 72 insertions(+), 118 deletions(-) diff --git a/packages/SwingSet/src/kernel/initializeKernel.js b/packages/SwingSet/src/kernel/initializeKernel.js index 575cd38286c..5ee988fbbb9 100644 --- a/packages/SwingSet/src/kernel/initializeKernel.js +++ b/packages/SwingSet/src/kernel/initializeKernel.js @@ -6,7 +6,6 @@ import { assertKnownOptions } from '../assertOptions.js'; import { insistVatID } from './id.js'; import { makeVatSlot } from '../parseVatSlots.js'; import { insistStorageAPI } from '../storageAPI.js'; -import { wrapStorage } from './state/storageWrapper.js'; import makeKernelKeeper from './state/kernelKeeper.js'; import { exportRootObject, doQueueToKref } from './kernel.js'; @@ -16,12 +15,9 @@ function makeVatRootObjectSlot() { export function initializeKernel(config, hostStorage, verbose = false) { const logStartup = verbose ? console.debug : () => 0; + insistStorageAPI(hostStorage.kvStore); - const { kvStore, streamStore } = hostStorage; - insistStorageAPI(kvStore); - const { enhancedCrankBuffer, commitCrank } = wrapStorage(kvStore); - - const kernelKeeper = makeKernelKeeper(enhancedCrankBuffer, streamStore); + const kernelKeeper = makeKernelKeeper(hostStorage); const wasInitialized = kernelKeeper.getInitialized(); assert(!wasInitialized); @@ -86,7 +82,7 @@ export function initializeKernel(config, hostStorage, verbose = false) { const kref = exportRootObject(kernelKeeper, vatID); // Pin, to prevent it being GC'd when only the kvStore points to it kernelKeeper.pinObject(kref); - kvStore.set('vatAdminRootKref', kref); + kernelKeeper.kvStore.set('vatAdminRootKref', kref); gotVatAdminRootKref = true; } } @@ -135,7 +131,7 @@ export function initializeKernel(config, hostStorage, verbose = false) { } kernelKeeper.setInitialized(); kernelKeeper.saveStats(); - commitCrank(); // commit initialized kernel state as crank #0 + kernelKeeper.commitCrank(); // commit initialized kernel state as crank #0 return bootstrapResultKpid; // ---------------------------------------------------------------------- diff --git a/packages/SwingSet/src/kernel/kernel.js b/packages/SwingSet/src/kernel/kernel.js index f94c101355c..acf927b347e 100644 --- a/packages/SwingSet/src/kernel/kernel.js +++ b/packages/SwingSet/src/kernel/kernel.js @@ -7,12 +7,10 @@ import { foreverPolicy } from '../runPolicies.js'; import { makeVatManagerFactory } from './vatManager/factory.js'; import { makeVatWarehouse } from './vatManager/vat-warehouse.js'; import makeDeviceManager from './deviceManager.js'; -import { wrapStorage } from './state/storageWrapper.js'; import makeKernelKeeper from './state/kernelKeeper.js'; import { kdebug, kdebugEnable, legibilizeMessageArgs } from './kdebug.js'; import { insistKernelType, parseKernelSlot } from './parseKernelSlots.js'; import { parseVatSlot } from '../parseVatSlots.js'; -import { insistStorageAPI } from '../storageAPI.js'; import { insistCapData } from '../capdata.js'; import { insistMessage, insistVatDeliveryResult } from '../message.js'; import { insistDeviceID, insistVatID } from './id.js'; @@ -138,25 +136,13 @@ export default function buildKernel( } = kernelOptions; const logStartup = verbose ? console.debug : () => 0; - const { - kvStore, - streamStore, - snapStore, - } = /** @type { HostStore } */ (hostStorage); - insistStorageAPI(kvStore); - const { enhancedCrankBuffer, abortCrank, commitCrank } = wrapStorage(kvStore); - const vatAdminRootKref = kvStore.get('vatAdminRootKref'); + const vatAdminRootKref = hostStorage.kvStore.get('vatAdminRootKref'); const kernelSlog = writeSlogObject ? makeSlogger(slogCallbacks, writeSlogObject) : makeDummySlogger(slogCallbacks, makeConsole); - const kernelKeeper = makeKernelKeeper( - enhancedCrankBuffer, - streamStore, - kernelSlog, - snapStore, - ); + const kernelKeeper = makeKernelKeeper(hostStorage, kernelSlog); let started = false; @@ -261,7 +247,6 @@ export default function buildKernel( const kernelSyscallHandler = makeKernelSyscallHandler({ kernelKeeper, - kvStore: enhancedCrankBuffer, ephemeral, // eslint-disable-next-line no-use-before-define notify, @@ -792,7 +777,7 @@ export default function buildKernel( const { vatID, shouldReject, info } = terminationTrigger; if (terminationTrigger.shouldAbortCrank) { // errors unwind any changes the vat made - abortCrank(); + kernelKeeper.abortCrank(); didAbort = true; // but metering deductions and underflow notifications must survive const { meterDeductions } = postAbortActions; @@ -813,7 +798,7 @@ export default function buildKernel( } kernelKeeper.processRefcounts(); kernelKeeper.saveStats(); - commitCrank(); + kernelKeeper.commitCrank(); kernelKeeper.incrementCrankNumber(); } finally { processQueueRunning = undefined; diff --git a/packages/SwingSet/src/kernel/kernelSyscall.js b/packages/SwingSet/src/kernel/kernelSyscall.js index caddf87dfaf..1e1a92c3dce 100644 --- a/packages/SwingSet/src/kernel/kernelSyscall.js +++ b/packages/SwingSet/src/kernel/kernelSyscall.js @@ -28,13 +28,14 @@ export function doSend(kernelKeeper, target, msg) { export function makeKernelSyscallHandler(tools) { const { kernelKeeper, - kvStore, ephemeral, notify, doResolve, setTerminationTrigger, } = tools; + const { kvStore } = kernelKeeper; + function send(target, msg) { return doSend(kernelKeeper, target, msg); } diff --git a/packages/SwingSet/src/kernel/state/kernelKeeper.js b/packages/SwingSet/src/kernel/state/kernelKeeper.js index f3b68cfb783..3954f604909 100644 --- a/packages/SwingSet/src/kernel/state/kernelKeeper.js +++ b/packages/SwingSet/src/kernel/state/kernelKeeper.js @@ -1,10 +1,14 @@ // @ts-check import { Nat } from '@agoric/nat'; import { assert, details as X } from '@agoric/assert'; +import { wrapStorage } from './storageWrapper.js'; import { initializeVatState, makeVatKeeper } from './vatKeeper.js'; import { initializeDeviceState, makeDeviceKeeper } from './deviceKeeper.js'; import { parseReachableAndVatSlot } from './reachable.js'; -import { insistEnhancedStorageAPI } from '../../storageAPI.js'; +import { + insistStorageAPI, + insistEnhancedStorageAPI, +} from '../../storageAPI.js'; import { insistKernelType, makeKernelSlot, @@ -125,18 +129,19 @@ const FIRST_CRANK_NUMBER = 0n; const FIRST_METER_ID = 1n; /** - * @param {KVStorePlus} kvStore - * @param {StreamStore} streamStore + * @param {HostStore} hostStorage * @param {KernelSlog} kernelSlog - * @param {SnapStore=} snapStore */ -export default function makeKernelKeeper( - kvStore, - streamStore, - kernelSlog, - snapStore = undefined, -) { +export default function makeKernelKeeper(hostStorage, kernelSlog) { + // the kernelKeeper wraps the host's raw key-value store in a crank buffer + const rawKVStore = hostStorage.kvStore; + insistStorageAPI(rawKVStore); + + const { abortCrank, commitCrank, enhancedCrankBuffer: kvStore } = wrapStorage( + rawKVStore, + ); insistEnhancedStorageAPI(kvStore); + const { streamStore, snapStore } = hostStorage; /** * @param {string} key @@ -1329,6 +1334,10 @@ export default function makeKernelKeeper( allocateDeviceIDForNameIfNeeded, allocateDeviceKeeperIfNeeded, + kvStore, + abortCrank, + commitCrank, + dump, }); } diff --git a/packages/SwingSet/test/test-clist.js b/packages/SwingSet/test/test-clist.js index c7d8a87cc55..791555ce929 100644 --- a/packages/SwingSet/test/test-clist.js +++ b/packages/SwingSet/test/test-clist.js @@ -4,14 +4,12 @@ import { test } from '../tools/prepare-test-env-ava.js'; import { initSimpleSwingStore } from '@agoric/swing-store-simple'; import { makeDummySlogger } from '../src/kernel/slogger.js'; import makeKernelKeeper from '../src/kernel/state/kernelKeeper.js'; -import { wrapStorage } from '../src/kernel/state/storageWrapper.js'; test(`clist reachability`, async t => { const slog = makeDummySlogger({}); const hostStorage = initSimpleSwingStore(); - const { enhancedCrankBuffer: s } = wrapStorage(hostStorage.kvStore); - - const kk = makeKernelKeeper(s, hostStorage.streamStore, slog); + const kk = makeKernelKeeper(hostStorage, slog); + const s = kk.kvStore; kk.createStartingKernelState('local'); const vatID = kk.allocateUnusedVatID(); const vk = kk.provideVatKeeper(vatID); @@ -95,9 +93,8 @@ test(`clist reachability`, async t => { test('getImporters', async t => { const slog = makeDummySlogger({}); const hostStorage = initSimpleSwingStore(); - const { enhancedCrankBuffer: s } = wrapStorage(hostStorage.kvStore); + const kk = makeKernelKeeper(hostStorage, slog); - const kk = makeKernelKeeper(s, hostStorage.streamStore, slog); kk.createStartingKernelState('local'); const vatID1 = kk.allocateUnusedVatID(); kk.addDynamicVatID(vatID1); diff --git a/packages/SwingSet/test/test-state.js b/packages/SwingSet/test/test-state.js index 109eda4f1ea..2c81cf7c045 100644 --- a/packages/SwingSet/test/test-state.js +++ b/packages/SwingSet/test/test-state.js @@ -12,7 +12,6 @@ import makeKernelKeeper from '../src/kernel/state/kernelKeeper.js'; import { buildCrankBuffer, addHelpers, - wrapStorage, } from '../src/kernel/state/storageWrapper.js'; function checkState(t, getState, expected) { @@ -230,22 +229,13 @@ test('storage helpers', t => { function buildKeeperStorageInMemory() { const store = initSimpleSwingStore(); - const { kvStore, streamStore } = store; - const { enhancedCrankBuffer, commitCrank } = wrapStorage(kvStore); - return { - kvStore: enhancedCrankBuffer, - streamStore, - getState: () => getAllState(store).kvStuff, - commitCrank, - }; + return { getState: () => getAllState(store).kvStuff, ...store }; } function duplicateKeeper(getState) { const store = initSimpleSwingStore(); - const { kvStore, streamStore } = store; setAllState(store, { kvStuff: getState(), streamStuff: new Map() }); - const { enhancedCrankBuffer } = wrapStorage(kvStore); - return makeKernelKeeper(enhancedCrankBuffer, streamStore); + return makeKernelKeeper(store); } test('hostStorage param guards', async t => { @@ -261,18 +251,14 @@ test('hostStorage param guards', async t => { }); test('kernel state', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); t.truthy(!k.getInitialized()); k.createStartingKernelState('local'); k.setInitialized(); - commitCrank(); + k.commitCrank(); checkState(t, getState, [ ['crankNumber', '0'], ['initialized', 'true'], @@ -292,13 +278,9 @@ test('kernel state', async t => { }); test('kernelKeeper vat names', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const v1 = k.allocateVatIDForNameIfNeeded('vatname5'); @@ -306,7 +288,7 @@ test('kernelKeeper vat names', async t => { t.is(v1, 'v1'); t.is(v2, 'v2'); - commitCrank(); + k.commitCrank(); checkState(t, getState, [ ['crankNumber', '0'], ['gcActions', '[]'], @@ -341,13 +323,9 @@ test('kernelKeeper vat names', async t => { }); test('kernelKeeper device names', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const d7 = k.allocateDeviceIDForNameIfNeeded('devicename5'); @@ -355,7 +333,7 @@ test('kernelKeeper device names', async t => { t.is(d7, 'd7'); t.is(d8, 'd8'); - commitCrank(); + k.commitCrank(); checkState(t, getState, [ ['crankNumber', '0'], ['gcActions', '[]'], @@ -390,13 +368,9 @@ test('kernelKeeper device names', async t => { }); test('kernelKeeper runQueue', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); t.truthy(k.isRunQueueEmpty()); @@ -410,7 +384,7 @@ test('kernelKeeper runQueue', async t => { t.falsy(k.isRunQueueEmpty()); t.is(k.getRunQueueLength(), 2); - commitCrank(); + k.commitCrank(); const k2 = duplicateKeeper(getState); t.deepEqual(k.getNextMsg(), { type: 'send', stuff: 'awesome' }); @@ -431,13 +405,9 @@ test('kernelKeeper runQueue', async t => { }); test('kernelKeeper promises', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const p1 = k.addKernelPromiseForVat('v4'); @@ -452,7 +422,7 @@ test('kernelKeeper promises', async t => { t.truthy(k.hasKernelPromise(p1)); t.falsy(k.hasKernelPromise('kp99')); - commitCrank(); + k.commitCrank(); let k2 = duplicateKeeper(getState); t.deepEqual(k2.getKernelPromise(p1), { @@ -475,7 +445,7 @@ test('kernelKeeper promises', async t => { decider: undefined, }); - commitCrank(); + k.commitCrank(); k2 = duplicateKeeper(getState); t.deepEqual(k2.getKernelPromise(p1), { state: 'unresolved', @@ -513,7 +483,7 @@ test('kernelKeeper promises', async t => { t.deepEqual(k.getKernelPromise(p1).refCount, 2); expectedRunqueue.push({ type: 'send', target: 'kp40', msg: m2 }); - commitCrank(); + k.commitCrank(); k2 = duplicateKeeper(getState); t.deepEqual(k2.getKernelPromise(p1).queue, [m1, m2]); @@ -532,7 +502,7 @@ test('kernelKeeper promises', async t => { }); t.truthy(k.hasKernelPromise(p1)); // all the subscriber/queue stuff should be gone - commitCrank(); + k.commitCrank(); checkState(t, getState, [ ['crankNumber', '0'], @@ -558,8 +528,8 @@ test('kernelKeeper promises', async t => { }); test('kernelKeeper promise resolveToData', async t => { - const { kvStore, streamStore } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const p1 = k.addKernelPromiseForVat('v4'); @@ -580,8 +550,8 @@ test('kernelKeeper promise resolveToData', async t => { }); test('kernelKeeper promise reject', async t => { - const { kvStore, streamStore } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const p1 = k.addKernelPromiseForVat('v4'); @@ -602,13 +572,9 @@ test('kernelKeeper promise reject', async t => { }); test('vatKeeper', async t => { - const { - kvStore, - streamStore, - getState, - commitCrank, - } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const { getState } = store; + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const v1 = k.allocateVatIDForNameIfNeeded('name1'); @@ -624,7 +590,7 @@ test('vatKeeper', async t => { t.is(vk.nextDeliveryNum(), 0n); t.is(vk.nextDeliveryNum(), 1n); - commitCrank(); + k.commitCrank(); let vk2 = duplicateKeeper(getState).provideVatKeeper(v1); t.is(vk2.mapVatSlotToKernelSlot(vatExport1), kernelExport1); t.is(vk2.mapKernelSlotToVatSlot(kernelExport1), vatExport1); @@ -637,15 +603,15 @@ test('vatKeeper', async t => { t.is(vk.mapKernelSlotToVatSlot(kernelImport2), vatImport2); t.is(vk.mapVatSlotToKernelSlot(vatImport2), kernelImport2); - commitCrank(); + k.commitCrank(); vk2 = duplicateKeeper(getState).provideVatKeeper(v1); t.is(vk2.mapKernelSlotToVatSlot(kernelImport2), vatImport2); t.is(vk2.mapVatSlotToKernelSlot(vatImport2), kernelImport2); }); test('vatKeeper.getOptions', async t => { - const { kvStore, streamStore } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const v1 = k.allocateVatIDForNameIfNeeded('name1'); @@ -662,15 +628,15 @@ test('vatKeeper.getOptions', async t => { }); test('XS vatKeeper defaultManagerType', async t => { - const { kvStore, streamStore } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const k = makeKernelKeeper(store); k.createStartingKernelState('xs-worker'); t.is(k.getDefaultManagerType(), 'xs-worker'); }); test('meters', async t => { - const { kvStore, streamStore } = buildKeeperStorageInMemory(); - const k = makeKernelKeeper(kvStore, streamStore); + const store = buildKeeperStorageInMemory(); + const k = makeKernelKeeper(store); k.createStartingKernelState('local'); const m1 = k.allocateMeter(100n, 10n); const m2 = k.allocateMeter(200n, 150n);