@fluidframework/container-runtime 2.0.0-internal.3.2.1 → 2.0.0-internal.3.3.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 (170) hide show
  1. package/dist/containerRuntime.d.ts +32 -53
  2. package/dist/containerRuntime.d.ts.map +1 -1
  3. package/dist/containerRuntime.js +55 -21
  4. package/dist/containerRuntime.js.map +1 -1
  5. package/dist/dataStores.d.ts.map +1 -1
  6. package/dist/dataStores.js +8 -3
  7. package/dist/dataStores.js.map +1 -1
  8. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  9. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  10. package/dist/deltaManagerSummarizerProxy.js +40 -0
  11. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  12. package/dist/gc/garbageCollection.d.ts +2 -33
  13. package/dist/gc/garbageCollection.d.ts.map +1 -1
  14. package/dist/gc/garbageCollection.js +36 -181
  15. package/dist/gc/garbageCollection.js.map +1 -1
  16. package/dist/gc/gcConfigs.d.ts +22 -0
  17. package/dist/gc/gcConfigs.d.ts.map +1 -0
  18. package/dist/gc/gcConfigs.js +138 -0
  19. package/dist/gc/gcConfigs.js.map +1 -0
  20. package/dist/gc/gcDefinitions.d.ts +101 -3
  21. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  22. package/dist/gc/gcDefinitions.js +8 -3
  23. package/dist/gc/gcDefinitions.js.map +1 -1
  24. package/dist/gc/gcHelpers.d.ts +12 -1
  25. package/dist/gc/gcHelpers.d.ts.map +1 -1
  26. package/dist/gc/gcHelpers.js +55 -1
  27. package/dist/gc/gcHelpers.js.map +1 -1
  28. package/dist/gc/gcSummaryStateTracker.d.ts +1 -2
  29. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  30. package/dist/gc/gcSummaryStateTracker.js +28 -37
  31. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  32. package/dist/gc/index.d.ts +3 -2
  33. package/dist/gc/index.d.ts.map +1 -1
  34. package/dist/gc/index.js +2 -1
  35. package/dist/gc/index.js.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/opLifecycle/batchManager.d.ts +9 -0
  40. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  41. package/dist/opLifecycle/batchManager.js +19 -2
  42. package/dist/opLifecycle/batchManager.js.map +1 -1
  43. package/dist/opLifecycle/index.d.ts +1 -1
  44. package/dist/opLifecycle/index.d.ts.map +1 -1
  45. package/dist/opLifecycle/index.js +2 -1
  46. package/dist/opLifecycle/index.js.map +1 -1
  47. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  48. package/dist/opLifecycle/opCompressor.js +24 -10
  49. package/dist/opLifecycle/opCompressor.js.map +1 -1
  50. package/dist/opLifecycle/opDecompressor.d.ts +4 -0
  51. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  52. package/dist/opLifecycle/opDecompressor.js +42 -4
  53. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  54. package/dist/opLifecycle/opSplitter.d.ts +14 -2
  55. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  56. package/dist/opLifecycle/opSplitter.js +35 -18
  57. package/dist/opLifecycle/opSplitter.js.map +1 -1
  58. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  59. package/dist/opLifecycle/outbox.js +29 -21
  60. package/dist/opLifecycle/outbox.js.map +1 -1
  61. package/dist/packageVersion.d.ts +1 -1
  62. package/dist/packageVersion.js +1 -1
  63. package/dist/packageVersion.js.map +1 -1
  64. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  65. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  66. package/dist/storageServiceWithAttachBlobs.js +32 -0
  67. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  68. package/dist/summary/runWhileConnectedCoordinator.d.ts +3 -2
  69. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  70. package/dist/summary/runWhileConnectedCoordinator.js +5 -4
  71. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  72. package/dist/summary/summarizerTypes.d.ts +2 -0
  73. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  74. package/dist/summary/summarizerTypes.js.map +1 -1
  75. package/lib/containerRuntime.d.ts +32 -53
  76. package/lib/containerRuntime.d.ts.map +1 -1
  77. package/lib/containerRuntime.js +56 -22
  78. package/lib/containerRuntime.js.map +1 -1
  79. package/lib/dataStores.d.ts.map +1 -1
  80. package/lib/dataStores.js +9 -4
  81. package/lib/dataStores.js.map +1 -1
  82. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  83. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  84. package/lib/deltaManagerSummarizerProxy.js +36 -0
  85. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  86. package/lib/gc/garbageCollection.d.ts +2 -33
  87. package/lib/gc/garbageCollection.d.ts.map +1 -1
  88. package/lib/gc/garbageCollection.js +39 -184
  89. package/lib/gc/garbageCollection.js.map +1 -1
  90. package/lib/gc/gcConfigs.d.ts +22 -0
  91. package/lib/gc/gcConfigs.d.ts.map +1 -0
  92. package/lib/gc/gcConfigs.js +134 -0
  93. package/lib/gc/gcConfigs.js.map +1 -0
  94. package/lib/gc/gcDefinitions.d.ts +101 -3
  95. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  96. package/lib/gc/gcDefinitions.js +7 -2
  97. package/lib/gc/gcDefinitions.js.map +1 -1
  98. package/lib/gc/gcHelpers.d.ts +12 -1
  99. package/lib/gc/gcHelpers.d.ts.map +1 -1
  100. package/lib/gc/gcHelpers.js +53 -0
  101. package/lib/gc/gcHelpers.js.map +1 -1
  102. package/lib/gc/gcSummaryStateTracker.d.ts +1 -2
  103. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  104. package/lib/gc/gcSummaryStateTracker.js +28 -37
  105. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  106. package/lib/gc/index.d.ts +3 -2
  107. package/lib/gc/index.d.ts.map +1 -1
  108. package/lib/gc/index.js +1 -1
  109. package/lib/gc/index.js.map +1 -1
  110. package/lib/index.d.ts +2 -2
  111. package/lib/index.d.ts.map +1 -1
  112. package/lib/index.js.map +1 -1
  113. package/lib/opLifecycle/batchManager.d.ts +9 -0
  114. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  115. package/lib/opLifecycle/batchManager.js +17 -1
  116. package/lib/opLifecycle/batchManager.js.map +1 -1
  117. package/lib/opLifecycle/index.d.ts +1 -1
  118. package/lib/opLifecycle/index.d.ts.map +1 -1
  119. package/lib/opLifecycle/index.js +1 -1
  120. package/lib/opLifecycle/index.js.map +1 -1
  121. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  122. package/lib/opLifecycle/opCompressor.js +25 -11
  123. package/lib/opLifecycle/opCompressor.js.map +1 -1
  124. package/lib/opLifecycle/opDecompressor.d.ts +4 -0
  125. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  126. package/lib/opLifecycle/opDecompressor.js +42 -4
  127. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  128. package/lib/opLifecycle/opSplitter.d.ts +14 -2
  129. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  130. package/lib/opLifecycle/opSplitter.js +35 -18
  131. package/lib/opLifecycle/opSplitter.js.map +1 -1
  132. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  133. package/lib/opLifecycle/outbox.js +30 -22
  134. package/lib/opLifecycle/outbox.js.map +1 -1
  135. package/lib/packageVersion.d.ts +1 -1
  136. package/lib/packageVersion.js +1 -1
  137. package/lib/packageVersion.js.map +1 -1
  138. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  139. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  140. package/lib/storageServiceWithAttachBlobs.js +28 -0
  141. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  142. package/lib/summary/runWhileConnectedCoordinator.d.ts +3 -2
  143. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  144. package/lib/summary/runWhileConnectedCoordinator.js +5 -4
  145. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  146. package/lib/summary/summarizerTypes.d.ts +2 -0
  147. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  148. package/lib/summary/summarizerTypes.js.map +1 -1
  149. package/package.json +20 -31
  150. package/src/containerRuntime.ts +92 -76
  151. package/src/dataStores.ts +9 -4
  152. package/src/deltaManagerSummarizerProxy.ts +46 -0
  153. package/src/gc/garbageCollection.ts +50 -290
  154. package/src/gc/gcConfigs.ts +177 -0
  155. package/src/gc/gcDefinitions.ts +110 -4
  156. package/src/gc/gcHelpers.ts +78 -1
  157. package/src/gc/gcSummaryStateTracker.ts +35 -42
  158. package/src/gc/index.ts +8 -2
  159. package/src/index.ts +1 -2
  160. package/src/opLifecycle/README.md +2 -2
  161. package/src/opLifecycle/batchManager.ts +19 -1
  162. package/src/opLifecycle/index.ts +1 -1
  163. package/src/opLifecycle/opCompressor.ts +31 -12
  164. package/src/opLifecycle/opDecompressor.ts +49 -5
  165. package/src/opLifecycle/opSplitter.ts +44 -20
  166. package/src/opLifecycle/outbox.ts +36 -22
  167. package/src/packageVersion.ts +1 -1
  168. package/src/storageServiceWithAttachBlobs.ts +38 -0
  169. package/src/summary/runWhileConnectedCoordinator.ts +7 -7
  170. package/src/summary/summarizerTypes.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"summarizerTypes.js","sourceRoot":"","sources":["../../src/summary/summarizerTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAA6B,aAAa,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIEvent,\n\tIEventProvider,\n\tITelemetryLogger,\n\tITelemetryProperties,\n} from \"@fluidframework/common-definitions\";\nimport { ITelemetryLoggerPropertyBag } from \"@fluidframework/telemetry-utils\";\nimport { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport { ContainerWarning, IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n\tISequencedDocumentMessage,\n\tISummaryTree,\n\tIDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { ISummaryStats } from \"@fluidframework/runtime-definitions\";\nimport { ISummaryConfigurationHeuristics } from \"../containerRuntime\";\nimport { ISummaryAckMessage, ISummaryNackMessage, ISummaryOpMessage } from \"./summaryCollection\";\nimport { SummarizeReason } from \"./summaryGenerator\";\n\n/**\n * @deprecated This will be removed in a later release.\n */\nexport const ISummarizer: keyof IProvideSummarizer = \"ISummarizer\";\n\n/**\n * @deprecated This will be removed in a later release.\n */\nexport interface IProvideSummarizer {\n\t/**\n\t * @deprecated This will be removed in a later release.\n\t */\n\treadonly ISummarizer: ISummarizer;\n}\n\n/**\n * Similar to AbortSignal, but using promise instead of events\n * @param T - cancellation reason type\n */\nexport interface ICancellationToken<T> {\n\t/** Tells if this cancellable token is cancelled */\n\treadonly cancelled: boolean;\n\t/**\n\t * Promise that gets fulfilled when this cancellable token is cancelled\n\t * @returns reason of cancellation\n\t */\n\treadonly waitCancelled: Promise<T>;\n}\n\n/* Similar to AbortSignal, but using promise instead of events */\nexport type ISummaryCancellationToken = ICancellationToken<SummarizerStopReason>;\n\nexport interface ISummarizerInternalsProvider {\n\t/** Encapsulates the work to walk the internals of the running container to generate a summary */\n\tsubmitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult>;\n\n\t/** Callback whenever a new SummaryAck is received, to update internal tracking state */\n\trefreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise<void>;\n}\n\n/**\n * @deprecated Options that control the behavior of a running summarizer.\n * */\nexport interface ISummarizerOptions {\n\t/**\n\t * Set to true to disable the default heuristics from running; false by default.\n\t * This affects only the heuristics around when a summarizer should\n\t * submit summaries. So when it is disabled, summarizer clients should\n\t * not be expected to summarize unless an on-demand summary is requested.\n\t */\n\tdisableHeuristics: boolean;\n}\n\nexport interface ISummarizingWarning extends ContainerWarning {\n\treadonly errorType: \"summarizingError\";\n\treadonly logged: boolean;\n}\n\nexport interface IConnectableRuntime {\n\treadonly disposed: boolean;\n\treadonly connected: boolean;\n\treadonly clientId: string | undefined;\n\treadonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;\n\tonce(event: \"connected\" | \"disconnected\" | \"dispose\", listener: () => void): this;\n}\n\nexport interface ISummarizerRuntime extends IConnectableRuntime {\n\treadonly logger: ITelemetryLogger;\n\t/** clientId of parent (non-summarizing) container that owns summarizer container */\n\treadonly summarizerClientId: string | undefined;\n\tdisposeFn?(): void;\n\tcloseFn(): void;\n}\n\n/** Options affecting summarize behavior. */\nexport interface ISummarizeOptions {\n\t/** True to generate the full tree with no handle reuse optimizations; defaults to false */\n\treadonly fullTree?: boolean;\n\t/** True to ask the server what the latest summary is first; defaults to false */\n\treadonly refreshLatestAck?: boolean;\n}\n\n/**\n * Data required to update internal tracking state after receiving a Summary Ack.\n */\nexport interface IRefreshSummaryAckOptions {\n\t/** Handle from the ack's summary op. */\n\treadonly proposalHandle: string | undefined;\n\t/** Handle from the summary ack just received */\n\treadonly ackHandle: string;\n\t/** Reference sequence number from the ack's summary op */\n\treadonly summaryRefSeq: number;\n\t/** Telemetry logger to which telemetry events will be forwarded. */\n\treadonly summaryLogger: ITelemetryLogger;\n}\n\nexport interface ISubmitSummaryOptions extends ISummarizeOptions {\n\t/** Logger to use for correlated summary events */\n\treadonly summaryLogger: ITelemetryLogger;\n\t/** Tells when summary process should be cancelled */\n\treadonly cancellationToken: ISummaryCancellationToken;\n}\n\nexport interface IOnDemandSummarizeOptions extends ISummarizeOptions {\n\t/** Reason for generating summary. */\n\treadonly reason: string;\n}\n\n/** Options to use when enqueueing a summarize attempt. */\nexport interface IEnqueueSummarizeOptions extends IOnDemandSummarizeOptions {\n\t/** If specified, The summarize attempt will not occur until after this sequence number. */\n\treadonly afterSequenceNumber?: number;\n\n\t/**\n\t * True to override the existing enqueued summarize attempt if there is one.\n\t * This will guarantee that this attempt gets enqueued. If override is false,\n\t * than an existing enqueued summarize attempt will block a new one from being\n\t * enqueued. There can only be one enqueued at a time. Defaults to false.\n\t */\n\treadonly override?: boolean;\n}\n\n/**\n * In addition to the normal summary tree + stats, this contains additional stats\n * only relevant at the root of the tree.\n */\nexport interface IGeneratedSummaryStats extends ISummaryStats {\n\t/** The total number of data stores in the container. */\n\treadonly dataStoreCount: number;\n\t/** The number of data stores that were summarized in this summary. */\n\treadonly summarizedDataStoreCount: number;\n\t/** The number of data stores whose GC reference state was updated in this summary. */\n\treadonly gcStateUpdatedDataStoreCount?: number;\n\t/** The size of the gc blobs in this summary. */\n\treadonly gcTotalBlobsSize?: number;\n\t/** The number of gc blobs in this summary. */\n\treadonly gcBlobNodeCount?: number;\n\t/** The summary number for a container's summary. Incremented on summaries throughout its lifetime. */\n\treadonly summaryNumber: number;\n}\n\n/** Base results for all submitSummary attempts. */\nexport interface IBaseSummarizeResult {\n\treadonly stage: \"base\";\n\t/** Error object related to failed summarize attempt. */\n\treadonly error: any;\n\t/** Reference sequence number as of the generate summary attempt. */\n\treadonly referenceSequenceNumber: number;\n\treadonly minimumSequenceNumber: number;\n}\n\n/** Results of submitSummary after generating the summary tree. */\nexport interface IGenerateSummaryTreeResult extends Omit<IBaseSummarizeResult, \"stage\"> {\n\treadonly stage: \"generate\";\n\t/** Generated summary tree. */\n\treadonly summaryTree: ISummaryTree;\n\t/** Stats for generated summary tree. */\n\treadonly summaryStats: IGeneratedSummaryStats;\n\t/** Time it took to generate the summary tree and stats. */\n\treadonly generateDuration: number;\n\t/** True if the full tree regeneration with no handle reuse optimizations was forced. */\n\treadonly forcedFullTree: boolean;\n}\n\n/** Results of submitSummary after uploading the tree to storage. */\nexport interface IUploadSummaryResult extends Omit<IGenerateSummaryTreeResult, \"stage\"> {\n\treadonly stage: \"upload\";\n\t/** The handle returned by storage pointing to the uploaded summary tree. */\n\treadonly handle: string;\n\t/** Time it took to upload the summary tree to storage. */\n\treadonly uploadDuration: number;\n}\n\n/** Results of submitSummary after submitting the summarize op. */\nexport interface ISubmitSummaryOpResult extends Omit<IUploadSummaryResult, \"stage\" | \"error\"> {\n\treadonly stage: \"submit\";\n\t/** The client sequence number of the summarize op submitted for the summary. */\n\treadonly clientSequenceNumber: number;\n\t/** Time it took to submit the summarize op to the broadcasting service. */\n\treadonly submitOpDuration: number;\n}\n\n/**\n * Strict type representing result of a submitSummary attempt.\n * The result consists of 4 possible stages, each with its own data.\n * The data is cumulative, so each stage will contain the data from the previous stages.\n * If the final \"submitted\" stage is not reached, the result may contain the error object.\n *\n * Stages:\n *\n * 1. \"base\" - stopped before the summary tree was even generated, and the result only contains the base data\n *\n * 2. \"generate\" - the summary tree was generated, and the result will contain that tree + stats\n *\n * 3. \"upload\" - the summary was uploaded to storage, and the result contains the server-provided handle\n *\n * 4. \"submit\" - the summarize op was submitted, and the result contains the op client sequence number.\n */\nexport type SubmitSummaryResult =\n\t| IBaseSummarizeResult\n\t| IGenerateSummaryTreeResult\n\t| IUploadSummaryResult\n\t| ISubmitSummaryOpResult;\n\nexport interface IBroadcastSummaryResult {\n\treadonly summarizeOp: ISummaryOpMessage;\n\treadonly broadcastDuration: number;\n}\n\nexport interface IAckSummaryResult {\n\treadonly summaryAckOp: ISummaryAckMessage;\n\treadonly ackNackDuration: number;\n}\n\nexport interface INackSummaryResult {\n\treadonly summaryNackOp: ISummaryNackMessage;\n\treadonly ackNackDuration: number;\n}\n\nexport type SummarizeResultPart<TSuccess, TFailure = undefined> =\n\t| {\n\t\t\tsuccess: true;\n\t\t\tdata: TSuccess;\n\t }\n\t| {\n\t\t\tsuccess: false;\n\t\t\tdata: TFailure | undefined;\n\t\t\tmessage: string;\n\t\t\terror: any;\n\t\t\tretryAfterSeconds?: number;\n\t };\n\nexport interface ISummarizeResults {\n\t/** Resolves when we generate, upload, and submit the summary. */\n\treadonly summarySubmitted: Promise<SummarizeResultPart<SubmitSummaryResult>>;\n\t/** Resolves when we observe our summarize op broadcast. */\n\treadonly summaryOpBroadcasted: Promise<SummarizeResultPart<IBroadcastSummaryResult>>;\n\t/** Resolves when we receive a summaryAck or summaryNack. */\n\treadonly receivedSummaryAckOrNack: Promise<\n\t\tSummarizeResultPart<IAckSummaryResult, INackSummaryResult>\n\t>;\n}\n\nexport type EnqueueSummarizeResult =\n\t| (ISummarizeResults & {\n\t\t\t/**\n\t\t\t * Indicates that another summarize attempt is not already enqueued,\n\t\t\t * and this attempt has been enqueued.\n\t\t\t */\n\t\t\treadonly alreadyEnqueued?: undefined;\n\t })\n\t| (ISummarizeResults & {\n\t\t\t/** Indicates that another summarize attempt was already enqueued. */\n\t\t\treadonly alreadyEnqueued: true;\n\t\t\t/**\n\t\t\t * Indicates that the other enqueued summarize attempt was abandoned,\n\t\t\t * and this attempt has been enqueued enqueued.\n\t\t\t */\n\t\t\treadonly overridden: true;\n\t })\n\t| {\n\t\t\t/** Indicates that another summarize attempt was already enqueued. */\n\t\t\treadonly alreadyEnqueued: true;\n\t\t\t/**\n\t\t\t * Indicates that the other enqueued summarize attempt remains enqueued,\n\t\t\t * and this attempt has not been enqueued.\n\t\t\t */\n\t\t\treadonly overridden?: undefined;\n\t };\n\nexport type SummarizerStopReason =\n\t/** Summarizer client failed to summarize in all 3 consecutive attempts. */\n\t| \"failToSummarize\"\n\t/** Parent client reported that it is no longer connected. */\n\t| \"parentNotConnected\"\n\t/**\n\t * Parent client reported that it is no longer elected the summarizer.\n\t * This is the normal flow; a disconnect will always trigger the parent\n\t * client to no longer be elected as responsible for summaries. Then it\n\t * tries to stop its spawned summarizer client.\n\t */\n\t| \"notElectedParent\"\n\t/**\n\t * We are not already running the summarizer and we are not the current elected client id.\n\t */\n\t| \"notElectedClient\"\n\t/** Summarizer client was disconnected */\n\t| \"summarizerClientDisconnected\"\n\t/* running summarizer threw an exception */\n\t| \"summarizerException\";\n\nexport interface ISummarizerEvents extends IEvent {\n\t/**\n\t * An event indicating that the Summarizer is having problems summarizing\n\t */\n\t(event: \"summarizingError\", listener: (error: ISummarizingWarning) => void);\n}\n\nexport interface ISummarizer\n\textends IEventProvider<ISummarizerEvents>,\n\t\tIFluidLoadable,\n\t\tPartial<IProvideSummarizer> {\n\t/*\n\t * Asks summarizer to move to exit.\n\t * Summarizer will finish current processes, which may take a while.\n\t * For example, summarizer may complete last summary before exiting.\n\t */\n\tstop(reason: SummarizerStopReason): void;\n\n\t/* Closes summarizer. Any pending processes (summary in flight) are abandoned. */\n\tclose(): void;\n\n\trun(onBehalfOf: string, disableHeuristics?: boolean): Promise<SummarizerStopReason>;\n\n\t/**\n\t * Attempts to generate a summary on demand. If already running, takes no action.\n\t * @param options - options controlling the summarize attempt\n\t * @returns an alreadyRunning promise if a summarize attempt is already in progress,\n\t * which will resolve when the current attempt completes. At that point caller can\n\t * decide to try again or not. Otherwise, it will return an object containing promises\n\t * that resolve as the summarize attempt progresses. They will resolve with success\n\t * false if a failure is encountered.\n\t */\n\tsummarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults;\n\t/**\n\t * Enqueue an attempt to summarize after the specified sequence number.\n\t * If afterSequenceNumber is provided, the summarize attempt is \"enqueued\"\n\t * to run once an eligible op comes in with sequenceNumber \\>= afterSequenceNumber.\n\t * @param options - options controlling the summarize attempt\n\t * @returns an object containing an alreadyEnqueued flag to indicate if another\n\t * summarize attempt has already been enqueued. It also may contain an overridden flag\n\t * when alreadyEnqueued is true, that indicates whether this attempt forced the\n\t * previous attempt to abort. If this attempt becomes enqueued, it returns an object\n\t * containing promises that resolve as the summarize attempt progresses. They will\n\t * resolve with success false if a failure is encountered.\n\t */\n\tenqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult;\n}\n\n/** Data about an attempt to summarize used for heuristics. */\nexport interface ISummarizeAttempt {\n\t/** Reference sequence number when summary was generated or attempted */\n\treadonly refSequenceNumber: number;\n\n\t/** Time of summary attempt after it was sent or attempted */\n\treadonly summaryTime: number;\n\n\t/** Sequence number of summary op */\n\tsummarySequenceNumber?: number;\n}\n\n/** Data relevant for summary heuristics. */\nexport interface ISummarizeHeuristicData {\n\t/** Latest received op sequence number */\n\tlastOpSequenceNumber: number;\n\n\t/** Most recent summary attempt from this client */\n\treadonly lastAttempt: ISummarizeAttempt;\n\n\t/** Most recent summary that received an ack */\n\treadonly lastSuccessfulSummary: Readonly<ISummarizeAttempt>;\n\n\t/** Number of runtime ops since last summary */\n\tnumRuntimeOps: number;\n\n\t/** Number of non-runtime ops since last summary */\n\tnumNonRuntimeOps: number;\n\n\t/** Cumulative size in bytes of all the ops since the last summary */\n\ttotalOpsSize: number;\n\n\t/** Wether or not this instance contains adjusted metrics due to missing op data */\n\thasMissingOpData: boolean;\n\n\t/**\n\t * Updates lastAttempt and lastSuccessfulAttempt based on the last summary.\n\t * @param lastSummary - last ack summary\n\t */\n\tupdateWithLastSummaryAckInfo(lastSummary: ISummarizeAttempt): void;\n\n\t/**\n\t * Records a summary attempt. If the attempt was successfully sent,\n\t * provide the reference sequence number, otherwise it will be set\n\t * to the last seen op sequence number.\n\t * @param referenceSequenceNumber - reference sequence number of sent summary\n\t */\n\trecordAttempt(referenceSequenceNumber?: number): void;\n\n\t/** Mark that the last sent summary attempt has received an ack */\n\tmarkLastAttemptAsSuccessful(): void;\n}\n\n/** Responsible for running heuristics determining when to summarize. */\nexport interface ISummarizeHeuristicRunner {\n\t/** Start specific heuristic trackers (ex: idle timer) */\n\tstart(): void;\n\n\t/** Runs the heuristics to determine if it should try to summarize */\n\trun(): void;\n\n\t/** Runs a different heuristic to check if it should summarize before closing */\n\tshouldRunLastSummary(): boolean;\n\n\t/** Disposes of resources */\n\tdispose(): void;\n}\n\ntype ISummarizeTelemetryRequiredProperties =\n\t/** Reason code for attempting to summarize */\n\t\"reason\";\n\ntype ISummarizeTelemetryOptionalProperties =\n\t/** Number of attempts within the last time window, used for calculating the throttle delay. */\n\t| \"summaryAttempts\"\n\t/** Number of attempts within the current phase (currently capped at 2 ) */\n\t| \"summaryAttemptsPerPhase\"\n\t/** One-based count of phases we've attempted (used to index into an array of ISummarizeOptions */\n\t| \"summaryAttemptPhase\"\n\t| keyof ISummarizeOptions;\n\nexport type ISummarizeTelemetryProperties = Pick<\n\tITelemetryProperties,\n\tISummarizeTelemetryRequiredProperties\n> &\n\tPartial<Pick<ITelemetryProperties, ISummarizeTelemetryOptionalProperties>>;\n\n/** Strategy used to heuristically determine when we should run a summary */\nexport interface ISummaryHeuristicStrategy {\n\t/** Summarize reason for this summarize heuristic strategy (ex: \"maxTime\") */\n\tsummarizeReason: Readonly<SummarizeReason>;\n\n\t/**\n\t * Determines if this strategy's summarize criteria been met\n\t * @param configuration - summary configuration we are to check against\n\t * @param heuristicData - heuristic data used to confirm conditions are met\n\t */\n\tshouldRunSummary(\n\t\tconfiguration: ISummaryConfigurationHeuristics,\n\t\theuristicData: ISummarizeHeuristicData,\n\t): boolean;\n}\n\ntype SummaryGeneratorRequiredTelemetryProperties =\n\t/** True to generate the full tree with no handle reuse optimizations */\n\t| \"fullTree\"\n\t/** Time since we last attempted to generate a summary */\n\t| \"timeSinceLastAttempt\"\n\t/** Time since we last successfully generated a summary */\n\t| \"timeSinceLastSummary\";\n\ntype SummaryGeneratorOptionalTelemetryProperties =\n\t/** Reference sequence number as of the generate summary attempt. */\n\t| \"referenceSequenceNumber\"\n\t/** minimum sequence number (at the reference sequence number) */\n\t| \"minimumSequenceNumber\"\n\t/** Delta between the current reference sequence number and the reference sequence number of the last attempt */\n\t| \"opsSinceLastAttempt\"\n\t/** Delta between the current reference sequence number and the reference sequence number of the last summary */\n\t| \"opsSinceLastSummary\"\n\t/**\n\t * Delta in sum of op sizes between the current reference sequence number and the reference\n\t * sequence number of the last summary\n\t */\n\t| \"opsSizesSinceLastSummary\"\n\t/** Delta between the number of non-runtime ops since the last summary */\n\t| \"nonRuntimeOpsSinceLastSummary\"\n\t/** Wether or not this instance contains adjusted metrics due to missing op data */\n\t| \"hasMissingOpData\"\n\t/** Time it took to generate the summary tree and stats. */\n\t| \"generateDuration\"\n\t/** The handle returned by storage pointing to the uploaded summary tree. */\n\t| \"handle\"\n\t/** Time it took to upload the summary tree to storage. */\n\t| \"uploadDuration\"\n\t/** The client sequence number of the summarize op submitted for the summary. */\n\t| \"clientSequenceNumber\"\n\t/** Time it took for this summary to be acked after it was generated */\n\t| \"ackWaitDuration\"\n\t/** Reference sequence number of the ack/nack message */\n\t| \"ackNackSequenceNumber\"\n\t/** Actual sequence number of the summary op proposal. */\n\t| \"summarySequenceNumber\"\n\t/** Optional Retry-After time in seconds. If specified, the client should wait this many seconds before retrying. */\n\t| \"nackRetryAfter\";\n\nexport type SummaryGeneratorTelemetry = Pick<\n\tITelemetryProperties,\n\tSummaryGeneratorRequiredTelemetryProperties\n> &\n\tPartial<Pick<ITelemetryProperties, SummaryGeneratorOptionalTelemetryProperties>>;\n\nexport interface ISummarizeRunnerTelemetry extends ITelemetryLoggerPropertyBag {\n\t/** Number of times the summarizer run. */\n\tsummarizeCount: () => number;\n\t/** Number of successful attempts to summarize. */\n\tsummarizerSuccessfulAttempts: () => number;\n}\n"]}
