@agoric/swingset-liveslots 0.10.3-other-dev-1f26562.0 → 0.10.3-other-dev-3eb1a1d.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/README.md +2 -0
- package/package.json +27 -19
- package/src/boyd-gc.js +598 -0
- package/src/cache.js +3 -2
- package/src/capdata.js +1 -2
- package/src/collectionManager.js +219 -103
- package/src/facetiousness.js +1 -1
- package/src/index.js +4 -2
- package/src/liveslots.js +131 -301
- package/src/message.js +5 -5
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.js +8 -2
- package/src/vatstore-iterators.js +2 -0
- package/src/virtualObjectManager.js +185 -71
- package/src/virtualReferences.js +135 -26
- package/src/watchedPromises.js +67 -17
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/clear-collection.test.js +586 -0
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +158 -14
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/dropped-weakset-9939.test.js +80 -0
- package/test/dummyMeterControl.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +2 -3
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +506 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
- package/test/liveslots-helpers.js +12 -7
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +62 -37
- package/test/{test-liveslots.js → liveslots.test.js} +14 -15
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/util.js +2 -2
- package/test/vat-environment.test.js +65 -0
- package/test/vat-util.js +2 -2
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -8
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.js +96 -0
- package/tools/vo-test-harness.js +143 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
package/src/collectionManager.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { assert, q, Fail } from '@
|
|
1
|
+
import { assert, q, Fail } from '@endo/errors';
|
|
2
2
|
import { Far, passStyleOf } from '@endo/far';
|
|
3
3
|
import {
|
|
4
4
|
zeroPad,
|
|
5
5
|
makeEncodePassable,
|
|
6
6
|
makeDecodePassable,
|
|
7
|
-
isEncodedRemotable,
|
|
8
7
|
compareRank,
|
|
9
8
|
} from '@endo/marshal';
|
|
10
9
|
import {
|
|
@@ -15,7 +14,10 @@ import {
|
|
|
15
14
|
makeCopySet,
|
|
16
15
|
makeCopyMap,
|
|
17
16
|
getRankCover,
|
|
17
|
+
getCopyMapEntries,
|
|
18
|
+
getCopySetKeys,
|
|
18
19
|
} from '@endo/patterns';
|
|
20
|
+
import { isCopyMap, isCopySet } from '@agoric/store';
|
|
19
21
|
import { makeBaseRef, parseVatSlot } from './parseVatSlots.js';
|
|
20
22
|
import {
|
|
21
23
|
enumerateKeysStartEnd,
|
|
@@ -23,6 +25,10 @@ import {
|
|
|
23
25
|
} from './vatstore-iterators.js';
|
|
24
26
|
import { makeCache } from './cache.js';
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @import {ToCapData, FromCapData} from '@endo/marshal';
|
|
30
|
+
*/
|
|
31
|
+
|
|
26
32
|
// XXX TODO: The following key length limit was put in place due to limitations
|
|
27
33
|
// in LMDB. With the move away from LMDB, it is no longer relevant, but I'm
|
|
28
34
|
// leaving it in place for the time being as a general defensive measure against
|
|
@@ -47,10 +53,24 @@ function throwNotDurable(value, slotIndex, serializedValue) {
|
|
|
47
53
|
Fail`value is not durable: ${value} at slot ${q(slotIndex)} of ${serializedValue.body}`;
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
function failNotFound(key, label) {
|
|
57
|
+
Fail`key ${key} not found in collection ${q(label)}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function failNotIterable(value) {
|
|
61
|
+
Fail`provided data source is not iterable: ${value}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
function prefixc(collectionID, dbEntryKey) {
|
|
51
65
|
return `vc.${collectionID}.${dbEntryKey}`;
|
|
52
66
|
}
|
|
53
67
|
|
|
68
|
+
export const collectionMetaKeys = new Set([
|
|
69
|
+
'|entryCount',
|
|
70
|
+
'|nextOrdinal',
|
|
71
|
+
'|schemata',
|
|
72
|
+
]);
|
|
73
|
+
|
|
54
74
|
/**
|
|
55
75
|
* @typedef {object} SchemaCacheValue
|
|
56
76
|
* @property {Pattern} keyShape
|
|
@@ -101,8 +121,8 @@ function makeSchemaCache(syscall, unserialize) {
|
|
|
101
121
|
* @param {(val: any) => string | undefined} convertValToSlot
|
|
102
122
|
* @param {*} convertSlotToVal
|
|
103
123
|
* @param {*} registerValue
|
|
104
|
-
* @param {
|
|
105
|
-
* @param {
|
|
124
|
+
* @param {ToCapData<string>} serialize
|
|
125
|
+
* @param {FromCapData<string>} unserialize
|
|
106
126
|
* @param {(capDatas: any) => void} assertAcceptableSyscallCapdataSize
|
|
107
127
|
*/
|
|
108
128
|
export function makeCollectionManager(
|
|
@@ -126,56 +146,48 @@ export function makeCollectionManager(
|
|
|
126
146
|
scalarMapStore: {
|
|
127
147
|
hasWeakKeys: false,
|
|
128
148
|
kindID: 0,
|
|
129
|
-
// eslint-disable-next-line no-use-before-define
|
|
130
149
|
reanimator: reanimateMapStore,
|
|
131
150
|
durable: false,
|
|
132
151
|
},
|
|
133
152
|
scalarWeakMapStore: {
|
|
134
153
|
hasWeakKeys: true,
|
|
135
154
|
kindID: 0,
|
|
136
|
-
// eslint-disable-next-line no-use-before-define
|
|
137
155
|
reanimator: reanimateWeakMapStore,
|
|
138
156
|
durable: false,
|
|
139
157
|
},
|
|
140
158
|
scalarSetStore: {
|
|
141
159
|
hasWeakKeys: false,
|
|
142
160
|
kindID: 0,
|
|
143
|
-
// eslint-disable-next-line no-use-before-define
|
|
144
161
|
reanimator: reanimateSetStore,
|
|
145
162
|
durable: false,
|
|
146
163
|
},
|
|
147
164
|
scalarWeakSetStore: {
|
|
148
165
|
hasWeakKeys: true,
|
|
149
166
|
kindID: 0,
|
|
150
|
-
// eslint-disable-next-line no-use-before-define
|
|
151
167
|
reanimator: reanimateWeakSetStore,
|
|
152
168
|
durable: false,
|
|
153
169
|
},
|
|
154
170
|
scalarDurableMapStore: {
|
|
155
171
|
hasWeakKeys: false,
|
|
156
172
|
kindID: 0,
|
|
157
|
-
// eslint-disable-next-line no-use-before-define
|
|
158
173
|
reanimator: reanimateMapStore,
|
|
159
174
|
durable: true,
|
|
160
175
|
},
|
|
161
176
|
scalarDurableWeakMapStore: {
|
|
162
177
|
hasWeakKeys: true,
|
|
163
178
|
kindID: 0,
|
|
164
|
-
// eslint-disable-next-line no-use-before-define
|
|
165
179
|
reanimator: reanimateWeakMapStore,
|
|
166
180
|
durable: true,
|
|
167
181
|
},
|
|
168
182
|
scalarDurableSetStore: {
|
|
169
183
|
hasWeakKeys: false,
|
|
170
184
|
kindID: 0,
|
|
171
|
-
// eslint-disable-next-line no-use-before-define
|
|
172
185
|
reanimator: reanimateSetStore,
|
|
173
186
|
durable: true,
|
|
174
187
|
},
|
|
175
188
|
scalarDurableWeakSetStore: {
|
|
176
189
|
hasWeakKeys: true,
|
|
177
190
|
kindID: 0,
|
|
178
|
-
// eslint-disable-next-line no-use-before-define
|
|
179
191
|
reanimator: reanimateWeakSetStore,
|
|
180
192
|
durable: true,
|
|
181
193
|
},
|
|
@@ -198,7 +210,6 @@ export function makeCollectionManager(
|
|
|
198
210
|
vrm.registerKind(
|
|
199
211
|
kindID,
|
|
200
212
|
storeKindInfo[kind].reanimator,
|
|
201
|
-
// eslint-disable-next-line no-use-before-define
|
|
202
213
|
deleteCollection,
|
|
203
214
|
storeKindInfo[kind].durable,
|
|
204
215
|
);
|
|
@@ -244,7 +255,11 @@ export function makeCollectionManager(
|
|
|
244
255
|
const kindInfo = storeKindInfo[kindName];
|
|
245
256
|
kindInfo || Fail`unknown collection kind ${kindName}`;
|
|
246
257
|
const { hasWeakKeys, durable } = kindInfo;
|
|
247
|
-
const getSchema = () =>
|
|
258
|
+
const getSchema = () => {
|
|
259
|
+
const result = schemaCache.get(collectionID);
|
|
260
|
+
assert(result !== undefined);
|
|
261
|
+
return result;
|
|
262
|
+
};
|
|
248
263
|
const dbKeyPrefix = `vc.${collectionID}.`;
|
|
249
264
|
let currentGenerationNumber = 0;
|
|
250
265
|
|
|
@@ -274,8 +289,21 @@ export function makeCollectionManager(
|
|
|
274
289
|
return `${dbKeyPrefix}${dbEntryKey}`;
|
|
275
290
|
}
|
|
276
291
|
|
|
292
|
+
// A "vref" is a string like "o-4" or "o+d44/2:0"
|
|
293
|
+
// An "EncodedKey" is the output of encode-passable:
|
|
294
|
+
// * strings become `s${string}`, like "foo" -> "sfoo"
|
|
295
|
+
// * small positive BigInts become `p${len}:${digits}`, like 47n -> "p2:47"
|
|
296
|
+
// * refs are assigned an "ordinal" and use `r${fixedLengthOrdinal}:${vref}`
|
|
297
|
+
// * e.g. vref(o-4) becomes "r0000000001:o-4"
|
|
298
|
+
// A "DBKey" is used to index the vatstore. DBKeys for collection
|
|
299
|
+
// entries join a collection prefix and an EncodedKey. Some
|
|
300
|
+
// possible DBKeys for entries of collection "5", using collection
|
|
301
|
+
// prefix "vc.5.", are:
|
|
302
|
+
// * "foo" -> "vc.5.sfoo"
|
|
303
|
+
// * 47n -> "vc.5.p2:47"
|
|
304
|
+
// * vref(o-4) -> "vc.5.r0000000001:o-4"
|
|
305
|
+
|
|
277
306
|
const encodeRemotable = remotable => {
|
|
278
|
-
// eslint-disable-next-line no-use-before-define
|
|
279
307
|
const ordinal = getOrdinal(remotable);
|
|
280
308
|
ordinal !== undefined || Fail`no ordinal for ${remotable}`;
|
|
281
309
|
const ordinalTag = zeroPad(ordinal, BIGINT_TAG_LEN);
|
|
@@ -289,10 +317,11 @@ export function makeCollectionManager(
|
|
|
289
317
|
// the resulting function will encode only `Key` arguments.
|
|
290
318
|
const encodeKey = makeEncodePassable({ encodeRemotable });
|
|
291
319
|
|
|
292
|
-
const
|
|
320
|
+
const vrefFromEncodedKey = encodedKey =>
|
|
321
|
+
encodedKey.substring(1 + BIGINT_TAG_LEN + 1);
|
|
293
322
|
|
|
294
323
|
const decodeRemotable = encodedKey =>
|
|
295
|
-
convertSlotToVal(
|
|
324
|
+
convertSlotToVal(vrefFromEncodedKey(encodedKey));
|
|
296
325
|
|
|
297
326
|
// `makeDecodePassable` has three named options:
|
|
298
327
|
// `decodeRemotable`, `decodeError`, and `decodePromise`.
|
|
@@ -328,32 +357,40 @@ export function makeCollectionManager(
|
|
|
328
357
|
}
|
|
329
358
|
|
|
330
359
|
function dbKeyToKey(dbKey) {
|
|
360
|
+
// convert e.g. vc.5.r0000000001:o+v10/1 to r0000000001:o+v10/1
|
|
331
361
|
const dbEntryKey = dbKey.substring(dbKeyPrefix.length);
|
|
332
362
|
return decodeKey(dbEntryKey);
|
|
333
363
|
}
|
|
334
364
|
|
|
365
|
+
function dbKeyToEncodedKey(dbKey) {
|
|
366
|
+
assert(dbKey.startsWith(dbKeyPrefix), dbKey);
|
|
367
|
+
return dbKey.substring(dbKeyPrefix.length);
|
|
368
|
+
}
|
|
369
|
+
|
|
335
370
|
function has(key) {
|
|
336
371
|
const { keyShape } = getSchema();
|
|
337
372
|
if (!matches(key, keyShape)) {
|
|
338
373
|
return false;
|
|
339
|
-
}
|
|
340
|
-
if (passStyleOf(key) === 'remotable') {
|
|
374
|
+
} else if (passStyleOf(key) === 'remotable') {
|
|
341
375
|
return getOrdinal(key) !== undefined;
|
|
342
376
|
} else {
|
|
343
377
|
return syscall.vatstoreGet(keyToDBKey(key)) !== undefined;
|
|
344
378
|
}
|
|
345
379
|
}
|
|
346
380
|
|
|
381
|
+
function mustGet(key, label) {
|
|
382
|
+
if (passStyleOf(key) === 'remotable' && getOrdinal(key) === undefined) {
|
|
383
|
+
failNotFound(key, label);
|
|
384
|
+
}
|
|
385
|
+
const dbKey = keyToDBKey(key);
|
|
386
|
+
const result = syscall.vatstoreGet(dbKey) || failNotFound(key, label);
|
|
387
|
+
return { dbKey, result };
|
|
388
|
+
}
|
|
389
|
+
|
|
347
390
|
function get(key) {
|
|
348
391
|
const { keyShape, label } = getSchema();
|
|
349
392
|
mustMatch(key, keyShape, makeInvalidKeyTypeMsg(label));
|
|
350
|
-
|
|
351
|
-
throw Fail`key ${key} not found in collection ${q(label)}`;
|
|
352
|
-
}
|
|
353
|
-
const result = syscall.vatstoreGet(keyToDBKey(key));
|
|
354
|
-
if (!result) {
|
|
355
|
-
throw Fail`key ${key} not found in collection ${q(label)}`;
|
|
356
|
-
}
|
|
393
|
+
const { result } = mustGet(key, label);
|
|
357
394
|
return unserializeValue(JSON.parse(result));
|
|
358
395
|
}
|
|
359
396
|
|
|
@@ -377,11 +414,11 @@ export function makeCollectionManager(
|
|
|
377
414
|
currentGenerationNumber += 1;
|
|
378
415
|
assertAcceptableSyscallCapdataSize([serializedValue]);
|
|
379
416
|
if (durable) {
|
|
380
|
-
serializedValue.slots.
|
|
417
|
+
for (const [slotIndex, vref] of serializedValue.slots.entries()) {
|
|
381
418
|
if (!vrm.isDurable(vref)) {
|
|
382
419
|
throwNotDurable(value, slotIndex, serializedValue);
|
|
383
420
|
}
|
|
384
|
-
}
|
|
421
|
+
}
|
|
385
422
|
}
|
|
386
423
|
if (passStyleOf(key) === 'remotable') {
|
|
387
424
|
/** @type {string} */
|
|
@@ -397,7 +434,9 @@ export function makeCollectionManager(
|
|
|
397
434
|
vrm.addReachableVref(vref);
|
|
398
435
|
}
|
|
399
436
|
}
|
|
400
|
-
serializedValue.slots
|
|
437
|
+
for (const vref of serializedValue.slots) {
|
|
438
|
+
vrm.addReachableVref(vref);
|
|
439
|
+
}
|
|
401
440
|
syscall.vatstoreSet(keyToDBKey(key), JSON.stringify(serializedValue));
|
|
402
441
|
updateEntryCount(1);
|
|
403
442
|
};
|
|
@@ -416,15 +455,13 @@ export function makeCollectionManager(
|
|
|
416
455
|
const after = serializeValue(harden(value));
|
|
417
456
|
assertAcceptableSyscallCapdataSize([after]);
|
|
418
457
|
if (durable) {
|
|
419
|
-
after.slots.
|
|
458
|
+
for (const [i, vref] of after.slots.entries()) {
|
|
420
459
|
if (!vrm.isDurable(vref)) {
|
|
421
460
|
throwNotDurable(value, i, after);
|
|
422
461
|
}
|
|
423
|
-
}
|
|
462
|
+
}
|
|
424
463
|
}
|
|
425
|
-
const dbKey =
|
|
426
|
-
const rawBefore = syscall.vatstoreGet(dbKey);
|
|
427
|
-
rawBefore || Fail`key ${key} not found in collection ${q(label)}`;
|
|
464
|
+
const { dbKey, result: rawBefore } = mustGet(key, label);
|
|
428
465
|
const before = JSON.parse(rawBefore);
|
|
429
466
|
vrm.updateReferenceCounts(before.slots, after.slots);
|
|
430
467
|
syscall.vatstoreSet(dbKey, JSON.stringify(after));
|
|
@@ -433,12 +470,7 @@ export function makeCollectionManager(
|
|
|
433
470
|
function deleteInternal(key) {
|
|
434
471
|
const { keyShape, label } = getSchema();
|
|
435
472
|
mustMatch(key, keyShape, makeInvalidKeyTypeMsg(label));
|
|
436
|
-
|
|
437
|
-
throw Fail`key ${key} not found in collection ${q(label)}`;
|
|
438
|
-
}
|
|
439
|
-
const dbKey = keyToDBKey(key);
|
|
440
|
-
const rawValue = syscall.vatstoreGet(dbKey);
|
|
441
|
-
rawValue || Fail`key ${key} not found in collection ${q(label)}`;
|
|
473
|
+
const { dbKey, result: rawValue } = mustGet(key, label);
|
|
442
474
|
const value = JSON.parse(rawValue);
|
|
443
475
|
const doMoreGC1 = value.slots.map(vrm.removeReachableVref).some(b => b);
|
|
444
476
|
syscall.vatstoreDelete(dbKey);
|
|
@@ -474,18 +506,15 @@ export function makeCollectionManager(
|
|
|
474
506
|
const end = prefix(coverEnd); // exclusive
|
|
475
507
|
|
|
476
508
|
const generationAtStart = currentGenerationNumber;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
}
|
|
509
|
+
const checkGen = () =>
|
|
510
|
+
currentGenerationNumber === generationAtStart ||
|
|
511
|
+
Fail`keys in store cannot be added to during iteration`;
|
|
482
512
|
|
|
483
513
|
const needToMatchKey = !matchAny(keyPatt);
|
|
484
514
|
const needToMatchValue = !matchAny(valuePatt);
|
|
485
515
|
|
|
486
|
-
// we
|
|
516
|
+
// we might not need to unserialize the dbKey or get the dbValue
|
|
487
517
|
const needKeys = yieldKeys || needToMatchKey;
|
|
488
|
-
// we don't always need the dbValue
|
|
489
518
|
const needValues = yieldValues || needToMatchValue;
|
|
490
519
|
|
|
491
520
|
/**
|
|
@@ -513,7 +542,7 @@ export function makeCollectionManager(
|
|
|
513
542
|
yield [yieldKeys ? key : undefined, yieldValues ? value : undefined];
|
|
514
543
|
}
|
|
515
544
|
}
|
|
516
|
-
|
|
545
|
+
harden(iter);
|
|
517
546
|
return iter();
|
|
518
547
|
}
|
|
519
548
|
|
|
@@ -523,6 +552,7 @@ export function makeCollectionManager(
|
|
|
523
552
|
yield entry[0];
|
|
524
553
|
}
|
|
525
554
|
}
|
|
555
|
+
harden(iter);
|
|
526
556
|
return iter();
|
|
527
557
|
}
|
|
528
558
|
|
|
@@ -539,40 +569,58 @@ export function makeCollectionManager(
|
|
|
539
569
|
*/
|
|
540
570
|
function clearInternalFull() {
|
|
541
571
|
let doMoreGC = false;
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
//
|
|
547
|
-
for (const dbKey of
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if (
|
|
553
|
-
|
|
572
|
+
|
|
573
|
+
// visit every DB entry associated with the collection, which
|
|
574
|
+
// (due to sorting) will be collection entries first, and then a
|
|
575
|
+
// mixture of ordinal-assignment mappings and size-independent
|
|
576
|
+
// metadata (both of which start with "|").
|
|
577
|
+
for (const dbKey of enumerateKeysWithPrefix(syscall, dbKeyPrefix)) {
|
|
578
|
+
const encodedKey = dbKeyToEncodedKey(dbKey);
|
|
579
|
+
|
|
580
|
+
// preserve general metadata ("|entryCount" and friends are
|
|
581
|
+
// cleared by our caller)
|
|
582
|
+
if (collectionMetaKeys.has(encodedKey)) continue;
|
|
583
|
+
|
|
584
|
+
if (encodedKey.startsWith('|')) {
|
|
585
|
+
// ordinal assignment; decref or de-recognize its vref
|
|
586
|
+
const keyVref = encodedKey.substring(1);
|
|
587
|
+
parseVatSlot(keyVref);
|
|
554
588
|
if (hasWeakKeys) {
|
|
555
589
|
vrm.removeRecognizableVref(keyVref, `${collectionID}`, true);
|
|
556
590
|
} else {
|
|
557
591
|
doMoreGC = vrm.removeReachableVref(keyVref) || doMoreGC;
|
|
558
592
|
}
|
|
559
|
-
|
|
593
|
+
} else {
|
|
594
|
+
// a collection entry; decref slots from its value
|
|
595
|
+
const value = JSON.parse(syscall.vatstoreGet(dbKey));
|
|
596
|
+
doMoreGC =
|
|
597
|
+
value.slots.map(vrm.removeReachableVref).some(b => b) || doMoreGC;
|
|
560
598
|
}
|
|
599
|
+
|
|
600
|
+
// in either case, delete the DB entry
|
|
601
|
+
syscall.vatstoreDelete(dbKey);
|
|
561
602
|
}
|
|
603
|
+
|
|
562
604
|
return doMoreGC;
|
|
563
605
|
}
|
|
564
606
|
|
|
565
607
|
function clearInternal(isDeleting, keyPatt, valuePatt) {
|
|
566
608
|
let doMoreGC = false;
|
|
567
|
-
if (isDeleting
|
|
609
|
+
if (isDeleting) {
|
|
568
610
|
doMoreGC = clearInternalFull();
|
|
611
|
+
// |entryCount will be deleted along with metadata keys
|
|
612
|
+
} else if (matchAny(keyPatt) && matchAny(valuePatt)) {
|
|
613
|
+
doMoreGC = clearInternalFull();
|
|
614
|
+
if (!hasWeakKeys) {
|
|
615
|
+
syscall.vatstoreSet(prefix('|entryCount'), '0');
|
|
616
|
+
}
|
|
569
617
|
} else {
|
|
618
|
+
let numDeleted = 0;
|
|
570
619
|
for (const k of keys(keyPatt, valuePatt)) {
|
|
620
|
+
numDeleted += 1;
|
|
571
621
|
doMoreGC = deleteInternal(k) || doMoreGC;
|
|
572
622
|
}
|
|
573
|
-
|
|
574
|
-
if (!hasWeakKeys && !isDeleting) {
|
|
575
|
-
syscall.vatstoreSet(prefix('|entryCount'), '0');
|
|
623
|
+
updateEntryCount(-numDeleted);
|
|
576
624
|
}
|
|
577
625
|
return doMoreGC;
|
|
578
626
|
}
|
|
@@ -587,6 +635,7 @@ export function makeCollectionManager(
|
|
|
587
635
|
yield entry[1];
|
|
588
636
|
}
|
|
589
637
|
}
|
|
638
|
+
harden(iter);
|
|
590
639
|
return iter();
|
|
591
640
|
}
|
|
592
641
|
|
|
@@ -596,12 +645,13 @@ export function makeCollectionManager(
|
|
|
596
645
|
yield entry;
|
|
597
646
|
}
|
|
598
647
|
}
|
|
648
|
+
harden(iter);
|
|
599
649
|
return iter();
|
|
600
650
|
}
|
|
601
651
|
|
|
602
652
|
function countEntries(keyPatt, valuePatt) {
|
|
603
653
|
let count = 0;
|
|
604
|
-
// eslint-disable-next-line no-
|
|
654
|
+
// eslint-disable-next-line no-unused-vars
|
|
605
655
|
for (const k of keys(keyPatt, valuePatt)) {
|
|
606
656
|
count += 1;
|
|
607
657
|
}
|
|
@@ -624,6 +674,34 @@ export function makeCollectionManager(
|
|
|
624
674
|
const snapshotMap = (keyPatt, valuePatt) =>
|
|
625
675
|
makeCopyMap(entries(keyPatt, valuePatt));
|
|
626
676
|
|
|
677
|
+
const addAllToSet = elems => {
|
|
678
|
+
if (typeof elems[Symbol.iterator] !== 'function') {
|
|
679
|
+
elems =
|
|
680
|
+
Object.isFrozen(elems) && isCopySet(elems)
|
|
681
|
+
? getCopySetKeys(elems)
|
|
682
|
+
: failNotIterable(elems);
|
|
683
|
+
}
|
|
684
|
+
for (const elem of elems) {
|
|
685
|
+
addToSet(elem);
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
const addAllToMap = mapEntries => {
|
|
690
|
+
if (typeof mapEntries[Symbol.iterator] !== 'function') {
|
|
691
|
+
mapEntries =
|
|
692
|
+
Object.isFrozen(mapEntries) && isCopyMap(mapEntries)
|
|
693
|
+
? getCopyMapEntries(mapEntries)
|
|
694
|
+
: failNotIterable(mapEntries);
|
|
695
|
+
}
|
|
696
|
+
for (const [key, value] of mapEntries) {
|
|
697
|
+
if (has(key)) {
|
|
698
|
+
set(key, value);
|
|
699
|
+
} else {
|
|
700
|
+
doInit(key, value, true);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
627
705
|
return {
|
|
628
706
|
has,
|
|
629
707
|
get,
|
|
@@ -635,6 +713,8 @@ export function makeCollectionManager(
|
|
|
635
713
|
keys,
|
|
636
714
|
values,
|
|
637
715
|
entries,
|
|
716
|
+
addAllToSet,
|
|
717
|
+
addAllToMap,
|
|
638
718
|
snapshotSet,
|
|
639
719
|
snapshotMap,
|
|
640
720
|
sizeInternal,
|
|
@@ -647,12 +727,23 @@ export function makeCollectionManager(
|
|
|
647
727
|
const hasWeakKeys = storeKindInfo[kindName].hasWeakKeys;
|
|
648
728
|
const raw = summonCollectionInternal(initial, collectionID, kindName);
|
|
649
729
|
|
|
650
|
-
const {
|
|
730
|
+
const {
|
|
731
|
+
has,
|
|
732
|
+
get,
|
|
733
|
+
init,
|
|
734
|
+
addToSet,
|
|
735
|
+
addAllToMap,
|
|
736
|
+
addAllToSet,
|
|
737
|
+
set,
|
|
738
|
+
delete: del,
|
|
739
|
+
} = raw;
|
|
651
740
|
const weakMethods = {
|
|
652
741
|
has,
|
|
653
742
|
get,
|
|
654
743
|
init,
|
|
655
744
|
addToSet,
|
|
745
|
+
addAllToSet,
|
|
746
|
+
addAllToMap,
|
|
656
747
|
set,
|
|
657
748
|
delete: del,
|
|
658
749
|
};
|
|
@@ -700,7 +791,9 @@ export function makeCollectionManager(
|
|
|
700
791
|
const collection = summonCollectionInternal(false, collectionID, kindName);
|
|
701
792
|
|
|
702
793
|
let doMoreGC = collection.clearInternal(true);
|
|
703
|
-
const
|
|
794
|
+
const record = schemaCache.get(collectionID);
|
|
795
|
+
assert(record !== undefined);
|
|
796
|
+
const { schemataCapData } = record;
|
|
704
797
|
doMoreGC =
|
|
705
798
|
schemataCapData.slots.map(vrm.removeReachableVref).some(b => b) ||
|
|
706
799
|
doMoreGC;
|
|
@@ -747,13 +840,15 @@ export function makeCollectionManager(
|
|
|
747
840
|
}
|
|
748
841
|
const schemataCapData = serialize(harden(schemata));
|
|
749
842
|
if (isDurable) {
|
|
750
|
-
schemataCapData.slots.
|
|
843
|
+
for (const [slotIndex, vref] of schemataCapData.slots.entries()) {
|
|
751
844
|
if (!vrm.isDurable(vref)) {
|
|
752
845
|
throwNotDurable(vref, slotIndex, schemataCapData);
|
|
753
846
|
}
|
|
754
|
-
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
for (const vref of schemataCapData.slots) {
|
|
850
|
+
vrm.addReachableVref(vref);
|
|
755
851
|
}
|
|
756
|
-
schemataCapData.slots.forEach(vrm.addReachableVref);
|
|
757
852
|
|
|
758
853
|
schemaCache.set(
|
|
759
854
|
collectionID,
|
|
@@ -764,12 +859,48 @@ export function makeCollectionManager(
|
|
|
764
859
|
}
|
|
765
860
|
|
|
766
861
|
function collectionToMapStore(collection) {
|
|
767
|
-
const {
|
|
768
|
-
|
|
862
|
+
const {
|
|
863
|
+
has,
|
|
864
|
+
get,
|
|
865
|
+
init,
|
|
866
|
+
set,
|
|
867
|
+
delete: del,
|
|
868
|
+
addAllToMap,
|
|
869
|
+
keys,
|
|
870
|
+
values,
|
|
871
|
+
entries,
|
|
872
|
+
snapshotMap,
|
|
873
|
+
getSize,
|
|
874
|
+
clear,
|
|
875
|
+
} = collection;
|
|
876
|
+
const mapStore = {
|
|
877
|
+
has,
|
|
878
|
+
get,
|
|
879
|
+
init,
|
|
880
|
+
set,
|
|
881
|
+
delete: del,
|
|
882
|
+
addAll: addAllToMap,
|
|
883
|
+
keys,
|
|
884
|
+
values,
|
|
885
|
+
entries,
|
|
886
|
+
snapshot: snapshotMap,
|
|
887
|
+
getSize,
|
|
888
|
+
clear,
|
|
889
|
+
};
|
|
890
|
+
return Far('mapStore', mapStore);
|
|
769
891
|
}
|
|
770
892
|
|
|
771
893
|
function collectionToWeakMapStore(collection) {
|
|
772
|
-
|
|
894
|
+
const { has, get, init, set, delete: del, addAllToMap } = collection;
|
|
895
|
+
const weakMapStore = {
|
|
896
|
+
has,
|
|
897
|
+
get,
|
|
898
|
+
init,
|
|
899
|
+
set,
|
|
900
|
+
delete: del,
|
|
901
|
+
addAll: addAllToMap,
|
|
902
|
+
};
|
|
903
|
+
return Far('weakMapStore', weakMapStore);
|
|
773
904
|
}
|
|
774
905
|
|
|
775
906
|
function collectionToSetStore(collection) {
|
|
@@ -777,50 +908,35 @@ export function makeCollectionManager(
|
|
|
777
908
|
has,
|
|
778
909
|
addToSet,
|
|
779
910
|
delete: del,
|
|
911
|
+
addAllToSet,
|
|
780
912
|
keys,
|
|
781
|
-
getSize,
|
|
782
913
|
snapshotSet,
|
|
914
|
+
getSize,
|
|
783
915
|
clear,
|
|
784
916
|
} = collection;
|
|
785
|
-
function* entries(patt) {
|
|
786
|
-
for (const k of keys(patt)) {
|
|
787
|
-
yield [k, k];
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
function addAll(elems) {
|
|
791
|
-
for (const elem of elems) {
|
|
792
|
-
addToSet(elem, null);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
917
|
|
|
796
918
|
const setStore = {
|
|
797
919
|
has,
|
|
798
920
|
add: addToSet,
|
|
799
|
-
addAll,
|
|
800
921
|
delete: del,
|
|
922
|
+
addAll: addAllToSet,
|
|
801
923
|
keys: patt => keys(patt),
|
|
802
924
|
values: patt => keys(patt),
|
|
803
|
-
entries,
|
|
804
|
-
getSize: patt => getSize(patt),
|
|
805
925
|
snapshot: snapshotSet,
|
|
926
|
+
getSize: patt => getSize(patt),
|
|
806
927
|
clear,
|
|
807
928
|
};
|
|
808
929
|
return Far('setStore', setStore);
|
|
809
930
|
}
|
|
810
931
|
|
|
811
932
|
function collectionToWeakSetStore(collection) {
|
|
812
|
-
const { has, addToSet, delete: del } = collection;
|
|
813
|
-
function addAll(elems) {
|
|
814
|
-
for (const elem of elems) {
|
|
815
|
-
addToSet(elem);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
933
|
+
const { has, addToSet, delete: del, addAllToSet } = collection;
|
|
818
934
|
|
|
819
935
|
const weakSetStore = {
|
|
820
936
|
has,
|
|
821
937
|
add: addToSet,
|
|
822
|
-
addAll,
|
|
823
938
|
delete: del,
|
|
939
|
+
addAll: addAllToSet,
|
|
824
940
|
};
|
|
825
941
|
return Far('weakSetStore', weakSetStore);
|
|
826
942
|
}
|
|
@@ -829,7 +945,7 @@ export function makeCollectionManager(
|
|
|
829
945
|
* Produce a big map.
|
|
830
946
|
*
|
|
831
947
|
* @template K,V
|
|
832
|
-
* @param {string} [label
|
|
948
|
+
* @param {string} [label] - diagnostic label for the store
|
|
833
949
|
* @param {StoreOptions} [options]
|
|
834
950
|
* @returns {MapStore<K,V>}
|
|
835
951
|
*/
|
|
@@ -873,7 +989,7 @@ export function makeCollectionManager(
|
|
|
873
989
|
* Produce a weak big map.
|
|
874
990
|
*
|
|
875
991
|
* @template K,V
|
|
876
|
-
* @param {string} [label
|
|
992
|
+
* @param {string} [label] - diagnostic label for the store
|
|
877
993
|
* @param {StoreOptions} [options]
|
|
878
994
|
* @returns {WeakMapStore<K,V>}
|
|
879
995
|
*/
|
|
@@ -902,7 +1018,7 @@ export function makeCollectionManager(
|
|
|
902
1018
|
* Produce a big set.
|
|
903
1019
|
*
|
|
904
1020
|
* @template K
|
|
905
|
-
* @param {string} [label
|
|
1021
|
+
* @param {string} [label] - diagnostic label for the store
|
|
906
1022
|
* @param {StoreOptions} [options]
|
|
907
1023
|
* @returns {SetStore<K>}
|
|
908
1024
|
*/
|
|
@@ -929,7 +1045,7 @@ export function makeCollectionManager(
|
|
|
929
1045
|
* Produce a weak big set.
|
|
930
1046
|
*
|
|
931
1047
|
* @template K
|
|
932
|
-
* @param {string} [label
|
|
1048
|
+
* @param {string} [label] - diagnostic label for the store
|
|
933
1049
|
* @param {StoreOptions} [options]
|
|
934
1050
|
* @returns {WeakSetStore<K>}
|
|
935
1051
|
*/
|
|
@@ -1006,7 +1122,7 @@ export function makeCollectionManager(
|
|
|
1006
1122
|
* remotables.
|
|
1007
1123
|
*
|
|
1008
1124
|
* @template K,V
|
|
1009
|
-
* @param {string} [label
|
|
1125
|
+
* @param {string} [label] - diagnostic label for the store
|
|
1010
1126
|
* @param {StoreOptions} [options]
|
|
1011
1127
|
* @returns {MapStore<K,V>}
|
|
1012
1128
|
*/
|
|
@@ -1018,7 +1134,7 @@ export function makeCollectionManager(
|
|
|
1018
1134
|
* primitives, or remotables.
|
|
1019
1135
|
*
|
|
1020
1136
|
* @template K,V
|
|
1021
|
-
* @param {string} [label
|
|
1137
|
+
* @param {string} [label] - diagnostic label for the store
|
|
1022
1138
|
* @param {StoreOptions} [options]
|
|
1023
1139
|
* @returns {WeakMapStore<K,V>}
|
|
1024
1140
|
*/
|
|
@@ -1030,7 +1146,7 @@ export function makeCollectionManager(
|
|
|
1030
1146
|
* remotables.
|
|
1031
1147
|
*
|
|
1032
1148
|
* @template K
|
|
1033
|
-
* @param {string} [label
|
|
1149
|
+
* @param {string} [label] - diagnostic label for the store
|
|
1034
1150
|
* @param {StoreOptions} [options]
|
|
1035
1151
|
* @returns {SetStore<K>}
|
|
1036
1152
|
*/
|
|
@@ -1042,7 +1158,7 @@ export function makeCollectionManager(
|
|
|
1042
1158
|
* primitives, or remotables.
|
|
1043
1159
|
*
|
|
1044
1160
|
* @template K
|
|
1045
|
-
* @param {string} [label
|
|
1161
|
+
* @param {string} [label] - diagnostic label for the store
|
|
1046
1162
|
* @param {StoreOptions} [options]
|
|
1047
1163
|
* @returns {WeakSetStore<K>}
|
|
1048
1164
|
*/
|