@fluidframework/container-runtime 0.49.2 → 0.50.1

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 (61) hide show
  1. package/dist/containerRuntime.d.ts +2 -2
  2. package/dist/containerRuntime.d.ts.map +1 -1
  3. package/dist/containerRuntime.js +73 -71
  4. package/dist/containerRuntime.js.map +1 -1
  5. package/dist/dataStoreContext.d.ts.map +1 -1
  6. package/dist/dataStoreContext.js +2 -1
  7. package/dist/dataStoreContext.js.map +1 -1
  8. package/dist/dataStores.d.ts.map +1 -1
  9. package/dist/dataStores.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/packageVersion.d.ts +1 -1
  14. package/dist/packageVersion.js +1 -1
  15. package/dist/packageVersion.js.map +1 -1
  16. package/dist/summarizer.d.ts +4 -1
  17. package/dist/summarizer.d.ts.map +1 -1
  18. package/dist/summarizer.js +3 -3
  19. package/dist/summarizer.js.map +1 -1
  20. package/dist/summarizerClientElection.d.ts +1 -1
  21. package/dist/summarizerClientElection.js +1 -1
  22. package/dist/summarizerClientElection.js.map +1 -1
  23. package/dist/summaryManager.d.ts +10 -3
  24. package/dist/summaryManager.d.ts.map +1 -1
  25. package/dist/summaryManager.js +9 -6
  26. package/dist/summaryManager.js.map +1 -1
  27. package/lib/containerRuntime.d.ts +2 -2
  28. package/lib/containerRuntime.d.ts.map +1 -1
  29. package/lib/containerRuntime.js +73 -71
  30. package/lib/containerRuntime.js.map +1 -1
  31. package/lib/dataStoreContext.d.ts.map +1 -1
  32. package/lib/dataStoreContext.js +2 -1
  33. package/lib/dataStoreContext.js.map +1 -1
  34. package/lib/dataStores.d.ts.map +1 -1
  35. package/lib/dataStores.js.map +1 -1
  36. package/lib/index.d.ts +1 -1
  37. package/lib/index.d.ts.map +1 -1
  38. package/lib/index.js.map +1 -1
  39. package/lib/packageVersion.d.ts +1 -1
  40. package/lib/packageVersion.js +1 -1
  41. package/lib/packageVersion.js.map +1 -1
  42. package/lib/summarizer.d.ts +4 -1
  43. package/lib/summarizer.d.ts.map +1 -1
  44. package/lib/summarizer.js +3 -3
  45. package/lib/summarizer.js.map +1 -1
  46. package/lib/summarizerClientElection.d.ts +1 -1
  47. package/lib/summarizerClientElection.js +1 -1
  48. package/lib/summarizerClientElection.js.map +1 -1
  49. package/lib/summaryManager.d.ts +10 -3
  50. package/lib/summaryManager.d.ts.map +1 -1
  51. package/lib/summaryManager.js +9 -6
  52. package/lib/summaryManager.js.map +1 -1
  53. package/package.json +16 -16
  54. package/src/containerRuntime.ts +106 -96
  55. package/src/dataStoreContext.ts +2 -1
  56. package/src/dataStores.ts +1 -1
  57. package/src/index.ts +1 -1
  58. package/src/packageVersion.ts +1 -1
  59. package/src/summarizer.ts +5 -2
  60. package/src/summarizerClientElection.ts +1 -1
  61. package/src/summaryManager.ts +17 -7
@@ -29,6 +29,7 @@ import { getLocalStorageFeatureGate } from "./localStorageFeatureGates";
29
29
  import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
30
30
  import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
31
31
  import { formExponentialFn, Throttler } from "./throttler";
32
+ import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
32
33
  export var ContainerMessageType;
33
34
  (function (ContainerMessageType) {
34
35
  // An op to be delivered to store
@@ -291,6 +292,7 @@ export class ContainerRuntime extends TypedEventEmitter {
291
292
  this.closeFn(normalizeError(error));
292
293
  });
293
294
  };
295
+ // @deprecated Needs to become private
294
296
  this.raiseContainerWarning = (warning) => {
295
297
  this.context.raiseContainerWarning(warning);
296
298
  };
@@ -384,40 +386,45 @@ export class ContainerRuntime extends TypedEventEmitter {
384
386
  }
385
387
  });
386
388
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
387
- const maxOpsSinceLastSummary = (_d = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _d !== void 0 ? _d : 7000;
388
- const defaultAction = () => {
389
- if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
390
- this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
391
- // unregister default to no log on every op after falling behind
392
- // and register summary ack handler to re-register this handler
393
- // after successful summary
394
- this.summaryCollection.once(MessageType.SummaryAck, () => {
395
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
396
- // we've caught up, so re-register the default action to monitor for
397
- // falling behind, and unregister ourself
398
- this.summaryCollection.on("default", defaultAction);
399
- });
400
- this.summaryCollection.off("default", defaultAction);
401
- }
402
- };
403
- this.summaryCollection.on("default", defaultAction);
404
- const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
405
- const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
406
- const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
407
- const summarizerClientElectionEnabled = (_e = getLocalStorageFeatureGate("summarizerClientElection")) !== null && _e !== void 0 ? _e : ((_f = this.runtimeOptions.summaryOptions) === null || _f === void 0 ? void 0 : _f.summarizerClientElection) === true;
408
- this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
409
389
  // Only create a SummaryManager if summaries are enabled and we are not the summarizer client
