@fluidframework/container-runtime 2.0.0-rc.3.0.1 → 2.0.0-rc.3.0.11

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 (127) hide show
  1. package/api-report/container-runtime.api.md +30 -12
  2. package/dist/channelCollection.d.ts +5 -3
  3. package/dist/channelCollection.d.ts.map +1 -1
  4. package/dist/channelCollection.js +88 -29
  5. package/dist/channelCollection.js.map +1 -1
  6. package/dist/containerRuntime.d.ts +6 -1
  7. package/dist/containerRuntime.d.ts.map +1 -1
  8. package/dist/containerRuntime.js +55 -48
  9. package/dist/containerRuntime.js.map +1 -1
  10. package/dist/dataStoreContext.d.ts +1 -1
  11. package/dist/dataStoreContexts.d.ts +2 -0
  12. package/dist/dataStoreContexts.d.ts.map +1 -1
  13. package/dist/dataStoreContexts.js +7 -0
  14. package/dist/dataStoreContexts.js.map +1 -1
  15. package/dist/gc/garbageCollection.d.ts +4 -11
  16. package/dist/gc/garbageCollection.d.ts.map +1 -1
  17. package/dist/gc/garbageCollection.js +45 -29
  18. package/dist/gc/garbageCollection.js.map +1 -1
  19. package/dist/gc/gcDefinitions.d.ts +26 -5
  20. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  21. package/dist/gc/gcDefinitions.js.map +1 -1
  22. package/dist/gc/gcHelpers.d.ts +5 -4
  23. package/dist/gc/gcHelpers.d.ts.map +1 -1
  24. package/dist/gc/gcHelpers.js +14 -2
  25. package/dist/gc/gcHelpers.js.map +1 -1
  26. package/dist/gc/gcTelemetry.d.ts +13 -2
  27. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  28. package/dist/gc/gcTelemetry.js +24 -21
  29. package/dist/gc/gcTelemetry.js.map +1 -1
  30. package/dist/gc/index.d.ts +2 -2
  31. package/dist/gc/index.d.ts.map +1 -1
  32. package/dist/gc/index.js +2 -2
  33. package/dist/gc/index.js.map +1 -1
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/legacy.d.ts +1 -0
  39. package/dist/metadata.d.ts +2 -2
  40. package/dist/metadata.d.ts.map +1 -1
  41. package/dist/metadata.js.map +1 -1
  42. package/dist/opLifecycle/batchManager.d.ts +4 -1
  43. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  44. package/dist/opLifecycle/batchManager.js +0 -10
  45. package/dist/opLifecycle/batchManager.js.map +1 -1
  46. package/dist/opLifecycle/outbox.d.ts +0 -4
  47. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  48. package/dist/opLifecycle/outbox.js +7 -38
  49. package/dist/opLifecycle/outbox.js.map +1 -1
  50. package/dist/packageVersion.d.ts +1 -1
  51. package/dist/packageVersion.d.ts.map +1 -1
  52. package/dist/packageVersion.js +1 -1
  53. package/dist/packageVersion.js.map +1 -1
  54. package/dist/summary/documentSchema.js +1 -1
  55. package/dist/summary/documentSchema.js.map +1 -1
  56. package/lib/channelCollection.d.ts +5 -3
  57. package/lib/channelCollection.d.ts.map +1 -1
  58. package/lib/channelCollection.js +90 -31
  59. package/lib/channelCollection.js.map +1 -1
  60. package/lib/containerRuntime.d.ts +6 -1
  61. package/lib/containerRuntime.d.ts.map +1 -1
  62. package/lib/containerRuntime.js +54 -47
  63. package/lib/containerRuntime.js.map +1 -1
  64. package/lib/dataStoreContext.d.ts +1 -1
  65. package/lib/dataStoreContexts.d.ts +2 -0
  66. package/lib/dataStoreContexts.d.ts.map +1 -1
  67. package/lib/dataStoreContexts.js +7 -0
  68. package/lib/dataStoreContexts.js.map +1 -1
  69. package/lib/gc/garbageCollection.d.ts +4 -11
  70. package/lib/gc/garbageCollection.d.ts.map +1 -1
  71. package/lib/gc/garbageCollection.js +47 -31
  72. package/lib/gc/garbageCollection.js.map +1 -1
  73. package/lib/gc/gcDefinitions.d.ts +26 -5
  74. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  75. package/lib/gc/gcDefinitions.js.map +1 -1
  76. package/lib/gc/gcHelpers.d.ts +5 -4
  77. package/lib/gc/gcHelpers.d.ts.map +1 -1
  78. package/lib/gc/gcHelpers.js +12 -1
  79. package/lib/gc/gcHelpers.js.map +1 -1
  80. package/lib/gc/gcTelemetry.d.ts +13 -2
  81. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  82. package/lib/gc/gcTelemetry.js +24 -21
  83. package/lib/gc/gcTelemetry.js.map +1 -1
  84. package/lib/gc/index.d.ts +2 -2
  85. package/lib/gc/index.d.ts.map +1 -1
  86. package/lib/gc/index.js +1 -1
  87. package/lib/gc/index.js.map +1 -1
  88. package/lib/index.d.ts +2 -2
  89. package/lib/index.d.ts.map +1 -1
  90. package/lib/index.js +1 -1
  91. package/lib/index.js.map +1 -1
  92. package/lib/legacy.d.ts +1 -0
  93. package/lib/metadata.d.ts +2 -2
  94. package/lib/metadata.d.ts.map +1 -1
  95. package/lib/metadata.js.map +1 -1
  96. package/lib/opLifecycle/batchManager.d.ts +4 -1
  97. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  98. package/lib/opLifecycle/batchManager.js +0 -10
  99. package/lib/opLifecycle/batchManager.js.map +1 -1
  100. package/lib/opLifecycle/outbox.d.ts +0 -4
  101. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  102. package/lib/opLifecycle/outbox.js +7 -38
  103. package/lib/opLifecycle/outbox.js.map +1 -1
  104. package/lib/packageVersion.d.ts +1 -1
  105. package/lib/packageVersion.d.ts.map +1 -1
  106. package/lib/packageVersion.js +1 -1
  107. package/lib/packageVersion.js.map +1 -1
  108. package/lib/summary/documentSchema.js +1 -1
  109. package/lib/summary/documentSchema.js.map +1 -1
  110. package/package.json +20 -20
  111. package/src/channelCollection.ts +108 -49
  112. package/src/containerRuntime.ts +66 -80
  113. package/src/dataStoreContexts.ts +12 -0
  114. package/src/gc/garbageCollection.ts +63 -41
  115. package/src/gc/gcDefinitions.ts +21 -9
  116. package/src/gc/gcHelpers.ts +14 -1
  117. package/src/gc/gcTelemetry.ts +56 -47
  118. package/src/gc/index.ts +2 -1
  119. package/src/index.ts +2 -0
  120. package/src/metadata.ts +2 -2
  121. package/src/opLifecycle/README.md +4 -4
  122. package/src/opLifecycle/batchManager.ts +5 -14
  123. package/src/opLifecycle/outbox.ts +7 -53
  124. package/src/packageVersion.ts +1 -1
  125. package/src/summary/documentSchema.ts +1 -1
  126. package/dist/public.d.ts +0 -12
  127. package/lib/public.d.ts +0 -12
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
7
+ exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DeletedResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
8
8
  const client_utils_1 = require("@fluid-internal/client-utils");
