@agoric/swingset-liveslots 0.10.3-other-dev-8f8782b.0 → 0.10.3-other-dev-fbe72e7.0.fbe72e7

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