Skip to content

Commit

Permalink
feat(swingset): defaultManagerType option in makeSwingsetController (#…
Browse files Browse the repository at this point in the history
…2266)

* build(xsnap): disable experimental mxMetering

* chore(moddable): update to Jan 19

* fix(xsnap): report exceptions in timer callbacks

* fix(xsnap): protect timer callbacks from GC

ref attachment from PH Tue Feb 2 07:28:28 2021 -0800

 - don't hold arraybuffer pointer across macros
 - replace C stack report / result with xsVar(1) and xsVar(2)

* style(xsnap): test-xsnap.js lint

* test(xsnap): reject regex with non-standard hyphen

 - accept std regex range

* test(xsnap): uncaught rejections should not be silent FAILing

* fix: replay deliveries in xs-worker

* fix(xs-worker): transformTildot was missing from vat powers

  - route call to manager
  - some VatPowers type annotations, esp. transformTildot

* feat(xs-worker): vatstoreGet, Set, Delete

we get an empty JSON response for at least vatstoreSet

These are missing from SwingSet/docs/vat-worker.md

* feat(swingset): defaultManagerType option in makeSwingsetController

... and to buildVatController

Usage: WORKER_TYPE=xs-worker yarn test
   or: XSNAP_DEBUG=1 WORKER_TYPE=xs-worker yarn test
   or: XSNAP_DEBUG=1 WORKER_TYPE=xs-worker yarn test --watch

ref #2260

  - fix: comms vat must be local to use setUp
  - chore(swingset): log fallback-to-local workerType
  - chore: refine xs-worker diagnostics
  - chore(xs-worker): include vatID in log messages
  - fix(xs-worker): catch exceptions from exception handler
  - chore(swingset): use ambient process.env unless caller overrides
  - fix(swingset): proplems in types.js shown by @ts-check

* chore(swingset): note setup implies local for comms vat
  • Loading branch information
