@fluidframework/container-runtime 1.2.1 → 2.0.0-internal.1.0.0.81601

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 (128) hide show
  1. package/dist/blobManager.d.ts +81 -25
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +301 -100
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +46 -3
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +98 -79
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStore.d.ts +1 -1
  10. package/dist/dataStore.d.ts.map +1 -1
  11. package/dist/dataStore.js +32 -26
  12. package/dist/dataStore.js.map +1 -1
  13. package/dist/dataStoreContext.d.ts +3 -4
  14. package/dist/dataStoreContext.d.ts.map +1 -1
  15. package/dist/dataStoreContext.js +16 -23
  16. package/dist/dataStoreContext.js.map +1 -1
  17. package/dist/dataStores.d.ts +5 -2
  18. package/dist/dataStores.d.ts.map +1 -1
  19. package/dist/dataStores.js +11 -3
  20. package/dist/dataStores.js.map +1 -1
  21. package/dist/opProperties.d.ts +7 -0
  22. package/dist/opProperties.d.ts.map +1 -0
  23. package/dist/opProperties.js +19 -0
  24. package/dist/opProperties.js.map +1 -0
  25. package/dist/packageVersion.d.ts +1 -1
  26. package/dist/packageVersion.d.ts.map +1 -1
  27. package/dist/packageVersion.js +1 -1
  28. package/dist/packageVersion.js.map +1 -1
  29. package/dist/runningSummarizer.d.ts +14 -4
  30. package/dist/runningSummarizer.d.ts.map +1 -1
  31. package/dist/runningSummarizer.js +68 -26
  32. package/dist/runningSummarizer.js.map +1 -1
  33. package/dist/summarizer.d.ts +0 -2
  34. package/dist/summarizer.d.ts.map +1 -1
  35. package/dist/summarizer.js +1 -12
  36. package/dist/summarizer.js.map +1 -1
  37. package/dist/summarizerHeuristics.d.ts +26 -4
  38. package/dist/summarizerHeuristics.d.ts.map +1 -1
  39. package/dist/summarizerHeuristics.js +95 -18
  40. package/dist/summarizerHeuristics.js.map +1 -1
  41. package/dist/summarizerTypes.d.ts +30 -10
  42. package/dist/summarizerTypes.d.ts.map +1 -1
  43. package/dist/summarizerTypes.js.map +1 -1
  44. package/dist/summaryCollection.js +1 -1
  45. package/dist/summaryCollection.js.map +1 -1
  46. package/dist/summaryFormat.d.ts +0 -5
  47. package/dist/summaryFormat.d.ts.map +1 -1
  48. package/dist/summaryFormat.js.map +1 -1
  49. package/dist/summaryGenerator.d.ts +1 -0
  50. package/dist/summaryGenerator.d.ts.map +1 -1
  51. package/dist/summaryGenerator.js +11 -9
  52. package/dist/summaryGenerator.js.map +1 -1
  53. package/lib/blobManager.d.ts +81 -25
  54. package/lib/blobManager.d.ts.map +1 -1
  55. package/lib/blobManager.js +302 -101
  56. package/lib/blobManager.js.map +1 -1
  57. package/lib/containerRuntime.d.ts +46 -3
  58. package/lib/containerRuntime.d.ts.map +1 -1
  59. package/lib/containerRuntime.js +99 -80
  60. package/lib/containerRuntime.js.map +1 -1
  61. package/lib/dataStore.d.ts +1 -1
  62. package/lib/dataStore.d.ts.map +1 -1
  63. package/lib/dataStore.js +32 -26
  64. package/lib/dataStore.js.map +1 -1
  65. package/lib/dataStoreContext.d.ts +3 -4
  66. package/lib/dataStoreContext.d.ts.map +1 -1
  67. package/lib/dataStoreContext.js +17 -24
  68. package/lib/dataStoreContext.js.map +1 -1
  69. package/lib/dataStores.d.ts +5 -2
  70. package/lib/dataStores.d.ts.map +1 -1
  71. package/lib/dataStores.js +11 -3
  72. package/lib/dataStores.js.map +1 -1
  73. package/lib/opProperties.d.ts +7 -0
  74. package/lib/opProperties.d.ts.map +1 -0
  75. package/lib/opProperties.js +15 -0
  76. package/lib/opProperties.js.map +1 -0
  77. package/lib/packageVersion.d.ts +1 -1
  78. package/lib/packageVersion.d.ts.map +1 -1
  79. package/lib/packageVersion.js +1 -1
  80. package/lib/packageVersion.js.map +1 -1
  81. package/lib/runningSummarizer.d.ts +14 -4
  82. package/lib/runningSummarizer.d.ts.map +1 -1
  83. package/lib/runningSummarizer.js +68 -26
  84. package/lib/runningSummarizer.js.map +1 -1
  85. package/lib/summarizer.d.ts +0 -2
  86. package/lib/summarizer.d.ts.map +1 -1
  87. package/lib/summarizer.js +1 -12
  88. package/lib/summarizer.js.map +1 -1
  89. package/lib/summarizerHeuristics.d.ts +26 -4
  90. package/lib/summarizerHeuristics.d.ts.map +1 -1
  91. package/lib/summarizerHeuristics.js +95 -18
  92. package/lib/summarizerHeuristics.js.map +1 -1
  93. package/lib/summarizerTypes.d.ts +30 -10
  94. package/lib/summarizerTypes.d.ts.map +1 -1
  95. package/lib/summarizerTypes.js.map +1 -1
  96. package/lib/summaryCollection.js +1 -1
  97. package/lib/summaryCollection.js.map +1 -1
  98. package/lib/summaryFormat.d.ts +0 -5
  99. package/lib/summaryFormat.d.ts.map +1 -1
  100. package/lib/summaryFormat.js.map +1 -1
  101. package/lib/summaryGenerator.d.ts +1 -0
  102. package/lib/summaryGenerator.d.ts.map +1 -1
  103. package/lib/summaryGenerator.js +11 -9
  104. package/lib/summaryGenerator.js.map +1 -1
  105. package/package.json +45 -20
  106. package/src/blobManager.ts +360 -119
  107. package/src/containerRuntime.ts +165 -89
  108. package/src/dataStore.ts +53 -38
  109. package/src/dataStoreContext.ts +16 -23
  110. package/src/dataStores.ts +14 -3
  111. package/src/opProperties.ts +19 -0
  112. package/src/packageVersion.ts +1 -1
  113. package/src/runningSummarizer.ts +75 -22
  114. package/src/summarizer.ts +1 -18
  115. package/src/summarizerHeuristics.ts +133 -19
  116. package/src/summarizerTypes.ts +37 -10
  117. package/src/summaryCollection.ts +1 -1
  118. package/src/summaryFormat.ts +0 -6
  119. package/src/summaryGenerator.ts +40 -22
  120. package/dist/opTelemetry.d.ts +0 -22
  121. package/dist/opTelemetry.d.ts.map +0 -1
  122. package/dist/opTelemetry.js +0 -59
  123. package/dist/opTelemetry.js.map +0 -1
  124. package/lib/opTelemetry.d.ts +0 -22
  125. package/lib/opTelemetry.d.ts.map +0 -1
  126. package/lib/opTelemetry.js +0 -55
  127. package/lib/opTelemetry.js.map +0 -1
  128. package/src/opTelemetry.ts +0 -71