9
9
  const container_definitions_1 = require("@fluidframework/container-definitions");
10
10
  const internal_1 = require("@fluidframework/container-definitions/internal");
@@ -61,6 +61,11 @@ exports.DefaultSummaryConfiguration = {
61
61
  runtimeOpWeight: 1.0,
62
62
  nonRuntimeHeuristicThreshold: 20,
63
63
  };
64
+ /**
65
+ * Error responses when requesting a deleted object will have this header set to true
66
+ * @alpha
67
+ */
68
+ exports.DeletedResponseHeaderKey = "wasDeleted";
64
69
  /**
65
70
  * Tombstone error responses will have this header set to true
66
71
  * @alpha
@@ -740,7 +745,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
740
745
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
741
746
  return this.submitSignalFn(envelope2, targetClientId);
742
747
  };
743
- this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (path, reason, timestampMs, packagePath, request, headerData) => this.garbageCollector.nodeUpdated(path, reason, timestampMs, packagePath, request, headerData), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
748
+ this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
744
749
  this.blobManager = new blobManager_js_1.BlobManager({
745
750
  routeContext: this.handleContext,
746
751
  snapshot: blobManagerSnapshot,
@@ -753,7 +758,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
753
758
  });
754
759
  }
755
760
  },
756
- blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
761
+ blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
762
+ node: { type: "Blob", path: blobPath },
763
+ reason: "Loaded",
764
+ }),
757
765
  isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
758
766
  runtime: this,
759
767
  stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
@@ -1236,6 +1244,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1236
1244
  this.emitDirtyDocumentEvent = false;
1237
1245
  let newState;
1238
1246
  try {
1247
+ this.submitIdAllocationOpIfNeeded(true);
1239
1248
  // replay the ops
1240
1249
  this.pendingStateManager.replayPendingStates();
1241
1250
  }
@@ -1412,9 +1421,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1412
1421
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1413
1422
  // but will not modify the contents object (likely it will replace it on the message).
1414
1423
  const messageCopy = { ...messageArg };
1424
+ const savedOp = messageCopy.metadata?.savedOp;
1415
1425
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1416
- if (modernRuntimeMessage) {
1417
- this.processCore({
1426
+ const msg = modernRuntimeMessage
1427
+ ? {
1418
1428
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1419
1429
  // There is nothing really ensuring that anytime original message.type is Operation that
1420
1430
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1422,12 +1432,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1422
1432
  message: message,
1423
1433
  local,
1424
1434
  modernRuntimeMessage,
1425
- });
1426
- }
1427
- else {
1428
- // Unrecognized message will be ignored.
1429
- this.processCore({ message, local, modernRuntimeMessage });
1430
- }
1435
+ }
1436
+ : // Unrecognized message will be ignored.
1437
+ {
1438
+ message,
1439
+ local,
1440
+ modernRuntimeMessage,
1441
+ };
1442
+ msg.savedOp = savedOp;
1443
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1444
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1431
1445
  }
1432
1446
  }
1433
1447
  /**
@@ -1492,9 +1506,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1492
1506
  // stashed ops flow. The compressor is stashed with these ops already processed.
1493
1507
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1494
1508
  // thus we need to process all the ops.
1495
- if (!(this.skipSavedCompressorOps &&
1496
- messageWithContext.message.metadata?.savedOp ===
1497
- true)) {
1509
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1498
1510
  const range = messageWithContext.message.contents;
1499
1511
  // Some other client turned on the id compressor. If we have not turned it on,
1500
1512
  // put it in a pending queue and delay finalization.
@@ -1623,9 +1635,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1623
1635
  let checkpoint;
1624
1636
  let result;
1625
1637
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1626
- // Note: we are not touching this.pendingAttachBatch here, for two reasons:
1627
- // 1. It would not help, as we flush attach ops as they become available.
1628
- // 2. There is no way to undo process of data store creation.
1638
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1639
+ // 1. It would not help, as other batches are flushed independently from main batch.
1640
+ // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
1629
1641
  checkpoint = this.outbox.checkpoint().mainBatch;
1630
1642
  }
1631
1643
  try {
@@ -1688,7 +1700,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1688
1700
  if (channel.entryPoint === undefined) {
1689
1701
  throw new internal_7.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1690
1702
  }
1691
- this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
1703
+ this.garbageCollector.nodeUpdated({
1704
+ node: { type: "DataStore", path: `/${internalId}` },
1705
+ reason: "Loaded",
1706
+ packagePath: context.packagePath,
1707
+ });
1692
1708
  return channel.entryPoint;
1693
1709
  }
1694
1710
  createDetachedDataStore(pkg, loadingGroupId) {
@@ -2083,9 +2099,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2083
2099
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
2084
2100
  const lastAck = this.summaryCollection.latestAck;
2085
2101
  const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
2102
+ /**
2103
+ * This was added to validate that the summarizer node tree has the same reference sequence number from the
2104
+ * top running summarizer down to the lowest summarizer node.
2105
+ *
2106
+ * The order of mismatch numbers goes (validate sequence number)-(node sequence number).
2107
+ * Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
2108
+ * summarizer nodes.
2109
+ */
2086
2110
  if (startSummaryResult.invalidNodes > 0 ||
2087
2111
  startSummaryResult.mismatchNumbers.size > 0) {
2088
- summaryLogger.sendErrorEvent({
2112
+ summaryLogger.sendTelemetryEvent({
2089
2113
  eventName: "LatestSummaryRefSeqNumMismatch",
2090
2114
  details: {
2091
2115
  ...startSummaryResult,
@@ -2358,9 +2382,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2358
2382
  this.verifyNotClosed();
2359
2383
  return this.blobManager.createBlob(blob, signal);
2360
2384
  }
2361
- submitIdAllocationOpIfNeeded() {
2385
+ submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
2362
2386
  if (this._idCompressor) {
2363
- const idRange = this._idCompressor.takeNextCreationRange();
2387
+ const idRange = resubmitOutstandingRanges
2388
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
2389
+ : this._idCompressor.takeNextCreationRange();
2364
2390
  // Don't include the idRange if there weren't any Ids allocated
2365
2391
  if (idRange?.ids !== undefined) {
2366
2392
  const idAllocationMessage = {
@@ -2422,32 +2448,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2422
2448
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2423
2449
  });
2424
2450
  }
2425
- // If this is attach message for new data store, and we are in a batch, send this op out of order
2426
- // Is it safe:
2427
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
2428
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
2429
- // is stored in some DDS, i.e. only after some other op.
2430
- // Why:
2431
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
2432
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
2433
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
2434
- // these issues.
2435
- // Cons:
2436
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
2437
- // This change creates new possibility of a lot of newly created data stores never being referenced
2438
- // because client died before it had a change to submit the rest of the ops. This will create more
2439
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
2440
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
2441
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
2442
- // issue than sending.
2443
- // Please note that this does not change file format, so it can be disabled in the future if this
2444
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
2445
- if (this.currentlyBatching() &&
2446
- type === messageTypes_js_1.ContainerMessageType.Attach &&
2447
- this.disableAttachReorder !== true) {
2448
- this.outbox.submitAttach(message);
2449
- }
2450
- else if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2451
+ if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2451
2452
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2452
2453
  this.outbox.submitBlobAttach(message);
2453
2454
  }
@@ -2579,7 +2580,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2579
2580
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
2580
2581
  break;
2581
2582
  case messageTypes_js_1.ContainerMessageType.IdAllocation: {
2582
- this.submit(message, localOpMetadata);
2583
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
2584
+ // avoid being submitted out of order. For example, if the pending state manager contained
2585
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
2586
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
2587
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
2588
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
2589
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
2583
2590
  break;
2584
2591
  }
2585
2592
  case messageTypes_js_1.ContainerMessageType.ChunkedOp: