Skip to content

Commit

Permalink
fix(SwingSet): don't do liveSlots logging in consensus mode
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Jan 25, 2022
1 parent 5e482fe commit d563783
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 75 deletions.
2 changes: 1 addition & 1 deletion packages/SwingSet/src/kernel/liveSlots.js
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ function build(
* @param {boolean} enableDisavow
* @param {boolean} enableVatstore
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent }
* @param {Console} [liveSlotsConsole]
* @param {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} [liveSlotsConsole]
* @returns {*} { vatGlobals, inescapableGlobalProperties, dispatch, setBuildRootObject }
*
* setBuildRootObject should be called, once, with a function that will
Expand Down
25 changes: 21 additions & 4 deletions packages/SwingSet/src/kernel/vatManager/manager-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ export function makeLocalVatManagerFactory(tools) {
testLog: allVatPowers.testLog,
});

const makeLogMaker = logger => {
const makeLog = level => {
const log = logger[level];
assert.typeof(log, 'function', X`logger[${level}] must be a function`);
return (...args) => {
// We have to dynamically wrap the consensus mode so that it can change
// during the lifetime of the supervisor (which when snapshotting, is
// restored to its current heap across restarts, not actually stopping
// until the vat is terminated).
if (consensusMode) {
return;
}

log(...args);
};
};
return makeLog;
};