dckc authored Feb 8, 2021
1 parent 04f6f81 commit b57f08f
Show file tree
Hide file tree
Showing 18 changed files with 267 additions and 126 deletions.
16 changes: 13 additions & 3 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ export async function makeSwingsetController(
) {
insistStorageAPI(hostStorage);

// Use ambient process.env only if caller did not specify.
const { env = process.env } = runtimeOptions;

// build console early so we can add console.log to diagnose early problems
const {
verbose,
debugPrefix = '',
slogFile,
testTrackDecref,
defaultManagerType = env.WORKER_TYPE || 'local',
} = runtimeOptions;
if (typeof Compartment === 'undefined') {
throw Error('SES must be installed before calling makeSwingsetController');
Expand Down Expand Up @@ -166,7 +170,7 @@ export async function makeSwingsetController(
name,
stdout: 'inherit',
stderr: 'inherit',
// debug: true,
debug: !!env.XSNAP_DEBUG,
});

const bundles = {
Expand Down Expand Up @@ -205,7 +209,7 @@ export async function makeSwingsetController(
FinalizationRegistry,
};

const kernelOptions = { verbose, testTrackDecref };
const kernelOptions = { verbose, testTrackDecref, defaultManagerType };
const kernel = buildKernel(kernelEndowments, deviceEndowments, kernelOptions);

if (runtimeOptions.verbose) {
Expand Down Expand Up @@ -298,8 +302,14 @@ export async function buildVatController(
kernelBundles,
debugPrefix,
testTrackDecref,
defaultManagerType,
} = runtimeOptions;
const actualRuntimeOptions = { verbose, debugPrefix, testTrackDecref };
const actualRuntimeOptions = {
verbose,
debugPrefix,
testTrackDecref,
defaultManagerType,
};
const initializationOptions = { verbose, kernelBundles };
let bootstrapResult;
if (!swingsetIsInitialized(hostStorage)) {
Expand Down
4 changes: 4 additions & 0 deletions packages/SwingSet/src/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,11 @@ export async function initializeSwingset(
bundle: kernelBundles.comms,
creationOptions: {
enablePipelining: true,
// The use of setup rather than buildRootObject requires
// a local worker. We have no plans to support setup on
// non-local workers any time soon.
enableSetup: true,
managerType: 'local',
},
};

Expand Down
7 changes: 6 additions & 1 deletion packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ export default function buildKernel(
FinalizationRegistry,
} = kernelEndowments;
deviceEndowments = { ...deviceEndowments }; // copy so we can modify
const { verbose, testTrackDecref = false } = kernelOptions;
const {
verbose,
testTrackDecref = false,
defaultManagerType = 'local',
} = kernelOptions;
const logStartup = verbose ? console.debug : () => 0;

insistStorageAPI(hostStorage);
Expand Down Expand Up @@ -562,6 +566,7 @@ export default function buildKernel(
startSubprocessWorkerNode,
startXSnap,
gcTools,
defaultManagerType,
});

function buildVatSyscallHandler(vatID, translators) {
Expand Down
25 changes: 20 additions & 5 deletions packages/SwingSet/src/kernel/vatManager/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function makeVatManagerFactory({
startSubprocessWorkerNode,
startXSnap,
gcTools,
defaultManagerType,
}) {
const localFactory = makeLocalVatManagerFactory({
allVatPowers,
Expand Down Expand Up @@ -44,6 +45,7 @@ export function makeVatManagerFactory({
const xsWorkerFactory = makeXsSubprocessFactory({
startXSnap,
kernelKeeper,
allVatPowers,
testLog: allVatPowers.testLog,
decref: gcTools.decref,
});
Expand Down Expand Up @@ -74,17 +76,30 @@ export function makeVatManagerFactory({
// returns promise for new vatManager
function vatManagerFactory(vatID, managerOptions) {
validateManagerOptions(managerOptions);
const { managerType = 'local', setup, bundle } = managerOptions;
const {
managerType = defaultManagerType,
setup,
bundle,
metered,
enableSetup,
} = managerOptions;

if (managerType === 'local') {
if (metered && managerType !== 'local') {
console.warn(
`TODO: support metered with ${managerType}; using local as work-around`,
);
}
if (setup && managerType !== 'local') {
console.warn(
`TODO: stop using setup() with ${managerType}; using local as work-around`,
);
}
if (managerType === 'local' || metered || enableSetup) {
if (setup) {
return localFactory.createFromSetup(vatID, setup, managerOptions);
}
return localFactory.createFromBundle(vatID, bundle, managerOptions);
}
// 'setup' based vats must be local. TODO: stop using 'setup' in vats,
// but tests and comms-vat still need it
assert(!setup, `setup()-based vats must use a local Manager`);

if (managerType === 'nodeWorker') {
return nodeWorkerFactory.createFromBundle(vatID, bundle, managerOptions);
Expand Down
47 changes: 32 additions & 15 deletions packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ const decoder = new TextDecoder();

/**
* @param {{
* startXSnap: (name: string, handleCommand: SyncHandler) => { worker: XSnap, bundles: Record<string, ExportBundle> },
* allVatPowers: VatPowers,
* kernelKeeper: KernelKeeper,
* startXSnap: (name: string, handleCommand: SyncHandler) => { worker: XSnap, bundles: Record<string, ExportBundle> },
* testLog: (...args: unknown[]) => void,
* decref: (vatID: unknown, vref: unknown, count: number) => void,
* }} tools
Expand All @@ -28,8 +29,9 @@ const decoder = new TextDecoder();
* @typedef { [unknown, ...unknown[]] } Tagged
*/
export function makeXsSubprocessFactory({
startXSnap,
allVatPowers: { transformTildot },
kernelKeeper,
startXSnap,
testLog,
decref,
}) {
Expand All @@ -39,10 +41,13 @@ export function makeXsSubprocessFactory({
* @param { ManagerOptions } managerOptions
*/
async function createFromBundle(vatID, bundle, managerOptions) {
parentLog('createFromBundle', { vatID });
parentLog(vatID, 'createFromBundle', { vatID });
const { vatParameters, virtualObjectCacheSize } = managerOptions;
assert(!managerOptions.metered, 'not supported yet');
assert(!managerOptions.enableSetup, 'not supported at all');
assert(!managerOptions.metered, 'xs-worker: metered not supported yet');
assert(
!managerOptions.enableSetup,
'xs-worker: enableSetup not supported at all',
);
if (managerOptions.enableInternalMetering) {
// TODO: warn+ignore, rather than throw, because the kernel enables it
// for all vats, because the Spawner still needs it. When the kernel
Expand Down Expand Up @@ -72,10 +77,10 @@ export function makeXsSubprocessFactory({

/** @type { (item: Tagged) => unknown } */
function handleUpstream([type, ...args]) {
parentLog(`handleUpstream`, type, args.length);
parentLog(vatID, `handleUpstream`, type, args.length);
switch (type) {
case 'syscall': {
parentLog(`syscall`, args);
parentLog(vatID, `syscall`, args[0], args.length);
const [scTag, ...vatSyscallArgs] = args;
return handleSyscall([scTag, ...vatSyscallArgs]);
}
Expand All @@ -97,22 +102,32 @@ export function makeXsSubprocessFactory({
vatDecref(vref, count);
return ['OK'];
}
case 'transformTildot': {
const [extjs] = args;
try {
const stdjs = transformTildot(extjs);
// console.log({ extjs, stdjs });
return ['ok', stdjs];
} catch (err) {
return ['err', err.message];
}
}
default:
throw new Error(`unrecognized uplink message ${type}`);
}
}

/** @type { (msg: Uint8Array) => Uint8Array } */
function handleCommand(msg) {
parentLog('handleCommand', { length: msg.byteLength });
// parentLog('handleCommand', { length: msg.byteLength });
const tagged = handleUpstream(JSON.parse(decoder.decode(msg)));
return encoder.encode(JSON.stringify(tagged));
}

// start the worker and establish a connection
const { worker, bundles } = startXSnap(`${vatID}`, handleCommand);
for await (const [it, superCode] of Object.entries(bundles)) {
parentLog('bundle', it);
parentLog(vatID, 'eval bundle', it);
assert(
superCode.moduleFormat === 'getExport',
details`${it} unexpected: ${superCode.moduleFormat}`,
Expand All @@ -122,15 +137,15 @@ export function makeXsSubprocessFactory({

/** @type { (item: Tagged) => Promise<Tagged> } */
async function issueTagged(item) {
parentLog('issueTagged', item[0]);
parentLog(item[0], '...', item.length - 1);
const txt = await worker.issueStringCommand(JSON.stringify(item));
const reply = JSON.parse(txt);
assert(Array.isArray(reply));
const [tag, ...rest] = reply;
return [tag, ...rest];
}

parentLog(`instructing worker to load bundle..`);
parentLog(vatID, `instructing worker to load bundle..`);
const bundleReply = await issueTagged([
'setBundle',
vatID,
Expand All @@ -139,16 +154,18 @@ export function makeXsSubprocessFactory({
virtualObjectCacheSize,
]);
if (bundleReply[0] === 'dispatchReady') {
parentLog(`bundle loaded. dispatch ready.`);
parentLog(vatID, `bundle loaded. dispatch ready.`);
} else {
throw new Error(`failed to setBundle: ${bundleReply}`);
}

/** @type { (item: Tagged) => Promise<Tagged> } */
async function deliver(delivery) {
parentLog(`sending delivery`, delivery);
parentLog(vatID, `sending delivery`, delivery);
transcriptManager.startDispatch(delivery);
const result = await issueTagged(['deliver', ...delivery]);
parentLog(`deliverDone`, result[0], result.length);
parentLog(vatID, `deliverDone`, result[0], result.length);
transcriptManager.finishDispatch();
return result;
}

Expand All @@ -175,7 +192,7 @@ export function makeXsSubprocessFactory({
shutdown,
});

parentLog('manager', Object.keys(manager));
parentLog(vatID, 'manager', Object.keys(manager));
return manager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const decoder = new TextDecoder();
function workerLog(first, ...args) {
// @ts-ignore
// eslint-disable-next-line
// print(`---worker: ${first}`, ...args);
// console.log(`---worker: ${first}`, ...args);
}

workerLog(`supervisor started`);
Expand All @@ -30,7 +30,7 @@ function managerPort(issueCommand) {
const encode = item => encoder.encode(JSON.stringify(item)).buffer;

/** @type { (msg: ArrayBuffer) => any } */
const decodeData = msg => JSON.parse(decoder.decode(msg));
const decodeData = msg => JSON.parse(decoder.decode(msg) || 'null');

/** @type { (msg: ArrayBuffer) => Tagged } */
function decode(msg) {
Expand Down Expand Up @@ -59,6 +59,7 @@ function managerPort(issueCommand) {
* @template T
*/
handlerFrom(f) {
const lastResort = encoder.encode(`exception from ${f.name}`).buffer;
return msg => {
const report = {};
f(decode(msg))
Expand All @@ -67,7 +68,10 @@ function managerPort(issueCommand) {
report.result = encode(item);
})
.catch(err => {
report.result = encode(['err', err.message]);
report.result = encode(['err', f.name, err.message]);
})
.catch(_err => {
report.result = lastResort;
});
return report;
};
Expand All @@ -82,12 +86,14 @@ function managerPort(issueCommand) {
function runAndWait(f, errmsg) {
Promise.resolve()
.then(f)
.then(undefined, err => workerLog(`doProcess: ${errmsg}:`, err));
.then(undefined, err => {
workerLog(`doProcess: ${errmsg}:`, err.message);
});
return waitUntilQuiescent();
}

/**
* @param { ReturnType<managerPort> } port
* @param { ReturnType<typeof managerPort> } port
*/
function makeWorker(port) {
/** @type { Record<string, (...args: unknown[]) => void> | null } */
Expand Down Expand Up @@ -141,6 +147,14 @@ function makeWorker(port) {
return harden(cons);
}

/** @type { (extSrc: string) => string } */
function transformTildot(extSrc) {
const reply = port.call(['transformTildot', extSrc]);
assert(Array.isArray(reply));
if (reply[0] === 'err') throw new Error(reply[1]);
return reply[1];
}

/**
* @param {unknown} vatID
* @param {unknown} bundle
Expand All @@ -167,12 +181,16 @@ function makeWorker(port) {
callNow: (...args) => doSyscall(['callNow', ...args]),
subscribe: (...args) => doSyscall(['subscribe', ...args]),
resolve: (...args) => doSyscall(['resolve', ...args]),
vatstoreGet: (...args) => doSyscall(['vatstoreGet', ...args]),
vatstoreSet: (...args) => doSyscall(['vatstoreSet', ...args]),
vatstoreDelete: (...args) => doSyscall(['vatstoreDelete', ...args]),
});

const vatPowers = {
Remotable,
getInterfaceOf,
makeMarshal,
transformTildot,
testLog: (...args) => port.send(['testLog', ...args]),
};

Expand Down
Loading

0 comments on commit b57f08f

Please sign in to comment.