@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
@@ -60,6 +60,11 @@ export const DefaultSummaryConfiguration = {
60
60
  runtimeOpWeight: 1.0,
61
61
  nonRuntimeHeuristicThreshold: 20,
62
62
  };
63
+ /**
64
+ * Error responses when requesting a deleted object will have this header set to true
65
+ * @alpha
66
+ */
67
+ export const DeletedResponseHeaderKey = "wasDeleted";
63
68
  /**
64
69
  * Tombstone error responses will have this header set to true
65
70
  * @alpha
@@ -736,7 +741,7 @@ export class ContainerRuntime extends TypedEventEmitter {
736
741
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
737
742
  return this.submitSignalFn(envelope2, targetClientId);
738
743
  };
739
- this.channelCollection = new ChannelCollection(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);
744
+ this.channelCollection = new ChannelCollection(getSummaryForDatastores(baseSnapshot, metadata), parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
740
745
  this.blobManager = new BlobManager({
741
746
  routeContext: this.handleContext,
742
747
  snapshot: blobManagerSnapshot,
@@ -749,7 +754,10 @@ export class ContainerRuntime extends TypedEventEmitter {
749
754
  });
750
755
  }
751
756
  },
752
- blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
757
+ blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
758
+ node: { type: "Blob", path: blobPath },
759
+ reason: "Loaded",
760
+ }),
753
761
  isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
754
762
  runtime: this,
755
763
  stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
@@ -1232,6 +1240,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1232
1240
  this.emitDirtyDocumentEvent = false;
1233
1241
  let newState;
1234
1242
  try {
1243
+ this.submitIdAllocationOpIfNeeded(true);
1235
1244
  // replay the ops
1236
1245
  this.pendingStateManager.replayPendingStates();
1237
1246
  }
@@ -1408,9 +1417,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1408
1417
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1409
1418
  // but will not modify the contents object (likely it will replace it on the message).
1410
1419
  const messageCopy = { ...messageArg };
1420
+ const savedOp = messageCopy.metadata?.savedOp;
1411
1421
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1412
- if (modernRuntimeMessage) {
1413
- this.processCore({
1422
+ const msg = modernRuntimeMessage
1423
+ ? {
1414
1424
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1415
1425
  // There is nothing really ensuring that anytime original message.type is Operation that
1416
1426
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1418,12 +1428,16 @@ export class ContainerRuntime extends TypedEventEmitter {
1418
1428
  message: message,
1419
1429
  local,
1420
1430
  modernRuntimeMessage,
1421
- });
1422
- }
1423
- else {
1424
- // Unrecognized message will be ignored.
1425
- this.processCore({ message, local, modernRuntimeMessage });
1426
- }
1431
+ }
1432
+ : // Unrecognized message will be ignored.
1433
+ {
1434
+ message,
1435
+ local,
1436
+ modernRuntimeMessage,
1437
+ };
1438
+ msg.savedOp = savedOp;
1439
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1440
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1427
1441
  }
1428
1442
  }
1429
1443
  /**
@@ -1488,9 +1502,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1488
1502
  // stashed ops flow. The compressor is stashed with these ops already processed.
1489
1503
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1490
1504
  // thus we need to process all the ops.
1491
- if (!(this.skipSavedCompressorOps &&
1492
- messageWithContext.message.metadata?.savedOp ===
1493
- true)) {
1505
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1494
1506
  const range = messageWithContext.message.contents;
1495
1507
  // Some other client turned on the id compressor. If we have not turned it on,
1496
1508
  // put it in a pending queue and delay finalization.
@@ -1619,9 +1631,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1619
1631
  let checkpoint;
1620
1632
  let result;
1621
1633
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1622
- // Note: we are not touching this.pendingAttachBatch here, for two reasons:
1623
- // 1. It would not help, as we flush attach ops as they become available.
1624
- // 2. There is no way to undo process of data store creation.
1634
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1635
+ // 1. It would not help, as other batches are flushed independently from main batch.
1636
+ // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
1625
1637
  checkpoint = this.outbox.checkpoint().mainBatch;
1626
1638
  }
1627
1639
  try {
@@ -1684,7 +1696,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1684
1696
  if (channel.entryPoint === undefined) {
1685
1697
  throw new UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1686
1698
  }
1687
- this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
1699
+ this.garbageCollector.nodeUpdated({
1700
+ node: { type: "DataStore", path: `/${internalId}` },
1701
+ reason: "Loaded",
1702
+ packagePath: context.packagePath,
1703
+ });
1688
1704
  return channel.entryPoint;
1689
1705
  }
1690
1706
  createDetachedDataStore(pkg, loadingGroupId) {
@@ -2079,9 +2095,17 @@ export class ContainerRuntime extends TypedEventEmitter {
2079
2095
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
2080
2096
  const lastAck = this.summaryCollection.latestAck;
2081
2097
  const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
2098
+ /**
2099
+ * This was added to validate that the summarizer node tree has the same reference sequence number from the
2100
+ * top running summarizer down to the lowest summarizer node.
2101
+ *
2102
+ * The order of mismatch numbers goes (validate sequence number)-(node sequence number).
2103
+ * Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
2104
+ * summarizer nodes.
2105
+ */
2082
2106
  if (startSummaryResult.invalidNodes > 0 ||
2083
2107
  startSummaryResult.mismatchNumbers.size > 0) {
2084
- summaryLogger.sendErrorEvent({
2108
+ summaryLogger.sendTelemetryEvent({
2085
2109
  eventName: "LatestSummaryRefSeqNumMismatch",
2086
2110
  details: {
2087
2111
  ...startSummaryResult,
@@ -2354,9 +2378,11 @@ export class ContainerRuntime extends TypedEventEmitter {
2354
2378
  this.verifyNotClosed();
2355
2379
  return this.blobManager.createBlob(blob, signal);
2356
2380
  }
2357
- submitIdAllocationOpIfNeeded() {
2381
+ submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
2358
2382
  if (this._idCompressor) {
2359
- const idRange = this._idCompressor.takeNextCreationRange();
2383
+ const idRange = resubmitOutstandingRanges
2384
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
2385
+ : this._idCompressor.takeNextCreationRange();
2360
2386
  // Don't include the idRange if there weren't any Ids allocated
2361
2387
  if (idRange?.ids !== undefined) {
2362
2388
  const idAllocationMessage = {
@@ -2418,32 +2444,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2418
2444
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2419
2445
  });
2420
2446
  }
2421
- // If this is attach message for new data store, and we are in a batch, send this op out of order
2422
- // Is it safe:
2423
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
2424
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
2425
- // is stored in some DDS, i.e. only after some other op.
2426
- // Why:
2427
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
2428
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
2429
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
2430
- // these issues.
2431
- // Cons:
2432
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
2433
- // This change creates new possibility of a lot of newly created data stores never being referenced
2434
- // because client died before it had a change to submit the rest of the ops. This will create more
2435
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
2436
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
2437
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
2438
- // issue than sending.
2439
- // Please note that this does not change file format, so it can be disabled in the future if this
2440
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
2441
- if (this.currentlyBatching() &&
2442
- type === ContainerMessageType.Attach &&
2443
- this.disableAttachReorder !== true) {
2444
- this.outbox.submitAttach(message);
2445
- }
2446
- else if (type === ContainerMessageType.BlobAttach) {
2447
+ if (type === ContainerMessageType.BlobAttach) {
2447
2448
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2448
2449
  this.outbox.submitBlobAttach(message);
2449
2450
  }
@@ -2575,7 +2576,13 @@ export class ContainerRuntime extends TypedEventEmitter {
2575
2576
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
2576
2577
  break;
2577
2578
  case ContainerMessageType.IdAllocation: {
2578
- this.submit(message, localOpMetadata);
2579
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
2580
+ // avoid being submitted out of order. For example, if the pending state manager contained
2581
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
2582
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
2583
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
2584
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
2585
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
2579
2586
  break;
2580
2587
  }
2581
2588
  case ContainerMessageType.ChunkedOp: