Skip to content

Commit

Permalink
feat: retire C-list entries for resolved promises
Browse files Browse the repository at this point in the history
  • Loading branch information
FUDCo committed Dec 22, 2020
1 parent 604e3ef commit f6c17af
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 258 deletions.
77 changes: 63 additions & 14 deletions packages/SwingSet/src/kernel/cleanup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { kdebug } from './kdebug';
// import { kdebug } from './kdebug';
import { parseKernelSlot } from './parseKernelSlots';

// XXX temporary flags to control features during development
Expand All @@ -18,45 +18,94 @@ export function deleteCListEntryIfEasy(

function scanKernelPromise(scanKPID, scanKernelData) {
visited.add(scanKPID);
kdebug(`@@@ scan ${scanKPID}`);
// kdebug(`@@@ scan ${scanKPID} ${JSON.stringify(scanKernelData)}`);
if (scanKernelData) {
for (const slot of scanKernelData.slots) {
const { type } = parseKernelSlot(slot);
if (type === 'promise') {
sawPromise = slot;
if (visited.has(slot)) {
kdebug(`@@@ ${slot} previously visited`);
// kdebug(`@@@ ${slot} previously visited`);
return true;
} else {
const { data, state } = kernelKeeper.getKernelPromise(slot);
const { data } = kernelKeeper.getKernelPromise(slot);
// const { data, state } = kernelKeeper.getKernelPromise(slot);
if (data) {
if (scanKernelPromise(slot, data)) {
kdebug(`@@@ scan ${slot} detects circularity`);
// kdebug(`@@@ scan ${slot} detects circularity`);
return true;
}
} else {
kdebug(`@@@ scan ${slot} state = ${state}`);
// kdebug(`@@@ scan ${slot} state = ${state}`);
}
}
}
}
}
kdebug(`@@@ scan ${scanKPID} detects no circularity`);
// kdebug(`@@@ scan ${scanKPID} detects no circularity`);
return false;
}

kdebug(`@@ checking ${vatID} ${kpid} for circularity`);
// kdebug(`@@ checking ${vatID} ${kpid} for circularity`);
if (scanKernelPromise(kpid, kernelData)) {
kdebug(
`Unable to delete ${vatID} clist entry ${kpid}<=>${vpid} because it is indirectly self-referential`,
);
// kdebug(
// `Unable to delete ${vatID} clist entry ${kpid}<=>${vpid} because it is indirectly self-referential`,
// );
return;
} else if (sawPromise) {
kdebug(
`Unable to delete ${vatID} clist entry ${kpid}<=>${vpid} because there was a contained promise ${sawPromise}`,
);
// kdebug(
// `Unable to delete ${vatID} clist entry ${kpid}<=>${vpid} because there was a contained promise ${sawPromise}`,
// );
return;
}
}
vatKeeper.deleteCListEntry(kpid, vpid);
}