1
+ {"version":3,"file":"summarizerTypes.js","sourceRoot":"","sources":["../../src/summary/summarizerTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAA6B,aAAa,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIEvent,\n\tIEventProvider,\n\tITelemetryLogger,\n\tITelemetryProperties,\n} from \"@fluidframework/common-definitions\";\nimport { ITelemetryLoggerPropertyBag } from \"@fluidframework/telemetry-utils\";\nimport { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport { ContainerWarning, IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n\tISequencedDocumentMessage,\n\tISummaryTree,\n\tIDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { ISummaryStats } from \"@fluidframework/runtime-definitions\";\nimport { ISummaryConfigurationHeuristics } from \"../containerRuntime\";\nimport { ISummaryAckMessage, ISummaryNackMessage, ISummaryOpMessage } from \"./summaryCollection\";\nimport { SummarizeReason } from \"./summaryGenerator\";\n\n/**\n * @deprecated This will be removed in a later release.\n */\nexport const ISummarizer: keyof IProvideSummarizer = \"ISummarizer\";\n\n/**\n * @deprecated This will be removed in a later release.\n */\nexport interface IProvideSummarizer {\n\t/**\n\t * @deprecated This will be removed in a later release.\n\t */\n\treadonly ISummarizer: ISummarizer;\n}\n\n/**\n * Similar to AbortSignal, but using promise instead of events\n * @param T - cancellation reason type\n */\nexport interface ICancellationToken<T> {\n\t/** Tells if this cancellable token is cancelled */\n\treadonly cancelled: boolean;\n\t/**\n\t * Promise that gets fulfilled when this cancellable token is cancelled\n\t * @returns reason of cancellation\n\t */\n\treadonly waitCancelled: Promise<T>;\n}\n\n/* Similar to AbortSignal, but using promise instead of events */\nexport type ISummaryCancellationToken = ICancellationToken<SummarizerStopReason>;\n\nexport interface ISummarizerInternalsProvider {\n\t/** Encapsulates the work to walk the internals of the running container to generate a summary */\n\tsubmitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult>;\n\n\t/** Callback whenever a new SummaryAck is received, to update internal tracking state */\n\trefreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise<void>;\n}\n\n/**\n * @deprecated Options that control the behavior of a running summarizer.\n * */\nexport interface ISummarizerOptions {\n\t/**\n\t * Set to true to disable the default heuristics from running; false by default.\n\t * This affects only the heuristics around when a summarizer should\n\t * submit summaries. So when it is disabled, summarizer clients should\n\t * not be expected to summarize unless an on-demand summary is requested.\n\t */\n\tdisableHeuristics: boolean;\n}\n\nexport interface ISummarizingWarning extends ContainerWarning {\n\treadonly errorType: \"summarizingError\";\n\treadonly logged: boolean;\n}\n\nexport interface IConnectableRuntime {\n\treadonly disposed: boolean;\n\treadonly connected: boolean;\n\treadonly clientId: string | undefined;\n\t/** @deprecated - Moved to `ISummarizerRuntime` as it's no longer needed here */\n\treadonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;\n\tonce(event: \"connected\" | \"disconnected\" | \"dispose\", listener: () => void): this;\n}\n\nexport interface ISummarizerRuntime extends IConnectableRuntime {\n\treadonly logger: ITelemetryLogger;\n\t/** clientId of parent (non-summarizing) container that owns summarizer container */\n\treadonly summarizerClientId: string | undefined;\n\treadonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;\n\tdisposeFn?(): void;\n\tcloseFn(): void;\n}\n\n/** Options affecting summarize behavior. */\nexport interface ISummarizeOptions {\n\t/** True to generate the full tree with no handle reuse optimizations; defaults to false */\n\treadonly fullTree?: boolean;\n\t/** True to ask the server what the latest summary is first; defaults to false */\n\treadonly refreshLatestAck?: boolean;\n}\n\n/**\n * Data required to update internal tracking state after receiving a Summary Ack.\n */\nexport interface IRefreshSummaryAckOptions {\n\t/** Handle from the ack's summary op. */\n\treadonly proposalHandle: string | undefined;\n\t/** Handle from the summary ack just received */\n\treadonly ackHandle: string;\n\t/** Reference sequence number from the ack's summary op */\n\treadonly summaryRefSeq: number;\n\t/** Telemetry logger to which telemetry events will be forwarded. */\n\treadonly summaryLogger: ITelemetryLogger;\n}\n\nexport interface ISubmitSummaryOptions extends ISummarizeOptions {\n\t/** Logger to use for correlated summary events */\n\treadonly summaryLogger: ITelemetryLogger;\n\t/** Tells when summary process should be cancelled */\n\treadonly cancellationToken: ISummaryCancellationToken;\n}\n\nexport interface IOnDemandSummarizeOptions extends ISummarizeOptions {\n\t/** Reason for generating summary. */\n\treadonly reason: string;\n}\n\n/** Options to use when enqueueing a summarize attempt. */\nexport interface IEnqueueSummarizeOptions extends IOnDemandSummarizeOptions {\n\t/** If specified, The summarize attempt will not occur until after this sequence number. */\n\treadonly afterSequenceNumber?: number;\n\n\t/**\n\t * True to override the existing enqueued summarize attempt if there is one.\n\t * This will guarantee that this attempt gets enqueued. If override is false,\n\t * than an existing enqueued summarize attempt will block a new one from being\n\t * enqueued. There can only be one enqueued at a time. Defaults to false.\n\t */\n\treadonly override?: boolean;\n}\n\n/**\n * In addition to the normal summary tree + stats, this contains additional stats\n * only relevant at the root of the tree.\n */\nexport interface IGeneratedSummaryStats extends ISummaryStats {\n\t/** The total number of data stores in the container. */\n\treadonly dataStoreCount: number;\n\t/** The number of data stores that were summarized in this summary. */\n\treadonly summarizedDataStoreCount: number;\n\t/** The number of data stores whose GC reference state was updated in this summary. */\n\treadonly gcStateUpdatedDataStoreCount?: number;\n\t/** The size of the gc blobs in this summary. */\n\treadonly gcTotalBlobsSize?: number;\n\t/** The number of gc blobs in this summary. */\n\treadonly gcBlobNodeCount?: number;\n\t/** The summary number for a container's summary. Incremented on summaries throughout its lifetime. */\n\treadonly summaryNumber: number;\n}\n\n/** Base results for all submitSummary attempts. */\nexport interface IBaseSummarizeResult {\n\treadonly stage: \"base\";\n\t/** Error object related to failed summarize attempt. */\n\treadonly error: any;\n\t/** Reference sequence number as of the generate summary attempt. */\n\treadonly referenceSequenceNumber: number;\n\treadonly minimumSequenceNumber: number;\n}\n\n/** Results of submitSummary after generating the summary tree. */\nexport interface IGenerateSummaryTreeResult extends Omit<IBaseSummarizeResult, \"stage\"> {\n\treadonly stage: \"generate\";\n\t/** Generated summary tree. */\n\treadonly summaryTree: ISummaryTree;\n\t/** Stats for generated summary tree. */\n\treadonly summaryStats: IGeneratedSummaryStats;\n\t/** Time it took to generate the summary tree and stats. */\n\treadonly generateDuration: number;\n\t/** True if the full tree regeneration with no handle reuse optimizations was forced. */\n\treadonly forcedFullTree: boolean;\n}\n\n/** Results of submitSummary after uploading the tree to storage. */\nexport interface IUploadSummaryResult extends Omit<IGenerateSummaryTreeResult, \"stage\"> {\n\treadonly stage: \"upload\";\n\t/** The handle returned by storage pointing to the uploaded summary tree. */\n\treadonly handle: string;\n\t/** Time it took to upload the summary tree to storage. */\n\treadonly uploadDuration: number;\n}\n\n/** Results of submitSummary after submitting the summarize op. */\nexport interface ISubmitSummaryOpResult extends Omit<IUploadSummaryResult, \"stage\" | \"error\"> {\n\treadonly stage: \"submit\";\n\t/** The client sequence number of the summarize op submitted for the summary. */\n\treadonly clientSequenceNumber: number;\n\t/** Time it took to submit the summarize op to the broadcasting service. */\n\treadonly submitOpDuration: number;\n}\n\n/**\n * Strict type representing result of a submitSummary attempt.\n * The result consists of 4 possible stages, each with its own data.\n * The data is cumulative, so each stage will contain the data from the previous stages.\n * If the final \"submitted\" stage is not reached, the result may contain the error object.\n *\n * Stages:\n *\n * 1. \"base\" - stopped before the summary tree was even generated, and the result only contains the base data\n *\n * 2. \"generate\" - the summary tree was generated, and the result will contain that tree + stats\n *\n * 3. \"upload\" - the summary was uploaded to storage, and the result contains the server-provided handle\n *\n * 4. \"submit\" - the summarize op was submitted, and the result contains the op client sequence number.\n */\nexport type SubmitSummaryResult =\n\t| IBaseSummarizeResult\n\t| IGenerateSummaryTreeResult\n\t| IUploadSummaryResult\n\t| ISubmitSummaryOpResult;\n\nexport interface IBroadcastSummaryResult {\n\treadonly summarizeOp: ISummaryOpMessage;\n\treadonly broadcastDuration: number;\n}\n\nexport interface IAckSummaryResult {\n\treadonly summaryAckOp: ISummaryAckMessage;\n\treadonly ackNackDuration: number;\n}\n\nexport interface INackSummaryResult {\n\treadonly summaryNackOp: ISummaryNackMessage;\n\treadonly ackNackDuration: number;\n}\n\nexport type SummarizeResultPart<TSuccess, TFailure = undefined> =\n\t| {\n\t\t\tsuccess: true;\n\t\t\tdata: TSuccess;\n\t }\n\t| {\n\t\t\tsuccess: false;\n\t\t\tdata: TFailure | undefined;\n\t\t\tmessage: string;\n\t\t\terror: any;\n\t\t\tretryAfterSeconds?: number;\n\t };\n\nexport interface ISummarizeResults {\n\t/** Resolves when we generate, upload, and submit the summary. */\n\treadonly summarySubmitted: Promise<SummarizeResultPart<SubmitSummaryResult>>;\n\t/** Resolves when we observe our summarize op broadcast. */\n\treadonly summaryOpBroadcasted: Promise<SummarizeResultPart<IBroadcastSummaryResult>>;\n\t/** Resolves when we receive a summaryAck or summaryNack. */\n\treadonly receivedSummaryAckOrNack: Promise<\n\t\tSummarizeResultPart<IAckSummaryResult, INackSummaryResult>\n\t>;\n}\n\nexport type EnqueueSummarizeResult =\n\t| (ISummarizeResults & {\n\t\t\t/**\n\t\t\t * Indicates that another summarize attempt is not already enqueued,\n\t\t\t * and this attempt has been enqueued.\n\t\t\t */\n\t\t\treadonly alreadyEnqueued?: undefined;\n\t })\n\t| (ISummarizeResults & {\n\t\t\t/** Indicates that another summarize attempt was already enqueued. */\n\t\t\treadonly alreadyEnqueued: true;\n\t\t\t/**\n\t\t\t * Indicates that the other enqueued summarize attempt was abandoned,\n\t\t\t * and this attempt has been enqueued enqueued.\n\t\t\t */\n\t\t\treadonly overridden: true;\n\t })\n\t| {\n\t\t\t/** Indicates that another summarize attempt was already enqueued. */\n\t\t\treadonly alreadyEnqueued: true;\n\t\t\t/**\n\t\t\t * Indicates that the other enqueued summarize attempt remains enqueued,\n\t\t\t * and this attempt has not been enqueued.\n\t\t\t */\n\t\t\treadonly overridden?: undefined;\n\t };\n\nexport type SummarizerStopReason =\n\t/** Summarizer client failed to summarize in all 3 consecutive attempts. */\n\t| \"failToSummarize\"\n\t/** Parent client reported that it is no longer connected. */\n\t| \"parentNotConnected\"\n\t/**\n\t * Parent client reported that it is no longer elected the summarizer.\n\t * This is the normal flow; a disconnect will always trigger the parent\n\t * client to no longer be elected as responsible for summaries. Then it\n\t * tries to stop its spawned summarizer client.\n\t */\n\t| \"notElectedParent\"\n\t/**\n\t * We are not already running the summarizer and we are not the current elected client id.\n\t */\n\t| \"notElectedClient\"\n\t/** Summarizer client was disconnected */\n\t| \"summarizerClientDisconnected\"\n\t/* running summarizer threw an exception */\n\t| \"summarizerException\";\n\nexport interface ISummarizerEvents extends IEvent {\n\t/**\n\t * An event indicating that the Summarizer is having problems summarizing\n\t */\n\t(event: \"summarizingError\", listener: (error: ISummarizingWarning) => void);\n}\n\nexport interface ISummarizer\n\textends IEventProvider<ISummarizerEvents>,\n\t\tIFluidLoadable,\n\t\tPartial<IProvideSummarizer> {\n\t/*\n\t * Asks summarizer to move to exit.\n\t * Summarizer will finish current processes, which may take a while.\n\t * For example, summarizer may complete last summary before exiting.\n\t */\n\tstop(reason: SummarizerStopReason): void;\n\n\t/* Closes summarizer. Any pending processes (summary in flight) are abandoned. */\n\tclose(): void;\n\n\trun(onBehalfOf: string, disableHeuristics?: boolean): Promise<SummarizerStopReason>;\n\n\t/**\n\t * Attempts to generate a summary on demand. If already running, takes no action.\n\t * @param options - options controlling the summarize attempt\n\t * @returns an alreadyRunning promise if a summarize attempt is already in progress,\n\t * which will resolve when the current attempt completes. At that point caller can\n\t * decide to try again or not. Otherwise, it will return an object containing promises\n\t * that resolve as the summarize attempt progresses. They will resolve with success\n\t * false if a failure is encountered.\n\t */\n\tsummarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults;\n\t/**\n\t * Enqueue an attempt to summarize after the specified sequence number.\n\t * If afterSequenceNumber is provided, the summarize attempt is \"enqueued\"\n\t * to run once an eligible op comes in with sequenceNumber \\>= afterSequenceNumber.\n\t * @param options - options controlling the summarize attempt\n\t * @returns an object containing an alreadyEnqueued flag to indicate if another\n\t * summarize attempt has already been enqueued. It also may contain an overridden flag\n\t * when alreadyEnqueued is true, that indicates whether this attempt forced the\n\t * previous attempt to abort. If this attempt becomes enqueued, it returns an object\n\t * containing promises that resolve as the summarize attempt progresses. They will\n\t * resolve with success false if a failure is encountered.\n\t */\n\tenqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult;\n}\n\n/** Data about an attempt to summarize used for heuristics. */\nexport interface ISummarizeAttempt {\n\t/** Reference sequence number when summary was generated or attempted */\n\treadonly refSequenceNumber: number;\n\n\t/** Time of summary attempt after it was sent or attempted */\n\treadonly summaryTime: number;\n\n\t/** Sequence number of summary op */\n\tsummarySequenceNumber?: number;\n}\n\n/** Data relevant for summary heuristics. */\nexport interface ISummarizeHeuristicData {\n\t/** Latest received op sequence number */\n\tlastOpSequenceNumber: number;\n\n\t/** Most recent summary attempt from this client */\n\treadonly lastAttempt: ISummarizeAttempt;\n\n\t/** Most recent summary that received an ack */\n\treadonly lastSuccessfulSummary: Readonly<ISummarizeAttempt>;\n\n\t/** Number of runtime ops since last summary */\n\tnumRuntimeOps: number;\n\n\t/** Number of non-runtime ops since last summary */\n\tnumNonRuntimeOps: number;\n\n\t/** Cumulative size in bytes of all the ops since the last summary */\n\ttotalOpsSize: number;\n\n\t/** Wether or not this instance contains adjusted metrics due to missing op data */\n\thasMissingOpData: boolean;\n\n\t/**\n\t * Updates lastAttempt and lastSuccessfulAttempt based on the last summary.\n\t * @param lastSummary - last ack summary\n\t */\n\tupdateWithLastSummaryAckInfo(lastSummary: ISummarizeAttempt): void;\n\n\t/**\n\t * Records a summary attempt. If the attempt was successfully sent,\n\t * provide the reference sequence number, otherwise it will be set\n\t * to the last seen op sequence number.\n\t * @param referenceSequenceNumber - reference sequence number of sent summary\n\t */\n\trecordAttempt(referenceSequenceNumber?: number): void;\n\n\t/** Mark that the last sent summary attempt has received an ack */\n\tmarkLastAttemptAsSuccessful(): void;\n}\n\n/** Responsible for running heuristics determining when to summarize. */\nexport interface ISummarizeHeuristicRunner {\n\t/** Start specific heuristic trackers (ex: idle timer) */\n\tstart(): void;\n\n\t/** Runs the heuristics to determine if it should try to summarize */\n\trun(): void;\n\n\t/** Runs a different heuristic to check if it should summarize before closing */\n\tshouldRunLastSummary(): boolean;\n\n\t/** Disposes of resources */\n\tdispose(): void;\n}\n\ntype ISummarizeTelemetryRequiredProperties =\n\t/** Reason code for attempting to summarize */\n\t\"reason\";\n\ntype ISummarizeTelemetryOptionalProperties =\n\t/** Number of attempts within the last time window, used for calculating the throttle delay. */\n\t| \"summaryAttempts\"\n\t/** Number of attempts within the current phase (currently capped at 2 ) */\n\t| \"summaryAttemptsPerPhase\"\n\t/** One-based count of phases we've attempted (used to index into an array of ISummarizeOptions */\n\t| \"summaryAttemptPhase\"\n\t| keyof ISummarizeOptions;\n\nexport type ISummarizeTelemetryProperties = Pick<\n\tITelemetryProperties,\n\tISummarizeTelemetryRequiredProperties\n> &\n\tPartial<Pick<ITelemetryProperties, ISummarizeTelemetryOptionalProperties>>;\n\n/** Strategy used to heuristically determine when we should run a summary */\nexport interface ISummaryHeuristicStrategy {\n\t/** Summarize reason for this summarize heuristic strategy (ex: \"maxTime\") */\n\tsummarizeReason: Readonly<SummarizeReason>;\n\n\t/**\n\t * Determines if this strategy's summarize criteria been met\n\t * @param configuration - summary configuration we are to check against\n\t * @param heuristicData - heuristic data used to confirm conditions are met\n\t */\n\tshouldRunSummary(\n\t\tconfiguration: ISummaryConfigurationHeuristics,\n\t\theuristicData: ISummarizeHeuristicData,\n\t): boolean;\n}\n\ntype SummaryGeneratorRequiredTelemetryProperties =\n\t/** True to generate the full tree with no handle reuse optimizations */\n\t| \"fullTree\"\n\t/** Time since we last attempted to generate a summary */\n\t| \"timeSinceLastAttempt\"\n\t/** Time since we last successfully generated a summary */\n\t| \"timeSinceLastSummary\";\n\ntype SummaryGeneratorOptionalTelemetryProperties =\n\t/** Reference sequence number as of the generate summary attempt. */\n\t| \"referenceSequenceNumber\"\n\t/** minimum sequence number (at the reference sequence number) */\n\t| \"minimumSequenceNumber\"\n\t/** Delta between the current reference sequence number and the reference sequence number of the last attempt */\n\t| \"opsSinceLastAttempt\"\n\t/** Delta between the current reference sequence number and the reference sequence number of the last summary */\n\t| \"opsSinceLastSummary\"\n\t/**\n\t * Delta in sum of op sizes between the current reference sequence number and the reference\n\t * sequence number of the last summary\n\t */\n\t| \"opsSizesSinceLastSummary\"\n\t/** Delta between the number of non-runtime ops since the last summary */\n\t| \"nonRuntimeOpsSinceLastSummary\"\n\t/** Wether or not this instance contains adjusted metrics due to missing op data */\n\t| \"hasMissingOpData\"\n\t/** Time it took to generate the summary tree and stats. */\n\t| \"generateDuration\"\n\t/** The handle returned by storage pointing to the uploaded summary tree. */\n\t| \"handle\"\n\t/** Time it took to upload the summary tree to storage. */\n\t| \"uploadDuration\"\n\t/** The client sequence number of the summarize op submitted for the summary. */\n\t| \"clientSequenceNumber\"\n\t/** Time it took for this summary to be acked after it was generated */\n\t| \"ackWaitDuration\"\n\t/** Reference sequence number of the ack/nack message */\n\t| \"ackNackSequenceNumber\"\n\t/** Actual sequence number of the summary op proposal. */\n\t| \"summarySequenceNumber\"\n\t/** Optional Retry-After time in seconds. If specified, the client should wait this many seconds before retrying. */\n\t| \"nackRetryAfter\";\n\nexport type SummaryGeneratorTelemetry = Pick<\n\tITelemetryProperties,\n\tSummaryGeneratorRequiredTelemetryProperties\n> &\n\tPartial<Pick<ITelemetryProperties, SummaryGeneratorOptionalTelemetryProperties>>;\n\nexport interface ISummarizeRunnerTelemetry extends ITelemetryLoggerPropertyBag {\n\t/** Number of times the summarizer run. */\n\tsummarizeCount: () => number;\n\t/** Number of successful attempts to summarize. */\n\tsummarizerSuccessfulAttempts: () => number;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-internal.3.2.1",
3
+ "version": "2.0.0-internal.3.3.0",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -37,32 +37,32 @@
37
37
  "dependencies": {
38
38
  "@fluidframework/common-definitions": "^0.20.1",
39
39
  "@fluidframework/common-utils": "^1.1.1",
40
- "@fluidframework/container-definitions": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
41
- "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
42
- "@fluidframework/container-utils": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
43
- "@fluidframework/core-interfaces": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
44
- "@fluidframework/datastore": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
45
- "@fluidframework/driver-definitions": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
46
- "@fluidframework/driver-utils": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
47
- "@fluidframework/garbage-collector": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
48
- "@fluidframework/protocol-base": "^0.1038.2000",
40
+ "@fluidframework/container-definitions": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
41
+ "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
42
+ "@fluidframework/container-utils": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
43
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
44
+ "@fluidframework/datastore": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
45
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
46
+ "@fluidframework/driver-utils": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
47
+ "@fluidframework/garbage-collector": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
48
+ "@fluidframework/protocol-base": "^0.1038.3000",
49
49
  "@fluidframework/protocol-definitions": "^1.1.0",
50
- "@fluidframework/runtime-definitions": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
51
- "@fluidframework/runtime-utils": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
52
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
50
+ "@fluidframework/runtime-definitions": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
51
+ "@fluidframework/runtime-utils": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
52
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
53
53
  "double-ended-queue": "^2.1.0-0",
54
54
  "events": "^3.1.0",
55
55
  "lz4js": "^0.2.0",
56
56
  "uuid": "^8.3.1"
57
57
  },
58
58
  "devDependencies": {
59
- "@fluid-tools/build-cli": "^0.10.0",
59
+ "@fluid-tools/build-cli": "^0.12.0",
60
60
  "@fluidframework/build-common": "^1.1.0",
61
- "@fluidframework/build-tools": "^0.10.0",
62
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.3.1.0",
61
+ "@fluidframework/build-tools": "^0.12.0",
62
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.3.2.0",
63
63
  "@fluidframework/eslint-config-fluid": "^2.0.0",
64
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
65
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.3.2.1 <2.0.0-internal.4.0.0",
64
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
65
+ "@fluidframework/test-runtime-utils": ">=2.0.0-internal.3.3.0 <2.0.0-internal.4.0.0",
66
66
  "@microsoft/api-extractor": "^7.22.2",
67
67
  "@rushstack/eslint-config": "^2.5.1",
68
68
  "@types/double-ended-queue": "^2.1.0",
@@ -82,18 +82,7 @@
82
82
  "typescript": "~4.5.5"
83
83
  },
84
84
  "typeValidation": {
85
- "version": "2.0.0-internal.3.2.0",
86
- "previousVersionStyle": "~previousMinor",
87
- "baselineRange": ">=2.0.0-internal.3.1.0 <2.0.0-internal.3.2.0",
88
- "baselineVersion": "2.0.0-internal.3.1.0",
89
- "broken": {
90
- "EnumDeclaration_RuntimeHeaders": {
91
- "forwardCompat": false
92
- },
93
- "ClassDeclaration_ContainerRuntime": {
94
- "forwardCompat": false
95
- }
96
- }
85
+ "broken": {}
97
86
  },
98
87
  "scripts": {
99
88
  "build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
@@ -120,7 +109,7 @@
120
109
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
121
110
  "tsc": "tsc",
122
111
  "tsc:watch": "tsc --watch",
123
- "typetests:gen": "flub generate typetests --generate --dir .",
112
+ "typetests:gen": "fluid-type-test-generator",
124
113
  "typetests:prepare": "flub generate typetests --prepare --dir . --pin"
125
114
  }
126
115
  }
@@ -31,7 +31,13 @@ import {
31
31
  IContainerRuntime,
32
32
  IContainerRuntimeEvents,
33
33
  } from "@fluidframework/container-runtime-definitions";
34
- import { assert, Trace, TypedEventEmitter, unreachableCase } from "@fluidframework/common-utils";
34
+ import {
35
+ assert,
36
+ LazyPromise,
37
+ Trace,
38
+ TypedEventEmitter,
39
+ unreachableCase,
40
+ } from "@fluidframework/common-utils";
35
41
  import {
36
42
  ChildLogger,
37
43
  raiseConnectedEvent,
@@ -147,8 +153,8 @@ import {
147
153
  GarbageCollector,
148
154
  GCNodeType,
149
155
  gcTombstoneGenerationOptionName,
150
- IGarbageCollectionRuntime,
151
156
  IGarbageCollector,
157
+ IGCRuntimeOptions,
152
158
  IGCStats,
153
159
  shouldAllowGcTombstoneEnforcement,
154
160
  } from "./gc";
@@ -168,6 +174,7 @@ import {
168
174
  OpSplitter,
169
175
  RemoteMessageProcessor,
170
176
  } from "./opLifecycle";
177
+ import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
171
178
 
172
179
  export enum ContainerMessageType {
173
180
  // An op to be delivered to store
@@ -312,54 +319,6 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
312
319
  nonRuntimeHeuristicThreshold: 20,
313
320
  };
314
321
 
315
- export interface IGCRuntimeOptions {
316
- /**
317
- * Flag that if true, will enable running garbage collection (GC) for a new container.
318
- *
319
- * GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
320
- * and marked as such in the summary. This option enables the mark phase.
321
- * In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
322
- * Sweep phase can be enabled via the "sweepAllowed" option.
323
- *
324
- * Note: This setting is persisted in the container's summary and cannot be changed.
325
- */
326
- gcAllowed?: boolean;
327
-
328
- /**
329
- * Flag that if true, enables GC's sweep phase for a new container.
330
- *
331
- * This will allow GC to eventually delete unreferenced objects from the container.
332
- * This flag should only be set to true if "gcAllowed" is true.
333
- *
334
- * Note: This setting is persisted in the container's summary and cannot be changed.
335
- */
336
- sweepAllowed?: boolean;
337
-
338
- /**
339
- * Flag that if true, will disable garbage collection for the session.
340
- * Can be used to disable running GC on containers where it is allowed via the gcAllowed option.
341
- */
342
- disableGC?: boolean;
343
-
344
- /**
345
- * Flag that will bypass optimizations and generate GC data for all nodes irrespective of whether a node
346
- * changed or not.
347
- */
348
- runFullGC?: boolean;
349
-
350
- /**
351
- * Maximum session duration for a new container. If not present, a default value will be used.
352
- *
353
- * Note: This setting is persisted in the container's summary and cannot be changed.
354
- */
355
- sessionExpiryTimeoutMs?: number;
356
-
357
- /**
358
- * Allows additional GC options to be passed.
359
- */
360
- [key: string]: any;
361
- }
362
-
363
322
  export interface ISummaryRuntimeOptions {
364
323
  /** Override summary configurations set by the server. */
365
324
  summaryConfigOverrides?: ISummaryConfiguration;
@@ -433,7 +392,8 @@ export interface IContainerRuntimeOptions {
433
392
  readonly maxBatchSizeInBytes?: number;
434
393
  /**
435
394
  * If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
436
- * how large the individual chunks will be. This is only supported when compression is enabled.
395
+ * how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
396
+ * batch size exceeds this value, it will be chunked into smaller ops of this size.
437
397
  *
438
398
  * If unspecified, if a batch exceeds `maxBatchSizeInBytes` after compression, the container will close with an instance
439
399
  * of `GenericError` with the `BatchTooLarge` message.
@@ -598,12 +558,7 @@ export function getDeviceSpec() {
598
558
  */
599
559
  export class ContainerRuntime
600
560
  extends TypedEventEmitter<IContainerRuntimeEvents>
601
- implements
602
- IContainerRuntime,
603
- IGarbageCollectionRuntime,
604
- IRuntime,
605
- ISummarizerRuntime,
606
- ISummarizerInternalsProvider
561
+ implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
607
562
  {
608
563
  public get IContainerRuntime() {
609
564
  return this;
@@ -651,13 +606,16 @@ export class ContainerRuntime
651
606
  * Load the stores from a snapshot and returns the runtime.
652
607
  * @param params - An object housing the runtime properties:
653
608
  * - context - Context of the container.
654
- * - registryEntries - Mapping to the stores.
655
- * - existing - When loading from an existing snapshot
656
- * - requestHandler - Request handlers for the container runtime
609
+ * - registryEntries - Mapping from data store types to their corresponding factories.
610
+ * - existing - Pass 'true' if loading from an existing snapshot.
611
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
612
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
657
613
  * - runtimeOptions - Additional options to be passed to the runtime
658
614
  * - containerScope - runtime services provided with context
659
615
  * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
660
616
  * This allows mixin classes to leverage this method to define their own async initializer.
617
+ * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
618
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
661
619
  */
662
620
  public static async loadRuntime(params: {
663
621
  context: IContainerContext;
@@ -667,6 +625,7 @@ export class ContainerRuntime
667
625
  runtimeOptions?: IContainerRuntimeOptions;
668
626
  containerScope?: FluidObject;
669
627
  containerRuntimeCtor?: typeof ContainerRuntime;
628
+ initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
670
629
  }): Promise<ContainerRuntime> {
671
630
  const {
672
631
  context,
@@ -676,6 +635,7 @@ export class ContainerRuntime
676
635
  runtimeOptions = {},
677
636
  containerScope = {},
678
637
  containerRuntimeCtor = ContainerRuntime,
638
+ initializeEntryPoint,
679
639
  } = params;
680
640
 
681
641
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
@@ -800,6 +760,8 @@ export class ContainerRuntime
800
760
  blobManagerSnapshot,
801
761
  storage,
802
762
  requestHandler,
763
+ undefined, // summaryConfiguration
764
+ initializeEntryPoint,
803
765
  );
804
766
 
805
767
  if (pendingRuntimeState) {
@@ -826,10 +788,6 @@ export class ContainerRuntime
826
788
  return this.context.clientDetails;
827
789
  }
828
790
 
829
- public get deltaManager(): IDeltaManager<ISequencedDocumentMessage, IDocumentMessage> {
830
- return this.context.deltaManager;
831
- }
832
-
833
791
  public get storage(): IDocumentStorageService {
834
792
  return this._storage;
835
793
  }
@@ -878,6 +836,19 @@ export class ContainerRuntime
878
836
  }
879
837
  private readonly handleContext: ContainerFluidHandleContext;
880
838
 
839
+ /**
840
+ * This is a proxy to the delta manager provided by the container context (innerDeltaManager). It restricts certain
841
+ * accesses such as sets "read-only" mode for the summarizer client. This is the default delta manager that should
842
+ * be used unless the innerDeltaManager is required.
843
+ */
844
+ public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
845
+ /**
846
+ * The delta manager provided by the container context. By default, using the default delta manager (proxy)
847
+ * should be sufficient. This should be used only if necessary. For example, for validating and propagating connected
848
+ * events which requires access to the actual real only info, this is needed.
849
+ */
850
+ private readonly innerDeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
851
+
881
852
  // internal logger for ContainerRuntime. Use this.logger for stores, summaries, etc.
882
853
  private readonly mc: MonitoringContext;
883
854
 
@@ -976,7 +947,6 @@ export class ContainerRuntime
976
947
  private readonly blobManager: BlobManager;
977
948
  private readonly pendingStateManager: PendingStateManager;
978
949
  private readonly outbox: Outbox;
979
-
980
950
  private readonly garbageCollector: IGarbageCollector;
981
951
 
982
952
  private readonly dataStores: DataStores;
@@ -1057,9 +1027,13 @@ export class ContainerRuntime
1057
1027
  // the runtime configuration overrides
1058
1028
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
1059
1029
  },
1030
+ initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1060
1031
  ) {
1061
1032
  super();
1062
1033
 
1034
+ this.innerDeltaManager = context.deltaManager;
1035
+ this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
1036
+
1063
1037
  let loadSummaryNumber: number;
1064
1038
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
1065
1039
  // get the values from the metadata blob.
@@ -1113,7 +1087,10 @@ export class ContainerRuntime
1113
1087
  runtimeOptions.maxBatchSizeInBytes,
1114
1088
  this.mc.logger,
1115
1089
  );
1116
- this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor());
1090
+ this.remoteMessageProcessor = new RemoteMessageProcessor(
1091
+ opSplitter,
1092
+ new OpDecompressor(this.mc.logger),
1093
+ );
1117
1094
 
1118
1095
  this.handleContext = new ContainerFluidHandleContext("", this);
1119
1096
 
@@ -1177,7 +1154,9 @@ export class ContainerRuntime
1177
1154
  getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
1178
1155
  readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
1179
1156
  getContainerDiagnosticId: () => this.context.id,
1180
- activeConnection: () => this.deltaManager.active,
1157
+ // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
1158
+ // delta manager would always return false for summarizer client.
1159
+ activeConnection: () => this.innerDeltaManager.active,
1181
1160
  });
