11import { getBaseMethods } from './base.ts' ;
2+ import { getCListMethods } from './clist.ts' ;
3+ import { getReachableMethods } from './reachable.ts' ;
24import type { EndpointId , KRef , VatConfig , VatId } from '../../types.ts' ;
3- import type { StoreContext } from '../types.ts' ;
5+ import type { StoreContext , VatCleanupWork } from '../types.ts' ;
46import { parseRef } from '../utils/parse-ref.ts' ;
57import { parseReachableAndVatSlot } from '../utils/reachable.ts' ;
68
@@ -22,6 +24,8 @@ const VAT_CONFIG_BASE_LEN = VAT_CONFIG_BASE.length;
2224export function getVatMethods ( ctx : StoreContext ) {
2325 const { kv } = ctx ;
2426 const { getPrefixedKeys, getSlotKey } = getBaseMethods ( ctx . kv ) ;
27+ const { decrementRefCount } = getCListMethods ( ctx ) ;
28+ const { clearReachableFlag } = getReachableMethods ( ctx ) ;
2529
2630 /**
2731 * Delete all persistent state associated with an endpoint.
@@ -129,6 +133,156 @@ export function getVatMethods(ctx: StoreContext) {
129133 return importers ;
130134 }
131135
136+ /**
137+ * Get the list of terminated vats.
138+ *
139+ * @returns an array of terminated vat IDs.
140+ */
141+ function getTerminatedVats ( ) : VatId [ ] {
142+ return JSON . parse ( ctx . terminatedVats . get ( ) ?? '[]' ) ;
143+ }
144+
145+ /**
146+ * Check if a vat is terminated.
147+ *
148+ * @param vatID - The ID of the vat to check.
149+ * @returns True if the vat is terminated, false otherwise.
150+ */
151+ function isVatTerminated ( vatID : VatId ) : boolean {
152+ return getTerminatedVats ( ) . includes ( vatID ) ;
153+ }
154+
155+ /**
156+ * Add a vat to the list of terminated vats.
157+ *
158+ * @param vatID - The ID of the vat to add.
159+ */
160+ function markVatAsTerminated ( vatID : VatId ) : void {
161+ const terminatedVats = getTerminatedVats ( ) ;
162+ if ( ! terminatedVats . includes ( vatID ) ) {
163+ terminatedVats . push ( vatID ) ;
164+ ctx . terminatedVats . set ( JSON . stringify ( terminatedVats ) ) ;
165+ }
166+ }
167+
168+ /**
169+ * Remove a vat from the list of terminated vats.
170+ *
171+ * @param vatID - The ID of the vat to remove.
172+ */
173+ function forgetTerminatedVat ( vatID : VatId ) : void {
174+ const terminatedVats = getTerminatedVats ( ) . filter ( ( id ) => id !== vatID ) ;
175+ ctx . terminatedVats . set ( JSON . stringify ( terminatedVats ) ) ;
176+ }
177+
178+ /**
179+ * Cleanup a terminated vat.
180+ *
181+ * @param vatID - The ID of the vat to cleanup.
182+ * @returns The work done during the cleanup.
183+ */
184+ function cleanupTerminatedVat ( vatID : VatId ) : VatCleanupWork {
185+ const work = {
186+ exports : 0 ,
187+ imports : 0 ,
188+ promises : 0 ,
189+ kv : 0 ,
190+ } ;
191+
192+ if ( ! isVatTerminated ( vatID ) ) {
193+ return work ;
194+ }
195+
196+ const clistPrefix = `${ vatID } .c.` ;
197+ const exportPrefix = `${ clistPrefix } o+` ;
198+ const importPrefix = `${ clistPrefix } o-` ;
199+ const promisePrefix = `${ clistPrefix } p` ;
200+
201+ // First, clean up exports (objects exported by the terminated vat)
202+ for ( const key of getPrefixedKeys ( exportPrefix ) ) {
203+ const vref = key . slice ( clistPrefix . length ) ;
204+ const kref = ctx . kv . get ( key ) ;
205+ if ( kref ) {
206+ const vatKey = getSlotKey ( vatID , vref ) ;
207+ const kernelKey = getSlotKey ( vatID , kref ) ;
208+ // Clear the reachable flag
209+ clearReachableFlag ( vatID , kref ) ;
210+ // Delete the c-list entries
211+ ctx . kv . delete ( kernelKey ) ;
212+ ctx . kv . delete ( vatKey ) ;
213+ // Delete the owner entry
214+ ctx . kv . delete ( `${ kref } .owner` ) ;
215+ // Add to maybeFreeKrefs for GC processing
216+ ctx . maybeFreeKrefs . add ( kref ) ;
217+ work . exports += 1 ;
218+ }
219+ }
220+
221+ // Next, clean up imports (objects imported by the terminated vat)
222+ for ( const key of getPrefixedKeys ( importPrefix ) ) {
223+ const vref = key . slice ( clistPrefix . length ) ;
224+ const kref = ctx . kv . get ( key ) ;
225+ if ( kref ) {
226+ const vatKey = getSlotKey ( vatID , vref ) ;
227+ const kernelKey = getSlotKey ( vatID , kref ) ;
228+ // Clear the reachable flag
229+ clearReachableFlag ( vatID , kref ) ;
230+ // Decrement ref count for the import
231+ decrementRefCount ( kref , {
232+ isExport : false ,
233+ onlyRecognizable : true ,
234+ } ) ;
235+ // Delete the c-list entries
236+ ctx . kv . delete ( kernelKey ) ;
237+ ctx . kv . delete ( vatKey ) ;
238+ work . imports += 1 ;
239+ }
240+ }
241+
242+ // Clean up promises
243+ for ( const key of getPrefixedKeys ( promisePrefix ) ) {
244+ const vref = key . slice ( clistPrefix . length ) ;
245+ const kref = ctx . kv . get ( key ) ;
246+ if ( kref ) {
247+ const vatKey = getSlotKey ( vatID , vref ) ;
248+ const kernelKey = getSlotKey ( vatID , kref ) ;
249+ // Decrement refcount for the promise
250+ decrementRefCount ( kref ) ;
251+ // Delete the c-list entries
252+ ctx . kv . delete ( kernelKey ) ;
253+ ctx . kv . delete ( vatKey ) ;
254+ work . promises += 1 ;
255+ }
256+ }
257+
258+ // Finally, clean up any remaining KV entries for this vat
259+ for ( const key of getPrefixedKeys ( `${ vatID } .` ) ) {
260+ ctx . kv . delete ( key ) ;
261+ work . kv += 1 ;
262+ }
263+
264+ // Clean up any remaining c-list entries and vat-specific counters
265+ deleteEndpoint ( vatID ) ;
266+
267+ // Remove the vat from the terminated vats list
268+ forgetTerminatedVat ( vatID ) ;
269+
270+ // Log the cleanup work done
271+ console . log ( `Cleaned up terminated vat ${ vatID } :` , work ) ;
272+
273+ return work ;
274+ }
275+
276+ /**
277+ * Get the next terminated vat to cleanup.
278+ *
279+ * @returns The work done during the cleanup.
280+ */
281+ function nextTerminatedVatCleanup ( ) : VatCleanupWork | undefined {
282+ const vatID = getTerminatedVats ( ) ?. [ 0 ] ;
283+ return vatID ? cleanupTerminatedVat ( vatID ) : undefined ;
284+ }
285+
132286 return {
133287 deleteEndpoint,
134288 getAllVatRecords,
@@ -138,5 +292,11 @@ export function getVatMethods(ctx: StoreContext) {
138292 getVatIDs,
139293 importsKernelSlot,
140294 getImporters,
295+ getTerminatedVats,
296+ markVatAsTerminated,
297+ forgetTerminatedVat,
298+ isVatTerminated,
299+ cleanupTerminatedVat,
300+ nextTerminatedVatCleanup,
141301 } ;
142302}
0 commit comments