@agoric/swingset-vat 0.32.3-dev-ad1e50e.0 → 0.32.3-dev-0eaf7cc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/src/controller/initializeKernel.js +34 -9
- package/src/controller/initializeSwingset.js +5 -2
- package/src/controller/upgradeSwingset.js +204 -0
- package/src/index.js +1 -1
- package/src/kernel/kernel.js +97 -25
- package/src/kernel/state/kernelKeeper.js +142 -50
- package/src/kernel/state/vatKeeper.js +117 -36
- package/src/kernel/vat-loader/manager-factory.js +0 -1
- package/src/kernel/vat-loader/vat-loader.js +1 -1
- package/src/lib/recordVatOptions.js +17 -5
- package/src/types-external.js +18 -15
- package/src/types-internal.js +52 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swingset-vat",
|
|
3
|
-
"version": "0.32.3-dev-
|
|
3
|
+
"version": "0.32.3-dev-0eaf7cc.0+0eaf7cc",
|
|
4
4
|
"description": "Vat/Container Launcher",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"@types/yargs-parser": "^21.0.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@agoric/internal": "0.3.3-dev-
|
|
31
|
-
"@agoric/kmarshal": "0.1.1-dev-
|
|
32
|
-
"@agoric/store": "0.9.3-dev-
|
|
33
|
-
"@agoric/swing-store": "0.9.2-dev-
|
|
34
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
35
|
-
"@agoric/swingset-xsnap-supervisor": "0.10.3-dev-
|
|
36
|
-
"@agoric/time": "0.3.3-dev-
|
|
37
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
38
|
-
"@agoric/xsnap": "0.14.3-dev-
|
|
39
|
-
"@agoric/xsnap-lockdown": "0.14.1-dev-
|
|
30
|
+
"@agoric/internal": "0.3.3-dev-0eaf7cc.0+0eaf7cc",
|
|
31
|
+
"@agoric/kmarshal": "0.1.1-dev-0eaf7cc.0+0eaf7cc",
|
|
32
|
+
"@agoric/store": "0.9.3-dev-0eaf7cc.0+0eaf7cc",
|
|
33
|
+
"@agoric/swing-store": "0.9.2-dev-0eaf7cc.0+0eaf7cc",
|
|
34
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-0eaf7cc.0+0eaf7cc",
|
|
35
|
+
"@agoric/swingset-xsnap-supervisor": "0.10.3-dev-0eaf7cc.0+0eaf7cc",
|
|
36
|
+
"@agoric/time": "0.3.3-dev-0eaf7cc.0+0eaf7cc",
|
|
37
|
+
"@agoric/vat-data": "0.5.3-dev-0eaf7cc.0+0eaf7cc",
|
|
38
|
+
"@agoric/xsnap": "0.14.3-dev-0eaf7cc.0+0eaf7cc",
|
|
39
|
+
"@agoric/xsnap-lockdown": "0.14.1-dev-0eaf7cc.0+0eaf7cc",
|
|
40
40
|
"@endo/base64": "^1.0.6",
|
|
41
41
|
"@endo/bundle-source": "^3.3.0",
|
|
42
42
|
"@endo/captp": "^4.2.2",
|
|
@@ -102,5 +102,5 @@
|
|
|
102
102
|
"typeCoverage": {
|
|
103
103
|
"atLeast": 75.1
|
|
104
104
|
},
|
|
105
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "0eaf7cc8151b4e1966f3f33e43362d3d021457aa"
|
|
106
106
|
}
|
|
@@ -9,14 +9,32 @@ import { insistVatID } from '../lib/id.js';
|
|
|
9
9
|
import { makeVatSlot } from '../lib/parseVatSlots.js';
|
|
10
10
|
import { insistStorageAPI } from '../lib/storageAPI.js';
|
|
11
11
|
import { makeVatOptionRecorder } from '../lib/recordVatOptions.js';
|
|
12
|
-
import makeKernelKeeper
|
|
12
|
+
import makeKernelKeeper, {
|
|
13
|
+
DEFAULT_DELIVERIES_PER_BOYD,
|
|
14
|
+
DEFAULT_GC_KREFS_PER_BOYD,
|
|
15
|
+
} from '../kernel/state/kernelKeeper.js';
|
|
13
16
|
import { exportRootObject } from '../kernel/kernel.js';
|
|
14
17
|
import { makeKernelQueueHandler } from '../kernel/kernelQueue.js';
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @typedef { import('../types-external.js').SwingSetKernelConfig } SwingSetKernelConfig
|
|
21
|
+
* @typedef { import('../types-external.js').SwingStoreKernelStorage } SwingStoreKernelStorage
|
|
22
|
+
* @typedef { import('../types-internal.js').InternalKernelOptions } InternalKernelOptions
|
|
23
|
+
* @typedef { import('../types-internal.js').ReapDirtThreshold } ReapDirtThreshold
|
|
24
|
+
*/
|
|
25
|
+
|
|
16
26
|
function makeVatRootObjectSlot() {
|
|
17
27
|
return makeVatSlot('object', true, 0);
|
|
18
28
|
}
|
|
19
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @param {SwingSetKernelConfig} config
|
|
32
|
+
* @param {SwingStoreKernelStorage} kernelStorage
|
|
33
|
+
* @param {*} [options]
|
|
34
|
+
* @returns {Promise<string | undefined>} KPID of the bootstrap message
|
|
35
|
+
* result promise
|
|
36
|
+
*/
|
|
37
|
+
|
|
20
38
|
export async function initializeKernel(config, kernelStorage, options = {}) {
|
|
21
39
|
const {
|
|
22
40
|
verbose = false,
|
|
@@ -25,22 +43,27 @@ export async function initializeKernel(config, kernelStorage, options = {}) {
|
|
|
25
43
|
const logStartup = verbose ? console.debug : () => 0;
|
|
26
44
|
insistStorageAPI(kernelStorage.kvStore);
|
|
27
45
|
|
|
28
|
-
const
|
|
29
|
-
const kernelKeeper = makeKernelKeeper(kernelStorage, kernelSlog);
|
|
46
|
+
const kernelKeeper = makeKernelKeeper(kernelStorage, 'uninitialized');
|
|
30
47
|
const optionRecorder = makeVatOptionRecorder(kernelKeeper, bundleHandler);
|
|
31
48
|
|
|
32
|
-
const wasInitialized = kernelKeeper.getInitialized();
|
|
33
|
-
assert(!wasInitialized);
|
|
34
49
|
const {
|
|
35
50
|
defaultManagerType,
|
|
36
|
-
defaultReapInterval,
|
|
51
|
+
defaultReapInterval = DEFAULT_DELIVERIES_PER_BOYD,
|
|
52
|
+
defaultReapGCKrefs = DEFAULT_GC_KREFS_PER_BOYD,
|
|
37
53
|
relaxDurabilityRules,
|
|
38
54
|
snapshotInitial,
|
|
39
55
|
snapshotInterval,
|
|
40
56
|
} = config;
|
|
57
|
+
/** @type { ReapDirtThreshold } */
|
|
58
|
+
const defaultReapDirtThreshold = {
|
|
59
|
+
deliveries: defaultReapInterval,
|
|
60
|
+
gcKrefs: defaultReapGCKrefs,
|
|
61
|
+
computrons: 'never', // TODO no knob?
|
|
62
|
+
};
|
|
63
|
+
/** @type { InternalKernelOptions } */
|
|
41
64
|
const kernelOptions = {
|
|
42
65
|
defaultManagerType,
|
|
43
|
-
|
|
66
|
+
defaultReapDirtThreshold,
|
|
44
67
|
relaxDurabilityRules,
|
|
45
68
|
snapshotInitial,
|
|
46
69
|
snapshotInterval,
|
|
@@ -49,7 +72,7 @@ export async function initializeKernel(config, kernelStorage, options = {}) {
|
|
|
49
72
|
|
|
50
73
|
for (const id of Object.keys(config.idToBundle || {})) {
|
|
51
74
|
const bundle = config.idToBundle[id];
|
|
52
|
-
assert
|
|
75
|
+
assert(bundle.moduleFormat === 'endoZipBase64');
|
|
53
76
|
if (!kernelKeeper.hasBundle(id)) {
|
|
54
77
|
kernelKeeper.addBundle(id, bundle);
|
|
55
78
|
}
|
|
@@ -64,7 +87,7 @@ export async function initializeKernel(config, kernelStorage, options = {}) {
|
|
|
64
87
|
|
|
65
88
|
// generate the genesis vats
|
|
66
89
|
await null;
|
|
67
|
-
if (config.vats) {
|
|
90
|
+
if (config.vats && Object.keys(config.vats).length) {
|
|
68
91
|
for (const name of Object.keys(config.vats)) {
|
|
69
92
|
const {
|
|
70
93
|
bundleID,
|
|
@@ -86,6 +109,8 @@ export async function initializeKernel(config, kernelStorage, options = {}) {
|
|
|
86
109
|
'useTranscript',
|
|
87
110
|
'critical',
|
|
88
111
|
'reapInterval',
|
|
112
|
+
'reapGCKrefs',
|
|
113
|
+
'neverReap',
|
|
89
114
|
'nodeOptions',
|
|
90
115
|
]);
|
|
91
116
|
const vatID = kernelKeeper.allocateVatIDForNameIfNeeded(name);
|
|
@@ -256,7 +256,10 @@ export async function loadSwingsetConfigFile(configPath) {
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
export function swingsetIsInitialized(kernelStorage) {
|
|
259
|
-
return !!
|
|
259
|
+
return !!(
|
|
260
|
+
kernelStorage.kvStore.get('version') ||
|
|
261
|
+
kernelStorage.kvStore.get('initialized')
|
|
262
|
+
);
|
|
260
263
|
}
|
|
261
264
|
|
|
262
265
|
/**
|
|
@@ -397,7 +400,7 @@ export async function initializeSwingset(
|
|
|
397
400
|
enableSetup: true,
|
|
398
401
|
managerType: 'local',
|
|
399
402
|
useTranscript: false,
|
|
400
|
-
|
|
403
|
+
neverReap: true,
|
|
401
404
|
},
|
|
402
405
|
};
|
|
403
406
|
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_REAP_DIRT_THRESHOLD_KEY,
|
|
3
|
+
DEFAULT_GC_KREFS_PER_BOYD,
|
|
4
|
+
getAllDynamicVats,
|
|
5
|
+
getAllStaticVats,
|
|
6
|
+
} from '../kernel/state/kernelKeeper.js';
|
|
7
|
+
|
|
8
|
+
const upgradeVatV0toV1 = (kvStore, defaultReapDirtThreshold, vatID) => {
|
|
9
|
+
// This is called, once per vat, when upgradeSwingset migrates from
|
|
10
|
+
// v0 to v1
|
|
11
|
+
|
|
12
|
+
// schema v0:
|
|
13
|
+
// Each vat has a `vNN.reapInterval` and `vNN.reapCountdown`.
|
|
14
|
+
// vNN.options has a `.reapInterval` property (however it was not
|
|
15
|
+
// updated by processChangeVatOptions). Either all are numbers, or
|
|
16
|
+
// all are 'never'.
|
|
17
|
+
|
|
18
|
+
const oldReapIntervalKey = `${vatID}.reapInterval`;
|
|
19
|
+
const oldReapCountdownKey = `${vatID}.reapCountdown`;
|
|
20
|
+
const vatOptionsKey = `${vatID}.options`;
|
|
21
|
+
|
|
22
|
+
// schema v1:
|
|
23
|
+
// Each vat has a `vNN.reapDirt`, and vNN.options has a
|
|
24
|
+
// `.reapDirtThreshold` property (which overrides kernel-wide
|
|
25
|
+
// `defaultReapDirtThreshold`)
|
|
26
|
+
|
|
27
|
+
const reapDirtKey = `${vatID}.reapDirt`;
|
|
28
|
+
|
|
29
|
+
assert(kvStore.has(oldReapIntervalKey), oldReapIntervalKey);
|
|
30
|
+
assert(kvStore.has(oldReapCountdownKey), oldReapCountdownKey);
|
|
31
|
+
assert(!kvStore.has(reapDirtKey), reapDirtKey);
|
|
32
|
+
|
|
33
|
+
const reapIntervalString = kvStore.get(oldReapIntervalKey);
|
|
34
|
+
const reapCountdownString = kvStore.get(oldReapCountdownKey);
|
|
35
|
+
assert(reapIntervalString !== undefined);
|
|
36
|
+
assert(reapCountdownString !== undefined);
|
|
37
|
+
|
|
38
|
+
const intervalIsNever = reapIntervalString === 'never';
|
|
39
|
+
const countdownIsNever = reapCountdownString === 'never';
|
|
40
|
+
// these were supposed to be the same
|
|
41
|
+
assert(
|
|
42
|
+
intervalIsNever === countdownIsNever,
|
|
43
|
+
`reapInterval=${reapIntervalString}, reapCountdown=${reapCountdownString}`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// initialize or upgrade state
|
|
47
|
+
const reapDirt = {}; // all missing keys are treated as zero
|
|
48
|
+
const threshold = {};
|
|
49
|
+
|
|
50
|
+
if (intervalIsNever) {
|
|
51
|
+
// old vats that were never reaped (eg comms) used
|
|
52
|
+
// reapInterval='never', so respect that and set the other
|
|
53
|
+
// threshold values to never as well
|
|
54
|
+
threshold.never = true;
|
|
55
|
+
} else {
|
|
56
|
+
// deduce delivery count from old countdown values
|
|
57
|
+
const reapInterval = Number.parseInt(reapIntervalString, 10);
|
|
58
|
+
const reapCountdown = Number.parseInt(reapCountdownString, 10);
|
|
59
|
+
const deliveries = reapInterval - reapCountdown;
|
|
60
|
+
reapDirt.deliveries = Math.max(deliveries, 0); // just in case
|
|
61
|
+
if (reapInterval !== defaultReapDirtThreshold.deliveries) {
|
|
62
|
+
threshold.deliveries = reapInterval;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
kvStore.delete(oldReapIntervalKey);
|
|
67
|
+
kvStore.delete(oldReapCountdownKey);
|
|
68
|
+
kvStore.set(reapDirtKey, JSON.stringify(reapDirt));
|
|
69
|
+
|
|
70
|
+
// Update options to use the new schema.
|
|
71
|
+
const options = JSON.parse(kvStore.get(vatOptionsKey));
|
|
72
|
+
delete options.reapInterval;
|
|
73
|
+
options.reapDirtThreshold = threshold;
|
|
74
|
+
kvStore.set(vatOptionsKey, JSON.stringify(options));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* (maybe) upgrade the kernel state to the current schema
|
|
79
|
+
*
|
|
80
|
+
* This function is responsible for bringing the kernel's portion of
|
|
81
|
+
* swing-store (kernelStorage) up to the current version. The host app
|
|
82
|
+
* must call this each time it launches with a new version of
|
|
83
|
+
* swingset, before using makeSwingsetController() to build the
|
|
84
|
+
* kernel/controller (which will throw an error if handed an old
|
|
85
|
+
* database). It is ok to call it only on those reboots, but it is
|
|
86
|
+
* also safe to call on every reboot, because upgradeSwingset() is a
|
|
87
|
+
* no-op if the DB is already up-to-date.
|
|
88
|
+
*
|
|
89
|
+
* If an upgrade is needed, this function will modify the DB state, so
|
|
90
|
+
* the host app must be prepared for export-data callbacks being
|
|
91
|
+
* called during the upgrade, and it is responsible for doing a
|
|
92
|
+
* `hostStorage.commit()` afterwards.
|
|
93
|
+
*
|
|
94
|
+
* @param {SwingStoreKernelStorage} kernelStorage
|
|
95
|
+
* @returns {boolean} true if any changes were made
|
|
96
|
+
*/
|
|
97
|
+
export const upgradeSwingset = kernelStorage => {
|
|
98
|
+
const { kvStore } = kernelStorage;
|
|
99
|
+
let modified = false;
|
|
100
|
+
let vstring = kvStore.get('version');
|
|
101
|
+
if (vstring === undefined) {
|
|
102
|
+
vstring = '0';
|
|
103
|
+
}
|
|
104
|
+
let version = Number(vstring);
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} key
|
|
108
|
+
* @returns {string}
|
|
109
|
+
*/
|
|
110
|
+
function getRequired(key) {
|
|
111
|
+
if (!kvStore.has(key)) {
|
|
112
|
+
throw Error(`storage lacks required key ${key}`);
|
|
113
|
+
}
|
|
114
|
+
// @ts-expect-error already checked .has()
|
|
115
|
+
return kvStore.get(key);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// kernelKeeper.js has a large comment that defines our current
|
|
119
|
+
// kvStore schema, with a section describing the deltas. The upgrade
|
|
120
|
+
// steps applied here must match.
|
|
121
|
+
|
|
122
|
+
// schema v0:
|
|
123
|
+
//
|
|
124
|
+
// The kernel overall has `kernel.defaultReapInterval` and
|
|
125
|
+
// `kernel.initialized = 'true'`.
|
|
126
|
+
//
|
|
127
|
+
// Each vat has a `vNN.reapInterval` and `vNN.reapCountdown`.
|
|
128
|
+
// vNN.options has a `.reapInterval` property (however it was not
|
|
129
|
+
// updated by processChangeVatOptions, so do not rely upon its
|
|
130
|
+
// value). Either all are numbers, or all are 'never'.
|
|
131
|
+
|
|
132
|
+
if (version < 1) {
|
|
133
|
+
// schema v1:
|
|
134
|
+
//
|
|
135
|
+
// The kernel overall has `kernel.defaultReapDirtThreshold` and
|
|
136
|
+
// `kernel.version = '1'` (instead of .initialized).
|
|
137
|
+
//
|
|
138
|
+
// Each vat has a `vNN.reapDirt`, and vNN.options has a
|
|
139
|
+
// `.reapDirtThreshold` property
|
|
140
|
+
|
|
141
|
+
// So:
|
|
142
|
+
// * replace `kernel.initialized` with `kernel.version`
|
|
143
|
+
// * replace `kernel.defaultReapInterval` with
|
|
144
|
+
// `kernel.defaultReapDirtThreshold`
|
|
145
|
+
// * replace vat's `vNN.reapInterval`/`vNN.reapCountdown` with
|
|
146
|
+
// `vNN.reapDirt` and a `vNN.reapDirtThreshold` in `vNN.options`
|
|
147
|
+
// * then do per-vat upgrades with upgradeVatV0toV1
|
|
148
|
+
|
|
149
|
+
assert(kvStore.has('initialized'));
|
|
150
|
+
kvStore.delete('initialized');
|
|
151
|
+
// 'version' will be set at the end
|
|
152
|
+
|
|
153
|
+
// upgrade from old kernel.defaultReapInterval
|
|
154
|
+
|
|
155
|
+
const oldDefaultReapIntervalKey = 'kernel.defaultReapInterval';
|
|
156
|
+
assert(kvStore.has(oldDefaultReapIntervalKey));
|
|
157
|
+
assert(!kvStore.has(DEFAULT_REAP_DIRT_THRESHOLD_KEY));
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @typedef { import('../types-internal.js').ReapDirtThreshold } ReapDirtThreshold
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
/** @type ReapDirtThreshold */
|
|
164
|
+
const threshold = {
|
|
165
|
+
deliveries: 'never',
|
|
166
|
+
gcKrefs: 'never',
|
|
167
|
+
computrons: 'never',
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const oldValue = getRequired(oldDefaultReapIntervalKey);
|
|
171
|
+
if (oldValue !== 'never') {
|
|
172
|
+
const value = Number.parseInt(oldValue, 10);
|
|
173
|
+
assert.typeof(value, 'number');
|
|
174
|
+
threshold.deliveries = value;
|
|
175
|
+
// if BOYD wasn't turned off entirely (eg
|
|
176
|
+
// defaultReapInterval='never', which only happens in unit
|
|
177
|
+
// tests), then pretend we wanted a gcKrefs= threshold all
|
|
178
|
+
// along, so all vats get a retroactive gcKrefs threshold, which
|
|
179
|
+
// we need for the upcoming slow-vat-deletion to not trigger
|
|
180
|
+
// gigantic BOYD and break the kernel
|
|
181
|
+
threshold.gcKrefs = DEFAULT_GC_KREFS_PER_BOYD;
|
|
182
|
+
}
|
|
183
|
+
harden(threshold);
|
|
184
|
+
kvStore.set(DEFAULT_REAP_DIRT_THRESHOLD_KEY, JSON.stringify(threshold));
|
|
185
|
+
kvStore.delete(oldDefaultReapIntervalKey);
|
|
186
|
+
|
|
187
|
+
// now upgrade all vats
|
|
188
|
+
for (const [_name, vatID] of getAllStaticVats(kvStore)) {
|
|
189
|
+
upgradeVatV0toV1(kvStore, threshold, vatID);
|
|
190
|
+
}
|
|
191
|
+
for (const vatID of getAllDynamicVats(getRequired)) {
|
|
192
|
+
upgradeVatV0toV1(kvStore, threshold, vatID);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
modified = true;
|
|
196
|
+
version = 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (modified) {
|
|
200
|
+
kvStore.set('version', `${version}`);
|
|
201
|
+
}
|
|
202
|
+
return modified;
|
|
203
|
+
};
|
|
204
|
+
harden(upgradeSwingset);
|
package/src/index.js
CHANGED
package/src/kernel/kernel.js
CHANGED
|
@@ -10,7 +10,9 @@ import { foreverPolicy } from '../lib/runPolicies.js';
|
|
|
10
10
|
import { makeVatManagerFactory } from './vat-loader/manager-factory.js';
|
|
11
11
|
import { makeVatWarehouse } from './vat-warehouse.js';
|
|
12
12
|
import makeDeviceManager from './deviceManager.js';
|
|
13
|
-
import makeKernelKeeper
|
|
13
|
+
import makeKernelKeeper, {
|
|
14
|
+
CURRENT_SCHEMA_VERSION,
|
|
15
|
+
} from './state/kernelKeeper.js';
|
|
14
16
|
import {
|
|
15
17
|
kdebug,
|
|
16
18
|
kdebugEnable,
|
|
@@ -112,7 +114,11 @@ export default function buildKernel(
|
|
|
112
114
|
? makeSlogger(slogCallbacks, writeSlogObject)
|
|
113
115
|
: makeDummySlogger(slogCallbacks, makeConsole('disabled slogger'));
|
|
114
116
|
|
|
115
|
-
const kernelKeeper = makeKernelKeeper(
|
|
117
|
+
const kernelKeeper = makeKernelKeeper(
|
|
118
|
+
kernelStorage,
|
|
119
|
+
CURRENT_SCHEMA_VERSION,
|
|
120
|
+
kernelSlog,
|
|
121
|
+
);
|
|
116
122
|
|
|
117
123
|
/** @type {ReturnType<makeVatWarehouse>} */
|
|
118
124
|
let vatWarehouse;
|
|
@@ -252,8 +258,7 @@ export default function buildKernel(
|
|
|
252
258
|
*/
|
|
253
259
|
async function terminateVat(vatID, shouldReject, info) {
|
|
254
260
|
console.log(`kernel terminating vat ${vatID} (failure=${shouldReject})`);
|
|
255
|
-
|
|
256
|
-
const critical = vatKeeper.getOptions().critical;
|
|
261
|
+
let critical = false;
|
|
257
262
|
insistCapData(info);
|
|
258
263
|
// ISSUE: terminate stuff in its own crank like creation?
|
|
259
264
|
// TODO: if a static vat terminates, panic the kernel?
|
|
@@ -264,6 +269,14 @@ export default function buildKernel(
|
|
|
264
269
|
// check will report 'false'. That's fine, there's no state to
|
|
265
270
|
// clean up.
|
|
266
271
|
if (kernelKeeper.vatIsAlive(vatID)) {
|
|
272
|
+
// If there was no vat state, we can't make a vatKeeper to ask for
|
|
273
|
+
// options. For now, pretend the vat was non-critical. This will fail
|
|
274
|
+
// to panic the kernel for startVat failures in critical vats
|
|
275
|
+
// (#9157). The fix will add .critical to CrankResults, populated by a
|
|
276
|
+
// getOptions query in deliveryCrankResults() or copied from
|
|
277
|
+
// dynamicOptions in processCreateVat.
|
|
278
|
+
critical = kernelKeeper.provideVatKeeper(vatID).getOptions().critical;
|
|
279
|
+
|
|
267
280
|
// Reject all promises decided by the vat, making sure to capture the list
|
|
268
281
|
// of kpids before that data is deleted.
|
|
269
282
|
const deadPromises = [...kernelKeeper.enumeratePromisesByDecider(vatID)];
|
|
@@ -357,6 +370,7 @@ export default function buildKernel(
|
|
|
357
370
|
*
|
|
358
371
|
* @typedef { import('@agoric/swingset-liveslots').MeterConsumption } MeterConsumption
|
|
359
372
|
* @typedef { import('../types-internal.js').MeterID } MeterID
|
|
373
|
+
* @typedef { import('../types-internal.js').Dirt } Dirt
|
|
360
374
|
*
|
|
361
375
|
* Any delivery crank (send, notify, start-vat.. anything which is allowed
|
|
362
376
|
* to make vat delivery) emits one of these status events if a delivery
|
|
@@ -375,7 +389,7 @@ export default function buildKernel(
|
|
|
375
389
|
* didDelivery?: VatID, // we made a delivery to a vat, for run policy and save-snapshot
|
|
376
390
|
* computrons?: BigInt, // computron count for run policy
|
|
377
391
|
* meterID?: string, // deduct those computrons from a meter
|
|
378
|
-
*
|
|
392
|
+
* measureDirt?: { vatID: VatID, dirt: Dirt }, // dirt counters should increment
|
|
379
393
|
* terminate?: { vatID: VatID, reject: boolean, info: SwingSetCapData }, // terminate vat, notify vat-admin
|
|
380
394
|
* vatAdminMethargs?: RawMethargs, // methargs to notify vat-admin about create/upgrade results
|
|
381
395
|
* } } CrankResults
|
|
@@ -442,16 +456,17 @@ export default function buildKernel(
|
|
|
442
456
|
* event handler.
|
|
443
457
|
*
|
|
444
458
|
* Two flags influence this:
|
|
445
|
-
* `
|
|
459
|
+
* `measureDirt` is used for non-BOYD deliveries
|
|
446
460
|
* `meterID` means we should check a meter
|
|
447
461
|
*
|
|
448
462
|
* @param {VatID} vatID
|
|
449
463
|
* @param {DeliveryStatus} status
|
|
450
|
-
* @param {boolean}
|
|
464
|
+
* @param {boolean} measureDirt
|
|
451
465
|
* @param {MeterID} [meterID]
|
|
466
|
+
* @param {number} [gcKrefs]
|
|
452
467
|
* @returns {CrankResults}
|
|
453
468
|
*/
|
|
454
|
-
function deliveryCrankResults(vatID, status,
|
|
469
|
+
function deliveryCrankResults(vatID, status, measureDirt, meterID, gcKrefs) {
|
|
455
470
|
let meterUnderrun = false;
|
|
456
471
|
let computrons;
|
|
457
472
|
if (status.metering?.compute) {
|
|
@@ -495,8 +510,16 @@ export default function buildKernel(
|
|
|
495
510
|
results.terminate = { vatID, ...status.vatRequestedTermination };
|
|
496
511
|
}
|
|
497
512
|
|
|
498
|
-
if (
|
|
499
|
-
|
|
513
|
+
if (measureDirt && !(results.abort || results.terminate)) {
|
|
514
|
+
const dirt = { deliveries: 1 };
|
|
515
|
+
if (computrons) {
|
|
516
|
+
// this is BigInt, but we use plain Number in Dirt records
|
|
517
|
+
dirt.computrons = Number(computrons);
|
|
518
|
+
}
|
|
519
|
+
if (gcKrefs) {
|
|
520
|
+
dirt.gcKrefs = gcKrefs;
|
|
521
|
+
}
|
|
522
|
+
results.measureDirt = { vatID, dirt };
|
|
500
523
|
}
|
|
501
524
|
|
|
502
525
|
// We leave results.consumeMessage up to the caller. Send failures
|
|
@@ -535,7 +558,8 @@ export default function buildKernel(
|
|
|
535
558
|
}
|
|
536
559
|
|
|
537
560
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
538
|
-
|
|
561
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
562
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
539
563
|
}
|
|
540
564
|
|
|
541
565
|
/**
|
|
@@ -581,7 +605,8 @@ export default function buildKernel(
|
|
|
581
605
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
582
606
|
vatKeeper.deleteCListEntriesForKernelSlots(targets);
|
|
583
607
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
584
|
-
|
|
608
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
609
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
585
610
|
}
|
|
586
611
|
|
|
587
612
|
/**
|
|
@@ -609,7 +634,9 @@ export default function buildKernel(
|
|
|
609
634
|
}
|
|
610
635
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
611
636
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
612
|
-
|
|
637
|
+
const meterID = undefined; // no meterID
|
|
638
|
+
const gcKrefs = krefs.length;
|
|
639
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
613
640
|
}
|
|
614
641
|
|
|
615
642
|
/**
|
|
@@ -624,11 +651,14 @@ export default function buildKernel(
|
|
|
624
651
|
if (!vatWarehouse.lookup(vatID)) {
|
|
625
652
|
return NO_DELIVERY_CRANK_RESULTS; // can't collect from the dead
|
|
626
653
|
}
|
|
654
|
+
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
627
655
|
/** @type { KernelDeliveryBringOutYourDead } */
|
|
628
656
|
const kd = harden([type]);
|
|
629
657
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
630
658
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
631
|
-
|
|
659
|
+
vatKeeper.clearReapDirt(); // BOYD zeros out the when-to-BOYD counters
|
|
660
|
+
// no gcKrefs, BOYD clears them anyways
|
|
661
|
+
return deliveryCrankResults(vatID, status, false); // no meter, BOYD clears dirt
|
|
632
662
|
}
|
|
633
663
|
|
|
634
664
|
/**
|
|
@@ -669,8 +699,9 @@ export default function buildKernel(
|
|
|
669
699
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
670
700
|
// note: if deliveryCrankResults() learns to suspend vats,
|
|
671
701
|
// startVat errors should still terminate them
|
|
702
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
672
703
|
const results = harden({
|
|
673
|
-
...deliveryCrankResults(vatID, status, true, meterID),
|
|
704
|
+
...deliveryCrankResults(vatID, status, true, meterID, gcKrefs),
|
|
674
705
|
consumeMessage: true,
|
|
675
706
|
});
|
|
676
707
|
return results;
|
|
@@ -735,9 +766,17 @@ export default function buildKernel(
|
|
|
735
766
|
function setKernelVatOption(vatID, option, value) {
|
|
736
767
|
switch (option) {
|
|
737
768
|
case 'reapInterval': {
|
|
769
|
+
// This still controls reapDirtThreshold.deliveries, and we do not
|
|
770
|
+
// yet offer controls for the other limits (gcKrefs or computrons).
|
|
738
771
|
if (value === 'never' || isNat(value)) {
|
|
739
772
|
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
740
|
-
vatKeeper.
|
|
773
|
+
const threshold = { ...vatKeeper.getReapDirtThreshold() };
|
|
774
|
+
if (value === 'never') {
|
|
775
|
+
threshold.deliveries = value;
|
|
776
|
+
} else {
|
|
777
|
+
threshold.deliveries = Number(value);
|
|
778
|
+
}
|
|
779
|
+
vatKeeper.setReapDirtThreshold(threshold);
|
|
741
780
|
} else {
|
|
742
781
|
console.log(`WARNING: invalid reapInterval value`, value);
|
|
743
782
|
}
|
|
@@ -877,6 +916,7 @@ export default function buildKernel(
|
|
|
877
916
|
const boydVD = vatWarehouse.kernelDeliveryToVatDelivery(vatID, boydKD);
|
|
878
917
|
const boydStatus = await deliverAndLogToVat(vatID, boydKD, boydVD);
|
|
879
918
|
const boydResults = deliveryCrankResults(vatID, boydStatus, false);
|
|
919
|
+
vatKeeper.clearReapDirt();
|
|
880
920
|
|
|
881
921
|
// we don't meter bringOutYourDead since no user code is running, but we
|
|
882
922
|
// still report computrons to the runPolicy
|
|
@@ -951,7 +991,14 @@ export default function buildKernel(
|
|
|
951
991
|
startVatKD,
|
|
952
992
|
startVatVD,
|
|
953
993
|
);
|
|
954
|
-
const
|
|
994
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
995
|
+
const startVatResults = deliveryCrankResults(
|
|
996
|
+
vatID,
|
|
997
|
+
startVatStatus,
|
|
998
|
+
true,
|
|
999
|
+
meterID,
|
|
1000
|
+
gcKrefs,
|
|
1001
|
+
);
|
|
955
1002
|
computrons = addComputrons(computrons, startVatResults.computrons);
|
|
956
1003
|
|
|
957
1004
|
if (startVatResults.terminate) {
|
|
@@ -1292,13 +1339,11 @@ export default function buildKernel(
|
|
|
1292
1339
|
}
|
|
1293
1340
|
}
|
|
1294
1341
|
}
|
|
1295
|
-
if (crankResults.
|
|
1342
|
+
if (crankResults.measureDirt) {
|
|
1296
1343
|
// deliveries cause garbage, garbage needs collection
|
|
1297
|
-
const { vatID } = crankResults.
|
|
1344
|
+
const { vatID, dirt } = crankResults.measureDirt;
|
|
1298
1345
|
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
1299
|
-
|
|
1300
|
-
kernelKeeper.scheduleReap(vatID);
|
|
1301
|
-
}
|
|
1346
|
+
vatKeeper.addDirt(dirt); // might schedule a reap for that vat
|
|
1302
1347
|
}
|
|
1303
1348
|
|
|
1304
1349
|
// Vat termination (during delivery) is triggered by an illegal
|
|
@@ -1572,10 +1617,14 @@ export default function buildKernel(
|
|
|
1572
1617
|
'bundleID',
|
|
1573
1618
|
'enablePipelining',
|
|
1574
1619
|
'reapInterval',
|
|
1620
|
+
'reapGCKrefs',
|
|
1621
|
+
'neverReap',
|
|
1575
1622
|
]);
|
|
1576
1623
|
const {
|
|
1577
1624
|
bundleID = 'b1-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
1578
1625
|
reapInterval = 'never',
|
|
1626
|
+
reapGCKrefs = 'never',
|
|
1627
|
+
neverReap = false,
|
|
1579
1628
|
enablePipelining,
|
|
1580
1629
|
} = creationOptions;
|
|
1581
1630
|
const vatID = kernelKeeper.allocateVatIDForNameIfNeeded(name);
|
|
@@ -1587,6 +1636,8 @@ export default function buildKernel(
|
|
|
1587
1636
|
const options = {
|
|
1588
1637
|
name,
|
|
1589
1638
|
reapInterval,
|
|
1639
|
+
reapGCKrefs,
|
|
1640
|
+
neverReap,
|
|
1590
1641
|
enablePipelining,
|
|
1591
1642
|
managerType,
|
|
1592
1643
|
};
|
|
@@ -1617,7 +1668,6 @@ export default function buildKernel(
|
|
|
1617
1668
|
throw Error('kernel.start already called');
|
|
1618
1669
|
}
|
|
1619
1670
|
started = true;
|
|
1620
|
-
kernelKeeper.getInitialized() || Fail`kernel not initialized`;
|
|
1621
1671
|
|
|
1622
1672
|
kernelKeeper.loadStats();
|
|
1623
1673
|
|
|
@@ -1733,14 +1783,36 @@ export default function buildKernel(
|
|
|
1733
1783
|
}
|
|
1734
1784
|
|
|
1735
1785
|
function changeKernelOptions(options) {
|
|
1736
|
-
assertKnownOptions(options, [
|
|
1786
|
+
assertKnownOptions(options, [
|
|
1787
|
+
'defaultReapInterval',
|
|
1788
|
+
'defaultReapGCKrefs',
|
|
1789
|
+
'snapshotInterval',
|
|
1790
|
+
]);
|
|
1737
1791
|
kernelKeeper.startCrank();
|
|
1738
1792
|
try {
|
|
1739
1793
|
for (const option of Object.getOwnPropertyNames(options)) {
|
|
1740
1794
|
const value = options[option];
|
|
1741
1795
|
switch (option) {
|
|
1742
1796
|
case 'defaultReapInterval': {
|
|
1743
|
-
|
|
1797
|
+
assert(
|
|
1798
|
+
(typeof value === 'number' && value > 0) || value === 'never',
|
|
1799
|
+
`defaultReapInterval ${value} must be a positive number or "never"`,
|
|
1800
|
+
);
|
|
1801
|
+
kernelKeeper.setDefaultReapDirtThreshold({
|
|
1802
|
+
...kernelKeeper.getDefaultReapDirtThreshold(),
|
|
1803
|
+
deliveries: value,
|
|
1804
|
+
});
|
|
1805
|
+
break;
|
|
1806
|
+
}
|
|
1807
|
+
case 'defaultReapGCKrefs': {
|
|
1808
|
+
assert(
|
|
1809
|
+
(typeof value === 'number' && value > 0) || value === 'never',
|
|
1810
|
+
`defaultReapGCKrefs ${value} must be a positive number or "never"`,
|
|
1811
|
+
);
|
|
1812
|
+
kernelKeeper.setDefaultReapDirtThreshold({
|
|
1813
|
+
...kernelKeeper.getDefaultReapDirtThreshold(),
|
|
1814
|
+
gcKrefs: value,
|
|
1815
|
+
});
|
|
1744
1816
|
break;
|
|
1745
1817
|
}
|
|
1746
1818
|
case 'snapshotInterval': {
|