1182
1161
 
1183
1162
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
@@ -1346,7 +1325,12 @@ export class ContainerRuntime
1346
1325
  this.handleContext,
1347
1326
  this.summaryCollection,
1348
1327
  async (runtime: IConnectableRuntime) =>
1349
- RunWhileConnectedCoordinator.create(runtime),
1328
+ RunWhileConnectedCoordinator.create(
1329
+ runtime,
1330
+ // Summarization runs in summarizer client and needs access to the real (non-proxy) active
1331
+ // information. The proxy delta manager would always return false for summarizer client.
1332
+ () => this.innerDeltaManager.active,
1333
+ ),
1350
1334
  );
1351
1335
  } else if (
1352
1336
  SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)
@@ -1396,8 +1380,9 @@ export class ContainerRuntime
1396
1380
  this.deltaManager.on("readonly", (readonly: boolean) => {
1397
1381
  // we accumulate ops while being in read-only state.
1398
1382
  // once user gets write permissions and we have active connection, flush all pending ops.
1383
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1399
1384
  assert(
1400
- readonly === this.deltaManager.readOnlyInfo.readonly,
1385
+ readonly === this.innerDeltaManager.readOnlyInfo.readonly,
1401
1386
  0x124 /* "inconsistent readonly property/event state" */,
1402
1387
  );
1403
1388
 
@@ -1447,6 +1432,8 @@ export class ContainerRuntime
1447
1432
 
1448
1433
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
1449
1434
  BindBatchTracker(this, this.logger);
1435
+
1436
+ this.entryPoint = new LazyPromise(async () => initializeEntryPoint?.(this));
1450
1437
  }
1451
1438
 
1452
1439
  /**
@@ -1566,6 +1553,14 @@ export class ContainerRuntime
1566
1553
  }
1567
1554
  }
1568
1555
 
1556
+ /**
1557
+ * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
1558
+ */
1559
+ public async getEntryPoint?(): Promise<FluidObject | undefined> {
1560
+ return this.entryPoint;
1561
+ }
1562
+ private readonly entryPoint: LazyPromise<FluidObject | undefined>;
1563
+
1569
1564
  private internalId(maybeAlias: string): string {
1570
1565
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
1571
1566
  }
@@ -1757,8 +1752,9 @@ export class ContainerRuntime
1757
1752
  // If attachment blobs were added while disconnected, we need to delay
1758
1753
  // propagation of the "connected" event until we have uploaded them to
1759
1754
  // ensure we don't submit ops referencing a blob that has not been uploaded
1755
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1760
1756
  const connecting =
1761
- connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
1757
+ connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1762
1758
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
1763
1759
  assert(
1764
1760
  !this.delayConnectClientId,
@@ -1890,7 +1886,23 @@ export class ContainerRuntime
1890
1886
  case ContainerMessageType.Rejoin:
1891
1887
  break;
1892
1888
  default:
1893
- assert(!runtimeMessage, 0x3ce /* Runtime message of unknown type */);
1889
+ if (runtimeMessage) {
1890
+ const error = DataProcessingError.create(
1891
+ // Former assert 0x3ce
1892
+ "Runtime message of unknown type",
1893
+ "OpProcessing",
1894
+ message,
1895
+ {
1896
+ local,
1897
+ type: message.type,
1898
+ contentType: typeof message.contents,
1899
+ batch: message.metadata?.batch,
1900
+ compression: message.compression,
1901
+ },
1902
+ );
1903
+ this.closeFn(error);
1904
+ throw error;
1905
+ }
1894
1906
  }
1895
1907
 
1896
1908
  // For back-compat, notify only about runtime messages for now.
@@ -2107,7 +2119,9 @@ export class ContainerRuntime
2107
2119
  }
