@fluidframework/container-runtime 2.0.0-internal.2.3.1 → 2.0.0-internal.3.0.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.
Files changed (79) hide show
  1. package/dist/blobManager.d.ts +3 -1
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +35 -2
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +45 -42
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +89 -40
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStoreContext.d.ts +1 -0
  10. package/dist/dataStoreContext.d.ts.map +1 -1
  11. package/dist/dataStoreContext.js +7 -2
  12. package/dist/dataStoreContext.js.map +1 -1
  13. package/dist/garbageCollection.d.ts +15 -7
  14. package/dist/garbageCollection.d.ts.map +1 -1
  15. package/dist/garbageCollection.js +96 -36
  16. package/dist/garbageCollection.js.map +1 -1
  17. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  18. package/dist/opLifecycle/outbox.js +0 -1
  19. package/dist/opLifecycle/outbox.js.map +1 -1
  20. package/dist/packageVersion.d.ts +1 -1
  21. package/dist/packageVersion.js +1 -1
  22. package/dist/packageVersion.js.map +1 -1
  23. package/dist/pendingStateManager.d.ts +4 -13
  24. package/dist/pendingStateManager.d.ts.map +1 -1
  25. package/dist/pendingStateManager.js +130 -160
  26. package/dist/pendingStateManager.js.map +1 -1
  27. package/dist/summarizer.js.map +1 -1
  28. package/dist/summarizerClientElection.d.ts +1 -2
  29. package/dist/summarizerClientElection.d.ts.map +1 -1
  30. package/dist/summarizerClientElection.js +3 -30
  31. package/dist/summarizerClientElection.js.map +1 -1
  32. package/dist/summarizerTypes.d.ts +0 -4
  33. package/dist/summarizerTypes.d.ts.map +1 -1
  34. package/dist/summarizerTypes.js.map +1 -1
  35. package/lib/blobManager.d.ts +3 -1
  36. package/lib/blobManager.d.ts.map +1 -1
  37. package/lib/blobManager.js +35 -2
  38. package/lib/blobManager.js.map +1 -1
  39. package/lib/containerRuntime.d.ts +45 -42
  40. package/lib/containerRuntime.d.ts.map +1 -1
  41. package/lib/containerRuntime.js +89 -40
  42. package/lib/containerRuntime.js.map +1 -1
  43. package/lib/dataStoreContext.d.ts +1 -0
  44. package/lib/dataStoreContext.d.ts.map +1 -1
  45. package/lib/dataStoreContext.js +7 -2
  46. package/lib/dataStoreContext.js.map +1 -1
  47. package/lib/garbageCollection.d.ts +15 -7
  48. package/lib/garbageCollection.d.ts.map +1 -1
  49. package/lib/garbageCollection.js +97 -37
  50. package/lib/garbageCollection.js.map +1 -1
  51. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  52. package/lib/opLifecycle/outbox.js +0 -1
  53. package/lib/opLifecycle/outbox.js.map +1 -1
  54. package/lib/packageVersion.d.ts +1 -1
  55. package/lib/packageVersion.js +1 -1
  56. package/lib/packageVersion.js.map +1 -1
  57. package/lib/pendingStateManager.d.ts +4 -13
  58. package/lib/pendingStateManager.d.ts.map +1 -1
  59. package/lib/pendingStateManager.js +130 -160
  60. package/lib/pendingStateManager.js.map +1 -1
  61. package/lib/summarizer.js.map +1 -1
  62. package/lib/summarizerClientElection.d.ts +1 -2
  63. package/lib/summarizerClientElection.d.ts.map +1 -1
  64. package/lib/summarizerClientElection.js +3 -30
  65. package/lib/summarizerClientElection.js.map +1 -1
  66. package/lib/summarizerTypes.d.ts +0 -4
  67. package/lib/summarizerTypes.d.ts.map +1 -1
  68. package/lib/summarizerTypes.js.map +1 -1
  69. package/package.json +55 -20
  70. package/src/blobManager.ts +41 -2
  71. package/src/containerRuntime.ts +118 -85
  72. package/src/dataStoreContext.ts +12 -6
  73. package/src/garbageCollection.ts +103 -34
  74. package/src/opLifecycle/outbox.ts +0 -2
  75. package/src/packageVersion.ts +1 -1
  76. package/src/pendingStateManager.ts +146 -187
  77. package/src/summarizer.ts +1 -1
  78. package/src/summarizerClientElection.ts +1 -30
  79. package/src/summarizerTypes.ts +0 -4