410
390
  if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
411
391
  this._logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
412
392
  }
413
393
  else {
394
+ const maxOpsSinceLastSummary = (_d = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _d !== void 0 ? _d : 7000;
395
+ const defaultAction = () => {
396
+ if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
397
+ this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
398
+ // unregister default to no log on every op after falling behind
399
+ // and register summary ack handler to re-register this handler
400
+ // after successful summary
401
+ this.summaryCollection.once(MessageType.SummaryAck, () => {
402
+ this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
403
+ // we've caught up, so re-register the default action to monitor for
404
+ // falling behind, and unregister ourself
405
+ this.summaryCollection.on("default", defaultAction);
406
+ });
407
+ this.summaryCollection.off("default", defaultAction);
408
+ }
409
+ };
410
+ this.summaryCollection.on("default", defaultAction);
411
+ const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
412
+ const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
413
+ const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
414
+ const summarizerClientElectionEnabled = (_e = getLocalStorageFeatureGate("summarizerClientElection")) !== null && _e !== void 0 ? _e : ((_f = this.runtimeOptions.summaryOptions) === null || _f === void 0 ? void 0 : _f.summarizerClientElection) === true;
415
+ this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
414
416
  if (this.context.clientDetails.type === summarizerClientType) {
415
- this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.IFluidHandleContext, this.summaryCollection);
417
+ this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.IFluidHandleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
416
418
  }
417
419
  else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
418
420
  // Create the SummaryManager and mark the initial state
421
+ const requestOptions = {
422
+ cache: false,
423
+ reconnect: false,
424
+ summarizingClient: true,
425
+ };
419
426
  this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
