Skip to content

Commit eff5c6a

Browse files
committed
Refactor kernel-store
1 parent f2ca7ce commit eff5c6a

29 files changed

+3755
-1242
lines changed

packages/kernel/src/Kernel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import type {
2222
import { processGCActionSet } from './services/garbage-collection.ts';
2323
import type { SlotValue } from './services/kernel-marshal.ts';
2424
import { kser, kunser, krefOf, kslot } from './services/kernel-marshal.ts';
25-
import { makeKernelStore } from './store/kernel-store.ts';
26-
import type { KernelStore } from './store/kernel-store.ts';
25+
import { makeKernelStore } from './store/index.ts';
26+
import type { KernelStore } from './store/index.ts';
2727
import { parseRef } from './store/utils/parse-ref.ts';
2828
import { isPromiseRef } from './store/utils/promise-ref.ts';
2929
import type {

packages/kernel/src/VatHandle.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import type { MockInstance } from 'vitest';
88
import { Kernel } from './Kernel.ts';
99
import { isVatCommandReply, VatCommandMethod } from './messages/index.ts';
1010
import type { VatCommand, VatCommandReply } from './messages/index.ts';
11-
import { makeKernelStore } from './store/kernel-store.ts';
12-
import type { KernelStore } from './store/kernel-store.ts';
11+
import { makeKernelStore } from './store/index.ts';
12+
import type { KernelStore } from './store/index.ts';
1313
import { VatHandle } from './VatHandle.ts';
1414
import { makeMapKernelDatabase } from '../test/storage.ts';
1515

packages/kernel/src/VatHandle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type {
1919
VatCommandReturnType,
2020
} from './messages/index.ts';
2121
import { kser } from './services/kernel-marshal.ts';
22-
import type { KernelStore } from './store/kernel-store.ts';
22+
import type { KernelStore } from './store/index.ts';
2323
import { parseRef } from './store/utils/parse-ref.ts';
2424
import type {
2525
PromiseCallbacks,

packages/kernel/src/services/garbage-collection.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach } from 'vitest';
22

33
import { processGCActionSet } from './garbage-collection.ts';
44
import { makeMapKernelDatabase } from '../../test/storage.ts';
5-
import { makeKernelStore } from '../store/kernel-store.ts';
5+
import { makeKernelStore } from '../store/index.ts';
66
import { RunQueueItemType } from '../types.ts';
77

88
describe('garbage-collection', () => {

packages/kernel/src/services/garbage-collection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { KernelStore } from '../store/kernel-store.ts';
1+
import type { KernelStore } from '../store/index.ts';
22
import { insistKernelType } from '../store/utils/kernel-slots.ts';
33
import type {
44
GCAction,

packages/kernel/src/store/kernel-store.test.ts renamed to packages/kernel/src/store/index.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Message } from '@agoric/swingset-liveslots';
22
import type { KernelDatabase } from '@ocap/store';
33
import { describe, it, expect, beforeEach } from 'vitest';
44

5-
import { makeKernelStore } from './kernel-store.ts';
5+
import { makeKernelStore } from './index.ts';
66
import { makeMapKernelDatabase } from '../../test/storage.ts';
77
import type { RunQueueItem } from '../types.ts';
88

@@ -77,6 +77,8 @@ describe('kernel store', () => {
7777
'getGCActions',
7878
'getKernelPromise',
7979
'getKernelPromiseMessageQueue',
80+
'getNextObjectId',
81+
'getNextPromiseId',
8082
'getNextRemoteId',
8183
'getNextVatId',
8284
'getObjectRefCount',
@@ -97,6 +99,7 @@ describe('kernel store', () => {
9799
'kv',
98100
'makeVatStore',
99101
'nextReapAction',
102+
'refCountKey',
100103
'reset',
101104
'resolveKernelPromise',
102105
'runQueueLength',

packages/kernel/src/store/index.ts

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Organization of keys in the key value store:
3+
*
4+
* Definitions
5+
* NN ::= some decimal integer
6+
* CAPDATA ::= capdata encoded structure value
7+
* JSON(${xx}) ::= JSON encoding of ${xx}
8+
*
9+
* ${koid} ::= ko${NN} // kernel object ID
10+
* ${kpid} ::= kp${NN} // kernel promise ID
11+
* ${kref} ::= ${koid} | ${kpid} // kernel reference
12+
* ${dir} ::= + | - // direction (for remote and vat references)
13+
* ${roid} ::= ro${dir}${NN} // remote object ID
14+
* ${rpid} ::= rp${dir}${NN} // remote promise ID
15+
* ${rref} ::= ${roid} | ${rpid} // remote reference
16+
* ${void} ::= o${dir}${NN} // vat object ID
17+
* ${vpid} ::= p${dir}${NN} // vat promise ID
18+
* ${vref} ::= ${void} | ${vpid} // vat reference
19+
* ${eref} ::= ${vref} | ${rref} // external reference
20+
* ${vatid} ::= v${NN} // vat ID
21+
* ${remid} ::= r${NN} // remote ID
22+
* ${endid} ::= ${vatid} | ${remid} // endpoint ID
23+
* ${queueName} ::= run | ${kpid}
24+
*
25+
* Queues
26+
* queue.${queueName}.head = NN // queue head index
27+
* queue.${queueName}.tail = NN // queue tail index
28+
* queue.${queueName}.${NN} = JSON(CAPDATA) // queue entry #NN
29+
*
30+
* Kernel objects
31+
* ${koid}.refCount = NN // reference count
32+
* ${koid}.owner = ${vatid} // owner (where the object is)
33+
*
34+
* Kernel promises
35+
* ${kpid}.refCount = NN // reference count
36+
* ${kpid}.state = unresolved | fulfilled | rejected // current state of settlement
37+
* ${kpid}.subscribers = JSON([${endid}]) // array of who is waiting for settlement
38+
* ${kpid}.decider = ${endid} // who decides on settlement
39+
* ${kpid}.value = JSON(CAPDATA) // value settled to, if settled
40+
*
41+
* C-lists
42+
* cle.${endid}.${eref} = ${kref} // ERef->KRef mapping
43+
* clk.${endid}.${kref} = ${eref} // KRef->ERef mapping
44+
*
45+
* Vat bookkeeping
46+
* e.nextObjectId.${endid} = NN // allocation counter for imported object ERefs
47+
* e.nextPromiseId.${endid} = NN // allocation counter for imported promise ERefs
48+
* vatConfig.${vatid} = JSON(CONFIG) // vat's configuration object
49+
*
50+
* Kernel bookkeeping
51+
* initialized = true // if set, indicates the store has been initialized
52+
* nextVatId = NN // allocation counter for vat IDs
53+
* nextRemoteId = NN // allocation counter for remote IDs
54+
* k.nextObjectId = NN // allocation counter for object KRefs
55+
* k.nextPromiseId = NN // allocation counter for promise KRefs
56+
*/
57+
58+
import type { KernelDatabase, KVStore, VatStore } from '@ocap/store';
59+
60+
import { getBaseMethods } from './methods/base.ts';
61+
import { getCListMethods } from './methods/clist.ts';
62+
import { getGCMethods } from './methods/gc.ts';
63+
import { getIdMethods } from './methods/id.ts';
64+
import { getObjectMethods } from './methods/object.ts';
65+
import { getPromiseMethods } from './methods/promise.ts';
66+
import { getQueueMethods } from './methods/queue.ts';
67+
import { getRefCountMethods } from './methods/refcount.ts';
68+
import { getVatMethods } from './methods/vat.ts';
69+
import type { StoreContext } from './types.ts';
70+
import type { KRef, VatId } from '../types.ts';
71+
72+
/**
73+
* Create a new KernelStore object wrapped around a raw kernel database. The
74+
* resulting object provides a variety of operations for accessing various
75+
* kernel-relevent persistent data structure abstractions on their own terms,
76+
* without burdening the kernel with the particular details of how they are
77+
* represented in storage. It is our hope that these operations may be later
78+
* reimplemented on top of a more sophisticated database layer that can realize
79+
* them more directly (and thus, one hopes, more efficiently) without requiring
80+
* the kernel itself to be any the wiser.
81+
*
82+
* @param kdb - The kernel database this store is based on.
83+
* @returns A KernelStore object that maps various persistent kernel data
84+
* structures onto `kdb`.
85+
*/
86+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
87+
export function makeKernelStore(kdb: KernelDatabase) {
88+
// Initialize core state
89+
90+
/** KV store in which all the kernel's own state is kept. */
91+
const kv: KVStore = kdb.kernelKVStore;
92+
93+
const { provideCachedStoredValue, provideStoredQueue } = getBaseMethods(kv);
94+
95+
const context: StoreContext = {
96+
kv,
97+
/** The kernel's run queue. */
98+
runQueue: provideStoredQueue('run', true),
99+
/** Cache of the run queue's current length */
100+
runQueueLengthCache: -1,
101+
/** Counter for allocating kernel object IDs */
102+
nextObjectId: provideCachedStoredValue('nextObjectId', '1'),
103+
/** Counter for allocating kernel promise IDs */
104+
nextPromiseId: provideCachedStoredValue('nextPromiseId', '1'),
105+
/** Counter for allocating VatIDs */
106+
nextVatId: provideCachedStoredValue('nextVatId', '1'),
107+
/** Counter for allocating RemoteIDs */
108+
nextRemoteId: provideCachedStoredValue('nextRemoteId', '1'),
109+
// As refcounts are decremented, we accumulate a set of krefs for which
110+
// action might need to be taken:
111+
// * promises which are now resolved and unreferenced can be deleted
112+
// * objects which are no longer reachable: export can be dropped
113+
// * objects which are no longer recognizable: export can be retired
114+
// This set is ephemeral: it lives in RAM, grows as deliveries and syscalls
115+
// cause decrefs, and will be harvested by processRefcounts(). This needs to be
116+
// called in the same transaction window as the syscalls/etc which prompted
117+
// the change, else removals might be lost (not performed during the next
118+
// replay).
119+
maybeFreeKrefs: new Set<KRef>(),
120+
// Garbage collection
121+
gcActions: provideCachedStoredValue('gcActions', '[]'),
122+
reapQueue: provideCachedStoredValue('reapQueue', '[]'),
123+
};
124+
125+
const id = getIdMethods(context);
126+
const refCount = getRefCountMethods(context);
127+
const object = getObjectMethods(context);
128+
const promise = getPromiseMethods(context);
129+
const gc = getGCMethods(context);
130+
const cList = getCListMethods(context);
131+
const queue = getQueueMethods(context);
132+
const vat = getVatMethods(context);
133+
134+
/**
135+
* Create a new VatStore for a vat.
136+
*
137+
* @param vatID - The vat for which this is being done.
138+
*
139+
* @returns a a VatStore object for the given vat.
140+
*/
141+
function makeVatStore(vatID: string): VatStore {
142+
return kdb.makeVatStore(vatID);
143+
}
144+
145+
/**
146+
* Delete all persistent state associated with a vat.
147+
*
148+
* @param vatId - The vat whose state is to be deleted.
149+
*/
150+
function deleteVat(vatId: VatId): void {
151+
vat.deleteEndpoint(vatId);
152+
vat.deleteVatConfig(vatId);
153+
kdb.deleteVatStore(vatId);
154+
}
155+
156+
/**
157+
* Reset the kernel's persistent state and reset all counters.
158+
*/
159+
function reset(): void {
160+
kdb.clear();
161+
context.maybeFreeKrefs.clear();
162+
context.runQueue = provideStoredQueue('run', true);
163+
context.gcActions = provideCachedStoredValue('gcActions', '[]');
164+
context.reapQueue = provideCachedStoredValue('reapQueue', '[]');
165+
context.nextObjectId = provideCachedStoredValue('nextObjectId', '1');
166+
context.nextPromiseId = provideCachedStoredValue('nextPromiseId', '1');
167+
context.nextVatId = provideCachedStoredValue('nextVatId', '1');
168+
context.nextRemoteId = provideCachedStoredValue('nextRemoteId', '1');
169+
}
170+
171+
/**
172+
* Delete everything from the database.
173+
*/
174+
function clear(): void {
175+
kdb.clear();
176+
}
177+
178+
return harden({
179+
...id,
180+
...queue,
181+
...refCount,
182+
...object,
183+
...promise,
184+
...gc,
185+
...cList,
186+
...vat,
187+
makeVatStore,
188+
deleteVat,
189+
clear,
190+
reset,
191+
kv,
192+
});
193+
}
194+
195+
export type KernelStore = ReturnType<typeof makeKernelStore>;

0 commit comments

Comments
 (0)