From 0077c1337b106dacecdb33a68171eef29aee9c8e Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Wed, 12 Apr 2023 11:37:26 -0700 Subject: [PATCH] VOM: split nextInstanceID into a separate vatstore key Previously, we stored both the static parts of a DurableKindDescriptor (tag, stateShape) and the dynamic part (nextInstanceID) in the same vatStore key (`vom.dkind.${kindID}`). This meant we had to re-write the whole thing each time we make a new instance, which seems like a waste. This change splits the next instance ID out to a separate key: * `vom.dkind.${kindID}.descriptor`: holds the static descriptor * `vom.dkind.${kindID}.nextID`: holds the next instance ID Note that KindIDs are always integers, and we always append the .descriptor/.nextID suffix, so I'm not worried about vatstore key confusion/collision. It also changes the merely-virtual Kind descriptor key to match: `vom.vkind.${kindID}.descriptor`. Note that we don't bother recording a `nextID` for virtual Kinds, since these never outlive an incarnation, so we can hold the nextInstanceID in RAM. We only write out the descriptor for external tooling and debugging, anyways. Internally, `nextInstanceID` is now a BigInt, because we use `Nat()` on the value we get back from the vatstore. This is not exposed to userspace, and vrefs are strings (which incorporate the ID). closes #7364 --- .../virtualObjects/test-representatives.js | 2 +- .../src/virtualObjectManager.js | 86 ++++++++++------ .../test/test-handled-promises.js | 5 +- .../swingset-liveslots/test/test-liveslots.js | 2 +- .../virtual-objects/test-virtualObjectGC.js | 16 +-- .../test-virtualObjectManager.js | 99 ++++++++++--------- 6 files changed, 122 insertions(+), 88 deletions(-) diff --git a/packages/SwingSet/test/virtualObjects/test-representatives.js b/packages/SwingSet/test/virtualObjects/test-representatives.js index b4214c889bb2..0e0fb1432f84 100644 --- a/packages/SwingSet/test/virtualObjects/test-representatives.js +++ b/packages/SwingSet/test/virtualObjects/test-representatives.js @@ -471,7 +471,7 @@ test('virtual object gc', async t => { [`${v}.vs.vom.rc.o+d6/1`]: '1', [`${v}.vs.vom.rc.o+d6/3`]: '1', [`${v}.vs.vom.rc.o+d6/4`]: '1', - [`${v}.vs.vom.vkind.10`]: '{"kindID":"10","tag":"thing"}', + [`${v}.vs.vom.vkind.10.descriptor`]: '{"kindID":"10","tag":"thing"}', [`${v}.vs.watchedPromiseTableID`]: 'o+d6/4', [`${v}.vs.watcherTableID`]: 'o+d6/3', }); diff --git a/packages/swingset-liveslots/src/virtualObjectManager.js b/packages/swingset-liveslots/src/virtualObjectManager.js index 29d4c16c866c..2406731f1758 100644 --- a/packages/swingset-liveslots/src/virtualObjectManager.js +++ b/packages/swingset-liveslots/src/virtualObjectManager.js @@ -4,6 +4,7 @@ import { assert, Fail } from '@agoric/assert'; import { assertPattern, mustMatch } from '@agoric/store'; import { defendPrototype, defendPrototypeKit } from '@agoric/store/tools.js'; import { Far, hasOwnPropertyOf, passStyleOf } from '@endo/marshal'; +import { Nat } from '@endo/nat'; import { parseVatSlot, makeBaseRef } from './parseVatSlots.js'; import { enumerateKeysWithPrefix } from './vatstore-iterators.js'; import { makeCache } from './cache.js'; @@ -544,7 +545,6 @@ export function makeVirtualObjectManager( /** * @typedef {{ * kindID: string, - * nextInstanceID: number, * tag: string, * unfaceted?: boolean, * facets?: string[], @@ -556,10 +556,38 @@ export function makeVirtualObjectManager( * @param {DurableKindDescriptor} durableKindDescriptor */ function saveDurableKindDescriptor(durableKindDescriptor) { - syscall.vatstoreSet( - `vom.dkind.${durableKindDescriptor.kindID}`, - JSON.stringify(durableKindDescriptor), - ); + const { kindID } = durableKindDescriptor; + const key = `vom.dkind.${kindID}.descriptor`; + syscall.vatstoreSet(key, JSON.stringify(durableKindDescriptor)); + } + + /** + * @param {string} kindID + * @returns {DurableKindDescriptor} durableKindDescriptor + */ + function loadDurableKindDescriptor(kindID) { + const key = `vom.dkind.${kindID}.descriptor`; + const raw = syscall.vatstoreGet(key); + raw || Fail`unknown kind ID ${kindID}`; + return JSON.parse(raw); + } + + function saveNextInstanceID(kindID) { + const key = `vom.dkind.${kindID}.nextID`; + syscall.vatstoreSet(key, `${nextInstanceIDs.get(kindID)}`); + } + + function loadNextInstanceID(kindID) { + const key = `vom.dkind.${kindID}.nextID`; + return Nat(Number(syscall.vatstoreGet(key))); + } + + function saveVirtualKindDescriptor(kindID, descriptor) { + // we never read these back: they're stored in the DB for the sake + // of diagnostics, debugging, and potential external DB + // cleanup/upgrade tools + const key = `vom.vkind.${kindID}.descriptor`; + syscall.vatstoreSet(key, JSON.stringify(descriptor)); } /** @@ -966,10 +994,10 @@ export function makeVirtualObjectManager( function reanimateDurableKindID(vobjID) { const kindID = `${parseVatSlot(vobjID).subid}`; - const raw = syscall.vatstoreGet(`vom.dkind.${kindID}`); - raw || Fail`unknown kind ID ${kindID}`; - const durableKindDescriptor = JSON.parse(raw); + const durableKindDescriptor = loadDurableKindDescriptor(kindID); + const nextInstanceID = loadNextInstanceID(kindID); kindIDToDescriptor.set(kindID, durableKindDescriptor); + nextInstanceIDs.set(kindID, nextInstanceID); const kindHandle = Far('kind', {}); kindHandleToID.set(kindHandle, kindID); // KindHandles are held strongly for the remainder of the incarnation, so @@ -994,21 +1022,18 @@ export function makeVirtualObjectManager( // kindDescriptors[kindID] const id = nextInstanceIDs.get(kindID); assert(id !== undefined); - const next = id + 1; + const next = id + 1n; nextInstanceIDs.set(kindID, next); if (isDurable) { - const durableKindDescriptor = kindIDToDescriptor.get(kindID); - assert(durableKindDescriptor); - durableKindDescriptor.nextInstanceID = next; - saveDurableKindDescriptor(durableKindDescriptor); + saveNextInstanceID(kindID); } return id; } function defineKind(tag, init, behavior, options) { const kindID = `${allocateExportID()}`; - syscall.vatstoreSet(`vom.vkind.${kindID}`, JSON.stringify({ kindID, tag })); - nextInstanceIDs.set(kindID, 1); + saveVirtualKindDescriptor(kindID, { kindID, tag }); + nextInstanceIDs.set(kindID, 1n); return defineKindInternal( kindID, tag, @@ -1022,8 +1047,8 @@ export function makeVirtualObjectManager( function defineKindMulti(tag, init, behavior, options) { const kindID = `${allocateExportID()}`; - syscall.vatstoreSet(`vom.vkind.${kindID}`, JSON.stringify({ kindID, tag })); - nextInstanceIDs.set(kindID, 1); + saveVirtualKindDescriptor(kindID, { kindID, tag }); + nextInstanceIDs.set(kindID, 1n); return defineKindInternal( kindID, tag, @@ -1043,16 +1068,19 @@ export function makeVirtualObjectManager( const makeKindHandle = tag => { assert(kindIDID, 'initializeKindHandleKind not called yet'); const kindID = `${allocateExportID()}`; - const kindIDvref = makeBaseRef(kindIDID, kindID, true); - const durableKindDescriptor = { kindID, tag, nextInstanceID: 1 }; + const durableKindDescriptor = { kindID, tag }; + const nextInstanceID = 1n; + kindIDToDescriptor.set(kindID, durableKindDescriptor); + nextInstanceIDs.set(kindID, nextInstanceID); + saveDurableKindDescriptor(durableKindDescriptor); + saveNextInstanceID(kindID); /** @type {import('@agoric/vat-data').DurableKindHandle} */ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error -- https://github.com/Agoric/agoric-sdk/issues/4620 // @ts-ignore cast const kindHandle = Far('kind', {}); kindHandleToID.set(kindHandle, kindID); - kindIDToDescriptor.set(kindID, durableKindDescriptor); + const kindIDvref = makeBaseRef(kindIDID, kindID, true); registerValue(kindIDvref, kindHandle, false); - saveDurableKindDescriptor(durableKindDescriptor); return kindHandle; }; @@ -1061,10 +1089,9 @@ export function makeVirtualObjectManager( const kindID = kindHandleToID.get(kindHandle); const durableKindDescriptor = kindIDToDescriptor.get(kindID); assert(durableKindDescriptor); - const { tag, nextInstanceID } = durableKindDescriptor; + const { tag } = durableKindDescriptor; !definedDurableKinds.has(kindID) || Fail`redefinition of durable kind ${tag}`; - nextInstanceIDs.set(kindID, nextInstanceID); const maker = defineKindInternal( kindID, tag, @@ -1084,10 +1111,9 @@ export function makeVirtualObjectManager( const kindID = kindHandleToID.get(kindHandle); const durableKindDescriptor = kindIDToDescriptor.get(kindID); assert(durableKindDescriptor); - const { tag, nextInstanceID } = durableKindDescriptor; + const { tag } = durableKindDescriptor; !definedDurableKinds.has(kindID) || Fail`redefinition of durable kind "${tag}"`; - nextInstanceIDs.set(kindID, nextInstanceID); const maker = defineKindInternal( kindID, tag, @@ -1107,10 +1133,12 @@ export function makeVirtualObjectManager( const missing = []; const prefix = 'vom.dkind.'; for (const key of enumerateKeysWithPrefix(syscall, prefix)) { - const value = syscall.vatstoreGet(key); - const durableKindDescriptor = JSON.parse(value); - if (!definedDurableKinds.has(durableKindDescriptor.kindID)) { - missing.push(durableKindDescriptor.tag); + if (key.endsWith('.descriptor')) { + const value = syscall.vatstoreGet(key); + const durableKindDescriptor = JSON.parse(value); + if (!definedDurableKinds.has(durableKindDescriptor.kindID)) { + missing.push(durableKindDescriptor.tag); + } } } if (missing.length) { diff --git a/packages/swingset-liveslots/test/test-handled-promises.js b/packages/swingset-liveslots/test/test-handled-promises.js index ac88375d6752..d00e24ad961c 100644 --- a/packages/swingset-liveslots/test/test-handled-promises.js +++ b/packages/swingset-liveslots/test/test-handled-promises.js @@ -160,8 +160,9 @@ const kvStoreDataV1 = Object.entries({ 'vc.4.|nextOrdinal': '1', 'vc.4.|schemata': '{"label":"watchedPromises","body":"#{\\"keyShape\\":{\\"#tag\\":\\"match:and\\",\\"payload\\":[{\\"#tag\\":\\"match:scalar\\",\\"payload\\":\\"#undefined\\"},{\\"#tag\\":\\"match:string\\",\\"payload\\":[]}]}}","slots":[]}', - 'vom.dkind.10': - '{"kindID":"10","tag":"DurablePromiseIgnorer","nextInstanceID":2,"unfaceted":true}', + 'vom.dkind.10.descriptor': + '{"kindID":"10","tag":"DurablePromiseIgnorer","unfaceted":true}', + 'vom.dkind.10.nextID': '2', 'vom.o+d10/1': '{}', 'vom.rc.o+d1/10': '1', 'vom.rc.o+d10/1': '3', diff --git a/packages/swingset-liveslots/test/test-liveslots.js b/packages/swingset-liveslots/test/test-liveslots.js index 4bbebcd4d36d..f73a08297790 100644 --- a/packages/swingset-liveslots/test/test-liveslots.js +++ b/packages/swingset-liveslots/test/test-liveslots.js @@ -666,7 +666,7 @@ test('capdata size limit on syscalls', async t => { const expectKindDef = kid => t.deepEqual(log.shift(), { type: 'vatstoreSet', - key: `vom.vkind.${kid}`, + key: `vom.vkind.${kid}.descriptor`, value: `{"kindID":"${kid}","tag":"test"}`, }); const expectStore = kid => diff --git a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js index e07ef98bc8d7..1bcfc92acd0a 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js @@ -972,7 +972,7 @@ async function voRefcountManagementTest1(t, isf) { // holder Kind is the next-to-last created kind, which gets idCounters.exportID-2 const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); await dispatchMessageSuccessfully('prepareStore3'); // create three VOs (tag "holder") which hold our vref in their vdata @@ -1013,7 +1013,7 @@ async function voRefcountManagementTest2(t, isf) { // holder Kind is the next-to-last created kind const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); await dispatchMessageSuccessfully('prepareStore3'); // create three VOs (tag "holder") which hold our vref in their vdata @@ -1054,7 +1054,7 @@ async function voRefcountManagementTest3(t, isf) { // holder Kind is the next-to-last created kind const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); // make a linked list with virtual "holder" objects await dispatchMessageSuccessfully('prepareStoreLinked'); @@ -1104,7 +1104,7 @@ test.serial('presence refcount management 1', async t => { // holder Kind is the next-to-last created kind, which gets idCounters.exportID-2 const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); // create three VOs (tag "holder") which hold our vref in their vdata await dispatchMessageSuccessfully('prepareStore3'); @@ -1143,7 +1143,7 @@ test.serial('presence refcount management 2', async t => { // holder Kind is the next-to-last created kind, which gets idCounters.exportID-2 const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); await dispatchMessageSuccessfully('prepareStore3'); @@ -1175,7 +1175,7 @@ test.serial('remotable refcount management 1', async t => { // holder Kind is the next-to-last created kind, which gets idCounters.exportID-2 const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); await dispatchMessageSuccessfully('makeAndHoldRemotable'); // the Remotable is currently held by RAM, and doesn't get a vref @@ -1217,7 +1217,7 @@ test.serial('remotable refcount management 2', async t => { const { fakestore } = v; const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); await dispatchMessageSuccessfully('makeAndHoldRemotable'); await dispatchMessageSuccessfully('prepareStore3'); @@ -1323,7 +1323,7 @@ test.serial('VO holding non-VO', async t => { await dispatchMessageSuccessfully('makeAndHoldRemotable'); // still held in RAM, no vref allocated yet const holderKindID = JSON.parse(fakestore.get(`idCounters`)).exportID - 2; - t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}`)).tag, 'holder'); + t.is(JSON.parse(fakestore.get(`vom.vkind.${holderKindID}.descriptor`)).tag, 'holder'); // holder is first instance created of that kind const holderVref = `o+v${holderKindID}/1`; diff --git a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js index f1ed2f763f52..4ac890b64cc5 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js @@ -129,7 +129,7 @@ test('multifaceted virtual objects', t => { t.deepEqual(log.splice(0), [ `get kindIDID => undefined`, `set kindIDID 1`, - `set vom.vkind.2 {"kindID":"2","tag":"multithing"}`, + `set vom.vkind.2.descriptor {"kindID":"2","tag":"multithing"}`, `set vom.${kid}/1 ${multiThingVal('foo', 1)}`, `set vom.${kid}/2 ${multiThingVal('other', 0)}`, ]); @@ -186,8 +186,8 @@ test('virtual object operations', t => { // phase 0: start t.deepEqual(dumpStore(), [ ['kindIDID', '1'], - ['vom.vkind.2', '{"kindID":"2","tag":"thing"}'], - ['vom.vkind.3', '{"kindID":"3","tag":"zot"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"thing"}'], + ['vom.vkind.3.descriptor', '{"kindID":"3","tag":"zot"}'], ]); // note: the "[t1-0].." comments show the expected cache contents, @@ -204,8 +204,8 @@ test('virtual object operations', t => { // t4-0: 'thing-4' 300 0 t.is(log.shift(), `get kindIDID => undefined`); t.is(log.shift(), `set kindIDID 1`); - t.is(log.shift(), `set vom.vkind.2 {"kindID":"2","tag":"thing"}`); - t.is(log.shift(), `set vom.vkind.3 {"kindID":"3","tag":"zot"}`); + t.is(log.shift(), `set vom.vkind.2.descriptor {"kindID":"2","tag":"thing"}`); + t.is(log.shift(), `set vom.vkind.3.descriptor {"kindID":"3","tag":"zot"}`); t.deepEqual(log, []); flushStateCache(); t.is(log.shift(), `set vom.${tid}/1 ${thingVal(0, 'thing-1', 0)}`); @@ -246,8 +246,8 @@ test('virtual object operations', t => { [`vom.${zid}/2`, zotVal(29, 'Bob', 'what are you saying?', 0)], // =z2-0 [`vom.${zid}/3`, zotVal(47, 'Carol', 'as if...', 0)], // =z3-0 [`vom.${zid}/4`, zotVal(66, 'Dave', 'you and what army?', 0)], // =z4-0 - ['vom.vkind.2', '{"kindID":"2","tag":"thing"}'], - ['vom.vkind.3', '{"kindID":"3","tag":"zot"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"thing"}'], + ['vom.vkind.3.descriptor', '{"kindID":"3","tag":"zot"}'], ]); // phase 2: first batch-o-stuff @@ -315,8 +315,8 @@ test('virtual object operations', t => { [`vom.${zid}/2`, zotVal(29, 'Bob', 'what are you saying?', 1)], // =z2-1 [`vom.${zid}/3`, zotVal(47, 'Carol', 'as if...', 1)], // =z3-1 [`vom.${zid}/4`, zotVal(66, 'Dave', 'you and what army?', 1)], // =z4-1 - ['vom.vkind.2', '{"kindID":"2","tag":"thing"}'], - ['vom.vkind.3', '{"kindID":"3","tag":"zot"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"thing"}'], + ['vom.vkind.3.descriptor', '{"kindID":"3","tag":"zot"}'], ]); // phase 3: second batch-o-stuff @@ -404,8 +404,8 @@ test('virtual object operations', t => { [`vom.${zid}/2`, zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 [`vom.${zid}/3`, zotVal(47, 'Chester', 'as if...', 3)], // =z3-3 [`vom.${zid}/4`, zotVal(66, 'Dave', 'you and what army?', 2)], // =z4-2 - ['vom.vkind.2', '{"kindID":"2","tag":"thing"}'], - ['vom.vkind.3', '{"kindID":"3","tag":"zot"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"thing"}'], + ['vom.vkind.3.descriptor', '{"kindID":"3","tag":"zot"}'], ]); // phase 4 @@ -428,8 +428,8 @@ test('virtual object operations', t => { [`vom.${zid}/2`, zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 [`vom.${zid}/3`, zotVal(47, 'Chester', 'as if...', 3)], // =z3-3 [`vom.${zid}/4`, zotVal(66, 'Dave', 'you and what army?', 2)], // =z4-2 - ['vom.vkind.2', '{"kindID":"2","tag":"thing"}'], - ['vom.vkind.3', '{"kindID":"3","tag":"zot"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"thing"}'], + ['vom.vkind.3.descriptor', '{"kindID":"3","tag":"zot"}'], ]); }); @@ -458,7 +458,7 @@ test('symbol named methods', t => { // phase 0: start t.deepEqual(dumpStore(), [ ['kindIDID', '1'], - ['vom.vkind.2', '{"kindID":"2","tag":"symthing"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"symthing"}'], ]); // phase 1: object creations @@ -468,7 +468,10 @@ test('symbol named methods', t => { // t2-0: 'thing-2' 100 0 t.is(log.shift(), `get kindIDID => undefined`); t.is(log.shift(), `set kindIDID 1`); - t.is(log.shift(), `set vom.vkind.2 {"kindID":"2","tag":"symthing"}`); + t.is( + log.shift(), + `set vom.vkind.2.descriptor {"kindID":"2","tag":"symthing"}`, + ); t.deepEqual(log, []); flushStateCache(); t.is(log.shift(), `set vom.${tid}/1 ${thingVal(0, 'thing-1', 0)}`); // write t1-0 @@ -478,7 +481,7 @@ test('symbol named methods', t => { ['kindIDID', '1'], [`vom.${tid}/1`, thingVal(0, 'thing-1', 0)], // =t1-0 [`vom.${tid}/2`, thingVal(100, 'thing-2', 0)], // =t2-0 - ['vom.vkind.2', '{"kindID":"2","tag":"symthing"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"symthing"}'], ]); // phase 2: call symbol-named method on thing1 @@ -492,7 +495,7 @@ test('symbol named methods', t => { ['kindIDID', '1'], [`vom.${tid}/1`, thingVal(1, 'thing-1', 0)], // =t1-1 [`vom.${tid}/2`, thingVal(100, 'thing-2', 0)], // =t2-0 - ['vom.vkind.2', '{"kindID":"2","tag":"symthing"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"symthing"}'], ]); // phase 3: call symbol-named method on thing2 @@ -506,7 +509,7 @@ test('symbol named methods', t => { ['kindIDID', '1'], [`vom.${tid}/1`, thingVal(1, 'thing-1', 0)], // =t1-1 [`vom.${tid}/2`, thingVal(101, 'thing-2', 0)], // =t2-1 - ['vom.vkind.2', '{"kindID":"2","tag":"symthing"}'], + ['vom.vkind.2.descriptor', '{"kindID":"2","tag":"symthing"}'], ]); }); @@ -575,8 +578,9 @@ test('durable kind IDs can be reanimated', t => { let kindHandle = makeKindHandle('testkind'); t.is( log.shift(), - 'set vom.dkind.10 {"kindID":"10","tag":"testkind","nextInstanceID":1}', + 'set vom.dkind.10.descriptor {"kindID":"10","tag":"testkind"}', ); + t.is(log.shift(), 'set vom.dkind.10.nextID 1'); t.deepEqual(log, []); const khid = `o+d1/10`; const kind = kslot(khid, 'kind'); @@ -605,25 +609,23 @@ test('durable kind IDs can be reanimated', t => { t.is(log.shift(), `get vc.1.ssavedKindID => ${vstr(kind)}`); t.is( log.shift(), - 'get vom.dkind.10 => {"kindID":"10","tag":"testkind","nextInstanceID":1}', + 'get vom.dkind.10.descriptor => {"kindID":"10","tag":"testkind"}', ); + t.is(log.shift(), 'get vom.dkind.10.nextID => 1'); t.deepEqual(log, []); // Use it now, to define a durable kind const makeThing = defineDurableKind(fetchedKindID, initThing, thingBehavior); t.is( log.shift(), - 'set vom.dkind.10 {"kindID":"10","tag":"testkind","nextInstanceID":1,"unfaceted":true,"stateShapeCapData":{"body":"#\\"#undefined\\"","slots":[]}}', + 'set vom.dkind.10.descriptor {"kindID":"10","tag":"testkind","unfaceted":true,"stateShapeCapData":{"body":"#\\"#undefined\\"","slots":[]}}', ); t.deepEqual(log, []); // Make an instance of the new kind, just to be sure it's there makeThing('laterThing'); flushStateCache(); - t.is( - log.shift(), - 'set vom.dkind.10 {"kindID":"10","tag":"testkind","nextInstanceID":2,"unfaceted":true,"stateShapeCapData":{"body":"#\\"#undefined\\"","slots":[]}}', - ); + t.is(log.shift(), 'set vom.dkind.10.nextID 2'); t.is(log.shift(), `set vom.o+d10/1 ${thingVal(0, 'laterThing', 0)}`); t.deepEqual(log, []); }); @@ -652,8 +654,11 @@ test('virtual object gc', t => { ]; t.is(log.shift(), `get storeKindIDTable => undefined`); t.is(log.shift(), `set ${skit[0]} ${skit[1]}`); - t.is(log.shift(), `set vom.vkind.10 {"kindID":"10","tag":"thing"}`); - t.is(log.shift(), `set vom.vkind.11 {"kindID":"11","tag":"ref"}`); + t.is( + log.shift(), + `set vom.vkind.10.descriptor {"kindID":"10","tag":"thing"}`, + ); + t.is(log.shift(), `set vom.vkind.11.descriptor {"kindID":"11","tag":"ref"}`); t.deepEqual(log, []); // make a bunch of things which we'll use @@ -686,8 +691,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // This is what the finalizer would do if the local reference was dropped and GC'd @@ -723,8 +728,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // drop export -- should delete @@ -762,8 +767,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // case 2: export, drop export, drop local ref @@ -790,8 +795,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // drop local ref -- should delete @@ -819,8 +824,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // case 3: drop local ref with no prior export @@ -848,8 +853,8 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // case 4: ref virtually, export, drop local ref, drop export @@ -869,8 +874,8 @@ test('virtual object gc', t => { [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], [`vom.rc.${tbase}/4`, '1'], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // export setExportStatus(`${tbase}/4`, 'reachable'); @@ -914,8 +919,8 @@ test('virtual object gc', t => { [`vom.${tbase}/9`, minThing('thing #9')], [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // drop local ref -- should not delete because ref'd virtually AND exported pretendGC(`${tbase}/5`, false); @@ -950,8 +955,8 @@ test('virtual object gc', t => { [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], [`vom.rc.${tbase}/6`, '1'], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); // drop local ref -- should not delete because ref'd virtually pretendGC(`${tbase}/6`, false); @@ -972,8 +977,8 @@ test('virtual object gc', t => { [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], [`vom.rc.${tbase}/6`, '1'], - ['vom.vkind.10', '{"kindID":"10","tag":"thing"}'], - ['vom.vkind.11', '{"kindID":"11","tag":"ref"}'], + ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], + ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], ]); });