diff --git a/packages/SwingSet/src/kernel/initializeKernel.js b/packages/SwingSet/src/kernel/initializeKernel.js index 45df8946444..19f7bae91ae 100644 --- a/packages/SwingSet/src/kernel/initializeKernel.js +++ b/packages/SwingSet/src/kernel/initializeKernel.js @@ -65,6 +65,7 @@ export function initializeKernel(config, hostStorage, verbose = false) { 'managerType', 'enableDisavow', 'enableSetup', + 'enableVatstore', 'virtualObjectCacheSize', 'useTranscript', ]); diff --git a/packages/SwingSet/src/kernel/liveSlots.js b/packages/SwingSet/src/kernel/liveSlots.js index 152ce4dfb94..be6fb206ab3 100644 --- a/packages/SwingSet/src/kernel/liveSlots.js +++ b/packages/SwingSet/src/kernel/liveSlots.js @@ -23,6 +23,7 @@ const DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE = 3; // XXX ridiculously small value to * @param {*} forVatID Vat ID label, for use in debug diagostics * @param {number} cacheSize Maximum number of entries in the virtual object state cache * @param {boolean} enableDisavow + * @param {boolean} enableVatstore * @param {*} vatPowers * @param {*} vatParameters * @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent, gcAndFinalize } @@ -40,6 +41,7 @@ function build( forVatID, cacheSize, enableDisavow, + enableVatstore, vatPowers, vatParameters, gcTools, @@ -916,6 +918,23 @@ function build( if (enableDisavow) { vpow.disavow = disavow; } + if (enableVatstore) { + vpow.vatstore = harden({ + get: key => { + assert.typeof(key, 'string'); + return syscall.vatstoreGet(`vvs.${key}`); + }, + set: (key, value) => { + assert.typeof(key, 'string'); + assert.typeof(value, 'string'); + syscall.vatstoreSet(`vvs.${key}`, value); + }, + delete: key => { + assert.typeof(key, 'string'); + syscall.vatstoreDelete(`vvs.${key}`); + }, + }); + } // here we finally invoke the vat code, and get back the root object const rootObject = buildRootObject(harden(vpow), harden(vatParameters)); @@ -1029,6 +1048,7 @@ function build( * @param {*} vatParameters * @param {number} cacheSize Upper bound on virtual object cache size * @param {boolean} enableDisavow + * @param {boolean} enableVatstore * @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent } * @param {Console} [liveSlotsConsole] * @returns {*} { vatGlobals, inescapableGlobalProperties, dispatch, setBuildRootObject } @@ -1062,6 +1082,7 @@ export function makeLiveSlots( vatParameters = harden({}), cacheSize = DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE, enableDisavow = false, + enableVatstore = false, gcTools, liveSlotsConsole = console, ) { @@ -1074,6 +1095,7 @@ export function makeLiveSlots( forVatID, cacheSize, enableDisavow, + enableVatstore, allVatPowers, vatParameters, gcTools, @@ -1102,6 +1124,7 @@ export function makeMarshaller(syscall, gcTools) { 'forVatID', DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE, false, + false, {}, {}, gcTools, diff --git a/packages/SwingSet/src/kernel/loadVat.js b/packages/SwingSet/src/kernel/loadVat.js index 42756446c4d..014d568e7fd 100644 --- a/packages/SwingSet/src/kernel/loadVat.js +++ b/packages/SwingSet/src/kernel/loadVat.js @@ -84,6 +84,7 @@ export function makeVatLoader(stuff) { 'vatParameters', 'enableSetup', 'enablePipelining', + 'enableVatstore', 'virtualObjectCacheSize', 'useTranscript', ]; @@ -96,6 +97,7 @@ export function makeVatLoader(stuff) { 'enableDisavow', 'enableSetup', 'enablePipelining', + 'enableVatstore', 'virtualObjectCacheSize', 'useTranscript', ]; @@ -141,6 +143,10 @@ export function makeVatLoader(stuff) { * without waiting for the promises to be resolved. If false, such * messages will be queued inside the kernel. Defaults to false. * + * 'enableVatstore' If true, the vat is provided with an object that allows + * individual keyed access (in an insolated subset of the key space) to + * the vatstore. Defaults to false. + * * 'useTranscript' If true, saves a transcript of a vat's inbound * deliveries and outbound syscalls so that the vat's internal state * can be reconstructed via replay. If false, no such record is kept. @@ -175,6 +181,7 @@ export function makeVatLoader(stuff) { enableSetup = false, enableDisavow = false, enablePipelining = false, + enableVatstore = false, virtualObjectCacheSize, useTranscript = true, name, @@ -206,6 +213,7 @@ export function makeVatLoader(stuff) { vatConsole: makeVatConsole('vat', vatID), liveSlotsConsole: makeVatConsole('ls', vatID), vatParameters, + enableVatstore, virtualObjectCacheSize, useTranscript, name, diff --git a/packages/SwingSet/src/kernel/vatManager/factory.js b/packages/SwingSet/src/kernel/vatManager/factory.js index 98f29bf1ce7..2ace13ee8ff 100644 --- a/packages/SwingSet/src/kernel/vatManager/factory.js +++ b/packages/SwingSet/src/kernel/vatManager/factory.js @@ -60,6 +60,7 @@ export function makeVatManagerFactory({ 'enableDisavow', 'enableSetup', 'liveSlotsConsole', + 'enableVatstore', 'virtualObjectCacheSize', 'useTranscript', 'vatParameters', diff --git a/packages/SwingSet/src/kernel/vatManager/manager-local.js b/packages/SwingSet/src/kernel/vatManager/manager-local.js index 2c27077d8ef..b7741dc2a87 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-local.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-local.js @@ -97,6 +97,7 @@ export function makeLocalVatManagerFactory(tools) { vatParameters = {}, vatConsole, liveSlotsConsole, + enableVatstore = false, virtualObjectCacheSize, compareSyscalls, useTranscript, @@ -139,6 +140,7 @@ export function makeLocalVatManagerFactory(tools) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, gcTools, liveSlotsConsole, ); diff --git a/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js b/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js index 303078e883c..265d33016ae 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js @@ -40,6 +40,7 @@ export function makeNodeWorkerVatManagerFactory(tools) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, compareSyscalls, useTranscript, } = managerOptions; @@ -114,6 +115,7 @@ export function makeNodeWorkerVatManagerFactory(tools) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ]); function deliverToWorker(delivery) { diff --git a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js index 686e100811a..63d2d198f00 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js @@ -20,6 +20,7 @@ export function makeNodeSubprocessFactory(tools) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, compareSyscalls, useTranscript, } = managerOptions; @@ -109,6 +110,7 @@ export function makeNodeSubprocessFactory(tools) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ]); function shutdown() { diff --git a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js index 4142eb62cd1..4b7bd55c05c 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js @@ -52,6 +52,7 @@ export function makeXsSubprocessFactory({ vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, name, metered, compareSyscalls, @@ -126,6 +127,7 @@ export function makeXsSubprocessFactory({ vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ]); if (bundleReply[0] === 'dispatchReady') { parentLog(vatID, `bundle loaded. dispatch ready.`); diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js b/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js index 0efc4e3bae9..3d8a3ccca00 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js @@ -57,6 +57,7 @@ parentPort.on('message', ([type, ...margs]) => { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ] = margs; function testLog(...args) { @@ -89,6 +90,7 @@ parentPort.on('message', ([type, ...margs]) => { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, gcTools, ); diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js index cc05db96e18..2cda6d911d1 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js @@ -72,6 +72,7 @@ fromParent.on('data', ([type, ...margs]) => { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ] = margs; function testLog(...args) { @@ -102,6 +103,7 @@ fromParent.on('data', ([type, ...margs]) => { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, gcTools, ); diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js index 23db6a85305..fd8fa5c5086 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js @@ -143,6 +143,7 @@ function makeWorker(port) { * @param {unknown} vatParameters * @param {unknown} virtualObjectCacheSize * @param {boolean} enableDisavow + * @param {boolean} enableVatstore * @returns { Promise } */ async function setBundle( @@ -151,6 +152,7 @@ function makeWorker(port) { vatParameters, virtualObjectCacheSize, enableDisavow, + enableVatstore, ) { /** @type { (vso: VatSyscallObject) => VatSyscallResult } */ function syscallToManager(vatSyscallObject) { @@ -195,6 +197,7 @@ function makeWorker(port) { vatParameters, cacheSize, enableDisavow, + enableVatstore, gcTools, ); @@ -227,7 +230,15 @@ function makeWorker(port) { case 'setBundle': { assert(!dispatch, 'cannot setBundle again'); const enableDisavow = !!args[4]; - return setBundle(args[0], args[1], args[2], args[3], enableDisavow); + const enableVatstore = !!args[5]; + return setBundle( + args[0], + args[1], + args[2], + args[3], + enableDisavow, + enableVatstore, + ); } case 'deliver': { assert(dispatch, 'cannot deliver before setBundle'); diff --git a/packages/SwingSet/src/kernel/virtualObjectManager.js b/packages/SwingSet/src/kernel/virtualObjectManager.js index ceee417149e..0005835fd49 100644 --- a/packages/SwingSet/src/kernel/virtualObjectManager.js +++ b/packages/SwingSet/src/kernel/virtualObjectManager.js @@ -174,7 +174,7 @@ export function makeVirtualObjectManager( * @returns {*} an object representing the object's stored state. */ function fetch(vobjID) { - return JSON.parse(syscall.vatstoreGet(vobjID)); + return JSON.parse(syscall.vatstoreGet(`vom.${vobjID}`)); } /** @@ -185,7 +185,7 @@ export function makeVirtualObjectManager( * @param {*} rawData A data object representing the state to be written. */ function store(vobjID, rawData) { - syscall.vatstoreSet(vobjID, JSON.stringify(rawData)); + syscall.vatstoreSet(`vom.${vobjID}`, JSON.stringify(rawData)); } const cache = makeCache(cacheSize, fetch, store); @@ -308,7 +308,7 @@ export function makeVirtualObjectManager( if (vobjID) { const { type, virtual, allocatedByVat } = parseVatSlot(vobjID); if (type === 'object' && (virtual || !allocatedByVat)) { - return `ws${storeID}.${vobjID}`; + return `vom.ws${storeID}.${vobjID}`; } } return undefined; diff --git a/packages/SwingSet/src/types.js b/packages/SwingSet/src/types.js index 0a420986e18..53aded75c27 100644 --- a/packages/SwingSet/src/types.js +++ b/packages/SwingSet/src/types.js @@ -26,6 +26,7 @@ * metered?: boolean, * enableDisavow?: boolean, * useTranscript?: boolean, + * enableVatstore?: boolean, * vatParameters: Record, * virtualObjectCacheSize: number, * name: string, diff --git a/packages/SwingSet/test/liveslots-helpers.js b/packages/SwingSet/test/liveslots-helpers.js index ed610ae325e..32897901461 100644 --- a/packages/SwingSet/test/liveslots-helpers.js +++ b/packages/SwingSet/test/liveslots-helpers.js @@ -54,6 +54,7 @@ export function makeDispatch( {}, undefined, enableDisavow, + false, gcTools, ); setBuildRootObject(build); diff --git a/packages/SwingSet/test/test-liveslots.js b/packages/SwingSet/test/test-liveslots.js index d2a835ef897..001d21d9f71 100644 --- a/packages/SwingSet/test/test-liveslots.js +++ b/packages/SwingSet/test/test-liveslots.js @@ -932,7 +932,16 @@ test('dropImports', async t => { return root; } - const ls = makeLiveSlots(syscall, 'vatA', {}, {}, undefined, false, gcTools); + const ls = makeLiveSlots( + syscall, + 'vatA', + {}, + {}, + undefined, + false, + false, + gcTools, + ); const { setBuildRootObject, dispatch, deadSet } = ls; setBuildRootObject(build); const allFRs = gcTools.getAllFRs(); diff --git a/packages/SwingSet/test/test-vatstore.js b/packages/SwingSet/test/test-vatstore.js new file mode 100644 index 00000000000..d02461b34b3 --- /dev/null +++ b/packages/SwingSet/test/test-vatstore.js @@ -0,0 +1,60 @@ +/* global require */ +// eslint-disable-next-line import/order +import { test } from '../tools/prepare-test-env-ava'; + +import { provideHostStorage } from '../src/hostStorage'; +import { buildVatController } from '../src/index'; +import { capargs } from './util.js'; + +test('vatstore', async t => { + const config = { + bootstrap: 'bootstrap', + vats: { + bootstrap: { + sourceSpec: require.resolve('./vat-vatstore.js'), + creationOptions: { + enableVatstore: true, + }, + }, + }, + }; + const hostStorage = provideHostStorage(); + const c = await buildVatController(config, [], { + hostStorage, + }); + + function send(msg, ...args) { + c.queueToVatExport('bootstrap', 'o+0', msg, capargs(args)); + } + + send('get', 'zot'); + await c.run(); + send('store', 'zot', 'first zot'); + send('get', 'zot'); + send('get', 'foo'); + send('store', 'zot', 'second zot'); + send('store', 'foo', 'first foo'); + send('get', 'zot'); + send('delete', 'zot'); + send('get', 'foo'); + send('get', 'zot'); + await c.run(); + + t.deepEqual(c.dump().log, [ + 'get zot -> ', + 'store zot <- "first zot"', + 'get zot -> "first zot"', + 'get foo -> ', + 'store zot <- "second zot"', + 'store foo <- "first foo"', + 'get zot -> "second zot"', + 'delete zot', + 'get foo -> "first foo"', + 'get zot -> ', + ]); + for (const k of hostStorage.kvStore.getKeys('', '')) { + if (k.endsWith('.foo')) { + t.is(k, 'v1.vs.vvs.foo'); + } + } +}); diff --git a/packages/SwingSet/test/vat-vatstore.js b/packages/SwingSet/test/vat-vatstore.js new file mode 100644 index 00000000000..801dfd25551 --- /dev/null +++ b/packages/SwingSet/test/vat-vatstore.js @@ -0,0 +1,26 @@ +import { Far } from '@agoric/marshal'; + +export function buildRootObject(vatPowers) { + const vatstore = vatPowers.vatstore; + const log = vatPowers.testLog; + + return Far('root', { + bootstrap(_vats) {}, + get(key) { + const value = vatstore.get(key); + if (value) { + log(`get ${key} -> "${value}"`); + } else { + log(`get ${key} -> `); + } + }, + store(key, value) { + vatstore.set(key, value); + log(`store ${key} <- "${value}"`); + }, + delete(key) { + vatstore.delete(key); + log(`delete ${key}`); + }, + }); +} diff --git a/packages/SwingSet/test/virtualObjects/test-representatives.js b/packages/SwingSet/test/virtualObjects/test-representatives.js index 247de1b02a9..1fe6a2796cc 100644 --- a/packages/SwingSet/test/virtualObjects/test-representatives.js +++ b/packages/SwingSet/test/virtualObjects/test-representatives.js @@ -264,7 +264,7 @@ test('exercise cache', async t => { await doSimple('holdThing', what); } function thingID(num) { - return `v1.vs.o+1/${num}`; + return `v1.vs.vom.o+1/${num}`; } function thingVal(name) { return JSON.stringify({ diff --git a/packages/SwingSet/test/virtualObjects/test-virtualObjectManager.js b/packages/SwingSet/test/virtualObjects/test-virtualObjectManager.js index 7618d9426d4..8408cf1a02a 100644 --- a/packages/SwingSet/test/virtualObjects/test-virtualObjectManager.js +++ b/packages/SwingSet/test/virtualObjects/test-virtualObjectManager.js @@ -105,41 +105,41 @@ test('virtual object operations', t => { const zot1 = zotMaker(23, 'Alice', 'is this on?'); // [z1-0 t4-0 t3-0 t2-0] evict t1-0 // z1-0: 23 'Alice' 'is this on?' 0 - t.is(log.shift(), `set o+1/1 ${thingVal(0, 'thing-1', 0)}`); // evict t1-0 + t.is(log.shift(), `set vom.o+1/1 ${thingVal(0, 'thing-1', 0)}`); // evict t1-0 t.deepEqual(log, []); const zot2 = zotMaker(29, 'Bob', 'what are you saying?'); // [z2-0 z1-0 t4-0 t3-0] evict t2-0 // z2-0: 29 'Bob' 'what are you saying?' 0 - t.is(log.shift(), `set o+1/2 ${thingVal(100, 'thing-2', 0)}`); // evict t2-0 + t.is(log.shift(), `set vom.o+1/2 ${thingVal(100, 'thing-2', 0)}`); // evict t2-0 t.deepEqual(log, []); const zot3 = zotMaker(47, 'Carol', 'as if...'); // [z3-0 z2-0 z1-0 t4-0] evict t3-0 // z3-0: 47 'Carol' 'as if...' 0 - t.is(log.shift(), `set o+1/3 ${thingVal(200, 'thing-3', 0)}`); // evict t3-0 + t.is(log.shift(), `set vom.o+1/3 ${thingVal(200, 'thing-3', 0)}`); // evict t3-0 t.deepEqual(log, []); const zot4 = zotMaker(66, 'Dave', 'you and what army?'); // [z4-0 z3-0 z2-0 z1-0] evict t4-0 // z4-0: 66 'Dave' 'you and what army?' 0 - t.is(log.shift(), `set o+1/4 ${thingVal(300, 'thing-4', 0)}`); // evict t4-0 + t.is(log.shift(), `set vom.o+1/4 ${thingVal(300, 'thing-4', 0)}`); // evict t4-0 t.deepEqual(log, []); t.deepEqual(dumpStore(), [ - ['o+1/1', thingVal(0, 'thing-1', 0)], // =t1-0 - ['o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 - ['o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 - ['o+1/4', thingVal(300, 'thing-4', 0)], // =t4-0 + ['vom.o+1/1', thingVal(0, 'thing-1', 0)], // =t1-0 + ['vom.o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 + ['vom.o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 + ['vom.o+1/4', thingVal(300, 'thing-4', 0)], // =t4-0 ]); // phase 2: first batch-o-stuff t.is(thing1.inc(), 1); // [t1-1 z4-0 z3-0 z2-0] evict z1-0 - t.is(log.shift(), `set o+2/1 ${zotVal(23, 'Alice', 'is this on?', 0)}`); // evict z1-0 - t.is(log.shift(), `get o+1/1 => ${thingVal(0, 'thing-1', 0)}`); // load t1-0 + t.is(log.shift(), `set vom.o+2/1 ${zotVal(23, 'Alice', 'is this on?', 0)}`); // evict z1-0 + t.is(log.shift(), `get vom.o+1/1 => ${thingVal(0, 'thing-1', 0)}`); // load t1-0 t.deepEqual(log, []); // t1-1: 'thing-1' 1 0 t.is(zot1.sayHello('hello'), 'hello Alice'); // [z1-1 t1-1 z4-0 z3-0] evict z2-0 - t.is(log.shift(), `set o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 0)}`); // evict z2-0 - t.is(log.shift(), `get o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 0)}`); // load z1-0 + t.is(log.shift(), `set vom.o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 0)}`); // evict z2-0 + t.is(log.shift(), `get vom.o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 0)}`); // load z1-0 t.deepEqual(log, []); // z1-1: 23 'Alice' 'is this on?' 1 @@ -148,8 +148,8 @@ test('virtual object operations', t => { // t1-2: 'thing-1' 2 0 t.is(zot2.sayHello('hi'), 'hi Bob'); // [z2-1 t1-2 z1-1 z4-0] evict z3-0 - t.is(log.shift(), `set o+2/3 ${zotVal(47, 'Carol', 'as if...', 0)}`); // evict z3-0 - t.is(log.shift(), `get o+2/2 => ${zotVal(29, 'Bob', 'what are you saying?', 0)}`); // load z2-0 + t.is(log.shift(), `set vom.o+2/3 ${zotVal(47, 'Carol', 'as if...', 0)}`); // evict z3-0 + t.is(log.shift(), `get vom.o+2/2 => ${zotVal(29, 'Bob', 'what are you saying?', 0)}`); // load z2-0 t.deepEqual(log, []); // z2-1: 29 'Bob' 'what are you saying?' 1 @@ -158,20 +158,20 @@ test('virtual object operations', t => { // t1-3: 'thing-1' 3 0 t.is(zot3.sayHello('aloha'), 'aloha Carol'); // [z3-1 t1-3 z2-1 z1-1] evict z4-0 - t.is(log.shift(), `set o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 0)}`); // evict z4-0 - t.is(log.shift(), `get o+2/3 => ${zotVal(47, 'Carol', 'as if...', 0)}`); // load z3-0 + t.is(log.shift(), `set vom.o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 0)}`); // evict z4-0 + t.is(log.shift(), `get vom.o+2/3 => ${zotVal(47, 'Carol', 'as if...', 0)}`); // load z3-0 t.deepEqual(log, []); // z3-1: 47 'Carol' 'as if...' 1 t.is(zot4.sayHello('bonjour'), 'bonjour Dave'); // [z4-1 z3-1 t1-3 z2-1] evict z1-1 - t.is(log.shift(), `set o+2/1 ${zotVal(23, 'Alice', 'is this on?', 1)}`); // evict z1-1 - t.is(log.shift(), `get o+2/4 => ${zotVal(66, 'Dave', 'you and what army?', 0)}`); // load z4-0 + t.is(log.shift(), `set vom.o+2/1 ${zotVal(23, 'Alice', 'is this on?', 1)}`); // evict z1-1 + t.is(log.shift(), `get vom.o+2/4 => ${zotVal(66, 'Dave', 'you and what army?', 0)}`); // load z4-0 t.deepEqual(log, []); // z4-1: 66 'Dave' 'you and what army?' 1 t.is(zot1.sayHello('hello again'), 'hello again Alice'); // [z1-2 z4-1 z3-1 t1-3] evict z2-1 - t.is(log.shift(), `set o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 1)}`); // evict z2-1 - t.is(log.shift(), `get o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 1)}`); // get z1-1 + t.is(log.shift(), `set vom.o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 1)}`); // evict z2-1 + t.is(log.shift(), `get vom.o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 1)}`); // get z1-1 t.deepEqual(log, []); // z1-2: 23 'Alice' 'is this on?' 2 @@ -179,25 +179,25 @@ test('virtual object operations', t => { thing2.describe(), // [t2-0 z1-2 z4-1 z3-1] evict t1-3 'thing-2 counter has been reset 0 times and is now 100', ); - t.is(log.shift(), `set o+1/1 ${thingVal(3, 'thing-1', 0)}`); // evict t1-3 - t.is(log.shift(), `get o+1/2 => ${thingVal(100, 'thing-2', 0)}`); // load t2-0 + t.is(log.shift(), `set vom.o+1/1 ${thingVal(3, 'thing-1', 0)}`); // evict t1-3 + t.is(log.shift(), `get vom.o+1/2 => ${thingVal(100, 'thing-2', 0)}`); // load t2-0 t.deepEqual(log, []); t.deepEqual(dumpStore(), [ - ['o+1/1', thingVal(3, 'thing-1', 0)], // =t1-3 - ['o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 - ['o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 - ['o+1/4', thingVal(300, 'thing-4', 0)], // =t4-0 - ['o+2/1', zotVal(23, 'Alice', 'is this on?', 1)], // =z1-1 - ['o+2/2', zotVal(29, 'Bob', 'what are you saying?', 1)], // =z2-1 - ['o+2/3', zotVal(47, 'Carol', 'as if...', 0)], // =z3-0 - ['o+2/4', zotVal(66, 'Dave', 'you and what army?', 0)], // =z4-0 + ['vom.o+1/1', thingVal(3, 'thing-1', 0)], // =t1-3 + ['vom.o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 + ['vom.o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 + ['vom.o+1/4', thingVal(300, 'thing-4', 0)], // =t4-0 + ['vom.o+2/1', zotVal(23, 'Alice', 'is this on?', 1)], // =z1-1 + ['vom.o+2/2', zotVal(29, 'Bob', 'what are you saying?', 1)], // =z2-1 + ['vom.o+2/3', zotVal(47, 'Carol', 'as if...', 0)], // =z3-0 + ['vom.o+2/4', zotVal(66, 'Dave', 'you and what army?', 0)], // =z4-0 ]); // phase 3: second batch-o-stuff t.is(thing1.get(), 3); // [t1-3 t2-0 z1-2 z4-1] evict z3-1 - t.is(log.shift(), `set o+2/3 ${zotVal(47, 'Carol', 'as if...', 1)}`); // evict z3-1 - t.is(log.shift(), `get o+1/1 => ${thingVal(3, 'thing-1', 0)}`); // load t1-3 + t.is(log.shift(), `set vom.o+2/3 ${zotVal(47, 'Carol', 'as if...', 1)}`); // evict z3-1 + t.is(log.shift(), `get vom.o+1/1 => ${thingVal(3, 'thing-1', 0)}`); // load t1-3 t.deepEqual(log, []); t.is(thing1.inc(), 4); // [t1-4 t2-0 z1-2 z4-1] @@ -205,26 +205,26 @@ test('virtual object operations', t => { // t1-4: 'thing-1' 4 0 t.is(thing4.reset(1000), 1); // [t4-1 t1-4 t2-0 z1-2] evict z4-1 - t.is(log.shift(), `set o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 1)}`); // evict z4-1 - t.is(log.shift(), `get o+1/4 => ${thingVal(300, 'thing-4', 0)}`); // load t4-0 + t.is(log.shift(), `set vom.o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 1)}`); // evict z4-1 + t.is(log.shift(), `get vom.o+1/4 => ${thingVal(300, 'thing-4', 0)}`); // load t4-0 t.deepEqual(log, []); // t4-1: 'thing-4' 1000 1 t.is(zot3.rename('Chester'), 'Chester'); // [z3-2 t4-1 t1-4 t2-0] evict z1-2 - t.is(log.shift(), `set o+2/1 ${zotVal(23, 'Alice', 'is this on?', 2)}`); // evict z1-2 - t.is(log.shift(), `get o+2/3 => ${zotVal(47, 'Carol', 'as if...', 1)}`); // load z3-1 + t.is(log.shift(), `set vom.o+2/1 ${zotVal(23, 'Alice', 'is this on?', 2)}`); // evict z1-2 + t.is(log.shift(), `get vom.o+2/3 => ${zotVal(47, 'Carol', 'as if...', 1)}`); // load z3-1 t.deepEqual(log, []); // z3-2: 47 'Chester' 'as if...' 2 t.is(zot1.getInfo(), 'zot Alice tag=is this on? count=3 arbitrary=23'); // [z1-3 z3-2 t4-1 t1-4] evict t2-0 // evict t2-0 does nothing because t2 is not dirty - t.is(log.shift(), `get o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 2)}`); // load z1-2 + t.is(log.shift(), `get vom.o+2/1 => ${zotVal(23, 'Alice', 'is this on?', 2)}`); // load z1-2 t.deepEqual(log, []); // z1-3: 23 'Alice' 'is this on?' 3 t.is(zot2.getInfo(), 'zot Bob tag=what are you saying? count=2 arbitrary=29'); // [z2-2 z1-3 z3-2 t4-1] evict t1-4 - t.is(log.shift(), `set o+1/1 ${thingVal(4, 'thing-1', 0)}`); // evict t1-4 - t.is(log.shift(), `get o+2/2 => ${zotVal(29, 'Bob', 'what are you saying?', 1)}`); // load z2-1 + t.is(log.shift(), `set vom.o+1/1 ${thingVal(4, 'thing-1', 0)}`); // evict t1-4 + t.is(log.shift(), `get vom.o+2/2 => ${zotVal(29, 'Bob', 'what are you saying?', 1)}`); // load z2-1 t.deepEqual(log, []); // z2-2: 29 'Bob' 'what are you saying?' 1 @@ -232,8 +232,8 @@ test('virtual object operations', t => { thing2.describe(), // [t2-0 z2-2 z1-3 z3-2] evict t4-1 'thing-2 counter has been reset 0 times and is now 100', ); - t.is(log.shift(), `set o+1/4 ${thingVal(1000, 'thing-4', 1)}`); // evict t4-1 - t.is(log.shift(), `get o+1/2 => ${thingVal(100, 'thing-2', 0)}`); // load t2-0 + t.is(log.shift(), `set vom.o+1/4 ${thingVal(1000, 'thing-4', 1)}`); // evict t4-1 + t.is(log.shift(), `get vom.o+1/2 => ${thingVal(100, 'thing-2', 0)}`); // load t2-0 t.deepEqual(log, []); t.is(zot3.getInfo(), 'zot Chester tag=as if... count=3 arbitrary=47'); // [z3-3 t2-0 z2-2 z1-3] @@ -241,14 +241,14 @@ test('virtual object operations', t => { // z3-3: 47 'Chester' 'as if...' 3 t.is(zot4.getInfo(), 'zot Dave tag=you and what army? count=2 arbitrary=66'); // [z4-1 z3-3 t2-0 z2-2] evict z1-3 - t.is(log.shift(), `set o+2/1 ${zotVal(23, 'Alice', 'is this on?', 3)}`); // evict z1-3 - t.is(log.shift(), `get o+2/4 => ${zotVal(66, 'Dave', 'you and what army?', 1)}`); // load z4-1 + t.is(log.shift(), `set vom.o+2/1 ${zotVal(23, 'Alice', 'is this on?', 3)}`); // evict z1-3 + t.is(log.shift(), `get vom.o+2/4 => ${zotVal(66, 'Dave', 'you and what army?', 1)}`); // load z4-1 t.deepEqual(log, []); // z4-2: 66 'Dave' 'you and what army?' 2 t.is(thing3.inc(), 201); // [t3-1 z4-2 z3-3 t2-0] evict z2-2 - t.is(log.shift(), `set o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 2)}`); // evict z2-2 - t.is(log.shift(), `get o+1/3 => ${thingVal(200, 'thing-3', 0)}`); // load t3-0 + t.is(log.shift(), `set vom.o+2/2 ${zotVal(29, 'Bob', 'what are you saying?', 2)}`); // evict z2-2 + t.is(log.shift(), `get vom.o+1/3 => ${thingVal(200, 'thing-3', 0)}`); // load t3-0 t.deepEqual(log, []); // t3-1: 'thing-3' 201 0 @@ -257,43 +257,43 @@ test('virtual object operations', t => { 'thing-4 counter has been reset 1 times and is now 1000', ); // evict t2-0 does nothing because t2 is not dirty - t.is(log.shift(), `get o+1/4 => ${thingVal(1000, 'thing-4', 1)}`); // load t4-1 + t.is(log.shift(), `get vom.o+1/4 => ${thingVal(1000, 'thing-4', 1)}`); // load t4-1 t.deepEqual(log, []); t.deepEqual(dumpStore(), [ - ['o+1/1', thingVal(4, 'thing-1', 0)], // =t1-4 - ['o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 - ['o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 - ['o+1/4', thingVal(1000, 'thing-4', 1)], // =t4-1 - ['o+2/1', zotVal(23, 'Alice', 'is this on?', 3)], // =z1-3 - ['o+2/2', zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 - ['o+2/3', zotVal(47, 'Carol', 'as if...', 1)], // =z3-1 - ['o+2/4', zotVal(66, 'Dave', 'you and what army?', 1)], // =z4-1 + ['vom.o+1/1', thingVal(4, 'thing-1', 0)], // =t1-4 + ['vom.o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 + ['vom.o+1/3', thingVal(200, 'thing-3', 0)], // =t3-0 + ['vom.o+1/4', thingVal(1000, 'thing-4', 1)], // =t4-1 + ['vom.o+2/1', zotVal(23, 'Alice', 'is this on?', 3)], // =z1-3 + ['vom.o+2/2', zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 + ['vom.o+2/3', zotVal(47, 'Carol', 'as if...', 1)], // =z3-1 + ['vom.o+2/4', zotVal(66, 'Dave', 'you and what army?', 1)], // =z4-1 ]); // phase 4: flush test t.is(thing1.inc(), 5); // [t1-5 t4-1 t3-1 z4-2] evict z3-3 - t.is(log.shift(), `set o+2/3 ${zotVal(47, 'Chester', 'as if...', 3)}`); // evict z3-3 - t.is(log.shift(), `get o+1/1 => ${thingVal(4, 'thing-1', 0)}`); // load t1-4 + t.is(log.shift(), `set vom.o+2/3 ${zotVal(47, 'Chester', 'as if...', 3)}`); // evict z3-3 + t.is(log.shift(), `get vom.o+1/1 => ${thingVal(4, 'thing-1', 0)}`); // load t1-4 t.deepEqual(log, []); // t1-5: 'thing-1' 5 0 flushCache(); // [] evict z4-2 t3-1 t4-1 t1-5 - t.is(log.shift(), `set o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 2)}`); // evict z4-2 - t.is(log.shift(), `set o+1/3 ${thingVal(201, 'thing-3', 0)}`); // evict t3-1 + t.is(log.shift(), `set vom.o+2/4 ${zotVal(66, 'Dave', 'you and what army?', 2)}`); // evict z4-2 + t.is(log.shift(), `set vom.o+1/3 ${thingVal(201, 'thing-3', 0)}`); // evict t3-1 // evict t4-1 does nothing because t4 is not dirty - t.is(log.shift(), `set o+1/1 ${thingVal(5, 'thing-1', 0)}`); // evict t1-5 + t.is(log.shift(), `set vom.o+1/1 ${thingVal(5, 'thing-1', 0)}`); // evict t1-5 t.deepEqual(log, []); t.deepEqual(dumpStore(), [ - ['o+1/1', thingVal(5, 'thing-1', 0)], // =t1-5 - ['o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 - ['o+1/3', thingVal(201, 'thing-3', 0)], // =t3-1 - ['o+1/4', thingVal(1000, 'thing-4', 1)], // =t4-1 - ['o+2/1', zotVal(23, 'Alice', 'is this on?', 3)], // =z1-3 - ['o+2/2', zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 - ['o+2/3', zotVal(47, 'Chester', 'as if...', 3)], // =z3-3 - ['o+2/4', zotVal(66, 'Dave', 'you and what army?', 2)], // =z4-2 + ['vom.o+1/1', thingVal(5, 'thing-1', 0)], // =t1-5 + ['vom.o+1/2', thingVal(100, 'thing-2', 0)], // =t2-0 + ['vom.o+1/3', thingVal(201, 'thing-3', 0)], // =t3-1 + ['vom.o+1/4', thingVal(1000, 'thing-4', 1)], // =t4-1 + ['vom.o+2/1', zotVal(23, 'Alice', 'is this on?', 3)], // =z1-3 + ['vom.o+2/2', zotVal(29, 'Bob', 'what are you saying?', 2)], // =z2-2 + ['vom.o+2/3', zotVal(47, 'Chester', 'as if...', 3)], // =z3-3 + ['vom.o+2/4', zotVal(66, 'Dave', 'you and what army?', 2)], // =z4-2 ]); });