// we might or might not use this, depending upon whether the vat exports
// 'buildRootObject' or a default 'setup' function
const ls = makeLiveSlots(
Expand All @@ -114,15 +133,13 @@ export function makeLocalVatManagerFactory(tools) {
enableDisavow,
enableVatstore,
gcTools,
liveSlotsConsole,
makeVatConsole(makeLogMaker(liveSlotsConsole)),
);

const endowments = harden({
...vatEndowments,
...ls.vatGlobals,
console: makeVatConsole(vatConsole, (logger, args) => {
consensusMode || logger(...args);
}),
console: makeVatConsole(makeLogMaker(vatConsole)),
assert,
TextEncoder,
TextDecoder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function makeXsSubprocessFactory({
metered,
compareSyscalls,
useTranscript,
liveSlotsConsole,
vatConsole,
} = managerOptions;
assert(
Expand All @@ -87,12 +88,16 @@ export function makeXsSubprocessFactory({
insistVatSyscallObject(vso);
return mk.syscallFromWorker(vso);
}
case 'liveSlotsConsole':
case 'console': {
const [level, ...rest] = args;
if (typeof level === 'string' && level in vatConsole) {
vatConsole[level](...rest);
// Choose the right console.
const myConsole =
(type === 'liveSlotsConsole' && liveSlotsConsole) || vatConsole;
if (typeof level === 'string' && level in myConsole) {
myConsole[level](...rest);
} else {
console.error('bad console level', level);
console.error(`bad ${type} level`, level);
}
return ['ok'];
}
Expand Down
37 changes: 11 additions & 26 deletions packages/SwingSet/src/kernel/vatManager/supervisor-helper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-check
import { assert, details as X } from '@agoric/assert';
import { assert } from '@agoric/assert';
import {
insistVatSyscallObject,
insistVatSyscallResult,
Expand Down Expand Up @@ -144,36 +144,21 @@ harden(makeSupervisorSyscall);
export { makeSupervisorSyscall };

/**
* Create a vat console, or a no-op if consensusMode is true.
* Create a vat console from a log stream maker.
*
* TODO: consider other methods per SES VirtualConsole.
* See https://github.com/Agoric/agoric-sdk/issues/2146
*
* @param {Record<'debug' | 'log' | 'info' | 'warn' | 'error', (...args: any[]) => void>} logger
* the backing log method
* @param {(logger: any, args: any[]) => void} [wrapper]
* @param {(level: string) => (...args: any[]) => void} makeLog
*/
function makeVatConsole(logger, wrapper) {
assert.typeof(
wrapper,
'function',
X`Invalid VatConsole wrapper value ${wrapper}`,
);
const cons = Object.fromEntries(
['debug', 'log', 'info', 'warn', 'error'].map(level => {
const backingLog = logger[level];

return [
level,
(...args) => {
// Wrap the actual backing log message, in case there is logic to impose.
wrapper(backingLog, args);
},
];
}),
);

return harden(cons);
function makeVatConsole(makeLog) {
return harden({
debug: makeLog('debug'),
log: makeLog('log'),
info: makeLog('info'),
warn: makeLog('warn'),
error: makeLog('error'),
});
}

harden(makeVatConsole);
Expand Down
29 changes: 23 additions & 6 deletions packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,27 @@ parentPort.on('message', ([type, ...margs]) => {
gcAndFinalize: makeGcAndFinalize(engineGC),
meterControl: makeDummyMeterControl(),
});

const makeLogMaker = tag => {
const logger = anylogger(tag);
const makeLog = level => {
const log = logger[level];
assert.typeof(log, 'function', X`logger[${level}] must be a function`);
return (...args) => {
// We have to dynamically wrap the consensus mode so that it can change
// during the lifetime of the supervisor (which when snapshotting, is
// restored to its current heap across restarts, not actually stopping
// until the vat is terminated).
if (consensusMode) {
return;
}

log(...args);
};
};
return makeLog;
};

const ls = makeLiveSlots(
syscall,
vatID,
Expand All @@ -88,16 +109,12 @@ parentPort.on('message', ([type, ...margs]) => {
enableDisavow,
enableVatstore,
gcTools,
makeVatConsole(makeLogMaker(`SwingSet:ls:${vatID}`)),
);

const endowments = {
...ls.vatGlobals,
console: makeVatConsole(
anylogger(`SwingSet:vat:${vatID}`),
(logger, args) => {
consensusMode || logger(...args);
},
),
console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)),
assert,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @ts-check

// this file is loaded at the start of a new subprocess
import '@agoric/install-ses';

Expand Down Expand Up @@ -81,6 +83,7 @@ fromParent.on('data', ([type, ...margs]) => {
sendUplink(['syscall', vatSyscallObject]);
}
// this 'syscall' throws or returns data
// @ts-expect-error the syscaller can return void when the second argument is false
const syscall = makeSupervisorSyscall(syscallToManager, false);
const vatID = 'demo-vatID';
const vatPowers = {
Expand All @@ -95,6 +98,27 @@ fromParent.on('data', ([type, ...margs]) => {
gcAndFinalize: makeGcAndFinalize(engineGC),
meterControl: makeDummyMeterControl(),
});

const makeLogMaker = tag => {
const logger = anylogger(tag);
const makeLog = level => {
const log = logger[level];
assert.typeof(log, 'function', X`logger[${level}] must be a function`);
return (...args) => {
// We have to dynamically wrap the consensus mode so that it can change
// during the lifetime of the supervisor (which when snapshotting, is
// restored to its current heap across restarts, not actually stopping
// until the vat is terminated).
if (consensusMode) {
return;
}

log(...args);
};
};
return makeLog;
};

const ls = makeLiveSlots(
syscall,
vatID,
Expand All @@ -104,17 +128,13 @@ fromParent.on('data', ([type, ...margs]) => {
enableDisavow,
enableVatstore,
gcTools,
makeVatConsole(makeLogMaker(`SwingSet:ls:${vatID}`)),
);

// Enable or disable the console accordingly.
const endowments = {
...ls.vatGlobals,
console: makeVatConsole(
anylogger(`SwingSet:vat:${vatID}`),
(logger, args) => {
consensusMode || logger(...args);
},
),
console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)),
assert,
};

Expand All @@ -125,7 +145,7 @@ fromParent.on('data', ([type, ...margs]) => {
workerLog(`got vatNS:`, Object.keys(vatNS).join(','));
sendUplink(['gotBundle']);
ls.setBuildRootObject(vatNS.buildRootObject);
dispatch = makeSupervisorDispatch(ls.dispatch, waitUntilQuiescent);
dispatch = makeSupervisorDispatch(ls.dispatch);
workerLog(`got dispatch:`, Object.keys(dispatch).join(','));
sendUplink(['dispatchReady']);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global globalThis WeakRef FinalizationRegistry */
// @ts-check
import { assert, details as X, q } from '@agoric/assert';
import { assert, details as X } from '@agoric/assert';
import { importBundle } from '@agoric/import-bundle';
import { makeMarshal } from '@agoric/marshal';
import '../../types.js';
Expand Down Expand Up @@ -204,6 +204,9 @@ function makeWorker(port) {
consensusMode,
gcEveryCrank,
) {
// Enable or disable the consensus mode according to current settings.
currentConsensusMode = consensusMode;

/** @type { (vso: VatSyscallObject) => VatSyscallResult } */
function syscallToManager(vatSyscallObject) {
workerLog('doSyscall', vatSyscallObject);
Expand Down Expand Up @@ -243,6 +246,41 @@ function makeWorker(port) {
meterControl,
});

/** @param {string} dst */
const makeLogMaker = dst => {
/** @param {string} level */
const makeLog = level => {
const printAll = console[level];
assert.typeof(printAll, 'function');
const portSendingPrinter = (...args) => {
port.send([dst, level, ...args]);
};
return (...args) => {
// We have to dynamically wrap the consensus mode so that it can change
// during the lifetime of the supervisor (which when snapshotting, is
// restored to its current heap across restarts, not actually stopping
// until the vat is terminated).
if (currentConsensusMode) {
return;
}

// Use the causal console, but output to the port.
//
// FIXME: This is a hack until the start compartment can create
// Console objects that log to a different destination than
// `globalThis.console`.
const { print: savePrinter } = globalThis;
try {
globalThis.print = portSendingPrinter;
printAll(...args);
} finally {
globalThis.print = savePrinter;
}
};
};
return makeLog;
};

const ls = makeLiveSlots(
syscall,
vatID,
Expand All @@ -252,37 +290,12 @@ function makeWorker(port) {
enableDisavow,
enableVatstore,
gcTools,
makeVatConsole(makeLogMaker('liveSlotsConsole')),
);

const makeLog = level => {
return (...args) => {
// TODO: use more faithful stringification
const jsonSafeArgs = JSON.parse(`${q(args)}`);
port.send(['console', level, ...jsonSafeArgs]);
};
};
const forwardingLogger = {
debug: makeLog('debug'),
log: makeLog('log'),
info: makeLog('info'),
warn: makeLog('warn'),
error: makeLog('error'),
};

// Enable or disable the console accordingly.
currentConsensusMode = consensusMode;
const endowments = {
...ls.vatGlobals,
console: makeVatConsole(
forwardingLogger,
// We have to dynamically wrap the consensus mode so that it can change
// during the lifetime of the supervisor (which when snapshotting, is
// restored to its current heap across restarts, not actually stopping
// until the vat is terminated).
(logger, args) => {
currentConsensusMode || logger(...args);
},
),
console: makeVatConsole(makeLogMaker('console')),
assert,
// bootstrap provides HandledPromise
HandledPromise: globalThis.HandledPromise,
Expand Down

0 comments on commit d563783

Please sign in to comment.