@fluidframework/container-runtime 2.0.0-dev-rc.5.0.0.271262 → 2.0.0-dev-rc.5.0.0.272251

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 (212) hide show
  1. package/api-extractor/api-extractor-lint-bundle.json +5 -0
  2. package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
  3. package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
  4. package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
  5. package/api-extractor/api-extractor-lint-public.esm.json +5 -0
  6. package/api-report/container-runtime.alpha.api.md +1 -1
  7. package/container-runtime.test-files.tar +0 -0
  8. package/dist/batchTracker.js +1 -5
  9. package/dist/batchTracker.js.map +1 -1
  10. package/dist/blobManager.js +14 -39
  11. package/dist/blobManager.js.map +1 -1
  12. package/dist/channelCollection.d.ts +12 -2
  13. package/dist/channelCollection.d.ts.map +1 -1
  14. package/dist/channelCollection.js +95 -110
  15. package/dist/channelCollection.js.map +1 -1
  16. package/dist/connectionTelemetry.js +14 -32
  17. package/dist/connectionTelemetry.js.map +1 -1
  18. package/dist/containerHandleContext.js +0 -4
  19. package/dist/containerHandleContext.js.map +1 -1
  20. package/dist/containerRuntime.d.ts +2 -1
  21. package/dist/containerRuntime.d.ts.map +1 -1
  22. package/dist/containerRuntime.js +51 -142
  23. package/dist/containerRuntime.js.map +1 -1
  24. package/dist/dataStore.js +1 -9
  25. package/dist/dataStore.js.map +1 -1
  26. package/dist/dataStoreContext.d.ts +2 -1
  27. package/dist/dataStoreContext.d.ts.map +1 -1
  28. package/dist/dataStoreContext.js +102 -143
  29. package/dist/dataStoreContext.js.map +1 -1
  30. package/dist/dataStoreContexts.js +28 -29
  31. package/dist/dataStoreContexts.js.map +1 -1
  32. package/dist/dataStoreRegistry.js +0 -1
  33. package/dist/dataStoreRegistry.js.map +1 -1
  34. package/dist/deltaManagerProxies.js +28 -33
  35. package/dist/deltaManagerProxies.js.map +1 -1
  36. package/dist/deltaScheduler.js +9 -13
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/error.js +1 -2
  39. package/dist/error.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts +4 -2
  41. package/dist/gc/garbageCollection.d.ts.map +1 -1
  42. package/dist/gc/garbageCollection.js +25 -43
  43. package/dist/gc/garbageCollection.js.map +1 -1
  44. package/dist/gc/gcDefinitions.d.ts +7 -4
  45. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  46. package/dist/gc/gcDefinitions.js.map +1 -1
  47. package/dist/gc/gcSummaryStateTracker.js +14 -19
  48. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  49. package/dist/gc/gcTelemetry.d.ts +1 -1
  50. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  51. package/dist/gc/gcTelemetry.js +5 -17
  52. package/dist/gc/gcTelemetry.js.map +1 -1
  53. package/dist/gc/gcUnreferencedStateTracker.js +1 -12
  54. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  55. package/dist/opLifecycle/batchManager.js +3 -5
  56. package/dist/opLifecycle/batchManager.js.map +1 -1
  57. package/dist/opLifecycle/opCompressor.js +0 -1
  58. package/dist/opLifecycle/opCompressor.js.map +1 -1
  59. package/dist/opLifecycle/opDecompressor.js +4 -6
  60. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  61. package/dist/opLifecycle/opGroupingManager.js +1 -3
  62. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  63. package/dist/opLifecycle/opSplitter.js +0 -6
  64. package/dist/opLifecycle/opSplitter.js.map +1 -1
  65. package/dist/opLifecycle/outbox.js +10 -15
  66. package/dist/opLifecycle/outbox.js.map +1 -1
  67. package/dist/opLifecycle/remoteMessageProcessor.js +0 -3
  68. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  69. package/dist/packageVersion.d.ts +1 -1
  70. package/dist/packageVersion.js +1 -1
  71. package/dist/packageVersion.js.map +1 -1
  72. package/dist/pendingStateManager.js +14 -20
  73. package/dist/pendingStateManager.js.map +1 -1
  74. package/dist/scheduleManager.js +4 -15
  75. package/dist/scheduleManager.js.map +1 -1
  76. package/dist/storageServiceWithAttachBlobs.js +0 -1
  77. package/dist/storageServiceWithAttachBlobs.js.map +1 -1
  78. package/dist/summary/documentSchema.js +1 -17
  79. package/dist/summary/documentSchema.js.map +1 -1
  80. package/dist/summary/orderedClientElection.js +11 -19
  81. package/dist/summary/orderedClientElection.js.map +1 -1
  82. package/dist/summary/runWhileConnectedCoordinator.js +2 -4
  83. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  84. package/dist/summary/runningSummarizer.js +38 -56
  85. package/dist/summary/runningSummarizer.js.map +1 -1
  86. package/dist/summary/summarizer.js +8 -17
  87. package/dist/summary/summarizer.js.map +1 -1
  88. package/dist/summary/summarizerClientElection.js +7 -18
  89. package/dist/summary/summarizerClientElection.js.map +1 -1
  90. package/dist/summary/summarizerHeuristics.js +25 -30
  91. package/dist/summary/summarizerHeuristics.js.map +1 -1
  92. package/dist/summary/summarizerNode/summarizerNode.js +3 -12
  93. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  94. package/dist/summary/summarizerNode/summarizerNodeUtils.js +0 -2
  95. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  96. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +6 -20
  97. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  98. package/dist/summary/summaryCollection.js +11 -23
  99. package/dist/summary/summaryCollection.js.map +1 -1
  100. package/dist/summary/summaryGenerator.js +5 -12
  101. package/dist/summary/summaryGenerator.js.map +1 -1
  102. package/dist/summary/summaryManager.js +48 -58
  103. package/dist/summary/summaryManager.js.map +1 -1
  104. package/dist/throttler.js +1 -4
  105. package/dist/throttler.js.map +1 -1
  106. package/lib/batchTracker.js +1 -5
  107. package/lib/batchTracker.js.map +1 -1
  108. package/lib/blobManager.js +14 -39
  109. package/lib/blobManager.js.map +1 -1
  110. package/lib/channelCollection.d.ts +12 -2
  111. package/lib/channelCollection.d.ts.map +1 -1
  112. package/lib/channelCollection.js +95 -110
  113. package/lib/channelCollection.js.map +1 -1
  114. package/lib/connectionTelemetry.js +14 -32
  115. package/lib/connectionTelemetry.js.map +1 -1
  116. package/lib/containerHandleContext.js +0 -4
  117. package/lib/containerHandleContext.js.map +1 -1
  118. package/lib/containerRuntime.d.ts +2 -1
  119. package/lib/containerRuntime.d.ts.map +1 -1
  120. package/lib/containerRuntime.js +52 -143
  121. package/lib/containerRuntime.js.map +1 -1
  122. package/lib/dataStore.js +1 -9
  123. package/lib/dataStore.js.map +1 -1
  124. package/lib/dataStoreContext.d.ts +2 -1
  125. package/lib/dataStoreContext.d.ts.map +1 -1
  126. package/lib/dataStoreContext.js +102 -143
  127. package/lib/dataStoreContext.js.map +1 -1
  128. package/lib/dataStoreContexts.js +28 -29
  129. package/lib/dataStoreContexts.js.map +1 -1
  130. package/lib/dataStoreRegistry.js +0 -1
  131. package/lib/dataStoreRegistry.js.map +1 -1
  132. package/lib/deltaManagerProxies.js +28 -33
  133. package/lib/deltaManagerProxies.js.map +1 -1
  134. package/lib/deltaScheduler.js +9 -13
  135. package/lib/deltaScheduler.js.map +1 -1
  136. package/lib/error.js +1 -2
  137. package/lib/error.js.map +1 -1
  138. package/lib/gc/garbageCollection.d.ts +4 -2
  139. package/lib/gc/garbageCollection.d.ts.map +1 -1
  140. package/lib/gc/garbageCollection.js +25 -43
  141. package/lib/gc/garbageCollection.js.map +1 -1
  142. package/lib/gc/gcDefinitions.d.ts +7 -4
  143. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  144. package/lib/gc/gcDefinitions.js.map +1 -1
  145. package/lib/gc/gcSummaryStateTracker.js +14 -19
  146. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  147. package/lib/gc/gcTelemetry.d.ts +1 -1
  148. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  149. package/lib/gc/gcTelemetry.js +5 -17
  150. package/lib/gc/gcTelemetry.js.map +1 -1
  151. package/lib/gc/gcUnreferencedStateTracker.js +1 -12
  152. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  153. package/lib/opLifecycle/batchManager.js +3 -5
  154. package/lib/opLifecycle/batchManager.js.map +1 -1
  155. package/lib/opLifecycle/opCompressor.js +0 -1
  156. package/lib/opLifecycle/opCompressor.js.map +1 -1
  157. package/lib/opLifecycle/opDecompressor.js +4 -6
  158. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  159. package/lib/opLifecycle/opGroupingManager.js +1 -3
  160. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  161. package/lib/opLifecycle/opSplitter.js +0 -6
  162. package/lib/opLifecycle/opSplitter.js.map +1 -1
  163. package/lib/opLifecycle/outbox.js +10 -15
  164. package/lib/opLifecycle/outbox.js.map +1 -1
  165. package/lib/opLifecycle/remoteMessageProcessor.js +0 -3
  166. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  167. package/lib/packageVersion.d.ts +1 -1
  168. package/lib/packageVersion.js +1 -1
  169. package/lib/packageVersion.js.map +1 -1
  170. package/lib/pendingStateManager.js +14 -20
  171. package/lib/pendingStateManager.js.map +1 -1
  172. package/lib/scheduleManager.js +4 -15
  173. package/lib/scheduleManager.js.map +1 -1
  174. package/lib/storageServiceWithAttachBlobs.js +0 -1
  175. package/lib/storageServiceWithAttachBlobs.js.map +1 -1
  176. package/lib/summary/documentSchema.js +1 -17
  177. package/lib/summary/documentSchema.js.map +1 -1
  178. package/lib/summary/orderedClientElection.js +11 -19
  179. package/lib/summary/orderedClientElection.js.map +1 -1
  180. package/lib/summary/runWhileConnectedCoordinator.js +2 -4
  181. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  182. package/lib/summary/runningSummarizer.js +38 -56
  183. package/lib/summary/runningSummarizer.js.map +1 -1
  184. package/lib/summary/summarizer.js +8 -17
  185. package/lib/summary/summarizer.js.map +1 -1
  186. package/lib/summary/summarizerClientElection.js +7 -18
  187. package/lib/summary/summarizerClientElection.js.map +1 -1
  188. package/lib/summary/summarizerHeuristics.js +25 -30
  189. package/lib/summary/summarizerHeuristics.js.map +1 -1
  190. package/lib/summary/summarizerNode/summarizerNode.js +3 -12
  191. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  192. package/lib/summary/summarizerNode/summarizerNodeUtils.js +0 -2
  193. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  194. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +6 -20
  195. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  196. package/lib/summary/summaryCollection.js +11 -23
  197. package/lib/summary/summaryCollection.js.map +1 -1
  198. package/lib/summary/summaryGenerator.js +5 -12
  199. package/lib/summary/summaryGenerator.js.map +1 -1
  200. package/lib/summary/summaryManager.js +48 -58
  201. package/lib/summary/summaryManager.js.map +1 -1
  202. package/lib/throttler.js +1 -4
  203. package/lib/throttler.js.map +1 -1
  204. package/package.json +27 -18
  205. package/src/channelCollection.ts +133 -123
  206. package/src/containerRuntime.ts +31 -4
  207. package/src/dataStoreContext.ts +3 -2
  208. package/src/gc/garbageCollection.ts +24 -7
  209. package/src/gc/gcDefinitions.ts +16 -4
  210. package/src/gc/gcTelemetry.ts +1 -7
  211. package/src/packageVersion.ts +1 -1
  212. package/tsdoc.json +4 -0