@@ -58,7 +58,6 @@ exports.DefaultSummaryConfiguration = {
58
58
  maxAckWaitTime: 10 * 60 * 1000,
59
59
  maxOpsSinceLastSummary: 7000,
60
60
  initialSummarizerDelayMs: 5 * 1000,
61
- summarizerClientElection: false,
62
61
  nonRuntimeOpWeight: 0.1,
63
62
  runtimeOpWeight: 1.0,
64
63
  nonRuntimeHeuristicThreshold: 20,
@@ -169,6 +168,14 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
169
168
  this.flushMicroTaskExists = false;
170
169
  this.savedOps = [];
171
170
  this.consecutiveReconnects = 0;
171
+ this.ensureNoDataModelChangesCalls = 0;
172
+ /**
173
+ * Tracks the number of detected reentrant ops to report,
174
+ * in order to self-throttle the telemetry events.
175
+ *
176
+ * This should be removed as part of ADO:2322
177
+ */
178
+ this.opReentryCallsToReport = 5;
172
179
  this._disposed = false;
173
180
  this.emitDirtyDocumentEvent = true;
174
181
  this.defaultTelemetrySignalSampleCount = 100;
@@ -241,7 +248,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
241
248
  && this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck") !== true;
242
249
  this.summariesDisabled = this.isSummariesDisabled();
243
250
  this.heuristicsDisabled = this.isHeuristicsDisabled();
244
- this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
245
251
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
246
252
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
247
253
  this.maxConsecutiveReconnects =
@@ -300,14 +306,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
300
306
  if (!this.disposed) {
301
307
  this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { localId, blobId });
302
308
  }
303
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (fromPath, toPath) => this.garbageCollector.addedOutboundReference(fromPath, toPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
309
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (fromPath, toPath) => this.garbageCollector.addedOutboundReference(fromPath, toPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, () => this.getCurrentReferenceTimestampMs());
304
310
  this.scheduleManager = new scheduleManager_1.ScheduleManager(context.deltaManager, this, () => this.clientId, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
305
311
  this.pendingStateManager = new pendingStateManager_1.PendingStateManager({
306
312
  applyStashedOp: this.applyStashedOp.bind(this),
307
313
  clientId: () => this.clientId,
308
314
  close: this.closeFn,
309
315
  connected: () => this.connected,
310
- flush: this.flush.bind(this),
311
316
  reSubmit: this.reSubmit.bind(this),
312
317
  rollback: this.rollback.bind(this),
313
318
  orderSequentially: this.orderSequentially.bind(this),
@@ -344,7 +349,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
344
349
  const orderedClientLogger = telemetry_utils_1.ChildLogger.create(this.logger, "OrderedClientElection");
345
350
  const orderedClientCollection = new orderedClientElection_1.OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
346
351
  const orderedClientElectionForSummarizer = new orderedClientElection_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, summarizerClientElection_1.SummarizerClientElection.isClientEligible);
347
- this.summarizerClientElection = new summarizerClientElection_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary, this.summarizerClientElectionEnabled);
352
+ this.summarizerClientElection = new summarizerClientElection_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
348
353
  if (this.context.clientDetails.type === summarizerClientElection_1.summarizerClientType) {
349
354
  this._summarizer = new summarizer_1.Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => runWhileConnectedCoordinator_1.RunWhileConnectedCoordinator.create(runtime));
350
355
  }
@@ -406,6 +411,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
406
411
  get IContainerRuntime() { return this; }
407
412
  get IFluidRouter() { return this; }
408
413
  /**
414
+ * @deprecated - use loadRuntime instead.
409
415
  * Load the stores from a snapshot and returns the runtime.
410
416
  * @param context - Context of the container.
411
417
  * @param registryEntries - Mapping to the stores.
@@ -416,7 +422,35 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
416
422
  * allows mixin classes to leverage this method to define their own async initializer.
417
423
  */
418
424
  static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
425
+ let existingFlag = true;
426
+ if (!existing) {
427
+ existingFlag = false;
428
+ }
429
+ return this.loadRuntime({
430
+ context,
431
+ registryEntries,
432
+ existing: existingFlag,
433
+ requestHandler,
434
+ runtimeOptions,
435
+ containerScope,
436
+ containerRuntimeCtor,
437
+ });
438
+ }
439
+ /**
440
+ * Load the stores from a snapshot and returns the runtime.
441
+ * @param params - An object housing the runtime properties:
442
+ * - context - Context of the container.
443
+ * - registryEntries - Mapping to the stores.
444
+ * - existing - When loading from an existing snapshot
445
+ * - requestHandler - Request handlers for the container runtime
446
+ * - runtimeOptions - Additional options to be passed to the runtime
447
+ * - containerScope - runtime services provided with context
448
+ * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
449
+ * This allows mixin classes to leverage this method to define their own async initializer.
450
+ */
451
+ static async loadRuntime(params) {
419
452
  var _a, _b, _c, _d;
453
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime } = params;
420
454
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
421
455
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
422
456
  const backCompatContext = context;
@@ -474,7 +508,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
474
508
  logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
475
509
  }
