@metamask/ocap-kernel
Version:
OCap kernel core components
1 lines • 13.8 kB
Source Map (JSON)
{"version":3,"file":"gc.mjs","sourceRoot":"","sources":["../../../src/store/methods/gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { Fail } from '@endo/errors';\n\nimport { getBaseMethods } from './base.ts';\nimport { getObjectMethods } from './object.ts';\nimport { getPromiseMethods } from './promise.ts';\nimport { getReachableMethods } from './reachable.ts';\nimport { getRefCountMethods } from './refcount.ts';\nimport { getSubclusterMethods } from './subclusters.ts';\nimport { getVatMethods } from './vat.ts';\nimport type {\n VatId,\n KRef,\n GCAction,\n RunQueueItemBringOutYourDead,\n} from '../../types.ts';\nimport { insistGCActionType, insistVatId } from '../../types.ts';\nimport type { StoreContext } from '../types.ts';\nimport { insistKernelType, parseKernelSlot } from '../utils/kernel-slots.ts';\n\n/**\n * Create a store for garbage collection.\n *\n * @param ctx - The store context.\n * @returns The GC store.\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport function getGCMethods(ctx: StoreContext) {\n const { getSlotKey, getOwnerKey } = getBaseMethods(ctx.kv);\n const { getRefCount, decrementRefCount } = getRefCountMethods(ctx);\n const { getObjectRefCount, deleteKernelObject } = getObjectMethods(ctx);\n const { getKernelPromise, deleteKernelPromise } = getPromiseMethods(ctx);\n const { getImporters, isVatTerminated } = getVatMethods(ctx);\n const { getReachableFlag, getReachableAndVatSlot } = getReachableMethods(ctx);\n const { clearEmptySubclusters } = getSubclusterMethods(ctx);\n\n /**\n * Get the set of GC actions to perform.\n *\n * @returns The set of GC actions to perform.\n */\n function getGCActions(): Set<GCAction> {\n return new Set(JSON.parse(ctx.gcActions.get() ?? '[]'));\n }\n\n /**\n * Set the set of GC actions to perform.\n *\n * @param actions - The set of GC actions to perform.\n */\n function setGCActions(actions: Set<GCAction>): void {\n const a = Array.from(actions);\n a.sort();\n ctx.gcActions.set(JSON.stringify(a));\n }\n\n /**\n * Add a new GC action to the set of GC actions to perform.\n *\n * @param newActions - The new GC action to add.\n */\n function addGCActions(newActions: GCAction[]): void {\n const actions = getGCActions();\n for (const action of newActions) {\n assert.typeof(action, 'string', 'addGCActions given bad action');\n const [vatId, type, kref] = action.split(' ');\n insistVatId(vatId);\n insistGCActionType(type);\n insistKernelType('object', kref);\n actions.add(action);\n }\n setGCActions(actions);\n }\n\n /**\n * Schedule a vat for reaping.\n *\n * @param vatId - The vat to schedule for reaping.\n */\n function scheduleReap(vatId: VatId): void {\n const queue = JSON.parse(ctx.reapQueue.get() ?? '[]');\n if (!queue.includes(vatId)) {\n queue.push(vatId);\n ctx.reapQueue.set(JSON.stringify(queue));\n }\n }\n\n /**\n * Get the next reap action.\n *\n * @returns The next reap action, or undefined if the queue is empty.\n */\n function nextReapAction(): RunQueueItemBringOutYourDead | undefined {\n const queue = JSON.parse(ctx.reapQueue.get() ?? '[]');\n if (queue.length > 0) {\n const vatId = queue.shift();\n ctx.reapQueue.set(JSON.stringify(queue));\n return harden({ type: 'bringOutYourDead', vatId });\n }\n return undefined;\n }\n\n /**\n * Retires kernel objects by notifying importers and removing the objects.\n *\n * @param koids - Array of kernel object IDs to retire.\n */\n function retireKernelObjects(koids: KRef[]): void {\n Array.isArray(koids) || Fail`retireExports given non-Array ${koids}`;\n const newActions: GCAction[] = [];\n for (const koid of koids) {\n const importers = getImporters(koid);\n for (const vatID of importers) {\n newActions.push(`${vatID} retireImport ${koid}`);\n }\n deleteKernelObject(koid);\n }\n addGCActions(newActions);\n }\n\n /**\n * Processes reference counts for kernel resources and performs garbage collection actions\n * for resources that are no longer referenced or should be retired.\n */\n function collectGarbage(): void {\n const actions: Set<GCAction> = new Set();\n for (const kref of ctx.maybeFreeKrefs.values()) {\n const { type } = parseKernelSlot(kref);\n if (type === 'promise') {\n const kpid = kref;\n const kp = getKernelPromise(kpid);\n const refCount = getRefCount(kpid);\n if (refCount === 0) {\n if (kp.state === 'fulfilled' || kp.state === 'rejected') {\n // https://github.com/Agoric/agoric-sdk/issues/9888 don't assume promise is settled\n for (const slot of kp.value?.slots ?? []) {\n // Note: the following decrement can result in an addition to the\n // maybeFreeKrefs set, which we are in the midst of iterating.\n // TC39 went to a lot of trouble to ensure that this is kosher.\n decrementRefCount(slot, 'gc|promise|slot');\n }\n }\n deleteKernelPromise(kpid);\n }\n }\n\n if (type === 'object') {\n const { reachable, recognizable } = getObjectRefCount(kref);\n if (reachable === 0) {\n const ownerKey = getOwnerKey(kref);\n let ownerVatID = ctx.kv.get(ownerKey);\n const terminated = isVatTerminated(ownerVatID as VatId);\n\n // Some objects that are still owned, but the owning vat\n // might still alive, or might be terminated and in the\n // process of being deleted. These two clauses are\n // mutually exclusive.\n if (ownerVatID && !terminated) {\n const vatConsidersReachable = getReachableFlag(ownerVatID, kref);\n if (vatConsidersReachable) {\n // the reachable count is zero, but the vat doesn't realize it\n actions.add(`${ownerVatID} dropExport ${kref}`);\n }\n if (recognizable === 0) {\n // TODO: rethink this assert\n // assert.equal(vatConsidersReachable, false, `${kref} is reachable but not recognizable`);\n actions.add(`${ownerVatID} retireExport ${kref}`);\n }\n } else if (ownerVatID && terminated) {\n // When we're slowly deleting a vat, and one of its\n // exports becomes unreferenced, we obviously must not\n // send dropExports or retireExports into the dead vat.\n // We fast-forward the abandonment that slow-deletion\n // would have done, then treat the object as orphaned.\n\n const { vatSlot } = getReachableAndVatSlot(ownerVatID, kref);\n // delete directly, not orphanKernelObject(), which\n // would re-submit to maybeFreeKrefs\n ctx.kv.delete(ownerKey);\n ctx.kv.delete(getSlotKey(ownerVatID, kref));\n ctx.kv.delete(getSlotKey(ownerVatID, vatSlot));\n // now fall through to the orphaned case\n ownerVatID = undefined;\n }\n\n // Now handle objects which were orphaned. NOTE: this\n // includes objects which were owned by a terminated (but\n // not fully deleted) vat, where `ownerVatID` was cleared\n // in the last line of that previous clause (the\n // fall-through case). Don't try to change this `if\n // (!ownerVatID)` into an `else if`: the two clauses are\n // *not* mutually-exclusive.\n if (!ownerVatID) {\n // orphaned and unreachable, so retire it. If the kref\n // is recognizable, then we need retireKernelObjects()\n // to scan for importers and send retireImports (and\n // delete), else we can call deleteKernelObject directly\n if (recognizable) {\n retireKernelObjects([kref]);\n } else {\n deleteKernelObject(kref);\n }\n }\n }\n }\n }\n addGCActions([...actions]);\n ctx.maybeFreeKrefs.clear();\n clearEmptySubclusters();\n }\n\n return {\n getGCActions,\n setGCActions,\n addGCActions,\n scheduleReap,\n nextReapAction,\n retireKernelObjects,\n collectGarbage,\n };\n}\n"]}