Skip to content

Commit

Permalink
fix(swingset): do not record GC syscalls in the transcript
Browse files Browse the repository at this point in the history
Consensus mode will depend upon GC being deterministic, but solo mode does
not. Solo mode requires GC be "sufficiently deterministic", which means a
finalizer may or may not run in any given crank.

To support this, we must not record the GC-related syscalls (dropImport,
retireImport, retireExport) in the transcript. When replaying a transcript,
we ignore these syscalls as well.

closes #3146
refs #2615
refs #2660
refs #2724
  • Loading branch information
warner committed May 21, 2021
1 parent 3b0662e commit d18ddf5
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
10 changes: 10 additions & 0 deletions packages/SwingSet/src/kernel/vatManager/transcript.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export function makeTranscriptManager(
};
}

const gcSyscalls = new Set(['dropImports', 'retireImports', 'retireExports']);

function addSyscall(d, response) {
const type = d[0];
if (gcSyscalls.has(type)) {
return;
}
if (currentEntry) {
currentEntry.syscalls.push({ d, response });
}
Expand Down Expand Up @@ -59,6 +65,10 @@ export function makeTranscriptManager(
let replayError;

function simulateSyscall(newSyscall) {
const type = newSyscall[0];
if (gcSyscalls.has(type)) {
return undefined;
}
const s = playbackSyscalls.shift();
const newReplayError = compareSyscalls(vatID, s.d, newSyscall);
if (newReplayError) {
Expand Down
85 changes: 85 additions & 0 deletions packages/SwingSet/test/test-gc-transcript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// eslint-disable-next-line import/order
import { test } from '../tools/prepare-test-env-ava';

import { makeDummySlogger } from '../src/kernel/slogger';
import { makeManagerKit } from '../src/kernel/vatManager/manager-helper';

const m1 = ['message', { method: 'foo', args: { body: '', slots: [] } }];

function setup(storedTranscript = []) {
const vatID = 'vatID';
const slog = makeDummySlogger({}, () => console);
const transcript = [];
const vatKeeper = {
addToTranscript(entry) {
transcript.push(entry);
},
vatStats() {
return { transcriptCount: storedTranscript.length };
},
getTranscript() {
return storedTranscript;
},
};
const kernelKeeper = {
getVatKeeper() {
return vatKeeper;
},
};
function vatSyscallHandler(_vso) {
return ['ok', null];
}
const workerCanBlock = false;
const mk = makeManagerKit(
vatID,
slog,
kernelKeeper,
vatSyscallHandler,
workerCanBlock,
);
const { syscallFromWorker } = mk;
function deliver(_delivery) {
// a syscall.subscribe is included in the transcript
syscallFromWorker(['subscribe', 'p-1']);
// but GC syscalls are not
syscallFromWorker(['dropImports', ['o-1']]);
syscallFromWorker(['retireImports', ['o-1']]);
syscallFromWorker(['retireExports', ['o+2']]);
syscallFromWorker(['subscribe', 'p-2']);
return Promise.resolve(['ok', null, { usage: 0 }]);
}
mk.setDeliverToWorker(deliver);
function shutdown() {}
const manager = mk.getManager(shutdown);
return { manager, transcript };
}

test('gc syscalls are not included in transcript', async t => {
const { manager, transcript } = setup();
await manager.deliver(m1);

t.is(transcript.length, 1);
t.deepEqual(transcript[0], {
d: m1,
syscalls: [
{ d: ['subscribe', 'p-1'], response: null },
{ d: ['subscribe', 'p-2'], response: null },
],
});
});

test('gc syscalls are ignored during replay', async t => {
const storedTranscript = [
{
d: m1,
syscalls: [
{ d: ['subscribe', 'p-1'], response: null },
{ d: ['subscribe', 'p-2'], response: null },
],
},
];
const { manager } = setup(storedTranscript);
await manager.replayTranscript();
// success is that replayTranscript didn't throw anachrophobia error
t.pass();
});

0 comments on commit d18ddf5

Please sign in to comment.