From 7c0240402a52ca82c948d9a0b9730824a84b4951 Mon Sep 17 00:00:00 2001 From: Chip Morningstar Date: Tue, 31 May 2022 14:24:09 -0700 Subject: [PATCH] feat: add fakeDurable option to assist durability conversion Closes #5454 --- .../src/liveslots/collectionManager.js | 56 ++++- .../src/liveslots/virtualObjectManager.js | 16 +- .../src/liveslots/virtualReferences.js | 11 +- .../test/stores/test-durabilityChecks.js | 202 +++++++++++++++++- packages/store/src/types.js | 8 + 5 files changed, 286 insertions(+), 7 deletions(-) diff --git a/packages/SwingSet/src/liveslots/collectionManager.js b/packages/SwingSet/src/liveslots/collectionManager.js index 52cd31f0862..a1903173eb0 100644 --- a/packages/SwingSet/src/liveslots/collectionManager.js +++ b/packages/SwingSet/src/liveslots/collectionManager.js @@ -792,8 +792,17 @@ export function makeCollectionManager( */ function makeScalarBigMapStore( label = 'map', - { keySchema = M.scalar(), valueSchema = undefined, durable = false } = {}, + { + keySchema = M.scalar(), + valueSchema = undefined, + durable = false, + fakeDurable = false, + } = {}, ) { + assert( + !durable || !fakeDurable, + 'durable and fakeDurable are mutually exclusive', + ); const kindName = durable ? 'scalarDurableMapStore' : 'scalarMapStore'; const [vobjID, collection] = makeCollection( label, @@ -803,6 +812,9 @@ export function makeCollectionManager( ); const store = collectionToMapStore(collection); registerValue(vobjID, store, false); + if (fakeDurable) { + vrm.registerFakeDurable(vobjID); + } return store; } @@ -834,8 +846,17 @@ export function makeCollectionManager( */ function makeScalarBigWeakMapStore( label = 'weakMap', - { keySchema = M.scalar(), valueSchema = undefined, durable = false } = {}, + { + keySchema = M.scalar(), + valueSchema = undefined, + durable = false, + fakeDurable = false, + } = {}, ) { + assert( + !durable || !fakeDurable, + 'durable and fakeDurable are mutually exclusive', + ); const kindName = durable ? 'scalarDurableWeakMapStore' : 'scalarWeakMapStore'; @@ -847,6 +868,9 @@ export function makeCollectionManager( ); const store = collectionToWeakMapStore(collection); registerValue(vobjID, store, false); + if (fakeDurable) { + vrm.registerFakeDurable(vobjID); + } return store; } @@ -861,8 +885,17 @@ export function makeCollectionManager( */ function makeScalarBigSetStore( label = 'set', - { keySchema = M.scalar(), valueSchema = undefined, durable = false } = {}, + { + keySchema = M.scalar(), + valueSchema = undefined, + durable = false, + fakeDurable = false, + } = {}, ) { + assert( + !durable || !fakeDurable, + 'durable and fakeDurable are mutually exclusive', + ); const kindName = durable ? 'scalarDurableSetStore' : 'scalarSetStore'; const [vobjID, collection] = makeCollection( label, @@ -872,6 +905,9 @@ export function makeCollectionManager( ); const store = collectionToSetStore(collection); registerValue(vobjID, store, false); + if (fakeDurable) { + vrm.registerFakeDurable(vobjID); + } return store; } @@ -886,8 +922,17 @@ export function makeCollectionManager( */ function makeScalarBigWeakSetStore( label = 'weakSet', - { keySchema = M.scalar(), valueSchema = undefined, durable = false } = {}, + { + keySchema = M.scalar(), + valueSchema = undefined, + durable = false, + fakeDurable = false, + } = {}, ) { + assert( + !durable || !fakeDurable, + 'durable and fakeDurable are mutually exclusive', + ); const kindName = durable ? 'scalarDurableWeakSetStore' : 'scalarWeakSetStore'; @@ -899,6 +944,9 @@ export function makeCollectionManager( ); const store = collectionToWeakSetStore(collection); registerValue(vobjID, store, false); + if (fakeDurable) { + vrm.registerFakeDurable(vobjID); + } return store; } diff --git a/packages/SwingSet/src/liveslots/virtualObjectManager.js b/packages/SwingSet/src/liveslots/virtualObjectManager.js index 0de7eb4771c..65616c9d997 100644 --- a/packages/SwingSet/src/liveslots/virtualObjectManager.js +++ b/packages/SwingSet/src/liveslots/virtualObjectManager.js @@ -572,7 +572,18 @@ export function makeVirtualObjectManager( options, durable, ) { - const finish = options ? options.finish : undefined; + let finish; + let fakeDurable; + if (options) { + ({ finish, fakeDurable } = options); + } + if (fakeDurable) { + assert( + durable, + `the fakeDurable option may only be applied to durable objects`, + ); + durable = false; + } let nextInstanceID = 1; let facetNames; let behaviorTemplate; @@ -742,6 +753,9 @@ export function makeVirtualObjectManager( } } cache.markDirty(innerSelf); + if (fakeDurable) { + vrm.registerFakeDurable(baseRef); + } return toExpose; } diff --git a/packages/SwingSet/src/liveslots/virtualReferences.js b/packages/SwingSet/src/liveslots/virtualReferences.js index f2b346733ec..158492694b5 100644 --- a/packages/SwingSet/src/liveslots/virtualReferences.js +++ b/packages/SwingSet/src/liveslots/virtualReferences.js @@ -243,6 +243,11 @@ export function makeVirtualReferenceManager( return durable; } + const fakeDurables = new Set(); + function registerFakeDurable(vref) { + fakeDurables.add(vref); + } + /** * Inquire if a given vref is something that can be stored in a durable store * or virtual object. @@ -252,7 +257,10 @@ export function makeVirtualReferenceManager( * @returns {boolean} true if the indicated object reference is durable. */ function isDurable(vref) { - const { type, id, virtual, allocatedByVat } = parseVatSlot(vref); + const { type, id, virtual, allocatedByVat, baseRef } = parseVatSlot(vref); + if (fakeDurables.has(baseRef)) { + return true; + } if (type !== 'object') { // promises and devices are not durable return false; @@ -619,6 +627,7 @@ export function makeVirtualReferenceManager( isDurable, isDurableKind, registerKind, + registerFakeDurable, rememberFacetNames, reanimate, addReachableVref, diff --git a/packages/SwingSet/test/stores/test-durabilityChecks.js b/packages/SwingSet/test/stores/test-durabilityChecks.js index c58b8985992..590b9df5d56 100644 --- a/packages/SwingSet/test/stores/test-durabilityChecks.js +++ b/packages/SwingSet/test/stores/test-durabilityChecks.js @@ -6,11 +6,17 @@ import { makeFakeVirtualStuff } from '../../tools/fakeVirtualSupport.js'; const { vom, cm } = makeFakeVirtualStuff({ cacheSize: 3 }); -const { makeScalarBigMapStore, makeScalarBigSetStore } = cm; +const { + makeScalarBigMapStore, + makeScalarBigWeakMapStore, + makeScalarBigSetStore, + makeScalarBigWeakSetStore, +} = cm; const { defineKind, defineDurableKind, makeKindHandle } = vom; const durableHolderKind = makeKindHandle('holder'); +const fakeDurableHolderKind = makeKindHandle('fholder'); const initHolder = (held = null) => ({ held }); const holderBehavior = { @@ -25,10 +31,17 @@ const makeDurableHolder = defineDurableKind( initHolder, holderBehavior, ); +const makeFakeDurableHolder = defineDurableKind( + fakeDurableHolderKind, + initHolder, + holderBehavior, + { fakeDurable: true }, +); const aString = 'zorch!'; const aVirtualObject = makeVirtualHolder(); const aDurableObject = makeDurableHolder(); +const aFakeDurableObject = makeFakeDurableHolder(); const aRemotableObject = Far('what', { aMethod() { return 'remote whatever'; @@ -41,36 +54,51 @@ const aNonScalarNonKey = harden([aPassableError]); const aVirtualStore = makeScalarBigMapStore('vstore'); const aDurableStore = makeScalarBigMapStore('dstore', { durable: true }); +const aFakeDurableStore = makeScalarBigMapStore('fdstore', { + fakeDurable: true, +}); const anObjectFullOfVirtualStuff = harden({ aString, aVirtualObject, aDurableObject, + aFakeDurableObject, aRemotableObject, aVirtualStore, aDurableStore, + aFakeDurableStore, durableHolderKind, + fakeDurableHolderKind, }); const anObjectFullOfDurableStuff = harden({ aString, aDurableObject, + aFakeDurableObject, aDurableStore, + aFakeDurableStore, durableHolderKind, + fakeDurableHolderKind, }); const anArrayFullOfVirtualStuff = harden([ aString, aVirtualObject, aDurableObject, + aFakeDurableObject, aRemotableObject, aVirtualStore, aDurableStore, + aFakeDurableStore, durableHolderKind, + fakeDurableHolderKind, ]); const anArrayFullOfDurableStuff = harden([ aString, aDurableObject, + aFakeDurableObject, aDurableStore, + aFakeDurableStore, durableHolderKind, + fakeDurableHolderKind, ]); function m(s) { @@ -90,6 +118,7 @@ test('durability checks', t => { const virtualMap = makeScalarBigMapStore('vmap'); const durableMap = makeScalarBigMapStore('dmap', { durable: true }); + const fakeDurableMap = makeScalarBigMapStore('fdmap', { fakeDurable: true }); passKey(() => virtualMap.init(aString, 'simple string key')); passKey(() => virtualMap.set(aString, 'revise string key')); @@ -97,147 +126,285 @@ test('durability checks', t => { passKey(() => virtualMap.set(aVirtualObject, 'revise virtual object key')); passKey(() => virtualMap.init(aDurableObject, 'durable object as key')); passKey(() => virtualMap.set(aDurableObject, 'revise durable object key')); + passKey(() => virtualMap.init(aFakeDurableObject, 'fake durable object as key')); + passKey(() => virtualMap.set(aFakeDurableObject, 'revise fake durable object key')); passKey(() => virtualMap.init(aRemotableObject, 'remotable object as key')); passKey(() => virtualMap.set(aRemotableObject, 'revise remotable object key')); passKey(() => virtualMap.init(aVirtualStore, 'virtual store as key')); passKey(() => virtualMap.set(aVirtualStore, 'revise virtual store key')); passKey(() => virtualMap.init(aDurableStore, 'durable store as key')); passKey(() => virtualMap.set(aDurableStore, 'revise durable store key')); + passKey(() => virtualMap.init(aFakeDurableStore, 'fake durable store as key')); + passKey(() => virtualMap.set(aFakeDurableStore, 'revise fake durable store key')); passKey(() => virtualMap.init(durableHolderKind, 'durable kind as key')); passKey(() => virtualMap.set(durableHolderKind, 'revise durable kind key')); + passKey(() => virtualMap.init(fakeDurableHolderKind, 'fake durable kind as key')); + passKey(() => virtualMap.set(fakeDurableHolderKind, 'revise fake durable kind key')); passKey(() => virtualMap.init('simple string value', aString)); passKey(() => virtualMap.init('virtual object value', aVirtualObject)); passKey(() => virtualMap.init('durable object value', aDurableObject)); + passKey(() => virtualMap.init('fake durable object value', aFakeDurableObject)); passKey(() => virtualMap.init('remotable object value', aRemotableObject)); passKey(() => virtualMap.init('virtual store value', aVirtualStore)); passKey(() => virtualMap.init('durable store value', aDurableStore)); + passKey(() => virtualMap.init('fake durable store value', aFakeDurableStore)); passKey(() => virtualMap.init('object full of virtual stuff', anObjectFullOfVirtualStuff)); passKey(() => virtualMap.init('array full of virtual stuff', anArrayFullOfVirtualStuff)); passKey(() => virtualMap.init('object full of durable stuff', anObjectFullOfDurableStuff)); passKey(() => virtualMap.init('array full of durable stuff', anArrayFullOfDurableStuff)); passKey(() => virtualMap.init('durable kind', durableHolderKind)); + passKey(() => virtualMap.init('fake durable kind', fakeDurableHolderKind)); passKey(() => virtualMap.init('changeme', 47)); passKey(() => virtualMap.set('changeme', aString)); passKey(() => virtualMap.set('changeme', aVirtualObject)); passKey(() => virtualMap.set('changeme', aDurableObject)); + passKey(() => virtualMap.set('changeme', aFakeDurableObject)); passKey(() => virtualMap.set('changeme', aRemotableObject)); passKey(() => virtualMap.set('changeme', aVirtualStore)); passKey(() => virtualMap.set('changeme', aDurableStore)); + passKey(() => virtualMap.set('changeme', aFakeDurableStore)); passKey(() => virtualMap.set('changeme', anObjectFullOfVirtualStuff)); passKey(() => virtualMap.set('changeme', anArrayFullOfVirtualStuff)); passKey(() => virtualMap.set('changeme', anObjectFullOfDurableStuff)); passKey(() => virtualMap.set('changeme', anArrayFullOfDurableStuff)); passKey(() => virtualMap.set('changeme', durableHolderKind)); + passKey(() => virtualMap.set('changeme', fakeDurableHolderKind)); passKey(() => durableMap.init(aString, 'simple string key')); passKey(() => durableMap.set(aString, 'revise string key')); failKey(() => durableMap.init(aVirtualObject, 'virtual object as key')); passKey(() => durableMap.init(aDurableObject, 'durable object as key')); passKey(() => durableMap.set(aDurableObject, 'revise durable object key')); + passKey(() => durableMap.init(aFakeDurableObject, 'fake durable object as key')); + passKey(() => durableMap.set(aFakeDurableObject, 'revise fake durable object key')); failKey(() => durableMap.init(aRemotableObject, 'remotable object as key')); failKey(() => durableMap.init(aVirtualStore, 'virtual store as key')); passKey(() => durableMap.init(aDurableStore, 'durable store as key')); passKey(() => durableMap.set(aDurableStore, 'revise durable store key')); + passKey(() => durableMap.init(aFakeDurableStore, 'fake durable store as key')); + passKey(() => durableMap.set(aFakeDurableStore, 'revise fake durable store key')); passKey(() => durableMap.init(durableHolderKind, 'durable kind as key')); passKey(() => durableMap.set(durableHolderKind, 'revise durable kind key')); + passKey(() => durableMap.init(fakeDurableHolderKind, 'fake durable kind as key')); + passKey(() => durableMap.set(fakeDurableHolderKind, 'revise fake durable kind key')); passVal(() => durableMap.init('simple string value', aString)); failVal(() => durableMap.init('virtual object value', aVirtualObject)); passVal(() => durableMap.init('durable object value', aDurableObject)); + passVal(() => durableMap.init('fake durable object value', aFakeDurableObject)); failVal(() => durableMap.init('remotable object value', aRemotableObject)); failVal(() => durableMap.init('virtual store value', aVirtualStore)); passVal(() => durableMap.init('durable store value', aDurableStore)); + passVal(() => durableMap.init('fake durable store value', aFakeDurableStore)); failVal(() => durableMap.init('object full of virtual stuff', anObjectFullOfVirtualStuff)); failVal(() => durableMap.init('array full of virtual stuff', anArrayFullOfVirtualStuff)); passVal(() => durableMap.init('object full of durable stuff', anObjectFullOfDurableStuff)); passVal(() => durableMap.init('array full of durable stuff', anArrayFullOfDurableStuff)); passVal(() => durableMap.init('durable kind', durableHolderKind)); + passVal(() => durableMap.init('fake durable kind', fakeDurableHolderKind)); passVal(() => durableMap.init('changeme', 47)); passVal(() => durableMap.set('changeme', aString)); failVal(() => durableMap.set('changeme', aVirtualObject)); passVal(() => durableMap.set('changeme', aDurableObject)); + passVal(() => durableMap.set('changeme', aFakeDurableObject)); failVal(() => durableMap.set('changeme', aRemotableObject)); failVal(() => durableMap.set('changeme', aVirtualStore)); passVal(() => durableMap.set('changeme', aDurableStore)); + passVal(() => durableMap.set('changeme', aFakeDurableStore)); failVal(() => durableMap.set('changeme', anObjectFullOfVirtualStuff)); failVal(() => durableMap.set('changeme', anArrayFullOfVirtualStuff)); passVal(() => durableMap.set('changeme', anObjectFullOfDurableStuff)); passVal(() => durableMap.set('changeme', anArrayFullOfDurableStuff)); passVal(() => durableMap.set('changeme', durableHolderKind)); + passVal(() => durableMap.set('changeme', fakeDurableHolderKind)); + + passKey(() => fakeDurableMap.init(aString, 'simple string key')); + passKey(() => fakeDurableMap.set(aString, 'revise string key')); + passKey(() => fakeDurableMap.init(aVirtualObject, 'virtual object as key')); + passKey(() => fakeDurableMap.set(aVirtualObject, 'revise virtual object key')); + passKey(() => fakeDurableMap.init(aDurableObject, 'durable object as key')); + passKey(() => fakeDurableMap.set(aDurableObject, 'revise durable object key')); + passKey(() => fakeDurableMap.init(aFakeDurableObject, 'fake durable object as key')); + passKey(() => fakeDurableMap.set(aFakeDurableObject, 'revise fake durable object key')); + passKey(() => fakeDurableMap.init(aRemotableObject, 'remotable object as key')); + passKey(() => fakeDurableMap.set(aRemotableObject, 'revise remotable object key')); + passKey(() => fakeDurableMap.init(aVirtualStore, 'virtual store as key')); + passKey(() => fakeDurableMap.set(aVirtualStore, 'revise virtual store key')); + passKey(() => fakeDurableMap.init(aDurableStore, 'durable store as key')); + passKey(() => fakeDurableMap.set(aDurableStore, 'revise durable store key')); + passKey(() => fakeDurableMap.init(aFakeDurableStore, 'fake durable store as key')); + passKey(() => fakeDurableMap.set(aFakeDurableStore, 'revise fake durable store key')); + passKey(() => fakeDurableMap.init(durableHolderKind, 'durable kind as key')); + passKey(() => fakeDurableMap.set(durableHolderKind, 'revise durable kind key')); + passKey(() => fakeDurableMap.init(fakeDurableHolderKind, 'fake durable kind as key')); + passKey(() => fakeDurableMap.set(fakeDurableHolderKind, 'revise fake durable kind key')); + + passKey(() => fakeDurableMap.init('simple string value', aString)); + passKey(() => fakeDurableMap.init('virtual object value', aVirtualObject)); + passKey(() => fakeDurableMap.init('durable object value', aDurableObject)); + passKey(() => fakeDurableMap.init('fake durable object value', aFakeDurableObject)); + passKey(() => fakeDurableMap.init('remotable object value', aRemotableObject)); + passKey(() => fakeDurableMap.init('virtual store value', aVirtualStore)); + passKey(() => fakeDurableMap.init('durable store value', aDurableStore)); + passKey(() => fakeDurableMap.init('fake durable store value', aFakeDurableStore)); + passKey(() => fakeDurableMap.init('object full of virtual stuff', anObjectFullOfVirtualStuff)); + passKey(() => fakeDurableMap.init('array full of virtual stuff', anArrayFullOfVirtualStuff)); + passKey(() => fakeDurableMap.init('object full of durable stuff', anObjectFullOfDurableStuff)); + passKey(() => fakeDurableMap.init('array full of durable stuff', anArrayFullOfDurableStuff)); + passKey(() => fakeDurableMap.init('durable kind', durableHolderKind)); + passKey(() => fakeDurableMap.init('fake durable kind', fakeDurableHolderKind)); + + passKey(() => fakeDurableMap.init('changeme', 47)); + passKey(() => fakeDurableMap.set('changeme', aString)); + passKey(() => fakeDurableMap.set('changeme', aVirtualObject)); + passKey(() => fakeDurableMap.set('changeme', aDurableObject)); + passKey(() => fakeDurableMap.set('changeme', aFakeDurableObject)); + passKey(() => fakeDurableMap.set('changeme', aRemotableObject)); + passKey(() => fakeDurableMap.set('changeme', aVirtualStore)); + passKey(() => fakeDurableMap.set('changeme', aDurableStore)); + passKey(() => fakeDurableMap.set('changeme', aFakeDurableStore)); + passKey(() => fakeDurableMap.set('changeme', anObjectFullOfVirtualStuff)); + passKey(() => fakeDurableMap.set('changeme', anArrayFullOfVirtualStuff)); + passKey(() => fakeDurableMap.set('changeme', anObjectFullOfDurableStuff)); + passKey(() => fakeDurableMap.set('changeme', anArrayFullOfDurableStuff)); + passKey(() => fakeDurableMap.set('changeme', durableHolderKind)); + passKey(() => fakeDurableMap.set('changeme', fakeDurableHolderKind)); const virtualSet = makeScalarBigSetStore('vset'); const durableSet = makeScalarBigSetStore('dset', { durable: true }); + const fakeDurableSet = makeScalarBigSetStore('fdset', { fakeDurable: true }); passKey(() => virtualSet.add(aString)); passKey(() => virtualSet.add(aVirtualObject)); passKey(() => virtualSet.add(aDurableObject)); + passKey(() => virtualSet.add(aFakeDurableObject)); passKey(() => virtualSet.add(aRemotableObject)); passKey(() => virtualSet.add(aVirtualStore)); passKey(() => virtualSet.add(aDurableStore)); + passKey(() => virtualSet.add(aFakeDurableStore)); passKey(() => virtualSet.add(durableHolderKind)); + passKey(() => virtualSet.add(fakeDurableHolderKind)); passKey(() => durableSet.add(aString)); failKey(() => durableSet.add(aVirtualObject)); passKey(() => durableSet.add(aDurableObject)); + passKey(() => durableSet.add(aFakeDurableObject)); failKey(() => durableSet.add(aRemotableObject)); failKey(() => durableSet.add(aVirtualStore)); passKey(() => durableSet.add(aDurableStore)); + passKey(() => durableSet.add(aFakeDurableStore)); passKey(() => durableSet.add(durableHolderKind)); + passKey(() => durableSet.add(fakeDurableHolderKind)); + + passKey(() => fakeDurableSet.add(aString)); + passKey(() => fakeDurableSet.add(aVirtualObject)); + passKey(() => fakeDurableSet.add(aDurableObject)); + passKey(() => fakeDurableSet.add(aFakeDurableObject)); + passKey(() => fakeDurableSet.add(aRemotableObject)); + passKey(() => fakeDurableSet.add(aVirtualStore)); + passKey(() => fakeDurableSet.add(aDurableStore)); + passKey(() => fakeDurableSet.add(aFakeDurableStore)); + passKey(() => fakeDurableSet.add(durableHolderKind)); + passKey(() => fakeDurableSet.add(fakeDurableHolderKind)); const virtualHolder = makeVirtualHolder(); passHold(() => makeVirtualHolder(aString)); passHold(() => makeVirtualHolder(aVirtualObject)); passHold(() => makeVirtualHolder(aDurableObject)); + passHold(() => makeVirtualHolder(aFakeDurableObject)); passHold(() => makeVirtualHolder(aRemotableObject)); passHold(() => makeVirtualHolder(aVirtualStore)); passHold(() => makeVirtualHolder(aDurableStore)); + passHold(() => makeVirtualHolder(aFakeDurableStore)); passHold(() => makeVirtualHolder(anObjectFullOfVirtualStuff)); passHold(() => makeVirtualHolder(anArrayFullOfVirtualStuff)); passHold(() => makeVirtualHolder(anObjectFullOfDurableStuff)); passHold(() => makeVirtualHolder(anArrayFullOfDurableStuff)); passHold(() => makeVirtualHolder(durableHolderKind)); + passHold(() => makeVirtualHolder(fakeDurableHolderKind)); passHold(() => virtualHolder.hold(aString)); passHold(() => virtualHolder.hold(aVirtualObject)); passHold(() => virtualHolder.hold(aDurableObject)); + passHold(() => virtualHolder.hold(aFakeDurableObject)); passHold(() => virtualHolder.hold(aRemotableObject)); passHold(() => virtualHolder.hold(aVirtualStore)); passHold(() => virtualHolder.hold(aDurableStore)); + passHold(() => virtualHolder.hold(aFakeDurableStore)); passHold(() => virtualHolder.hold(anObjectFullOfVirtualStuff)); passHold(() => virtualHolder.hold(anArrayFullOfVirtualStuff)); passHold(() => virtualHolder.hold(anObjectFullOfDurableStuff)); passHold(() => virtualHolder.hold(anArrayFullOfDurableStuff)); passHold(() => virtualHolder.hold(durableHolderKind)); + passHold(() => virtualHolder.hold(fakeDurableHolderKind)); const durableHolder = makeDurableHolder(); passHold(() => makeDurableHolder(aString)); failHold(() => makeDurableHolder(aVirtualObject)); passHold(() => makeDurableHolder(aDurableObject)); + passHold(() => makeDurableHolder(aFakeDurableObject)); failHold(() => makeDurableHolder(aRemotableObject)); failHold(() => makeDurableHolder(aVirtualStore)); passHold(() => makeDurableHolder(aDurableStore)); + passHold(() => makeDurableHolder(aFakeDurableStore)); failHold(() => makeDurableHolder(anObjectFullOfVirtualStuff)); failHold(() => makeDurableHolder(anArrayFullOfVirtualStuff)); passHold(() => makeDurableHolder(anObjectFullOfDurableStuff)); passHold(() => makeDurableHolder(anArrayFullOfDurableStuff)); passHold(() => makeDurableHolder(durableHolderKind)); + passHold(() => makeDurableHolder(fakeDurableHolderKind)); passHold(() => durableHolder.hold(aString)); failHold(() => durableHolder.hold(aVirtualObject)); passHold(() => durableHolder.hold(aDurableObject)); + passHold(() => durableHolder.hold(aFakeDurableObject)); failHold(() => durableHolder.hold(aRemotableObject)); failHold(() => durableHolder.hold(aVirtualStore)); passHold(() => durableHolder.hold(aDurableStore)); + passHold(() => durableHolder.hold(aFakeDurableStore)); failHold(() => durableHolder.hold(anObjectFullOfVirtualStuff)); failHold(() => durableHolder.hold(anArrayFullOfVirtualStuff)); passHold(() => durableHolder.hold(anObjectFullOfDurableStuff)); passHold(() => durableHolder.hold(anArrayFullOfDurableStuff)); passHold(() => durableHolder.hold(durableHolderKind)); + passHold(() => durableHolder.hold(fakeDurableHolderKind)); + + const fakeDurableHolder = makeFakeDurableHolder(); + + passHold(() => makeFakeDurableHolder(aString)); + passHold(() => makeFakeDurableHolder(aVirtualObject)); + passHold(() => makeFakeDurableHolder(aDurableObject)); + passHold(() => makeFakeDurableHolder(aFakeDurableObject)); + passHold(() => makeFakeDurableHolder(aRemotableObject)); + passHold(() => makeFakeDurableHolder(aVirtualStore)); + passHold(() => makeFakeDurableHolder(aDurableStore)); + passHold(() => makeFakeDurableHolder(aFakeDurableStore)); + passHold(() => makeFakeDurableHolder(anObjectFullOfVirtualStuff)); + passHold(() => makeFakeDurableHolder(anArrayFullOfVirtualStuff)); + passHold(() => makeFakeDurableHolder(anObjectFullOfDurableStuff)); + passHold(() => makeFakeDurableHolder(anArrayFullOfDurableStuff)); + passHold(() => makeFakeDurableHolder(durableHolderKind)); + passHold(() => makeFakeDurableHolder(fakeDurableHolderKind)); + + passHold(() => fakeDurableHolder.hold(aString)); + passHold(() => fakeDurableHolder.hold(aVirtualObject)); + passHold(() => fakeDurableHolder.hold(aDurableObject)); + passHold(() => fakeDurableHolder.hold(aFakeDurableObject)); + passHold(() => fakeDurableHolder.hold(aRemotableObject)); + passHold(() => fakeDurableHolder.hold(aVirtualStore)); + passHold(() => fakeDurableHolder.hold(aDurableStore)); + passHold(() => fakeDurableHolder.hold(aFakeDurableStore)); + passHold(() => fakeDurableHolder.hold(anObjectFullOfVirtualStuff)); + passHold(() => fakeDurableHolder.hold(anArrayFullOfVirtualStuff)); + passHold(() => fakeDurableHolder.hold(anObjectFullOfDurableStuff)); + passHold(() => fakeDurableHolder.hold(anArrayFullOfDurableStuff)); + passHold(() => fakeDurableHolder.hold(durableHolderKind)); + passHold(() => fakeDurableHolder.hold(fakeDurableHolderKind)); failNonKey(() => virtualMap.init(aPassablePromise, 47)); failNonKey(() => virtualMap.init(aPassableError, 47)); @@ -249,6 +416,11 @@ test('durability checks', t => { failNonKey(() => durableMap.init(aNonScalarKey, 47)); failNonKey(() => durableMap.init(aNonScalarNonKey, 47)); + failNonKey(() => fakeDurableMap.init(aPassablePromise, 47)); + failNonKey(() => fakeDurableMap.init(aPassableError, 47)); + failNonKey(() => fakeDurableMap.init(aNonScalarKey, 47)); + failNonKey(() => fakeDurableMap.init(aNonScalarNonKey, 47)); + passVal(() => virtualMap.init('promise', aPassablePromise)); passVal(() => virtualMap.init('error', aPassableError)); passVal(() => virtualMap.init('non-scalar key', aNonScalarKey)); @@ -258,4 +430,32 @@ test('durability checks', t => { passVal(() => durableMap.init('error', aPassableError)); passVal(() => durableMap.init('non-scalar key', aNonScalarKey)); passVal(() => durableMap.init('non-scalar non-key', aNonScalarNonKey)); + + passVal(() => fakeDurableMap.init('promise', aPassablePromise)); + passVal(() => fakeDurableMap.init('error', aPassableError)); + passVal(() => fakeDurableMap.init('non-scalar key', aNonScalarKey)); + passVal(() => fakeDurableMap.init('non-scalar non-key', aNonScalarNonKey)); +}); + +test('fake durability flag sanity', t => { + const badOpts = { durable: true, fakeDurable: true }; + t.throws(() => makeScalarBigMapStore('badflag1', badOpts), { + message: 'durable and fakeDurable are mutually exclusive', + }); + t.throws(() => makeScalarBigWeakMapStore('badflag2', badOpts), { + message: 'durable and fakeDurable are mutually exclusive', + }); + t.throws(() => makeScalarBigSetStore('badflag3', badOpts), { + message: 'durable and fakeDurable are mutually exclusive', + }); + t.throws(() => makeScalarBigWeakSetStore('badflag4', badOpts), { + message: 'durable and fakeDurable are mutually exclusive', + }); + t.throws( + () => + defineKind('badflag5', initHolder, holderBehavior, { fakeDurable: true }), + { + message: 'the fakeDurable option may only be applied to durable objects', + }, + ); }); diff --git a/packages/store/src/types.js b/packages/store/src/types.js index 41709482cca..90551ba0c54 100644 --- a/packages/store/src/types.js +++ b/packages/store/src/types.js @@ -105,6 +105,14 @@ * @property {boolean=} durable The contents of this store survive termination * of its containing process, allowing for restart or upgrade but at the cost * of forbidding storage of references to ephemeral data. Defaults to false. + * @property {boolean=} fakeDurable This store pretends to be a durable store + * but does not enforce that the things stored in it actually be themselves + * durable (whereas an actual durable store would forbid storage of such + * items). This is in service of allowing incremental transition to use of + * durable stores, to enable normal operation and testing when some stuff + * intended to eventually be durable has not yet been made durable. A store + * marked as fakeDurable will appear to operate normally but any attempt to + * upgrade its containing vat will fail with an error. * @property {Pattern=} keySchema * @property {Pattern=} valueSchema */