Skip to content

Commit

Permalink
Merge pull request #5706 from Agoric/5679-unpersist-kernel-bundle
Browse files Browse the repository at this point in the history
fix(swingset): stop using a persistent kernel bundle
  • Loading branch information
mergify[bot] committed Jul 1, 2022
2 parents cc16105 + ec2c30d commit f2cb70e
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 92 deletions.
18 changes: 13 additions & 5 deletions packages/SwingSet/src/controller/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { makeGcAndFinalize } from '../lib-nodejs/gc-and-finalize.js';
import { insistStorageAPI } from '../lib/storageAPI.js';
import { provideHostStorage } from './hostStorage.js';
import {
buildKernelBundle,
swingsetIsInitialized,
initializeSwingset,
} from './initializeSwingset.js';
Expand Down Expand Up @@ -168,7 +169,8 @@ export function makeStartXSnap(bundles, { snapStore, env, spawn }) {
* warehousePolicy?: { maxVatsOnline?: number },
* overrideVatManagerOptions?: unknown,
* spawn?: typeof import('child_process').spawn,
* env?: Record<string, string | undefined>
* env?: Record<string, string | undefined>,
* kernelBundle?: Bundle
* }} runtimeOptions
*/
export async function makeSwingsetController(
Expand Down Expand Up @@ -238,6 +240,10 @@ export async function makeSwingsetController(
// see https://github.com/Agoric/SES-shim/issues/292 for details
harden(console);

writeSlogObject({ type: 'bundle-kernel-start' });
const { kernelBundle = await buildKernelBundle() } = runtimeOptions;
writeSlogObject({ type: 'bundle-kernel-finish' });

// FIXME: Put this somewhere better.
const handlers = process.listeners('unhandledRejection');
let haveUnhandledRejectionHandler = false;
Expand All @@ -254,8 +260,6 @@ export async function makeSwingsetController(
function kernelRequire(what) {
assert.fail(X`kernelRequire unprepared to satisfy require(${what})`);
}
// @ts-expect-error assume kernelBundle is set
const kernelBundle = JSON.parse(kvStore.get('kernelBundle'));
writeSlogObject({ type: 'import-kernel-start' });
const kernelNS = await importBundle(kernelBundle, {
filePrefix: 'kernel/...',
Expand Down Expand Up @@ -515,7 +519,7 @@ export async function makeSwingsetController(
* @param {SwingSetConfig} config
* @param {string[]} argv
* @param {{ hostStorage?: HostStore, env?: Record<string, string>, verbose?:
* boolean, kernelBundles?: Record<string, string>, debugPrefix?: string,
* boolean, kernelBundles?: Record<string, Bundle>, debugPrefix?: string,
* slogCallbacks?: unknown, testTrackDecref?: unknown, warehousePolicy?: {
* maxVatsOnline?: number }, slogFile?: string }} runtimeOptions
* @typedef { import('@agoric/swing-store').KVStore } KVStore
Expand All @@ -529,19 +533,23 @@ export async function buildVatController(
hostStorage = provideHostStorage(),
env,
verbose,
kernelBundles,
kernelBundles: kernelAndOtherBundles = {},
debugPrefix,
slogCallbacks,
warehousePolicy,
slogFile,
} = runtimeOptions;
const { kernel: kernelBundle, ...otherBundles } = kernelAndOtherBundles;
const kernelBundles = runtimeOptions.kernelBundles ? otherBundles : undefined;

const actualRuntimeOptions = {
env,
verbose,
debugPrefix,
slogCallbacks,
warehousePolicy,
slogFile,
kernelBundle,
};
const initializationOptions = { verbose, kernelBundles };
let bootstrapResult;
Expand Down
75 changes: 44 additions & 31 deletions packages/SwingSet/src/controller/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,45 +28,61 @@ const { keys, values, fromEntries } = Object;
const allValues = async obj =>
fromEntries(zip(keys(obj), await Promise.all(values(obj))));

const bundleRelative = rel =>
bundleSource(new URL(rel, import.meta.url).pathname);
const bundleRelativeGE = rel =>
bundleSource(new URL(rel, import.meta.url).pathname, { format: 'getExport' });

/**
* Build the source bundles for the kernel and xsnap vat worker.
*
* @param {object} [options]
* @param {ModuleFormat} [options.bundleFormat]
* Build the source bundles for the kernel. makeSwingsetController()
* calls this on each launch, to get the
* current kernel sources
*/
export async function buildKernelBundles(options = {}) {
// this takes 2.7s on my computer

const { bundleFormat = undefined } = options;

const src = rel =>
bundleSource(new URL(rel, import.meta.url).pathname, {
format: bundleFormat,
});
const srcGE = rel =>
bundleSource(new URL(rel, import.meta.url).pathname, {
format: 'getExport',
});
export async function buildKernelBundle() {
// this takes about 1.0s on my computer
const kernelBundle = await bundleRelative('../kernel/kernel.js');
return harden(kernelBundle);
}

/**
* Build the source bundles for built-in vats and devices, and for the
* xsnap vat worker.
*/
export async function buildVatAndDeviceBundles() {
const bundles = await allValues({
kernel: src('../kernel/kernel.js'),
adminDevice: src('../devices/vat-admin/device-vat-admin.js'),
adminVat: src('../vats/vat-admin/vat-vat-admin.js'),
comms: src('../vats/comms/index.js'),
vattp: src('../vats/vattp/vat-vattp.js'),
timer: src('../vats/timer/vat-timer.js'),

lockdown: srcGE(
adminDevice: bundleRelative('../devices/vat-admin/device-vat-admin.js'),
adminVat: bundleRelative('../vats/vat-admin/vat-vat-admin.js'),
comms: bundleRelative('../vats/comms/index.js'),
vattp: bundleRelative('../vats/vattp/vat-vattp.js'),
timer: bundleRelative('../vats/timer/vat-timer.js'),

lockdown: bundleRelativeGE(
'../supervisors/subprocess-xsnap/lockdown-subprocess-xsnap.js',
),
supervisor: srcGE(
supervisor: bundleRelativeGE(
'../supervisors/subprocess-xsnap/supervisor-subprocess-xsnap.js',
),
});

return harden(bundles);
}

// Unit tests can call this to amortize the bundling costs: pass the
// result to initializeSwingset's initializationOptions.kernelBundles
// (for the vat/device/worker bundles), and you can pass .kernelBundle
// individually to makeSwingsetController's
// runtimeOptions.kernelBundle

// Tests can also pass the whole result to buildVatController's
// runtimeOptions.kernelBundles, which will pass it through to both.

export async function buildKernelBundles() {
const bp = buildVatAndDeviceBundles();
const kp = buildKernelBundle();
const [vdBundles, kernelBundle] = await Promise.all([bp, kp]);
return harden({ kernel: kernelBundle, ...vdBundles });
}

function byName(a, b) {
if (a.name < b.name) {
return -1;
Expand Down Expand Up @@ -256,7 +272,7 @@ function sortObjectProperties(obj, firsts = []) {
return result;
}

/** @typedef {{ kernelBundles?: Record<string, string>, verbose?: boolean,
/** @typedef {{ kernelBundles?: Record<string, Bundle>, verbose?: boolean,
* addVatAdmin?: boolean, addComms?: boolean, addVattp?: boolean,
* addTimer?: boolean,
* }} InitializationOptions
Expand Down Expand Up @@ -318,17 +334,14 @@ export async function initializeSwingset(
}

const {
kernelBundles = await buildKernelBundles({
bundleFormat: config.bundleFormat,
}),
kernelBundles = await buildVatAndDeviceBundles(),
verbose,
addVatAdmin = true,
addComms = true,
addVattp = true,
addTimer = true,
} = initializationOptions;

kvStore.set('kernelBundle', JSON.stringify(kernelBundles.kernel));
kvStore.set('lockdownBundle', JSON.stringify(kernelBundles.lockdown));
kvStore.set('supervisorBundle', JSON.stringify(kernelBundles.supervisor));

Expand Down
1 change: 0 additions & 1 deletion packages/SwingSet/src/kernel/state/kernelKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const enableKernelGC = true;
// device.nextID = $NN
// meter.nextID = $NN // used to make m$NN

// kernelBundle = JSON(bundle)
// namedBundleID.$NAME = bundleID
// bundle.$BUNDLEID = JSON(bundle)
//
Expand Down
4 changes: 3 additions & 1 deletion packages/SwingSet/test/device-hooks/test-device-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ test('add hook', async t => {
addVattp: false,
addTimer: false,
};
const { kernelBundle } = t.context.data.kernelBundles;
const runtimeOpts = { kernelBundle };
await initializeSwingset(config, [], hostStorage, initOpts);
const c = await makeSwingsetController(hostStorage, {});
const c = await makeSwingsetController(hostStorage, {}, runtimeOpts);

let hookreturn;
function setHookReturn(args, slots = []) {
Expand Down
31 changes: 18 additions & 13 deletions packages/SwingSet/test/device-mailbox/test-device-mailbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
buildMailboxStateMap,
buildMailbox,
} from '../../src/devices/mailbox/mailbox.js';
import { bundleOpts } from '../util.js';

test.before(async t => {
const kernelBundles = await buildKernelBundles();
Expand All @@ -37,13 +38,14 @@ test('mailbox outbound', async t => {
},
},
};
const deviceEndowments = {
const devEndows = {
mailbox: { ...mb.endowments },
};

const { initOpts, runtimeOpts } = bundleOpts(t.context.data);
const hostStorage = provideHostStorage();
await initializeSwingset(config, ['mailbox1'], hostStorage, t.context.data);
const c = await makeSwingsetController(hostStorage, deviceEndowments);
await initializeSwingset(config, ['mailbox1'], hostStorage, initOpts);
const c = await makeSwingsetController(hostStorage, devEndows, runtimeOpts);
await c.run();
// exportToData() provides plain Numbers to the host that needs to convey the messages
t.deepEqual(s.exportToData(), {
Expand Down Expand Up @@ -85,13 +87,14 @@ test('mailbox inbound', async t => {
},
},
};
const deviceEndowments = {
const devEndows = {
mailbox: { ...mb.endowments },
};

const { initOpts, runtimeOpts } = bundleOpts(t.context.data);
const hostStorage = provideHostStorage();
await initializeSwingset(config, ['mailbox2'], hostStorage, t.context.data);
const c = await makeSwingsetController(hostStorage, deviceEndowments);
await initializeSwingset(config, ['mailbox2'], hostStorage, initOpts);
const c = await makeSwingsetController(hostStorage, devEndows, runtimeOpts);
await c.run();
const m1 = [1, 'msg1'];
const m2 = [2, 'msg2'];
Expand Down Expand Up @@ -143,23 +146,25 @@ async function initializeMailboxKernel(t) {
},
},
};
const { initOpts } = bundleOpts(t.context.data);
const hostStorage = provideHostStorage();
await initializeSwingset(
config,
['mailbox-determinism'],
hostStorage,
t.context.data,
initOpts,
);
return hostStorage;
}

async function makeMailboxKernel(hostStorage) {
async function makeMailboxKernel(t, hostStorage) {
const s = buildMailboxStateMap();
const mb = buildMailbox(s);
const deviceEndowments = {
const devEndows = {
mailbox: { ...mb.endowments },
};
const c = await makeSwingsetController(hostStorage, deviceEndowments);
const { runtimeOpts } = bundleOpts(t.context.data);
const c = await makeSwingsetController(hostStorage, devEndows, runtimeOpts);
c.pinVatRoot('bootstrap');
await c.run();
return [c, mb];
Expand All @@ -169,8 +174,8 @@ test('mailbox determinism', async t => {
// we run two kernels in parallel
const hostStorage1 = await initializeMailboxKernel(t);
const hostStorage2 = await initializeMailboxKernel(t);
const [c1a, mb1a] = await makeMailboxKernel(hostStorage1);
const [c2, mb2] = await makeMailboxKernel(hostStorage2);
const [c1a, mb1a] = await makeMailboxKernel(t, hostStorage1);
const [c2, mb2] = await makeMailboxKernel(t, hostStorage2);

// they get the same inbound message
const msg1 = [[1, 'msg1']];
Expand All @@ -195,7 +200,7 @@ test('mailbox determinism', async t => {
);

// then one is restarted, but the other keeps running
const [c1b, mb1b] = await makeMailboxKernel(hostStorage1);
const [c1b, mb1b] = await makeMailboxKernel(t, hostStorage1);

// Now we repeat delivery of that message to both. The mailbox should send
// it to vattp, even though it's duplicate, because the mailbox doesn't
Expand Down
Loading

0 comments on commit f2cb70e

Please sign in to comment.