420
- this.summaryCollection, this.logger, formRequestSummarizerFn(this.context.loader, this.context.deltaManager), new Throttler(60 * 1000, // 60 sec delay window
427
+ this.summaryCollection, this.logger, formRequestSummarizerFn(this.context.loader, this.context.deltaManager.lastSequenceNumber, requestOptions), new Throttler(60 * 1000, // 60 sec delay window
421
428
  30 * 1000, // 30 sec max delay
422
429
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
423
430
  formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
@@ -592,7 +599,8 @@ export class ContainerRuntime extends TypedEventEmitter {
592
599
  }
593
600
  /** clientId of parent (non-summarizing) container that owns summarizer container */
594
601
  get summarizerClientId() {
595
- return this.summarizerClientElection.electedClientId;
602
+ var _a;
603
+ return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
596
604
  }
597
605
  get summaryConfiguration() {
598
606
  var _a, _b, _c;
@@ -790,6 +798,7 @@ export class ContainerRuntime extends TypedEventEmitter {
790
798
  return root;
791
799
  }
792
800
  addContainerBlobsToSummary(summaryTree) {
801
+ var _a;
793
802
  if (this.shouldWriteMetadata) {
794
803
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(this.formMetadata()));
795
804
  }
@@ -797,8 +806,10 @@ export class ContainerRuntime extends TypedEventEmitter {
797
806
  const content = JSON.stringify([...this.chunkMap]);
798
807
  addBlobToSummary(summaryTree, chunksBlobName, content);
799
808
  }
800
- const electedSummarizerContent = JSON.stringify(this.summarizerClientElection.serialize());
801
- addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
809
+ if (this.summarizerClientElection) {
810
+ const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
811
+ addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
812
+ }
802
813
  const snapshot = this.blobManager.snapshot();
803
814
  // Some storage (like git) doesn't allow empty tree, so we can omit it.
804
815
  // and the blob manager can handle the tree not existing when loading
@@ -1007,7 +1018,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1007
1018
  }
1008
1019
  async createRootDataStore(pkg, rootDataStoreId) {
1009
1020
  const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
1010
- fluidDataStore.bindToContext();
1021
+ fluidDataStore.attachGraph();
1011
1022
  return fluidDataStore;
1012
1023
  }
1013
1024
  createDetachedRootDataStore(pkg, rootDataStoreId) {
@@ -1017,7 +1028,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1017
1028
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1018
1029
  }
1019
1030
  async _createDataStoreWithProps(pkg, props, id = uuid(), isRoot = false) {
1020
- return this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1031
+ const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1032
+ if (isRoot) {
1033
+ fluidDataStore.attachGraph();
1034
+ }
1035
+ return fluidDataStore;
1021
1036
  }
1022
1037
  async _createDataStore(pkg, isRoot, id = uuid()) {
1023
1038
  return this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot).realize();
@@ -1116,39 +1131,33 @@ export class ContainerRuntime extends TypedEventEmitter {
1116
1131
  return PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
1117
1132
  var _a;
1118
1133
  const gcStats = {};
1119
- try {
1120
- // Get the container's GC data and run GC on the reference graph in it.
1121
- const gcData = await this.dataStores.getGCData(fullGC);
1122
- const { referencedNodeIds, deletedNodeIds } = runGarbageCollection(gcData.gcNodes, ["/"], this.logger);
1123
- // Update our summarizer node's used routes. Updating used routes in summarizer node before
1124
- // summarizing is required and asserted by the the summarizer node. We are the root and are
1125
- // always referenced, so the used routes is only self-route (empty string).
1126
- this.summarizerNode.updateUsedRoutes([""]);
1127
- // Remove this node's route ("/") and notify data stores of routes that are used in it.
1128
- const usedRoutes = referencedNodeIds.filter((id) => { return id !== "/"; });
1129
- const { dataStoreCount, unusedDataStoreCount } = this.dataStores.updateUsedRoutes(usedRoutes, (_a =
1130
- // For now, we use the timestamp of the last op for gcTimestamp. However, there can be cases where
1131
- // we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
1132
- // of this client's connection - https://github.com/microsoft/FluidFramework/issues/7152.
1133
- this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp);
1134
- // Update stats to be reported in the peformance event.
1135
- gcStats.deletedNodes = deletedNodeIds.length;
1136
- gcStats.totalNodes = referencedNodeIds.length + deletedNodeIds.length;
1137
- gcStats.deletedDataStores = unusedDataStoreCount;
1138
- gcStats.totalDataStores = dataStoreCount;
1139
- // If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios
1140
- // involving access to deleted data.
1141
- if (this.gcTestMode) {
1142
- this.dataStores.deleteUnusedRoutes(deletedNodeIds);
1143
- }
1144
- }
1145
- catch (error) {
1146
- event.cancel(gcStats, error);
1147
- throw error;
1134
+ // Get the container's GC data and run GC on the reference graph in it.
1135
+ const gcData = await this.dataStores.getGCData(fullGC);
1136
+ const { referencedNodeIds, deletedNodeIds } = runGarbageCollection(gcData.gcNodes, ["/"], this.logger);
1137
+ // Update our summarizer node's used routes. Updating used routes in summarizer node before
1138
+ // summarizing is required and asserted by the the summarizer node. We are the root and are
1139
+ // always referenced, so the used routes is only self-route (empty string).
1140
+ this.summarizerNode.updateUsedRoutes([""]);
1141
+ // Remove this node's route ("/") and notify data stores of routes that are used in it.
1142
+ const usedRoutes = referencedNodeIds.filter((id) => { return id !== "/"; });
1143
+ const { dataStoreCount, unusedDataStoreCount } = this.dataStores.updateUsedRoutes(usedRoutes, (_a =
1144
+ // For now, we use the timestamp of the last op for gcTimestamp. However, there can be cases where
1145
+ // we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
1146
+ // of this client's connection - https://github.com/microsoft/FluidFramework/issues/7152.
1147
+ this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp);
1148
+ // Update stats to be reported in the peformance event.
1149
+ gcStats.deletedNodes = deletedNodeIds.length;
1150
+ gcStats.totalNodes = referencedNodeIds.length + deletedNodeIds.length;
1151
+ gcStats.deletedDataStores = unusedDataStoreCount;
1152
+ gcStats.totalDataStores = dataStoreCount;
1153
+ // If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios
1154
+ // involving access to deleted data.
1155
+ if (this.gcTestMode) {
1156
+ this.dataStores.deleteUnusedRoutes(deletedNodeIds);
1148
1157
  }
1149
1158
  event.end(gcStats);
1150
1159
  return gcStats;
1151
- });
1160
+ }, { end: true, cancel: "error" });
1152
1161
  }
1153
1162
  async summarizeInternal(fullTree, trackState) {
1154
1163
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState);
@@ -1544,10 +1553,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1544
1553
  }
1545
1554
  }
1546
1555
  async fetchSnapshotFromStorage(versionId, logger, event) {
1547
- const perfEvent = PerformanceEvent.start(logger, event);
1548
- const stats = {};
1549
- let snapshot;
1550
- try {
1556
+ return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
1557
+ const stats = {};
1551
1558
  const trace = Trace.start();
1552
1559
  const versions = await this.storage.getVersions(versionId, 1);
1553
1560
  assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
@@ -1555,14 +1562,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1555
1562
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
1556
1563
  assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
1557
1564
  stats.getSnapshotDuration = trace.trace().duration;
1558
- snapshot = maybeSnapshot;
1559
- }
1560
- catch (error) {
1561
- perfEvent.cancel(stats, error);
1562
- throw error;
1563
- }
1564
- perfEvent.end(stats);
1565
- return snapshot;
1565
+ perfEvent.end(stats);
1566
+ return maybeSnapshot;
1567
+ });
1566
1568
  }
1567
1569
  getPendingLocalState() {
1568
1570
  return this.pendingStateManager.getLocalState();