Skip to content

Commit

Permalink
feat: refactor object pinning
Browse files Browse the repository at this point in the history
  • Loading branch information
FUDCo committed Jul 13, 2021
1 parent 7edfa24 commit 9941a08
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 19 deletions.
13 changes: 8 additions & 5 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { waitUntilQuiescent } from './waitUntilQuiescent.js';
import { makeGcAndFinalize } from './gc-and-finalize.js';
import { insistStorageAPI } from './storageAPI.js';
import { insistCapData } from './capdata.js';
import { parseVatSlot } from './parseVatSlots.js';
import { provideHostStorage } from './hostStorage.js';
import {
swingsetIsInitialized,
Expand Down Expand Up @@ -361,6 +360,12 @@ export async function makeSwingsetController(
return defensiveCopy(kernel.getStatus());
},

pinVatRoot(vatName) {
const vatID = kernel.vatNameToID(vatName);
const kref = kernel.getRootObject(vatID);
kernel.pinObject(kref);
},

// these are for tests

kpStatus(kpid) {
Expand All @@ -379,17 +384,15 @@ export async function makeSwingsetController(

/**
* @param {string} vatName
* @param {string} exportID
* @param {string} method
* @param {CapData<unknown>} args
* @param {ResolutionPolicy} resultPolicy
*/
queueToVatExport(vatName, exportID, method, args, resultPolicy = 'ignore') {
queueToVatRoot(vatName, method, args, resultPolicy = 'ignore') {
const vatID = kernel.vatNameToID(vatName);
parseVatSlot(exportID);
assert.typeof(method, 'string');
insistCapData(args);
const kref = kernel.addExport(vatID, exportID);
const kref = kernel.getRootObject(vatID);
const kpid = kernel.queueToKref(kref, method, args, resultPolicy);
if (kpid) {
kernel.kpRegisterInterest(kpid);
Expand Down
14 changes: 6 additions & 8 deletions packages/SwingSet/src/kernel/initializeKernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { makeVatSlot } from '../parseVatSlots';
import { insistStorageAPI } from '../storageAPI';
import { wrapStorage } from './state/storageWrapper';
import makeKernelKeeper from './state/kernelKeeper';
import { doAddExport, doQueueToKref } from './kernel';
import { exportRootObject, doQueueToKref } from './kernel';

function makeVatRootObjectSlot() {
return makeVatSlot('object', true, 0);
Expand Down Expand Up @@ -82,11 +82,10 @@ export function initializeKernel(config, hostStorage, verbose = false) {
vatKeeper.setSourceAndOptions({ bundle, bundleName }, creationOptions);
if (name === 'vatAdmin') {
// Create a kref for the vatAdmin root, so the kernel can tell it
// about creation/termination of dynamic vats. doAddExport will
// increment the refcount so it won't go away, despite being
// unreferenced by any other vat.
const rootVref = makeVatRootObjectSlot();
const kref = doAddExport(kernelKeeper, vatID, rootVref);
// about creation/termination of dynamic vats.
const kref = exportRootObject(kernelKeeper, vatID);
// Pin, to prevent it being GC'd when only the kvStore points to it
kernelKeeper.pinObject(kref);
kvStore.set('vatAdminRootKref', kref);
gotVatAdminRootKref = true;
}
Expand Down Expand Up @@ -193,8 +192,7 @@ export function initializeKernel(config, hostStorage, verbose = false) {
});
const args = harden([vatObj0s, deviceObj0s]);
// doQueueToKref() takes kernel-refs (ko+NN, kd+NN) in s.slots
const rootVref = makeVatRootObjectSlot();
const rootKref = doAddExport(kernelKeeper, bootstrapVatID, rootVref);
const rootKref = exportRootObject(kernelKeeper, bootstrapVatID);
const resultKpid = doQueueToKref(
kernelKeeper,
rootKref,
Expand Down
29 changes: 25 additions & 4 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { makeSlogger, makeDummySlogger } from './slogger.js';
import { getKpidsToRetire } from './cleanup.js';
import { processNextGCAction } from './gc-actions.js';

import { makeVatRootObjectSlot, makeVatLoader } from './loadVat.js';
import { makeVatLoader } from './loadVat.js';
import { makeDeviceTranslators } from './deviceTranslator.js';
import { notifyTermination } from './notifyTermination.js';

Expand All @@ -43,6 +43,20 @@ function makeError(message, name = 'Error') {

const VAT_TERMINATION_ERROR = makeError('vat terminated');

/**
* Provide the kref of a vat's root object, as if it had been exported.
*
* @param {*} kernelKeeper Kernel keeper managing persistent kernel state.
* @param {string} vatID Vat ID of the vat whose root kref is sought.
*
* @returns {string} the kref of the root object of the given vat.
*/
export function exportRootObject(kernelKeeper, vatID) {
insistVatID(vatID);
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
return vatKeeper.mapVatSlotToKernelSlot('o+0');
}

/*
* Pretend that a vat just exported an object, and increment the refcount on
* the resulting kref so nothing tries to delete it for being unreferenced.
Expand All @@ -60,8 +74,7 @@ export function doAddExport(kernelKeeper, fromVatID, vref) {

/**
* Enqueue a message to some kernel object, as if the message had been sent
* by some other vat. This requires a kref as a target, so use e.g.
* doAddExport to acquire one and increment its refcount to keep it alive.
* by some other vat. This requires a kref as a target.
*
* @param {*} kernelKeeper Kernel keeper managing persistent kernel state
* @param {string} kref Target of the message
Expand Down Expand Up @@ -236,6 +249,10 @@ export default function buildKernel(
return vatKeeper.mapKernelSlotToVatSlot(kernelSlot);
}

function pinObject(kref) {
kernelKeeper.pinObject(kref);
}

function addExport(fromVatID, vatSlot) {
if (!started) {
throw new Error('must do kernel.start() before addExport()');
Expand Down Expand Up @@ -576,7 +593,7 @@ export default function buildKernel(
function makeSuccessResponse() {
// build success message, giving admin vat access to the new vat's root
// object
const kernelRootObjSlot = addExport(vatID, makeVatRootObjectSlot());
const kernelRootObjSlot = exportRootObject(kernelKeeper, vatID);
return {
body: JSON.stringify([
vatID,
Expand Down Expand Up @@ -1068,6 +1085,10 @@ export default function buildKernel(

addImport,
addExport,
getRootObject(vatID) {
return exportRootObject(kernelKeeper, vatID);
},
pinObject,
vatNameToID,
deviceNameToID,
queueToKref,
Expand Down
12 changes: 12 additions & 0 deletions packages/SwingSet/src/kernel/state/kernelKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const enableKernelGC = true;

// runQueue = JSON(runQueue) // usually empty on disk
// gcActions = JSON(gcActions) // usually empty on disk
// pinnedObjects = ko$NN[,ko$NN..]

// ko.nextID = $NN
// ko$NN.owner = $vatID
Expand Down Expand Up @@ -1055,6 +1056,16 @@ export default function makeKernelKeeper(
return importers;
}

function pinObject(kref) {
const pinList = kvStore.get('pinnedObjects') || '';
const pinned = new Set(commaSplit(pinList));
if (!pinned.has(kref)) {
incrementRefCount(kref, 'pin');
pinned.add(kref);
kvStore.set('pinnedObjects', [...pinned].sort().join(','));
}
}

// used for debugging, and tests. This returns a JSON-serializable object.
// It includes references to live (mutable) kernel state, so don't mutate
// the pieces, and be sure to serialize/deserialize before passing it
Expand Down Expand Up @@ -1173,6 +1184,7 @@ export default function makeKernelKeeper(
kernelObjectExists,
getImporters,
deleteKernelObject,
pinObject,

addKernelPromise,
addKernelPromiseForVat,
Expand Down
9 changes: 7 additions & 2 deletions packages/swingset-runner/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ export async function main() {
config,
bootstrapArgv,
hostStorage,
{ verbose },
runtimeOptions,
);
swingStore.commit();
Expand All @@ -424,6 +425,11 @@ export async function main() {
deviceEndowments,
runtimeOptions,
);
if (benchmarkRounds > 0) {
// Pin the vat root that will run benchmark rounds so it'll still be there
// when it comes time to run them.
controller.pinVatRoot(launchIndirectly ? 'launcher' : 'bootstrap');
}

let blockNumber = 0;
let statLogger = null;
Expand Down Expand Up @@ -560,9 +566,8 @@ export async function main() {
let totalSteps = 0;
let totalDeltaT = 0n;
for (let i = 0; i < rounds; i += 1) {
const roundResult = controller.queueToVatExport(
const roundResult = controller.queueToVatRoot(
launchIndirectly ? 'launcher' : 'bootstrap',
'o+0',
'runBenchmarkRound',
args,
'ignore',
Expand Down

0 comments on commit 9941a08

Please sign in to comment.