UNPKG

@metamask/ocap-kernel

Version:
213 lines 9.74 kB
/* * Organization of keys in the key value store: * * Definitions * NN ::= some decimal integer * CAPDATA ::= capdata encoded structure value * JSON(${xx}) ::= JSON encoding of ${xx} * * ${koid} ::= ko${NN} // kernel object ID * ${kpid} ::= kp${NN} // kernel promise ID * ${kref} ::= ${koid} | ${kpid} // kernel reference * ${dir} ::= + | - // direction (for remote and vat references) * ${roid} ::= ro${dir}${NN} // remote object ID * ${rpid} ::= rp${dir}${NN} // remote promise ID * ${rref} ::= ${roid} | ${rpid} // remote reference * ${void} ::= o${dir}${NN} // vat object ID * ${vpid} ::= p${dir}${NN} // vat promise ID * ${vref} ::= ${void} | ${vpid} // vat reference * ${eref} ::= ${vref} | ${rref} // external reference * ${vatid} ::= v${NN} // vat ID * ${remid} ::= r${NN} // remote ID * ${endid} ::= ${vatid} | ${remid} // endpoint ID * ${queueName} ::= run | ${kpid} * * Queues * queue.${queueName}.head = NN // queue head index * queue.${queueName}.tail = NN // queue tail index * queue.${queueName}.${NN} = JSON(CAPDATA) // queue entry #NN * * Kernel objects * ${koid}.refCount = NN // reference count * ${koid}.owner = ${vatid} // owner (where the object is) * * Kernel promises * ${kpid}.refCount = NN // reference count * ${kpid}.state = unresolved | fulfilled | rejected // current state of settlement * ${kpid}.subscribers = JSON([${endid}]) // array of who is waiting for settlement * ${kpid}.decider = ${endid} // who decides on settlement * ${kpid}.value = JSON(CAPDATA) // value settled to, if settled * * C-lists * cle.${endid}.${eref} = ${kref} // ERef->KRef mapping * clk.${endid}.${kref} = ${eref} // KRef->ERef mapping * * Vat bookkeeping * e.nextObjectId.${endid} = NN // allocation counter for imported object ERefs * e.nextPromiseId.${endid} = NN // allocation counter for imported promise ERefs * vatConfig.${vatid} = JSON(CONFIG) // vat's configuration object * * Kernel bookkeeping * initialized = true // if set, indicates the store has been initialized * nextVatId = NN // allocation counter for vat IDs * nextRemoteId = NN // allocation counter for remote IDs * k.nextObjectId = NN // allocation counter for object KRefs * k.nextPromiseId = NN // allocation counter for promise KRefs */ import { Logger } from "@metamask/logger"; import { getBaseMethods } from "./methods/base.mjs"; import { getCListMethods } from "./methods/clist.mjs"; import { getCrankMethods } from "./methods/crank.mjs"; import { getGCMethods } from "./methods/gc.mjs"; import { getIdMethods } from "./methods/id.mjs"; import { getObjectMethods } from "./methods/object.mjs"; import { getPinMethods } from "./methods/pinned.mjs"; import { getPromiseMethods } from "./methods/promise.mjs"; import { getQueueMethods } from "./methods/queue.mjs"; import { getReachableMethods } from "./methods/reachable.mjs"; import { getRefCountMethods } from "./methods/refcount.mjs"; import { getRevocationMethods } from "./methods/revocation.mjs"; import { getSubclusterMethods } from "./methods/subclusters.mjs"; import { getTranslators } from "./methods/translators.mjs"; import { getVatMethods } from "./methods/vat.mjs"; /** * Create a new KernelStore object wrapped around a raw kernel database. The * resulting object provides a variety of operations for accessing various * kernel-relevent persistent data structure abstractions on their own terms, * without burdening the kernel with the particular details of how they are * represented in storage. It is our hope that these operations may be later * reimplemented on top of a more sophisticated database layer that can realize * them more directly (and thus, one hopes, more efficiently) without requiring * the kernel itself to be any the wiser. * * @param kdb - The kernel database this store is based on. * @param logger - The logger to use. * @returns A KernelStore object that maps various persistent kernel data * structures onto `kdb`. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function makeKernelStore(kdb, logger) { // Initialize core state /** KV store in which all the kernel's own state is kept. */ const kv = kdb.kernelKVStore; const { provideCachedStoredValue, provideStoredQueue } = getBaseMethods(kv); const context = { kv, /** The kernel's run queue. */ runQueue: provideStoredQueue('run', true), /** Cache of the run queue's current length */ runQueueLengthCache: -1, /** Counter for allocating kernel object IDs */ nextObjectId: provideCachedStoredValue('nextObjectId', '1'), /** Counter for allocating kernel promise IDs */ nextPromiseId: provideCachedStoredValue('nextPromiseId', '1'), /** Counter for allocating VatIDs */ nextVatId: provideCachedStoredValue('nextVatId', '1'), /** Counter for allocating RemoteIDs */ nextRemoteId: provideCachedStoredValue('nextRemoteId', '1'), // As refcounts are decremented, we accumulate a set of krefs for which // action might need to be taken: // * promises which are now resolved and unreferenced can be deleted // * objects which are no longer reachable: export can be dropped // * objects which are no longer recognizable: export can be retired // This set is ephemeral: it lives in RAM, grows as deliveries and syscalls // cause decrefs, and will be harvested by processRefcounts(). This needs to be // called in the same transaction window as the syscalls/etc which prompted // the change, else removals might be lost (not performed during the next // replay). maybeFreeKrefs: new Set(), // Garbage collection gcActions: provideCachedStoredValue('gcActions', '[]'), reapQueue: provideCachedStoredValue('reapQueue', '[]'), terminatedVats: provideCachedStoredValue('vats.terminated', '[]'), inCrank: false, savepoints: [], // Subclusters subclusters: provideCachedStoredValue('subclusters', '[]'), nextSubclusterId: provideCachedStoredValue('nextSubclusterId', '1'), vatToSubclusterMap: provideCachedStoredValue('vatToSubclusterMap', '{}'), // Logging logger: logger ?? new Logger({ tags: ['kernel-store'] }), }; const id = getIdMethods(context); const refCount = getRefCountMethods(context); const object = getObjectMethods(context); const promise = getPromiseMethods(context); const revocation = getRevocationMethods(context); const gc = getGCMethods(context); const cList = getCListMethods(context); const queue = getQueueMethods(context); const vat = getVatMethods(context); const reachable = getReachableMethods(context); const translators = getTranslators(context); const pinned = getPinMethods(context); const crank = getCrankMethods(context, kdb); const subclusters = getSubclusterMethods(context); /** * Create a new VatStore for a vat. * * @param vatID - The vat for which this is being done. * * @returns a a VatStore object for the given vat. */ function makeVatStore(vatID) { return kdb.makeVatStore(vatID); } /** * Delete all persistent state associated with a vat. * * @param vatId - The vat whose state is to be deleted. */ function deleteVat(vatId) { vat.deleteVatConfig(vatId); kdb.deleteVatStore(vatId); subclusters.removeVatFromSubcluster(vatId); } /** * Reset the kernel's persistent state and reset all counters. */ function reset() { kdb.clear(); context.maybeFreeKrefs.clear(); context.runQueue = provideStoredQueue('run', true); context.gcActions = provideCachedStoredValue('gcActions', '[]'); context.reapQueue = provideCachedStoredValue('reapQueue', '[]'); context.terminatedVats = provideCachedStoredValue('vats.terminated', '[]'); context.nextObjectId = provideCachedStoredValue('nextObjectId', '1'); context.nextPromiseId = provideCachedStoredValue('nextPromiseId', '1'); context.nextVatId = provideCachedStoredValue('nextVatId', '1'); context.nextRemoteId = provideCachedStoredValue('nextRemoteId', '1'); context.subclusters = provideCachedStoredValue('subclusters', '[]'); context.nextSubclusterId = provideCachedStoredValue('nextSubclusterId', '1'); context.vatToSubclusterMap = provideCachedStoredValue('vatToSubclusterMap', '{}'); crank.releaseAllSavepoints(); } /** * Delete everything from the database. */ function clear() { kdb.clear(); } return harden({ ...id, ...queue, ...refCount, ...object, ...promise, ...revocation, ...gc, ...reachable, ...cList, ...vat, ...translators, ...pinned, ...crank, ...subclusters, makeVatStore, deleteVat, clear, reset, kv, }); } //# sourceMappingURL=index.mjs.map