@@ -1,6 +1,6 @@
1
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
2
  import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
3
- import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
3
+ import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
4
4
  import { DriverHeader } from "@fluidframework/driver-definitions";
5
5
  import { readAndParse, isUnpackedRuntimeMessage } from "@fluidframework/driver-utils";
6
6
  import { DataCorruptionError, DataProcessingError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
@@ -29,7 +29,6 @@ import { GarbageCollector, GCNodeType, gcTreeKey, } from "./garbageCollection";
29
29
  import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
30
30
  import { BindBatchTracker } from "./batchTracker";
31
31
  import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
32
- import { OpTracker } from "./opTelemetry";
33
32
  export var ContainerMessageType;
34
33
  (function (ContainerMessageType) {
35
34
  // An op to be delivered to store
@@ -47,14 +46,18 @@ export var ContainerMessageType;
47
46
  })(ContainerMessageType || (ContainerMessageType = {}));
48
47
  export const DefaultSummaryConfiguration = {
49
48
  state: "enabled",
50
- idleTime: 5000 * 3,
51
- maxTime: 5000 * 12,
49
+ idleTime: 15 * 1000,
50
+ minIdleTime: 0,
51
+ maxIdleTime: 30 * 1000,
52
+ maxTime: 60 * 1000,
52
53
  maxOps: 100,
53
54
  minOpsForLastSummaryAttempt: 10,
54
- maxAckWaitTime: 6 * 10 * 1000,
55
+ maxAckWaitTime: 10 * 60 * 1000,
55
56
  maxOpsSinceLastSummary: 7000,
56
- initialSummarizerDelayMs: 5000,
57
+ initialSummarizerDelayMs: 5 * 1000,
57
58
  summarizerClientElection: false,
59
+ nonRuntimeOpWeight: 0.1,
60
+ runtimeOpWeight: 1.0,
58
61
  };
59
62
  /**
60
63
  * Accepted header keys for requests coming to the runtime.
@@ -81,10 +84,6 @@ const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
81
84
  // in order to account for some extra overhead from serialization
82
85
  // to not reach the 1MB limits in socket.io and Kafka.
83
86
  const defaultMaxOpSizeInBytes = 768000;
84
- // By default, the size of the contents for the incoming ops is tracked.
85
- // However, in certain situations, this may incur a performance hit.
86
- // The feature-gate below can be used to disable this feature.
87
- const disableOpTrackingKey = "Fluid.ContainerRuntime.DisableOpTracking";
88
87
  const defaultFlushMode = FlushMode.TurnBased;
89
88
  export var RuntimeMessage;
90
89
  (function (RuntimeMessage) {
@@ -373,7 +372,7 @@ export function getDeviceSpec() {
373
372
  */
374
373
  export class ContainerRuntime extends TypedEventEmitter {
375
374
  constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
376
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
375
+ var _a, _b, _c, _d, _e, _f, _g, _h;
377
376
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
378
377
  super();
379
378
  this.context = context;
@@ -434,6 +433,9 @@ export class ContainerRuntime extends TypedEventEmitter {
434
433
  this.chunkMap = new Map(chunks);
435
434
  this.handleContext = new ContainerFluidHandleContext("", this);
436
435
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
436
+ if (this.summaryConfiguration.state === "enabled") {
437
+ this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
438
+ }
437
439
  this.summariesDisabled = this.isSummariesDisabled();
438
440
  this.heuristicsDisabled = this.isHeuristicsDisabled();
439
441
  this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
@@ -481,7 +483,7 @@ export class ContainerRuntime extends TypedEventEmitter {
481
483
  this.summarizerNode.loadBaseSummaryWithoutDifferential(baseSnapshot);
482
484
  }
483
485
  this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
484
- this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, this.logger);
486
+ this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this);
485
487
  this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
486
488
  this.deltaSender = this.deltaManager;
487
489
  this.pendingStateManager = new PendingStateManager({
@@ -572,9 +574,9 @@ export class ContainerRuntime extends TypedEventEmitter {
572
574
  createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
573
575
  createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
574
576
  };
575
- // back-compat 0.59.3000 - Older document may either write summaryCount or not write it at all. If it does
576
- // not write it, initialize summaryNumber to 0.
577
- loadSummaryNumber = (_j = (_h = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _h !== void 0 ? _h : metadata === null || metadata === void 0 ? void 0 : metadata.summaryCount) !== null && _j !== void 0 ? _j : 0;
577
+ // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
578
+ // the count is reset to 0.
579
+ loadSummaryNumber = (_h = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _h !== void 0 ? _h : 0;
578
580
  }
579
581
  else {
580
582
  this.createContainerMetadata = {
@@ -587,7 +589,6 @@ export class ContainerRuntime extends TypedEventEmitter {
587
589
  this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
588
590
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
589
591
  BindBatchTracker(this, this.logger);
590
- this.opTracker = new OpTracker(this.deltaManager, this.mc.config.getBoolean(disableOpTrackingKey) === true);
591
592
  }
592
593
  get IContainerRuntime() { return this; }
593
594
  get IFluidRouter() { return this; }
@@ -856,12 +857,12 @@ export class ContainerRuntime extends TypedEventEmitter {
856
857
  return this.resolveHandle(requestParser.createSubRequest(1));
857
858
  }
858
859
  if (id === BlobManager.basePath && requestParser.isLeaf(2)) {
859
- const handle = await this.blobManager.getBlob(requestParser.pathParts[1]);
860
- if (handle) {
860
+ const blob = await this.blobManager.getBlob(requestParser.pathParts[1]);
861
+ if (blob) {
861
862
  return {
862
863
  status: 200,
863
864
  mimeType: "fluid/object",
864
- value: handle.get(),
865
+ value: blob,
865
866
  };
866
867
  }
867
868
  else {
@@ -884,13 +885,14 @@ export class ContainerRuntime extends TypedEventEmitter {
884
885
  }
885
886
  internalId(maybeAlias) {
886
887
  var _a;
887
- return (_a = this.dataStores.aliases().get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
888
+ return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
888
889
  }
889
890
  async getDataStoreFromRequest(id, request) {
890
891
  var _a, _b, _c;
891
892
  const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
892
893
  ? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait]
893
894
  : true;
895
+ await this.dataStores.waitIfPendingAlias(id);
894
896
  const internalId = this.internalId(id);
895
897
  const dataStoreContext = await this.dataStores.getDataStore(internalId, wait);
896
898
  /**
@@ -920,8 +922,6 @@ export class ContainerRuntime extends TypedEventEmitter {
920
922
  addMetadataToSummary(summaryTree) {
921
923
  var _a;
922
924
  const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
923
- // back-compat 0.59.3000: This is renamed to summaryNumber. Can be removed when 0.59.3000 saturates.
924
- summaryCount: this.nextSummaryNumber,
925
925
  // Increment the summary number for the next summary that will be generated.
926
926
  summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined }), this.garbageCollector.getMetadata()), {
927
927
  // The last message processed at the time of summary. If there are no new messages, use the message from the
@@ -936,7 +936,7 @@ export class ContainerRuntime extends TypedEventEmitter {
936
936
  const content = JSON.stringify([...this.chunkMap]);
937
937
  addBlobToSummary(summaryTree, chunksBlobName, content);
938
938
  }
939
- const dataStoreAliases = this.dataStores.aliases();
939
+ const dataStoreAliases = this.dataStores.aliases;
940
940
  if (dataStoreAliases.size > 0) {
941
941
  addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
942
942
  }
@@ -1033,6 +1033,35 @@ export class ContainerRuntime extends TypedEventEmitter {
1033
1033
  }
1034
1034
  }
1035
1035
  setConnectionState(connected, clientId) {
1036
+ if (connected === false && this.delayConnectClientId !== undefined) {
1037
+ this.delayConnectClientId = undefined;
1038
+ this.mc.logger.sendTelemetryEvent({
1039
+ eventName: "UnsuccessfulConnectedTransition",
1040
+ });
1041
+ // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1042
+ return;
1043
+ }
1044
+ // If attachment blobs were added while disconnected, we need to delay
1045
+ // propagation of the "connected" event until we have uploaded them to
1046
+ // ensure we don't submit ops referencing a blob that has not been uploaded
1047
+ const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
1048
+ if (connecting && this.blobManager.hasPendingOfflineUploads) {
1049
+ assert(!this.delayConnectClientId, "Connect event delay must be canceled before subsequent connect event");
1050
+ assert(!!clientId, "Must have clientId when connecting");
1051
+ this.delayConnectClientId = clientId;
1052
+ this.blobManager.onConnected().then(() => {
1053
+ // make sure we didn't reconnect before the promise resolved
1054
+ if (this.delayConnectClientId === clientId && !this.disposed) {
1055
+ this.delayConnectClientId = undefined;
1056
+ this.setConnectionStateCore(connected, clientId);
1057
+ }
1058
+ }, (error) => this.closeFn(error));
1059
+ return;
1060
+ }
1061
+ this.setConnectionStateCore(connected, clientId);
1062
+ }
1063
+ setConnectionStateCore(connected, clientId) {
1064
+ assert(!this.delayConnectClientId, "connect event delay must be cleared before propagating connect event");
1036
1065
  this.verifyNotClosed();
1037
1066
  // There might be no change of state due to Container calling this API after loading runtime.
1038
1067
  const changeOfState = this._connected !== connected;
@@ -1063,7 +1092,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1063
1092
  raiseConnectedEvent(this.mc.logger, this, connected, clientId);
1064
1093
  }
1065
1094
  process(messageArg, local) {
1066
- var _a, _b;
1095
+ var _a;
1067
1096
  this.verifyNotClosed();
1068
1097
  // If it's not message for runtime, bail out right away.
1069
1098
  if (!isUnpackedRuntimeMessage(messageArg)) {
@@ -1110,8 +1139,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1110
1139
  this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1111
1140
  break;
1112
1141
  case ContainerMessageType.BlobAttach:
1113
- assert((_b = message === null || message === void 0 ? void 0 : message.metadata) === null || _b === void 0 ? void 0 : _b.blobId, 0x12a /* "Missing blob id on metadata" */);
1114
- this.blobManager.processBlobAttachOp(message.metadata.blobId, local);
1142
+ this.blobManager.processBlobAttachOp(message, local);
1115
1143
  break;
1116
1144
  default:
1117
1145
  }
@@ -1181,6 +1209,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1181
1209
  this.dataStores.processSignal(envelope.address, transformed, local);
1182
1210
  }
1183
1211
  async getRootDataStore(id, wait = true) {
1212
+ return this.getRootDataStoreChannel(id, wait);
1213
+ }
1214
+ async getRootDataStoreChannel(id, wait = true) {
1215
+ await this.dataStores.waitIfPendingAlias(id);
1184
1216
  const internalId = this.internalId(id);
1185
1217
  const context = await this.dataStores.getDataStore(internalId, wait);
1186
1218
  assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
@@ -1281,14 +1313,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1281
1313
  */
1282
1314
  async createRootDataStoreLegacy(pkg, rootDataStoreId) {
1283
1315
  const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
1284
- // back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel. For
1285
- // older versions, we still have to call bindToContext.
1286
- if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
1287
- fluidDataStore.makeVisibleAndAttachGraph();
1288
- }
1289
- else {
1290
- fluidDataStore.bindToContext();
1291
- }
1316
+ fluidDataStore.makeVisibleAndAttachGraph();
1292
1317
  return fluidDataStore;
1293
1318
  }
1294
1319
  /**
@@ -1315,23 +1340,22 @@ export class ContainerRuntime extends TypedEventEmitter {
1315
1340
  */
1316
1341
  async createAndAliasDataStore(pkg, alias, props) {
1317
1342
  const internalId = uuid();
1318
- const dataStore = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
1319
- const aliasedDataStore = channelToDataStore(dataStore, internalId, this, this.dataStores, this.mc.logger);
1320
- const result = await aliasedDataStore.trySetAlias(alias);
1321
- if (result !== "Success") {
1322
- throw new GenericError("dataStoreAliasFailure", undefined /* error */, {
1323
- alias: {
1324
- value: alias,
1325
- tag: TelemetryDataTag.UserData,
1326
- },
1327
- internalId: {
1328
- value: internalId,
1329
- tag: TelemetryDataTag.PackageData,
1330
- },
1331
- aliasResult: result,
1332
- });
1343
+ try {
1344
+ // A similar call may have been initiated by the same client, so we should try to get
1345
+ // a possible existing aliased datastore first.
1346
+ const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
1347
+ return channelToDataStore(existingDataStore, internalId, this, this.dataStores, this.mc.logger, true);
1348
+ }
1349
+ catch (err) {
1350
+ const newChannel = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
1351
+ const newDataStore = channelToDataStore(newChannel, internalId, this, this.dataStores, this.mc.logger);
1352
+ const aliasResult = await newDataStore.trySetAlias(alias);
1353
+ if (aliasResult === "Success") {
1354
+ return newDataStore;
1355
+ }
1356
+ const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
1357
+ return channelToDataStore(existingDataStore, internalId, this, this.dataStores, this.mc.logger, true);
1333
1358
  }
1334
- return aliasedDataStore;
1335
1359
  }
1336
1360
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1337
1361
  if (rootDataStoreId.includes("/")) {
@@ -1351,14 +1375,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1351
1375
  async _createDataStoreWithPropsLegacy(pkg, props, id = uuid(), isRoot = false) {
1352
1376
  const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1353
1377
  if (isRoot) {
1354
- // back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel.
1355
- // For older versions, we still have to call bindToContext.
1356
- if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
1357
- fluidDataStore.makeVisibleAndAttachGraph();
1358
- }
1359
- else {
1360
- fluidDataStore.bindToContext();
1361
- }
1378
+ fluidDataStore.makeVisibleAndAttachGraph();
1362
1379
  this.logger.sendTelemetryEvent({
1363
1380
  eventName: "Root datastore with props",
1364
1381
  hasProps: props !== undefined,
@@ -1639,7 +1656,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1639
1656
  * @param options - options controlling how the summary is generated or submitted
1640
1657
  */
1641
1658
  async submitSummary(options) {
1642
- var _a, _b, _c;
1659
+ var _a, _b;
1643
1660
  const { fullTree, refreshLatestAck, summaryLogger } = options;
1644
1661
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1645
1662
  // use it for all events logged during this summary.
@@ -1664,17 +1681,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1664
1681
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1665
1682
  const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1666
1683
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
1667
- // We should be here is we haven't processed be here. If we are of if the last message's sequence number
1668
- // doesn't match the last processed sequence number, log an error.
1669
- if (summaryRefSeqNum !== ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber)) {
1670
- summaryNumberLogger.sendErrorEvent({
1671
- eventName: "LastSequenceMismatch",
1672
- error: message,
1673
- });
1674
- }
1684
+ const lastAck = this.summaryCollection.latestAck;
1675
1685
  this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
1676
1686
  // Helper function to check whether we should still continue between each async step.
1677
1687
  const checkContinue = () => {
1688
+ var _a;
1678
1689
  // Do not check for loss of connectivity directly! Instead leave it up to
1679
1690
  // RunWhileConnectedCoordinator to control policy in a single place.
1680
1691
  // This will allow easier change of design if we chose to. For example, we may chose to allow
@@ -1698,6 +1709,14 @@ export class ContainerRuntime extends TypedEventEmitter {
1698
1709
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1699
1710
  };
1700
1711
  }
1712
+ assert(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), "it's one and the same thing");
1713
+ if (lastAck !== this.summaryCollection.latestAck) {
1714
+ return {
1715
+ continue: false,
1716
+ // eslint-disable-next-line max-len
1717
+ error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
1718
+ };
1719
+ }
1701
1720
  return { continue: true };
1702
1721
  };
1703
1722
  let continueResult = checkContinue();
@@ -1742,7 +1761,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1742
1761
  const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
1743
1762
  ? calculateStats(summaryTree.tree[gcTreeKey])
1744
1763
  : undefined;
1745
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_b = summarizeResult.gcStats) === null || _b === void 0 ? void 0 : _b.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, opsSizesSinceLastSummary: this.opTracker.opsSizeAccumulator, nonSystemOpsSinceLastSummary: this.opTracker.nonSystemOpCount, summaryNumber }, partialStats);
1764
+ const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_a = summarizeResult.gcStats) === null || _a === void 0 ? void 0 : _a.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, summaryNumber }, partialStats);
1746
1765
  const generateSummaryData = {
1747
1766
  referenceSequenceNumber: summaryRefSeqNum,
1748
1767
  minimumSequenceNumber,
@@ -1755,11 +1774,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1755
1774
  if (!continueResult.continue) {
1756
1775
  return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1757
1776
  }
1758
- const lastAck = this.summaryCollection.latestAck;
1759
1777
  const summaryContext = lastAck === undefined
1760
1778
  ? {
1761
1779
  proposalHandle: undefined,
1762
- ackHandle: (_c = this.context.getLoadedFromVersion()) === null || _c === void 0 ? void 0 : _c.id,
1780
+ ackHandle: (_b = this.context.getLoadedFromVersion()) === null || _b === void 0 ? void 0 : _b.id,
1763
1781
  referenceSequenceNumber: summaryRefSeqNum,
1764
1782
  }
1765
1783
  : {
@@ -1796,7 +1814,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1796
1814
  }
1797
1815
  const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
1798
1816
  this.summarizerNode.completeSummary(handle);
1799
- this.opTracker.reset();
1800
1817
  return submitData;
1801
1818
  }
1802
1819
  finally {
@@ -1907,14 +1924,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1907
1924
  // instead of splitting the content, we will fail by explicitly close the container
1908
1925
  this.closeFn(new GenericError("OpTooLarge",
1909
1926
  /* error */ undefined, {
1910
- length: {
1911
- value: serializedContent.length,
1912
- tag: TelemetryDataTag.PackageData,
1913
- },
1914
- limit: {
1915
- value: this._maxOpSizeInBytes,
1916
- tag: TelemetryDataTag.PackageData,
1917
- },
1927
+ length: serializedContent.length,
1928
+ limit: this._maxOpSizeInBytes,
1918
1929
  }));
1919
1930
  return -1;
1920
1931
  }
@@ -1989,7 +2000,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1989
2000
  case ContainerMessageType.ChunkedOp:
1990
2001
  throw new Error(`chunkedOp not expected here`);
1991
2002
  case ContainerMessageType.BlobAttach:
1992
- this.submit(type, content, localOpMetadata, opMetadata);
2003
+ this.blobManager.reSubmit(opMetadata);
1993
2004
  break;
1994
2005
  case ContainerMessageType.Rejoin:
1995
2006
  this.submit(type, content);
@@ -2126,6 +2137,14 @@ export class ContainerRuntime extends TypedEventEmitter {
2126
2137
  // don't have any more saved ops
2127
2138
  await this.pendingStateManager.applyStashedOpsAt();
2128
2139
  }
2140
+ validateSummaryHeuristicConfiguration(configuration) {
2141
+ // eslint-disable-next-line no-restricted-syntax
2142
+ for (const prop in configuration) {
2143
+ if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
2144
+ throw new UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
2145
+ }
2146
+ }
2147
+ }
2129
2148
  }
2130
2149
  /**
2131
2150
  * Wait for a specific sequence number. Promise should resolve when we reach that number,