2108
2120
 
2109
2121
  private canSendOps() {
2110
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
2122
+ // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
2123
+ // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
2124
+ return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
2111
2125
  }
2112
2126
 
2113
2127
  /**
@@ -2339,10 +2353,10 @@ export class ContainerRuntime
2339
2353
  }
2340
2354
 
2341
2355
  /**
2342
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
2343
2356
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
2344
2357
  * the garbage collector of references detected since the last GC run. Most references are notified immediately
2345
2358
  * but there can be some for which async operation is required (such as detecting new root data stores).
2359
+ * @see IGarbageCollectionRuntime.updateStateBeforeGC
2346
2360
  */
2347
2361
  public async updateStateBeforeGC() {
2348
2362
  return this.dataStores.updateStateBeforeGC();
@@ -2353,9 +2367,9 @@ export class ContainerRuntime
2353
2367
  }
2354
2368
 
2355
2369
  /**
2356
- * Implementation of IGarbageCollectionRuntime::getGCData.
2357
2370
  * Generates and returns the GC data for this container.
2358
2371
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
2372
+ * @see IGarbageCollectionRuntime.getGCData
2359
2373
  */
2360
2374
  public async getGCData(fullGC?: boolean): Promise<IGarbageCollectionData> {
2361
2375
  const builder = new GCDataBuilder();
@@ -2368,9 +2382,9 @@ export class ContainerRuntime
2368
2382
  }