@@ -152,28 +152,21 @@ export function getLocalDataStoreType(localDataStore) {
152
152
  * @internal
153
153
  */
154
154
  export class ChannelCollection {
155
- baseSnapshot;
156
- parentContext;
157
- gcNodeUpdated;
158
- isDataStoreDeleted;
159
- aliasMap;
160
- // Stores tracked by the Domain
161
- pendingAttach = new Map();
162
- // 0.24 back-compat attachingBeforeSummary
163
- attachOpFiredForDataStore = new Set();
164
- mc;
165
- disposeOnce = new Lazy(() => this.contexts.dispose());
166
- entryPoint;
167
- containerLoadStats;
168
- pendingAliasMap = new Map();
169
- contexts;
170
- aliasedDataStores;
171
155
  constructor(baseSnapshot, parentContext, baseLogger, gcNodeUpdated, isDataStoreDeleted, aliasMap, provideEntryPoint) {
172
156
  this.baseSnapshot = baseSnapshot;
173
157
  this.parentContext = parentContext;
174
158
  this.gcNodeUpdated = gcNodeUpdated;
175
159
  this.isDataStoreDeleted = isDataStoreDeleted;
176
160
  this.aliasMap = aliasMap;
161
+ // Stores tracked by the Domain
162
+ this.pendingAttach = new Map();
163
+ // 0.24 back-compat attachingBeforeSummary
164
+ this.attachOpFiredForDataStore = new Set();
165
+ this.disposeOnce = new Lazy(() => this.contexts.dispose());
166
+ this.pendingAliasMap = new Map();
167
+ /** For sampling. Only log once per container */
168
+ this.shouldSendAttachLog = true;
169
+ this.dispose = () => this.disposeOnce.value;
177
170
  this.mc = createChildMonitoringContext({ logger: baseLogger });
178
171
  this.contexts = new DataStoreContexts(baseLogger);
179
172
  this.entryPoint = new FluidObjectHandle(new LazyPromise(async () => provideEntryPoint(this)), "", this.parentContext.IFluidHandleContext);
@@ -250,8 +243,6 @@ export class ChannelCollection {
250
243
  const pendingAliasPromise = this.pendingAliases.get(maybeAlias);
251
244
  return pendingAliasPromise ?? "Success";
252
245
  }
253
- /** For sampling. Only log once per container */
254
- shouldSendAttachLog = true;
255
246
  wrapContextForInnerChannel(id) {
256
247
  return wrapContextForInnerChannel(id, this.parentContext);
257
248
  }
@@ -269,7 +260,7 @@ export class ChannelCollection {
269
260
  const foundGCData = processAttachMessageGCData(attachMessage.snapshot, (nodeId, toPath) => {
270
261
  // nodeId is the relative path under the node being attached. Always starts with "/", but no trailing "/" after an id
271
262
  const fromPath = `/${attachMessage.id}${nodeId === "/" ? "" : nodeId}`;
272
- this.parentContext.addedGCOutboundRoute(fromPath, toPath);
263
+ this.parentContext.addedGCOutboundRoute(fromPath, toPath, message.timestamp);
273
264
  });
274
265
  // Only log once per container to avoid noise/cost.
275
266
  // Allows longitudinal tracking of various state (e.g. foundGCData), and some sampled details
@@ -341,12 +332,12 @@ export class ChannelCollection {
341
332
  });
342
333
  }
343
334
  const resolve = localOpMetadata;
344
- const aliasResult = this.processAliasMessageCore(aliasMessage.internalId, aliasMessage.alias);
335
+ const aliasResult = this.processAliasMessageCore(aliasMessage.internalId, aliasMessage.alias, message.timestamp);
345
336
  if (local) {
346
337
  resolve(aliasResult);
347
338
  }
348
339
  }
349
- processAliasMessageCore(internalId, alias) {
340
+ processAliasMessageCore(internalId, alias, messageTimestampMs) {
350
341
  if (this.alreadyProcessed(alias)) {
351
342
  return false;
352
343
  }
@@ -363,7 +354,11 @@ export class ChannelCollection {
363
354
  });
364
355
  return false;
365
356
  }
366
- this.parentContext.addedGCOutboundRoute("/", `/${internalId}`);
357
+ // If message timestamp doesn't exist, this is called in a detached container. Don't notify GC in that case
358
+ // because it doesn't run in detached container and doesn't need to know about this route.
359
+ if (messageTimestampMs) {
360
+ this.parentContext.addedGCOutboundRoute("/", `/${internalId}`, messageTimestampMs);
361
+ }
367
362
  this.aliasMap.set(alias, context.id);
368
363
  this.aliasedDataStores.add(context.id);
369
364
  context.setInMemoryRoot();
@@ -474,7 +469,6 @@ export class ChannelCollection {
474
469
  get disposed() {
475
470
  return this.disposeOnce.evaluated;
476
471
  }
477
- dispose = () => this.disposeOnce.value;
478
472
  reSubmit(type, content, localOpMetadata) {
479
473
  switch (type) {
480
474
  case ContainerMessageType.Attach:
@@ -597,7 +591,7 @@ export class ChannelCollection {
597
591
  };
598
592
  this.processChannelOp(envelope.address, transformed, local, localMessageMetadata);
599
593
  // Notify GC of any outbound references that were added by this op.
600
- detectOutboundReferences(envelope.address, transformed.contents, (fromPath, toPath) => this.parentContext.addedGCOutboundRoute(fromPath, toPath));
594
+ detectOutboundReferences(envelope.address, transformed.contents, (fromPath, toPath) => this.parentContext.addedGCOutboundRoute(fromPath, toPath, message.timestamp));
601
595
  break;
602
596
  }
603
597
  default:
@@ -770,61 +764,24 @@ export class ChannelCollection {
770
764
  get size() {
771
765
  return this.contexts.size;
772
766
  }
773
- async summarize(fullTree, trackState, telemetryContext) {
774
- const summaryBuilder = new SummaryTreeBuilder();
775
- // Iterate over each store and ask it to snapshot
776
- await Promise.all(Array.from(this.contexts)
777
- .filter(([_, context]) => {
778
- // Summarizer works only with clients with no local changes. A data store in attaching
779
- // state indicates an op was sent to attach a local data store, and the the attach op
780
- // had not yet round tripped back to the client.
781
- if (context.attachState === AttachState.Attaching) {
782
- // Formerly assert 0x588
783
- const error = DataProcessingError.create("Local data store detected in attaching state during summarize", "summarize");
784
- throw error;
785
- }
786
- return context.attachState === AttachState.Attached;
787
- })
788
- .map(async ([contextId, context]) => {
789
- const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
790
- summaryBuilder.addWithStats(contextId, contextSummary);
791
- }));
792
- return summaryBuilder.getSummaryTree();
793
- }
794
767
  /**
795
768
  * Create a summary. Used when attaching or serializing a detached container.
796
769
  */
797
770
  getAttachSummary(telemetryContext) {
798
771
  const builder = new SummaryTreeBuilder();
799
- // Attaching graph of some stores can cause other stores to get bound too.
800
- // So keep taking summary until no new stores get bound.
801
- let notBoundContextsLength;
802
- do {
803
- const builderTree = builder.summary.tree;
804
- notBoundContextsLength = this.contexts.notBoundLength();
805
- // Iterate over each data store and ask it to snapshot
806
- Array.from(this.contexts)
807
- .filter(([key, _]) =>
808
- // Take summary of bounded data stores only, make sure we haven't summarized them already
809
- // and no attach op has been fired for that data store because for loader versions <= 0.24
810
- // we set attach state as "attaching" before taking createNew summary.
811
- !(this.contexts.isNotBound(key) ||
812
- builderTree[key] ||
813
- this.attachOpFiredForDataStore.has(key)))
814
- .map(([key, value]) => {
815
- let dataStoreSummary;
816
- if (value.isLoaded) {
817
- dataStoreSummary = value.getAttachSummary(telemetryContext);
818
- }
819
- else {
820
- // If this data store is not yet loaded, then there should be no changes in the snapshot from
821
- // which it was created as it is detached container. So just use the previous snapshot.
822
- assert(!!this.baseSnapshot, 0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
823
- dataStoreSummary = convertSnapshotTreeToSummaryTree(getSnapshotTree(this.baseSnapshot).trees[key]);
824
- }
825
- builder.addWithStats(key, dataStoreSummary);
826
- });
827
- } while (notBoundContextsLength !== this.contexts.notBoundLength());
772
+ this.visitLocalBoundContextsDuringAttach((contextId, context) => {
773
+ let dataStoreSummary;
774
+ if (context.isLoaded) {
775
+ dataStoreSummary = context.getAttachSummary(telemetryContext);
776
+ }
777
+ else {
778
+ // If this data store is not yet loaded, then there should be no changes in the snapshot from
779
+ // which it was created as it is detached container. So just use the previous snapshot.
780
+ assert(!!this.baseSnapshot, 0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
781
+ dataStoreSummary = convertSnapshotTreeToSummaryTree(getSnapshotTree(this.baseSnapshot).trees[contextId]);
782
+ }
783
+ builder.addWithStats(contextId, dataStoreSummary);
784
+ });
828
785
  return builder.getSummaryTree();
829
786
  }
830
787
  /**
@@ -832,27 +789,70 @@ export class ChannelCollection {
832
789
  */
833
790
  getAttachGCData(telemetryContext) {
834
791
  const builder = new GCDataBuilder();
835
- // Attaching graph of some stores can cause other stores to get bound too.
836
- // So keep taking summary until no new stores get bound.
837
- let notBoundContextsLength;
838
- do {
839
- notBoundContextsLength = this.contexts.notBoundLength();
840
- // Iterate over each data store and ask for its GC data.
841
- Array.from(this.contexts)
842
- .filter(([key, _]) =>
843
- // Take GC data of bounded data stores only.
844
- !this.contexts.isNotBound(key))
845
- .map(([key, value]) => {
846
- const contextGCData = value.getAttachGCData(telemetryContext);
847
- // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
848
- // This also gradually builds the id of each node to be a path from the root.
849
- builder.prefixAndAddNodes(key, contextGCData.gcNodes);
850
- });
851
- } while (notBoundContextsLength !== this.contexts.notBoundLength());
792
+ this.visitLocalBoundContextsDuringAttach((contextId, context) => {
793
+ const contextGCData = context.getAttachGCData(telemetryContext);
794
+ // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
795
+ // This also gradually builds the id of each node to be a path from the root.
796
+ builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
797
+ });
852
798
  // Get the outbound routes (aliased data stores) and add a GC node for this channel.
853
799
  builder.addNode("/", Array.from(this.aliasedDataStores));
854
800
  return builder.getGCData();
855
801
  }
802
+ /**
803
+ * Helper method for preparing to attach this channel.
804
+ * Runs the callback for each bound context to incorporate its data however the caller specifies
805
+ */
806
+ visitLocalBoundContextsDuringAttach(visitor) {
807
+ const visitedContexts = new Set();
808
+ let visitedLength = -1;
809
+ let notBoundContextsLength = -1;
810
+ while (visitedLength !== visitedContexts.size &&
811
+ notBoundContextsLength !== this.contexts.notBoundLength()) {
812
+ // detect changes in the visitedContexts set, as on visiting a context
813
+ // it could could make contexts available by removing other contexts
814
+ // from the not bound context list, so we need to ensure those get processed as well.
815
+ // only once the loop can run with no new contexts added to the visitedContexts set do we
816
+ // know for sure all possible contexts have been visited.
817
+ visitedLength = visitedContexts.size;
818
+ notBoundContextsLength = this.contexts.notBoundLength();
819
+ for (const [contextId, context] of this.contexts) {
820
+ if (!(visitedContexts.has(contextId) ||
821
+ this.contexts.isNotBound(contextId) ||
822
+ this.attachOpFiredForDataStore.has(contextId))) {
823
+ visitor(contextId, context);
824
+ visitedContexts.add(contextId);
825
+ }
826
+ }
827
+ }
828
+ }
829
+ /**
830
+ * Helper method for preparing to summarize this channel.
831
+ * Runs the callback for each bound context to incorporate its data however the caller specifies
832
+ */
833
+ async visitContextsDuringSummary(visitor) {
834
+ for (const [contextId, context] of this.contexts) {
835
+ // Summarizer client and hence GC works only with clients with no local changes. A data store in
836
+ // attaching state indicates an op was sent to attach a local data store, and the the attach op
837
+ // had not yet round tripped back to the client.
838
+ // Formerly assert 0x589
839
+ if (context.attachState === AttachState.Attaching) {
840
+ const error = DataProcessingError.create("Local data store detected in attaching state", "summarize/getGCData");
841
+ throw error;
842
+ }
843
+ if (context.attachState === AttachState.Attached) {
844
+ await visitor(contextId, context);
845
+ }
846
+ }
847
+ }
848
+ async summarize(fullTree, trackState, telemetryContext) {
849
+ const summaryBuilder = new SummaryTreeBuilder();
850
+ await this.visitContextsDuringSummary(async (contextId, context) => {
851
+ const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
852
+ summaryBuilder.addWithStats(contextId, contextSummary);
853
+ });
854
+ return summaryBuilder.getSummaryTree();
855
+ }
856
856
  /**
857
857
  * Generates data used for garbage collection. It does the following:
858
858
  *
@@ -868,25 +868,12 @@ export class ChannelCollection {
868
868
  */
869
869
  async getGCData(fullGC = false) {
870
870
  const builder = new GCDataBuilder();
871
- // Iterate over each store and get their GC data.
872
- await Promise.all(Array.from(this.contexts)
873
- .filter(([_, context]) => {
874
- // Summarizer client and hence GC works only with clients with no local changes. A data store in
875
- // attaching state indicates an op was sent to attach a local data store, and the the attach op
876
- // had not yet round tripped back to the client.
877
- // Formerly assert 0x589
878
- if (context.attachState === AttachState.Attaching) {
879
- const error = DataProcessingError.create("Local data store detected in attaching state while running GC", "getGCData");
880
- throw error;
881
- }
882
- return context.attachState === AttachState.Attached;
883
- })
884
- .map(async ([contextId, context]) => {
871
+ await this.visitContextsDuringSummary(async (contextId, context) => {
885
872
  const contextGCData = await context.getGCData(fullGC);
886
873
  // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
887
874
  // This also gradually builds the id of each node to be a path from the root.
888
875
  builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
889
- }));
876
+ });
890
877
  // Get the outbound routes and add a GC node for this channel.
891
878
  builder.addNode("/", await this.getOutboundRoutes());
892
879
  return builder.getGCData();
@@ -1063,6 +1050,7 @@ export class ChannelCollection {
1063
1050
  packagePath: details.pkg,
1064
1051
  request,
1065
1052
  headerData,
1053
+ timestampMs: undefined, // This will be added by the parent context if needed.
1066
1054
  });
1067
1055
  const dataStore = await dataStoreContext.realize();
1068
1056
  const subRequest = requestParser.createSubRequest(1);
@@ -1129,15 +1117,12 @@ export function detectOutboundReferences(address, contents, addedOutboundReferen
1129
1117
  }
1130
1118
  /** @internal */
1131
1119
  export class ChannelCollectionFactory {
1132
- provideEntryPoint;
1133
- ctor;
1134
- type = "ChannelCollectionChannel";
1135
- IFluidDataStoreRegistry;
1136
1120
  constructor(registryEntries,
1137
1121
  // ADO:7302 We need a better type here
1138
1122
  provideEntryPoint, ctor) {
1139
1123
  this.provideEntryPoint = provideEntryPoint;
1140
1124
  this.ctor = ctor;
1125
+ this.type = "ChannelCollectionChannel";
1141
1126
  this.IFluidDataStoreRegistry = new FluidDataStoreRegistry(registryEntries);
1142
1127
  }
1143
1128
  get IFluidDataStoreFactory() {