export function getKpidsToRetire(
vatID,
vatKeeper,
kernelKeeper,
rootKPID,
rootKernelData,
) {
const seen = new Set();
function scanKernelPromise(kpid, kernelData) {
// kdebug(`### scanning ${kpid} ${JSON.stringify(kernelData)}`);
if (vatKeeper.hasCListEntry(kpid)) {
// kdebug(`## adding ${kpid} to scan results`);
seen.add(kpid);
if (kernelData) {
for (const slot of kernelData.slots) {
const { type } = parseKernelSlot(slot);
// kdebug(`## examine ${kpid} slot ${slot}`);
if (type === 'promise') {
if (!seen.has(slot)) {
const kp = kernelKeeper.getKernelPromise(slot);
const { data, state } = kp;
// kdebug(`## state of ${slot} is: ${JSON.stringify(kp)}`);
if (state !== 'unresolved') {
if (data) {
scanKernelPromise(slot, data);
}
} else {
// kdebug(`## ${slot} is still unresolved`);
}
} else {
// kdebug(`## ${slot} previously seen`);
}
} else {
// kdebug(`## ${slot} is not a promise`);
}
}
} else {
// kdebug(`## ${kpid} has no data`);
}
} else {
// kdebug(`## ${kpid} has no c-list entry for ${vatID}`);
}
}

scanKernelPromise(rootKPID, rootKernelData);
return Array.from(seen);
}
11 changes: 10 additions & 1 deletion packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,16 @@ export default function buildKernel(
kernelKeeper.incStat(statNameForNotify(p.state));
const kd = harden(['notify', kpid, p]);
const vd = vat.translators.kernelDeliveryToVatDelivery(kd);
await deliverAndLogToVat(vatID, kd, vd);
if (vd) {
await deliverAndLogToVat(vatID, kd, vd);

const resolutions = vd[1];
const vatKeeper = kernelKeeper.getVatKeeper(vatID);
for (const vpid of Object.keys(resolutions)) {
const kpidToDelete = vatKeeper.mapVatSlotToKernelSlot(vpid);
vatKeeper.deleteCListEntry(kpidToDelete, vpid);
}
}
}
}

Expand Down
41 changes: 22 additions & 19 deletions packages/SwingSet/src/kernel/liveSlots.js
Original file line number Diff line number Diff line change
Expand Up @@ -509,30 +509,33 @@ function build(syscall, forVatID, cacheSize, vatPowers, vatParameters) {
};
}

