Skip to content

Commit

Permalink
chore: refactor kernelKeeper to expose helper functions for upgrade
Browse files Browse the repository at this point in the history
Most of the kernelKeeper API methods are defined inside
makeKernelKeeper, so they can close over some helper functions, which
makes it difficult to use those methods from outside a
kernelKeeper (e.g. from upgradeSwingset). This commit rearranges
things to export two helper functions:

* incrementReferenceCount()
* addToQueue()

The upcoming #9039 remediation work will need access to these.
  • Loading branch information
warner committed Oct 11, 2024
1 parent a38cdd7 commit dbc4bce
Showing 1 changed file with 78 additions and 60 deletions.
138 changes: 78 additions & 60 deletions packages/SwingSet/src/kernel/state/kernelKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,77 @@ export const getAllDynamicVats = getRequired => {
return JSON.parse(getRequired('vat.dynamicIDs'));
};

const getObjectReferenceCount = (kvStore, kref) => {
const data = kvStore.get(`${kref}.refCount`);
if (!data) {
return { reachable: 0, recognizable: 0 };
}
const [reachable, recognizable] = commaSplit(data).map(Number);
reachable <= recognizable ||
Fail`refmismatch(get) ${kref} ${reachable},${recognizable}`;
return { reachable, recognizable };
};

const setObjectReferenceCount = (kvStore, kref, counts) => {
const { reachable, recognizable } = counts;
assert.typeof(reachable, 'number');
assert.typeof(recognizable, 'number');
(reachable >= 0 && recognizable >= 0) ||
Fail`${kref} underflow ${reachable},${recognizable}`;
reachable <= recognizable ||
Fail`refmismatch(set) ${kref} ${reachable},${recognizable}`;
kvStore.set(`${kref}.refCount`, `${reachable},${recognizable}`);
};

/**
* Increment the reference count associated with some kernel object.
*
* We track references to promises and objects, but not devices. Promises
* have only a "reachable" count, whereas objects track both "reachable"
* and "recognizable" counts.
*
* @param { string => string} getRequired
* @param { import('@agoric/swing-store').SwingStoreKernelStorage.kvStore } kvStore
* @param {string} kref The kernel slot whose refcount is to be incremented.
* @param {string?} tag Debugging note with rough source of the reference.
* @param {{ isExport?: boolean, onlyRecognizable?: boolean }} options
* 'isExport' means the reference comes from a clist export, which counts
* for promises but not objects. 'onlyRecognizable' means the reference
* provides only recognition, not reachability
*/
export const incrementReferenceCount = (
getRequired,
kvStore,
kref,
tag,
options = {},
) => {
const { isExport = false, onlyRecognizable = false } = options;
kref || Fail`incrementRefCount called with empty kref, tag=${tag}`;
const { type } = parseKernelSlot(kref);
if (type === 'promise') {
const refCount = Nat(BigInt(getRequired(`${kref}.refCount`))) + 1n;
// kdebug(`++ ${kref} ${tag} ${refCount}`);
kvStore.set(`${kref}.refCount`, `${refCount}`);
}
if (type === 'object' && !isExport) {
let { reachable, recognizable } = getObjectReferenceCount(kvStore, kref);
if (!onlyRecognizable) {
reachable += 1;
}
recognizable += 1;
// kdebug(`++ ${kref} ${tag} ${reachable},${recognizable}`);
setObjectReferenceCount(kvStore, kref, { reachable, recognizable });
}
};

export const addToQueue = (queue, item, getRequired, kvStore, incStat) => {
const [head, tail] = JSON.parse(getRequired(`${queue}`));
kvStore.set(`${queue}.${tail}`, JSON.stringify(item));
kvStore.set(`${queue}`, JSON.stringify([head, tail + 1]));
incStat(`${queue}Length`);
};

// we use different starting index values for the various vNN/koNN/kdNN/kpNN
// slots, to reduce confusing overlap when looking at debug messages (e.g.
// seeing both kp1 and ko1, which are completely unrelated despite having the
Expand Down Expand Up @@ -364,12 +435,8 @@ export default function makeKernelKeeper(
kvStore.set(`${queue}`, JSON.stringify([1, 1]));
}