476
510
  else {
477
- // Call both close and dispose as close implementation will no longer dispose runtime in future (2.0.0-internal.3.0.0)
511
+ // Call both close and dispose as closeFn implementation will no longer dispose runtime in future
478
512
  context.closeFn(error);
479
513
  (_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
480
514
  }
@@ -547,6 +581,23 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
547
581
  get IFluidHandleContext() {
548
582
  return this.handleContext;
549
583
  }
584
+ /**
585
+ * Invokes the given callback and expects that no ops are submitted
586
+ * until execution finishes. If an op is submitted, an error will be raised.
587
+ *
588
+ * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
589
+ *
590
+ * @param callback - the callback to be invoked
591
+ */
592
+ ensureNoDataModelChanges(callback) {
593
+ this.ensureNoDataModelChangesCalls++;
594
+ try {
595
+ return callback();
596
+ }
597
+ finally {
598
+ this.ensureNoDataModelChangesCalls--;
599
+ }
600
+ }
550
601
  get connected() {
551
602
  return this._connected;
552
603
  }
@@ -561,42 +612,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
561
612
  return this._summarizer;
562
613
  }
563
614
  isSummariesDisabled() {
564
- // back-compat: disableSummaries was moved from ISummaryRuntimeOptions
565
- // to ISummaryConfiguration in 0.60.
566
- if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
567
- return true;
568
- }
569
615
  return this.summaryConfiguration.state === "disabled";
570
616
  }
571
617
  isHeuristicsDisabled() {
572
- var _a;
573
- // back-compat: disableHeuristics was moved from ISummarizerOptions
574
- // to ISummaryConfiguration in 0.60.
575
- if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
576
- return true;
577
- }
578
618
  return this.summaryConfiguration.state === "disableHeuristics";
579
619
  }
580
- isSummarizerClientElectionEnabled() {
581
- var _a;
582
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
583
- return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
584
- }
585
- // back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
586
- // to ISummaryConfiguration in 0.60.
587
- if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
588
- return true;
589
- }
590
- return this.summaryConfiguration.state !== "disabled"
591
- ? this.summaryConfiguration.summarizerClientElection === true
592
- : false;
593
- }
594
620
  getMaxOpsSinceLastSummary() {
595
- // back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
596
- // to ISummaryConfiguration in 0.60.
597
- if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
598
- return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
599
- }
600
621
  return this.summaryConfiguration.state !== "disabled"
601
622
  ? this.summaryConfiguration.maxOpsSinceLastSummary
602
623
  : 0;
@@ -1097,7 +1118,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1097
1118
  finally {
1098
1119
  this._orderSequentiallyCalls--;
1099
1120
  }
1100
- if (this.flushMode === runtime_definitions_1.FlushMode.Immediate && this._orderSequentiallyCalls === 0) {
1121
+ // We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
1122
+ if (this.flushMode !== runtime_definitions_1.FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
1101
1123
  this.flush();
1102
1124
  }
1103
1125
  return result;
@@ -1621,6 +1643,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1621
1643
  }
1622
1644
  submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
1623
1645
  this.verifyNotClosed();
1646
+ this.verifyCanSubmitOps();
1624
1647
  // There should be no ops in detached container state!
1625
1648
  (0, common_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1626
1649
  const deserializedContent = { type, contents };
@@ -1702,6 +1725,32 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1702
1725
  throw new Error("Runtime is closed");
1703
1726
  }
1704
1727
  }
1728
+ verifyCanSubmitOps() {
1729
+ if (this.ensureNoDataModelChangesCalls > 0) {
1730
+ const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
1731
+ if (this.opReentryCallsToReport > 0) {
1732
+ this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
1733
+ // We need to capture the call stack in order to inspect the source of this usage pattern
1734
+ new container_utils_1.UsageError(errorMessage));
1735
+ this.opReentryCallsToReport--;
1736
+ }
1737
+ // Creating ops while processing ops can lead
1738
+ // to undefined behavior and events observed in the wrong order.
1739
+ // For example, we have two callbacks registered for a DDS, A and B.
1740
+ // Then if on change #1 callback A creates change #2, the invocation flow will be:
1741
+ //
1742
+ // A because of #1
1743
+ // A because of #2
1744
+ // B because of #2
1745
+ // B because of #1
1746
+ //
1747
+ // The runtime must enforce op coherence by not allowing ops to be submitted
1748
+ // while ops are being processed.
1749
+ if (this.enableOpReentryCheck) {
1750
+ throw new container_utils_1.UsageError(errorMessage);
1751
+ }
1752
+ }
1753
+ }
1705
1754
  /**
1706
1755
  * Finds the right store and asks it to resubmit the message. This typically happens when we
1707
1756
  * reconnect and there are pending messages.
@@ -1854,13 +1903,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1854
1903
  if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
1855
1904
  throw new container_utils_1.UsageError("can't get state when offline load disabled");
1856
1905
  }
1906
+ if (this._orderSequentiallyCalls !== 0) {
1907
+ throw new container_utils_1.UsageError("can't get state during orderSequentially");
1908
+ }
1857
1909
  // Flush pending batch.
1858
1910
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
1859
1911
  // to close current batch.
1860
1912
  this.flush();
1861
- if (this._orderSequentiallyCalls !== 0) {
1862
- throw new container_utils_1.UsageError("can't get state during orderSequentially");
1863
- }
1864
1913
  const previousPendingState = this.context.pendingLocalState;
1865
1914
  if (previousPendingState) {
1866
1915
  return {