Skip to content

Commit

Permalink
feat: Add incarnation number to the transcript store records
Browse files Browse the repository at this point in the history
Closes #7482
  • Loading branch information
FUDCo committed Apr 25, 2023
1 parent cf84dc7 commit 2879e51
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 65 deletions.
5 changes: 2 additions & 3 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ export default function buildKernel(
// cleanup done, now we reset the worker to a clean state with no
// transcript or snapshot and prime everything for the next incarnation.

await vatWarehouse.resetWorker(vatID);
const newIncarnation = await vatWarehouse.resetWorker(vatID);
// update source and bundleIDs, store back to vat metadata
const source = { bundleID };
const origOptions = vatKeeper.getOptions();
Expand All @@ -927,7 +927,6 @@ export default function buildKernel(
});
const vatOptions = harden({ ...origOptions, workerOptions });
vatKeeper.setSourceAndOptions(source, vatOptions);
const incarnationNumber = vatKeeper.incIncarnationNumber();
// TODO: decref the bundleID once setSourceAndOptions increfs it

// pause, take a deep breath, appreciate this moment of silence
Expand Down Expand Up @@ -960,7 +959,7 @@ export default function buildKernel(
return results;
}

const args = [upgradeID, true, undefined, incarnationNumber];
const args = [upgradeID, true, undefined, newIncarnation];
/** @type {RawMethargs} */
const vatAdminMethargs = ['vatUpgradeCallback', args];
const results = harden({
Expand Down
17 changes: 5 additions & 12 deletions packages/SwingSet/src/kernel/state/vatKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export function initializeVatState(kvStore, transcriptStore, vatID) {
kvStore.set(`${vatID}.p.nextID`, `${FIRST_PROMISE_ID}`);
kvStore.set(`${vatID}.d.nextID`, `${FIRST_DEVICE_ID}`);
kvStore.set(`${vatID}.nextDeliveryNum`, `0`);
kvStore.set(`${vatID}.incarnationNumber`, `1`);
transcriptStore.initTranscript(vatID);
}

Expand Down Expand Up @@ -171,13 +170,8 @@ export function makeVatKeeper(
}

function getIncarnationNumber() {
return Number(getRequired(`${vatID}.incarnationNumber`));
}

function incIncarnationNumber() {
const newIncarnationNumber = getIncarnationNumber() + 1;
kvStore.set(`${vatID}.incarnationNumber`, `${newIncarnationNumber}`);
return newIncarnationNumber;
const { incarnation } = transcriptStore.getCurrentSpanBounds(vatID);
return incarnation;
}

function getReachableFlag(kernelSlot) {
Expand Down Expand Up @@ -549,11 +543,11 @@ export function makeVatKeeper(
transcriptStore.deleteVatTranscripts(vatID);
}

function dropSnapshotAndResetTranscript() {
function beginNewIncarnation() {
if (snapStore) {
snapStore.stopUsingLastSnapshot(vatID);
}
transcriptStore.rolloverSpan(vatID);
return transcriptStore.rolloverIncarnation(vatID);
}

function vatStats() {
Expand Down Expand Up @@ -607,7 +601,6 @@ export function makeVatKeeper(
updateReapInterval,
nextDeliveryNum,
getIncarnationNumber,
incIncarnationNumber,
importsKernelSlot,
mapVatSlotToKernelSlot,
mapKernelSlotToVatSlot,
Expand All @@ -626,6 +619,6 @@ export function makeVatKeeper(
saveSnapshot,
getSnapshotInfo,
deleteSnapshotsAndTranscript,
dropSnapshotAndResetTranscript,
beginNewIncarnation,
});
}
4 changes: 2 additions & 2 deletions packages/SwingSet/src/kernel/vat-warehouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,12 @@ export function makeVatWarehouse({
* with new source code)
*
* @param {string} vatID
* @returns {Promise<void>}
* @returns {Promise<number>} the incarnation number of the new incarnation
*/
async function resetWorker(vatID) {
await evict(vatID);
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
vatKeeper.dropSnapshotAndResetTranscript();
return vatKeeper.beginNewIncarnation();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ async function unlimitedMeterTest(t, doVatAdminRestarts) {
// if we restarted the vatAdmin vat, that will have broken the done promise
// for the vat that's going to outrun the compute meter
kpidRejected(t, c, doneKPID, {
incarnationNumber: 2,
incarnationNumber: 1,
name: 'vatUpgraded',
upgradeMessage: 'vat vatAdmin upgraded',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async function testPromiseWatcher(t) {
const [v2status /* , v2capdata */] = await run('upgradeV2', []);
t.is(v2status, 'fulfilled');
const doString =
'{"incarnationNumber":1,"name":"vatUpgraded","upgradeMessage":"test upgrade"}';
'{"incarnationNumber":0,"name":"vatUpgraded","upgradeMessage":"test upgrade"}';
t.deepEqual(c.dump().log, [
...beforeReference,
`lp3-pw rejected ${doString} version v2 via watcher []`,
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/test/test-promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ test('local promises are rejected by vat upgrade', async t => {
reason: {
name: 'vatUpgraded',
upgradeMessage: 'vat upgraded',
incarnationNumber: 1,
incarnationNumber: 0,
},
},
});
Expand Down
4 changes: 2 additions & 2 deletions packages/SwingSet/test/upgrade/test-upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ const testUpgrade = async (t, defaultManagerType, options = {}) => {
data: ['some', 'data'],
remoerr: Error('vat terminated'),
});
t.deepEqual(v2result.upgradeResult, { incarnationNumber: 2 });
t.deepEqual(v2result.upgradeResult, { incarnationNumber: 1 });
const v2MarkerKref = verifyPresence(v2result.marker, 'marker');
t.deepEqual(v2MarkerKref, v1MarkerKref);

Expand All @@ -479,7 +479,7 @@ const testUpgrade = async (t, defaultManagerType, options = {}) => {
const vatUpgradedError = {
name: 'vatUpgraded',
upgradeMessage: 'test upgrade',
incarnationNumber: 1,
incarnationNumber: 0,
};
t.deepEqual(kunser(c.kpResolution(v1p1Kref)), vatUpgradedError);
t.is(c.kpStatus(v1p2Kref), 'rejected');
Expand Down
1 change: 1 addition & 0 deletions packages/swing-store/src/swingStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ function makeSwingStore(dirPath, forceReset, options = {}) {
const transcriptStorePublic = {
initTranscript: transcriptStore.initTranscript,
rolloverSpan: transcriptStore.rolloverSpan,
rolloverIncarnation: transcriptStore.rolloverIncarnation,
getCurrentSpanBounds: transcriptStore.getCurrentSpanBounds,
addItem: transcriptStore.addItem,
readSpan: transcriptStore.readSpan,
Expand Down
103 changes: 71 additions & 32 deletions packages/swing-store/src/transcriptStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { createSHA256 } from './hasher.js';
*
* @typedef {{
* initTranscript: (vatID: string) => void,
* rolloverSpan: (vatID: string) => void,
* getCurrentSpanBounds: (vatID: string) => { startPos: number, endPos: number, hash: string },
* rolloverSpan: (vatID: string) => number,
* rolloverIncarnation: (vatID: string) => number,
* getCurrentSpanBounds: (vatID: string) => { startPos: number, endPos: number, hash: string, incarnation: number },
* deleteVatTranscripts: (vatID: string) => void,
* addItem: (vatID: string, item: string) => void,
* readSpan: (vatID: string, startPos?: number) => IterableIterator<string>,
Expand Down Expand Up @@ -64,6 +65,7 @@ export function makeTranscriptStore(
vatID TEXT,
position INTEGER,
item TEXT,
incarnation INTEGER,
PRIMARY KEY (vatID, position)
)
`);
Expand All @@ -89,6 +91,7 @@ export function makeTranscriptStore(
endPos INTEGER, -- exclusive
hash TEXT, -- cumulative hash of this item and previous cumulative hash
isCurrent INTEGER CHECK (isCurrent = 1),
incarnation INTEGER,
PRIMARY KEY (vatID, startPos),
UNIQUE (vatID, isCurrent)
)
Expand All @@ -106,7 +109,7 @@ export function makeTranscriptStore(
`);

const sqlDumpSpansQuery = db.prepare(`
SELECT vatID, startPos, endPos, isCurrent
SELECT vatID, startPos, endPos, isCurrent, incarnation
FROM transcriptSpans
ORDER BY vatID, startPos
`);
Expand Down Expand Up @@ -160,9 +163,9 @@ export function makeTranscriptStore(
}
}

function spanRec(vatID, startPos, endPos, hash, isCurrent) {
function spanRec(vatID, startPos, endPos, hash, isCurrent, incarnation) {
isCurrent = isCurrent ? 1 : 0;
return { vatID, startPos, endPos, hash, isCurrent };
return { vatID, startPos, endPos, hash, isCurrent, incarnation };
}

/**
Expand All @@ -188,8 +191,8 @@ export function makeTranscriptStore(

const sqlWriteSpan = db.prepare(`
INSERT INTO transcriptSpans
(vatID, startPos, endPos, hash, isCurrent)
VALUES (?, ?, ?, ?, ?)
(vatID, startPos, endPos, hash, isCurrent, incarnation)
VALUES (?, ?, ?, ?, ?, ?)
`);

/**
Expand All @@ -199,13 +202,13 @@ export function makeTranscriptStore(
*/
function initTranscript(vatID) {
ensureTxn();
sqlWriteSpan.run(vatID, 0, 0, initialHash, 1);
const newRec = spanRec(vatID, 0, 0, initialHash, 1);
sqlWriteSpan.run(vatID, 0, 0, initialHash, 1, 0);
const newRec = spanRec(vatID, 0, 0, initialHash, 1, 0);
noteExport(spanMetadataKey(newRec), JSON.stringify(newRec));
}

const sqlGetCurrentSpanBounds = db.prepare(`
SELECT startPos, endPos, hash
SELECT startPos, endPos, hash, incarnation
FROM transcriptSpans
WHERE vatID = ? AND isCurrent = 1
`);
Expand All @@ -215,7 +218,7 @@ export function makeTranscriptStore(
*
* @param {string} vatID The vat in question
*
* @returns {{startPos: number, endPos: number, hash: string}}
* @returns {{startPos: number, endPos: number, hash: string, incarnation: number}}
*/
function getCurrentSpanBounds(vatID) {
const bounds = sqlGetCurrentSpanBounds.get(vatID);
Expand All @@ -234,24 +237,51 @@ export function makeTranscriptStore(
WHERE vatID = ? AND position < ?
`);

/**
* End the current transcript span for a vat and start a new one.
*
* @param {string} vatID The vat whose transcript is to rollover to a new
* span.
*/
function rolloverSpan(vatID) {
function doSpanRollover(vatID, isNewIncarnation) {
ensureTxn();
const { hash, startPos, endPos } = getCurrentSpanBounds(vatID);
const rec = spanRec(vatID, startPos, endPos, hash, 0);
const { hash, startPos, endPos, incarnation } = getCurrentSpanBounds(vatID);
const rec = spanRec(vatID, startPos, endPos, hash, 0, incarnation);
noteExport(spanMetadataKey(rec), JSON.stringify(rec));
sqlEndCurrentSpan.run(vatID);
sqlWriteSpan.run(vatID, endPos, endPos, initialHash, 1);
const newRec = spanRec(vatID, endPos, endPos, initialHash, 1);
const incarnationToUse = isNewIncarnation ? incarnation + 1 : incarnation;
sqlWriteSpan.run(vatID, endPos, endPos, initialHash, 1, incarnationToUse);
const newRec = spanRec(
vatID,
endPos,
endPos,
initialHash,
1,
incarnationToUse,
);
noteExport(spanMetadataKey(newRec), JSON.stringify(newRec));
if (!keepTranscripts) {
sqlDeleteOldItems.run(vatID, endPos);
}
return incarnationToUse;
}

/**
* End the current transcript span for a vat and start a new one in a new incarnation.
*
* @param {string} vatID The vat whose transcript is to rollover to a new
* span.
*
* @returns {number} the new incarnation number
*/
function rolloverIncarnation(vatID) {
return doSpanRollover(vatID, true);
}

/**
* End the current transcript span for a vat and start a new one.
*
* @param {string} vatID The vat whose transcript is to rollover to a new
* span.
*
* @returns {number} the incarnation number
*/
function rolloverSpan(vatID) {
return doSpanRollover(vatID, false);
}

const sqlDeleteVatSpans = db.prepare(`
Expand Down Expand Up @@ -287,13 +317,13 @@ export function makeTranscriptStore(
}

const sqlGetAllSpanMetadata = db.prepare(`
SELECT vatID, startPos, endPos, hash, isCurrent
SELECT vatID, startPos, endPos, hash, isCurrent, incarnation
FROM transcriptSpans
ORDER BY vatID, startPos
`);

const sqlGetCurrentSpanMetadata = db.prepare(`
SELECT vatID, startPos, endPos, hash, isCurrent
SELECT vatID, startPos, endPos, hash, isCurrent, incarnation
FROM transcriptSpans
WHERE isCurrent = 1
ORDER BY vatID, startPos
Expand Down Expand Up @@ -331,8 +361,15 @@ export function makeTranscriptStore(
? sqlGetAllSpanMetadata
: sqlGetCurrentSpanMetadata;
for (const rec of sql.iterate()) {
const { vatID, startPos, endPos, hash, isCurrent } = rec;
const exportRec = spanRec(vatID, startPos, endPos, hash, isCurrent);
const { vatID, startPos, endPos, hash, isCurrent, incarnation } = rec;
const exportRec = spanRec(
vatID,
startPos,
endPos,
hash,
isCurrent,
incarnation,
);
yield [spanMetadataKey(rec), JSON.stringify(exportRec)];
}
}
Expand Down Expand Up @@ -449,8 +486,8 @@ export function makeTranscriptStore(
}

const sqlAddItem = db.prepare(`
INSERT INTO transcriptItems (vatID, item, position)
VALUES (?, ?, ?)
INSERT INTO transcriptItems (vatID, item, position, incarnation)
VALUES (?, ?, ?, ?)
`);

const sqlUpdateSpan = db.prepare(`
Expand All @@ -467,12 +504,12 @@ export function makeTranscriptStore(
*/
const addItem = (vatID, item) => {
ensureTxn();
const { startPos, endPos, hash } = getCurrentSpanBounds(vatID);
sqlAddItem.run(vatID, item, endPos);
const { startPos, endPos, hash, incarnation } = getCurrentSpanBounds(vatID);
sqlAddItem.run(vatID, item, endPos, incarnation);
const newEndPos = endPos + 1;
const newHash = updateSpanHash(hash, item);
sqlUpdateSpan.run(newEndPos, newHash, vatID);
const rec = spanRec(vatID, startPos, newEndPos, newHash, 1);
const rec = spanRec(vatID, startPos, newEndPos, newHash, 1, incarnation);
noteExport(spanMetadataKey(rec), JSON.stringify(rec));
};

Expand Down Expand Up @@ -510,7 +547,7 @@ export function makeTranscriptStore(
let pos = startPos;
for await (const line of lineStream) {
const item = line.trimEnd();
sqlAddItem.run(vatID, item, pos);
sqlAddItem.run(vatID, item, pos, info.incarnation);
hash = updateSpanHash(hash, item);
pos += 1;
}
Expand All @@ -523,12 +560,14 @@ export function makeTranscriptStore(
info.endPos,
info.hash,
info.isCurrent ? 1 : null,
info.incarnation,
);
}

return harden({
initTranscript,
rolloverSpan,
rolloverIncarnation,
getCurrentSpanBounds,
addItem,
readSpan,
Expand Down
Loading

0 comments on commit 2879e51

Please sign in to comment.