function notify(primaryPromiseID, resolutions) {
function notifyOnePromise(promiseID, rejected, data) {
insistCapData(data);
lsdebug(
`ls.dispatch.notify(${promiseID}, ${rejected}, ${data.body}, [${data.slots}])`,
);
insistVatType('promise', promiseID);
// TODO: insist that we do not have decider authority for promiseID
if (!importedPromisesByPromiseID.has(promiseID)) {
throw new Error(`unknown promiseID '${promiseID}'`);
}
const pRec = importedPromisesByPromiseID.get(promiseID);
const val = m.unserialize(data);
if (rejected) {
pRec.reject(val);
} else {
pRec.resolve(val);
}
}

function notify(resolutions) {
assert(didRoot);
for (const vpid of Object.keys(resolutions)) {
const vp = resolutions[vpid];
insistCapData(vp.data);
lsdebug(
`ls.dispatch.notify(${primaryPromiseID} ${vpid}, ${vp.rejected}, ${vp.data.body}, [${vp.data.slots}])`,
);
insistVatType('promise', vpid);
// TODO: insist that we do not have decider authority for promiseID
if (!importedPromisesByPromiseID.has(vpid)) {
throw new Error(`unknown promiseID '${vpid}'`);
}
const pRec = importedPromisesByPromiseID.get(vpid);
const val = m.unserialize(vp.data);
if (vp.rejected) {
pRec.reject(val);
} else {
pRec.resolve(val);
}
notifyOnePromise(vpid, vp.rejected, vp.data);
}
for (const vpid of Object.keys(resolutions)) {
const vp = resolutions[vpid];
retirePromiseIDIfEasy(vpid, vp.data);
retirePromiseID(vpid);
}
}

Expand Down
12 changes: 12 additions & 0 deletions packages/SwingSet/src/kernel/state/vatKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,17 @@ export function makeVatKeeper(
return storage.get(kernelKey);
}

/**
* Test if there's a c-list entry for some slot.
*
* @param {string} slot The slot of interest
*
* @returns {boolean} true iff this vat has a c-list entry mapping for `slot`.
*/
function hasCListEntry(slot) {
return storage.has(`${vatID}.c.${slot}`);
}

/**
* Remove an entry from the vat's c-list.
*
Expand Down Expand Up @@ -271,6 +282,7 @@ export function makeVatKeeper(
getSourceAndOptions,
mapVatSlotToKernelSlot,
mapKernelSlotToVatSlot,
hasCListEntry,
deleteCListEntry,
getTranscript,
addToTranscript,
Expand Down
6 changes: 3 additions & 3 deletions packages/SwingSet/src/kernel/vatManager/deliver.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ export function makeDeliver(tools, dispatch) {
);
}

async function deliverOneNotification(primaryVpid, resolutions) {
const errmsg = `vat[${vatID}].promise[${primaryVpid}] failed`;
return doProcess(['notify', primaryVpid, resolutions], errmsg);
async function deliverOneNotification(resolutions) {
const errmsg = `vat[${vatID}].notify failed`;
return doProcess(['notify', resolutions], errmsg);
}

// vatDeliverObject is:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ function doMessage(targetSlot, msg) {
);
}

function doNotify(primaryVpid, resolutions) {
const errmsg = `vat.promise[${primaryVpid}] failed`;
return doProcess(['notify', primaryVpid, resolutions], errmsg);
function doNotify(resolutions) {
const errmsg = `vat.notify failed`;
return doProcess(['notify', resolutions], errmsg);
}

parentPort.on('message', ([type, ...margs]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ function doMessage(targetSlot, msg) {
);
}

function doNotify(primaryVpid, resolutions) {
const errmsg = `vat.promise[${primaryVpid}] failed`;
return doProcess(['notify', primaryVpid, resolutions], errmsg);
function doNotify(resolutions) {
const errmsg = `vat.notify failed`;
return doProcess(['notify', resolutions], errmsg);
}

const toParent = arrayEncoderStream();
Expand Down
29 changes: 22 additions & 7 deletions packages/SwingSet/src/kernel/vatTranslator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { insistKernelType, parseKernelSlot } from './parseKernelSlots';
import { insistVatType, parseVatSlot } from '../parseVatSlots';
import { insistCapData } from '../capdata';
import { kdebug, legibilizeMessageArgs, legibilizeValue } from './kdebug';
import { deleteCListEntryIfEasy } from './cleanup';
import { deleteCListEntryIfEasy, getKpidsToRetire } from './cleanup';

/*
* Return a function that converts KernelDelivery objects into VatDelivery
Expand Down Expand Up @@ -79,12 +79,27 @@ function makeTranslateKernelDeliveryToVatDelivery(vatID, kernelKeeper) {

function translateNotify(kpid, kp) {
assert(kp.state !== 'unresolved', details`spurious notification ${kpid}`);
const vpid = mapKernelSlotToVatSlot(kpid);
const resolutions = {};
resolutions[vpid] = translatePromiseDescriptor(kp);
deleteCListEntryIfEasy(vatID, vatKeeper, kernelKeeper, kpid, vpid, kp.data);
const vatDelivery = harden(['notify', vpid, resolutions]);
return vatDelivery;
kdebug(`notify ${kpid} ${JSON.stringify(kp)}`);
const targets = getKpidsToRetire(
vatID,
vatKeeper,
kernelKeeper,
kpid,
kp.data,
);
if (targets.length > 0) {
for (const toResolve of targets) {
const p = kernelKeeper.getKernelPromise(toResolve);
const vpid = mapKernelSlotToVatSlot(toResolve);
resolutions[vpid] = translatePromiseDescriptor(p);
}
const vatDelivery = harden(['notify', resolutions]);
return vatDelivery;
} else {
kdebug(`skipping notify of ${kpid} because it's already been done`);
return null;
}
}

function kernelDeliveryToVatDelivery(kd) {
Expand All @@ -97,7 +112,7 @@ function makeTranslateKernelDeliveryToVatDelivery(vatID, kernelKeeper) {
default:
throw Error(`unknown kernelDelivery.type ${type}`);
}
// returns ['message', target, msg] or ['notify', vpid, vp]
// returns ['message', target, msg] or ['notify', resolutions] or null
}

return kernelDeliveryToVatDelivery;
Expand Down
Loading

0 comments on commit f6c17af

Please sign in to comment.