2369
2383
 
2370
2384
  /**
2371
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
2372
2385
  * After GC has run, called to notify this container's nodes of routes that are used in it.
2373
2386
  * @param usedRoutes - The routes that are used in all nodes in this Container.
2387
+ * @see IGarbageCollectionRuntime.updateUsedRoutes
2374
2388
  */
2375
2389
  public updateUsedRoutes(usedRoutes: string[]) {
2376
2390
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
@@ -2834,7 +2848,9 @@ export class ContainerRuntime
2834
2848
 
2835
2849
  const serializedContent = JSON.stringify({ type, contents });
2836
2850
 
2837
- if (this.deltaManager.readOnlyInfo.readonly) {
2851
+ // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2852
+ // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
2853
+ if (this.innerDeltaManager.readOnlyInfo.readonly) {
2838
2854
  this.logger.sendTelemetryEvent({
2839
2855
  eventName: "SubmitOpInReadonly",
2840
2856
  connected: this.connected,
package/src/dataStores.ts CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  TelemetryDataTag,
44
44
  } from "@fluidframework/telemetry-utils";
45
45
  import { AttachState } from "@fluidframework/container-definitions";
46
- import { BlobCacheStorageService, buildSnapshotTree } from "@fluidframework/driver-utils";
46
+ import { buildSnapshotTree } from "@fluidframework/driver-utils";
47
47
  import { assert, Lazy } from "@fluidframework/common-utils";
48
48
  import { v4 as uuid } from "uuid";
49
49
  import { GCDataBuilder, unpackChildNodesUsedRoutes } from "@fluidframework/garbage-collector";
@@ -61,6 +61,7 @@ import {
61
61
  createAttributesBlob,
62
62
  LocalDetachedFluidDataStoreContext,
63
63
  } from "./dataStoreContext";
64
+ import { StorageServiceWithAttachBlobs } from "./storageServiceWithAttachBlobs";
64
65
  import { IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
65
66
  import {
66
67
  GCNodeType,
@@ -245,10 +246,10 @@ export class DataStores implements IDisposable {
245
246
  throw error;
246
247
  }
247
248
 
248
- const flatBlobs = new Map<string, ArrayBufferLike>();
249
+ const flatAttachBlobs = new Map<string, ArrayBufferLike>();
249
250
  let snapshotTree: ISnapshotTree | undefined;
250
251
  if (attachMessage.snapshot) {
251
- snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
252
+ snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatAttachBlobs);
252
253
  }
253
254
 
254
255
  // Include the type of attach message which is the pkg of the store to be
@@ -258,7 +259,7 @@ export class DataStores implements IDisposable {
258
259
  id: attachMessage.id,
259
260
  snapshotTree,
260
261
  runtime: this.runtime,
261
- storage: new BlobCacheStorageService(this.runtime.storage, flatBlobs),
262
+ storage: new StorageServiceWithAttachBlobs(this.runtime.storage, flatAttachBlobs),
262
263
  scope: this.runtime.scope,
263
264
  createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(attachMessage.id, {
264
265
  type: CreateSummarizerNodeSource.FromAttach,
@@ -576,6 +577,10 @@ export class DataStores implements IDisposable {
576
577
  eventName: "SetConnectionStateError",
577
578
  clientId,
578
579
  fluidDataStore,
580
+ details: JSON.stringify({
581
+ runtimeConnected: this.runtime.connected,
582
+ connected,
583
+ }),
579
584
  },
580
585
  error,
581
586
  );
@@ -0,0 +1,46 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { IDeltaManager, ReadOnlyInfo } from "@fluidframework/container-definitions";
7
+ import { DeltaManagerProxyBase } from "@fluidframework/container-utils";
8
+ import { IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
9
+ import { summarizerClientType } from "./summary";
10
+
11
+ /**
12
+ * Proxy to the real IDeltaManager for restricting certain access to layers below container runtime in summarizer clients:
13
+ * - Summarizer client should be read-only to layers below the container runtime to restrict local changes.
14
+ * - Summarizer client should not be active to layers below the container runtime to restrict local changes.
15
+ */
16
+ export class DeltaManagerSummarizerProxy
17
+ extends DeltaManagerProxyBase
18
+ implements IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>
19
+ {
20
+ public get active(): boolean {
21
+ // Summarize clients should not be active. There shouldn't be any local changes (writes) in the summarizer
22
+ // except for the SummarizeOp which is generated by the runtime.
23
+ return !this.isSummarizerClient && this.deltaManager.active;
24
+ }
25
+
26
+ public get readOnlyInfo(): ReadOnlyInfo {
27
+ // Summarizer clients should be read-only as far as the runtime and layers below are concerned. There shouldn't
28
+ // be any local changes (writes) in the summarizer except for the summarize op which is generated by the runtime.
29
+ if (this.isSummarizerClient) {
30
+ return {
31
+ readonly: true,
32
+ forced: false,
33
+ permissions: undefined,
34
+ storageOnly: false,
35
+ };
36
+ }
37
+ return this.deltaManager.readOnlyInfo;
38
+ }
39
+
40
+ private readonly isSummarizerClient: boolean;
41
+
42
+ constructor(deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>) {
43
+ super(deltaManager);
44
+ this.isSummarizerClient = this.deltaManager.clientDetails.type === summarizerClientType;
45
+ }
46
+ }