From cceee4464c43df93e58661cbacf62d52cccb5405 Mon Sep 17 00:00:00 2001 From: Chip Morningstar Date: Wed, 6 Dec 2023 18:28:44 -0800 Subject: [PATCH] feat: add a `reapAllVats` call to the controller Closes #8626 --- .../SwingSet/src/controller/controller.js | 4 + packages/SwingSet/src/kernel/kernel.js | 10 +++ packages/SwingSet/src/types-external.js | 5 +- .../test/reap-all/bootstrap-reap-all.js | 23 ++++++ .../SwingSet/test/reap-all/test-reap-all.js | 80 +++++++++++++++++++ packages/SwingSet/test/reap-all/vat-dumbo.js | 9 +++ 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 packages/SwingSet/test/reap-all/bootstrap-reap-all.js create mode 100644 packages/SwingSet/test/reap-all/test-reap-all.js create mode 100644 packages/SwingSet/test/reap-all/vat-dumbo.js diff --git a/packages/SwingSet/src/controller/controller.js b/packages/SwingSet/src/controller/controller.js index 58661fcab813..9ab9421dc55d 100644 --- a/packages/SwingSet/src/controller/controller.js +++ b/packages/SwingSet/src/controller/controller.js @@ -319,6 +319,10 @@ export async function makeSwingsetController( return kernel.shutdown(); }, + reapAllVats() { + kernel.reapAllVats(); + }, + changeKernelOptions(options) { kernel.changeKernelOptions(options); }, diff --git a/packages/SwingSet/src/kernel/kernel.js b/packages/SwingSet/src/kernel/kernel.js index 10df109655bb..fc27f45022a4 100644 --- a/packages/SwingSet/src/kernel/kernel.js +++ b/packages/SwingSet/src/kernel/kernel.js @@ -1750,6 +1750,15 @@ export default function buildKernel( } } + function reapAllVats() { + for (const [_, vatID] of kernelKeeper.getStaticVats()) { + kernelKeeper.scheduleReap(vatID); + } + for (const vatID of kernelKeeper.getDynamicVats()) { + kernelKeeper.scheduleReap(vatID); + } + } + async function step() { if (kernelPanic) { throw kernelPanic; @@ -1935,6 +1944,7 @@ export default function buildKernel( step, run, shutdown, + reapAllVats, changeKernelOptions, // the rest are for testing and debugging diff --git a/packages/SwingSet/src/types-external.js b/packages/SwingSet/src/types-external.js index 8b6317a73745..72179e46ce90 100644 --- a/packages/SwingSet/src/types-external.js +++ b/packages/SwingSet/src/types-external.js @@ -155,7 +155,10 @@ export {}; * @typedef {{ * bundle: Bundle * }} BundleRef - * @typedef {(SourceSpec | BundleSpec | BundleRef ) & { + * @typedef {{ + * bundleName: string + * }} BundleName + * @typedef {(SourceSpec | BundleSpec | BundleRef | BundleName ) & { * creationOptions?: Record, * parameters?: Record, * }} SwingSetConfigProperties diff --git a/packages/SwingSet/test/reap-all/bootstrap-reap-all.js b/packages/SwingSet/test/reap-all/bootstrap-reap-all.js new file mode 100644 index 000000000000..36766638d341 --- /dev/null +++ b/packages/SwingSet/test/reap-all/bootstrap-reap-all.js @@ -0,0 +1,23 @@ +import { Far, E } from '@endo/far'; + +export function buildRootObject() { + let vatAdmin; + let bcap; + + return Far('root', { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + bcap = await E(vatAdmin).getNamedBundleCap('dumbo'); + console.log('end of bootstrap, vatAdmin', vatAdmin); + }, + + async createDynamicVats() { + const roots = []; + for (let i = 0; i < 3; i += 1) { + const res = await E(vatAdmin).createVat(bcap); + roots.push(res.root); + } + return roots; + }, + }); +} diff --git a/packages/SwingSet/test/reap-all/test-reap-all.js b/packages/SwingSet/test/reap-all/test-reap-all.js new file mode 100644 index 000000000000..f34e50a46fbe --- /dev/null +++ b/packages/SwingSet/test/reap-all/test-reap-all.js @@ -0,0 +1,80 @@ +// eslint-disable-next-line import/order +import { test } from '../../tools/prepare-test-env-ava.js'; + +import { initSwingStore } from '@agoric/swing-store'; +import { kunser } from '@agoric/kmarshal'; + +import { initializeSwingset, makeSwingsetController } from '../../src/index.js'; + +function bfile(name) { + return new URL(name, import.meta.url).pathname; +} + +test('reap all vats', async t => { + /** @type {SwingSetConfig} */ + const config = { + defaultManagerType: 'local', + defaultReapInterval: 4, + bootstrap: 'bootstrap', + vats: { + bootstrap: { sourceSpec: bfile('bootstrap-reap-all.js') }, + staticDumbo1: { bundleName: 'dumbo' }, + staticDumbo2: { bundleName: 'dumbo' }, + staticDumbo3: { bundleName: 'dumbo' }, + }, + bundles: { + dumbo: { sourceSpec: bfile('vat-dumbo.js') }, + }, + }; + + const kernelStorage = initSwingStore().kernelStorage; + await initializeSwingset(config, [], kernelStorage); + const c = await makeSwingsetController(kernelStorage); + t.teardown(c.shutdown); + c.pinVatRoot('bootstrap'); + c.pinVatRoot('staticDumbo1'); + c.pinVatRoot('staticDumbo2'); + c.pinVatRoot('staticDumbo3'); + await c.run(); + + const kpid = c.queueToVatRoot('bootstrap', 'createDynamicVats'); + await c.run(); + + const dynamicRoots = kunser(c.kpResolution(kpid)); + for (let i = 0; i < 3; i += 1) { + for (let j = 0; j < i + 1; j += 1) { + c.queueToVatRoot(`staticDumbo${i + 1}`, 'doSomething', [ + `staticDumbo${i + 1} #${j + 1}`, + ]); + } + } + for (let i = 0; i < 3; i += 1) { + for (let j = 0; j < i + 1; j += 1) { + c.queueToVatObject(dynamicRoots[i], 'doSomething', [ + `dynamicDumbo${i + 1} #${j + 1}`, + ]); + } + } + // Note: no call to c.run() here, so all the above messages are still enqueued + + const dumpBefore = c.dump(); + t.is(dumpBefore.acceptanceQueue.length, 12); + t.is(dumpBefore.reapQueue.length, 0); + + c.reapAllVats(); + const dumpPreReap = c.dump(); + t.is(dumpPreReap.acceptanceQueue.length, 12); + t.is(dumpPreReap.reapQueue.length, 11); + t.deepEqual( + dumpPreReap.reapQueue, + // prettier-ignore + ['v1', 'v3', 'v6', 'v7', 'v8', 'v5', 'v2', 'v4', 'v9', 'v10', 'v11'], + ); + + await c.run(); + const dumpPostReap = c.dump(); + t.is(dumpPostReap.acceptanceQueue.length, 0); + t.is(dumpPostReap.reapQueue.length, 0); + + t.pass(); +}); diff --git a/packages/SwingSet/test/reap-all/vat-dumbo.js b/packages/SwingSet/test/reap-all/vat-dumbo.js new file mode 100644 index 000000000000..3770cd3dde11 --- /dev/null +++ b/packages/SwingSet/test/reap-all/vat-dumbo.js @@ -0,0 +1,9 @@ +import { Far } from '@endo/far'; + +export function buildRootObject() { + return Far('root', { + doSomething(msg) { + console.log(`doSomething: ${msg}`); + }, + }); +}