function enqueue(queue, item) {
const [head, tail] = JSON.parse(getRequired(`${queue}`));
kvStore.set(`${queue}.${tail}`, JSON.stringify(item));
kvStore.set(`${queue}`, JSON.stringify([head, tail + 1]));
incStat(`${queue}Length`);
}
const enqueue = (queue, item) =>
addToQueue(queue, item, getRequired, kvStore, incStat);

function dequeue(queue) {
const [head, tail] = JSON.parse(getRequired(`${queue}`));
Expand Down Expand Up @@ -621,26 +688,9 @@ export default function makeKernelKeeper(
return parseReachableAndVatSlot(kvStore.get(kernelKey));
}

function getObjectRefCount(kernelSlot) {
const data = kvStore.get(`${kernelSlot}.refCount`);
if (!data) {
return { reachable: 0, recognizable: 0 };
}
const [reachable, recognizable] = commaSplit(data).map(Number);
reachable <= recognizable ||
Fail`refmismatch(get) ${kernelSlot} ${reachable},${recognizable}`;
return { reachable, recognizable };
}

function setObjectRefCount(kernelSlot, { reachable, recognizable }) {
assert.typeof(reachable, 'number');
assert.typeof(recognizable, 'number');
(reachable >= 0 && recognizable >= 0) ||
Fail`${kernelSlot} underflow ${reachable},${recognizable}`;
reachable <= recognizable ||
Fail`refmismatch(set) ${kernelSlot} ${reachable},${recognizable}`;
kvStore.set(`${kernelSlot}.refCount`, `${reachable},${recognizable}`);
}
const getObjectRefCount = kref => getObjectReferenceCount(kvStore, kref);
const setObjectRefCount = (kref, counts) =>
setObjectReferenceCount(kvStore, kref, counts);

/**
* Iterate over non-durable objects exported by a vat.
Expand Down Expand Up @@ -1426,40 +1476,8 @@ export default function makeKernelKeeper(
maybeFreeKrefs.add(kref);
}

/**
* Increment the reference count associated with some kernel object.
*
* We track references to promises and objects, but not devices. Promises
* have only a "reachable" count, whereas objects track both "reachable"
* and "recognizable" counts.
*
* @param {unknown} kernelSlot The kernel slot whose refcount is to be incremented.
* @param {string?} tag Debugging note with rough source of the reference.
* @param {{ isExport?: boolean, onlyRecognizable?: boolean }} options
* 'isExport' means the reference comes from a clist export, which counts
* for promises but not objects. 'onlyRecognizable' means the reference
* provides only recognition, not reachability
*/
function incrementRefCount(kernelSlot, tag, options = {}) {
const { isExport = false, onlyRecognizable = false } = options;
kernelSlot ||
Fail`incrementRefCount called with empty kernelSlot, tag=${tag}`;
const { type } = parseKernelSlot(kernelSlot);
if (type === 'promise') {
const refCount = Nat(BigInt(getRequired(`${kernelSlot}.refCount`))) + 1n;
// kdebug(`++ ${kernelSlot} ${tag} ${refCount}`);
kvStore.set(`${kernelSlot}.refCount`, `${refCount}`);
}
if (type === 'object' && !isExport) {
let { reachable, recognizable } = getObjectRefCount(kernelSlot);
if (!onlyRecognizable) {
reachable += 1;
}
recognizable += 1;
// kdebug(`++ ${kernelSlot} ${tag} ${reachable},${recognizable}`);
setObjectRefCount(kernelSlot, { reachable, recognizable });
}
}
const incrementRefCount = (kref, tag, options = {}) =>
incrementReferenceCount(getRequired, kvStore, kref, tag, options);

/**
* Decrement the reference count associated with some kernel object.
Expand Down

0 comments on commit dbc4bce

Please sign in to comment.