@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":"gcSummaryStateTracker.js","sourceRoot":"","sources":["../../src/gc/gcSummaryStateTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { getGCDataFromSnapshot } from \"@fluidframework/garbage-collector\";\nimport { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n\tmergeStats,\n\tReadAndParseBlob,\n\tRefreshSummaryResult,\n\tSummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName } from \"../summary\";\nimport {\n\tcurrentGCVersion,\n\tGCVersion,\n\tgcVersionUpgradeToV2Key,\n\tstableGCVersion,\n} from \"./gcDefinitions\";\nimport { generateSortedGCState, getGCVersion } from \"./gcHelpers\";\n\n/**\n * The GC data that is tracked for a summary.\n */\ninterface IGCSummaryTrackingData {\n\tserializedGCState: string | undefined;\n\tserializedTombstones: string | undefined;\n\tserializedDeletedNodes: string | undefined;\n}\n\n/**\n * Encapsulates the garbage collection state that is tracked across summaries.\n * It maintains the GC state as per the latest summary in by the server. It updates state when a summary tracked by this\n * client is acked by the server or from a snapshot is downloaded from the server.\n * On summarize, it decides whether to write new state or re-use previous summary's state.\n */\nexport class GCSummaryStateTracker {\n\t// The current version of GC running.\n\tpublic readonly currentGCVersion: GCVersion;\n\t// This is the version of GC data in the latest summary being tracked.\n\tprivate latestSummaryGCVersion: GCVersion;\n\n\t// Keeps track of the GC data from the latest summary successfully acked by the server.\n\tprivate latestSummaryData: IGCSummaryTrackingData | undefined;\n\t// Keeps track of the GC data from the last summary submitted to the server but not yet acked.\n\tprivate pendingSummaryData: IGCSummaryTrackingData | undefined;\n\n\t// Tracks whether there was GC was run in latest summary being tracked.\n\tprivate wasGCRunInLatestSummary: boolean;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly shouldRunGC: boolean,\n\t\t// Tells whether GC state should be tracked across summaries or not.\n\t\tprivate readonly trackGCState: boolean,\n\t\t// Tells whether tombstone mode is enabled or not.\n\t\tprivate readonly tombstoneMode: boolean,\n\t\tprivate readonly mc: MonitoringContext,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t\t// The GC version in the base snapshot this container loaded from.\n\t\tgcVersionInBaseSnapshot: GCVersion | undefined,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\n\t\t// If version upgrade is not enabled, fall back to the stable GC version.\n\t\tthis.currentGCVersion =\n\t\t\tthis.mc.config.getBoolean(gcVersionUpgradeToV2Key) === true\n\t\t\t\t? currentGCVersion\n\t\t\t\t: stableGCVersion;\n\t\t// For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n\t\t// latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n\t\tthis.latestSummaryGCVersion = gcVersionInBaseSnapshot ?? this.currentGCVersion;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset. This can happen under 3 conditions:\n\t *\n\t * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n\t * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n\t *\n\t * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n\t * a document and the first time GC is enabled after is was disabled before.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * Note that the state will be reset only once for the first summary generated after this returns true. After that,\n\t * this will return false.\n\t */\n\tpublic doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.shouldRunGC;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n\t *\n\t * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n\t *\n\t * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * 4. The GC version in the latest summary is different from the current GC version. This can happen if:\n\t *\n\t * 4.1. The summary this client loaded with has data from a different GC version.\n\t *\n\t * 4.2. This client's latest summary was updated from a snapshot that has a different GC version.\n\t */\n\tpublic doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset() ||\n\t\t\t(this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion)\n\t\t);\n\t}\n\n\t/**\n\t * Summarizes three component of the GC data - GC state, tombstones and deleted nodes.\n\t * It does incremental summary, i.e., it writes summary tree / summary blob only for the component that changed.\n\t * For components that did not change, a summary handle is returned that points to the previous successful summary.\n\t * If none of the components changed, it returns a summary handle for the entire GC data.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\tgcState: IGarbageCollectionState,\n\t\tdeletedNodes: Set<string>,\n\t\ttombstones: string[],\n\t): ISummarizeResult | undefined {\n\t\tif (!this.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst serializedGCState = JSON.stringify(generateSortedGCState(gcState));\n\t\t// Serialize and write deleted nodes, if any. This is done irrespective of whether sweep is enabled or not so\n\t\t// to identify deleted nodes' usage.\n\t\tconst serializedDeletedNodes =\n\t\t\tdeletedNodes.size > 0 ? JSON.stringify(Array.from(deletedNodes).sort()) : undefined;\n\t\t// If running in tombstone mode, serialize and write tombstones, if any.\n\t\tconst serializedTombstones = this.tombstoneMode\n\t\t\t? tombstones.length > 0\n\t\t\t\t? JSON.stringify(tombstones.sort())\n\t\t\t\t: undefined\n\t\t\t: undefined;\n\n\t\t/**\n\t\t * Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,\n\t\t * write summary handle instead of summary tree for GC.\n\t\t * Otherwise, write the GC summary tree. In the tree, for each of these that changed, write a summary blob and\n\t\t * for each of these that did not change, write a summary handle.\n\t\t */\n\t\tif (this.trackGCState) {\n\t\t\tthis.pendingSummaryData = {\n\t\t\t\tserializedGCState,\n\t\t\t\tserializedTombstones,\n\t\t\t\tserializedDeletedNodes,\n\t\t\t};\n\t\t\tif (trackState && !fullTree && this.latestSummaryData !== undefined) {\n\t\t\t\t// If nothing changed since last summary, send a summary handle for the entire GC data.\n\t\t\t\tif (\n\t\t\t\t\tthis.latestSummaryData.serializedGCState === serializedGCState &&\n\t\t\t\t\tthis.latestSummaryData.serializedTombstones === serializedTombstones\n\t\t\t\t) {\n\t\t\t\t\tconst stats = mergeStats();\n\t\t\t\t\tstats.handleNodeCount++;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsummary: {\n\t\t\t\t\t\t\ttype: SummaryType.Handle,\n\t\t\t\t\t\t\thandle: `/${gcTreeKey}`,\n\t\t\t\t\t\t\thandleType: SummaryType.Tree,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstats,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// If some state changed, build a GC summary tree.\n\t\t\t\treturn this.buildGCSummaryTree(\n\t\t\t\t\tserializedGCState,\n\t\t\t\t\tserializedTombstones,\n\t\t\t\t\tserializedDeletedNodes,\n\t\t\t\t\ttrue /* trackState */,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// If not tracking GC state, build a GC summary tree without any summary handles.\n\t\treturn this.buildGCSummaryTree(\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t\tfalse /* trackState */,\n\t\t);\n\t}\n\n\t/**\n\t * Builds the GC summary tree which contains GC state, deleted nodes and tombstones.\n\t * If trackState is false, all of GC state, deleted nodes and tombstones are written as summary blobs.\n\t * If trackState is true, only states that changed are written. Rest are written as handles.\n\t * @param serializedGCState - The GC state serialized as string.\n\t * @param serializedTombstones - The tombstone state serialized as string.\n\t * @param serializedDeletedNodes - Deleted nodes serialized as string.\n\t * @param trackState - Whether we are tracking GC state across summaries.\n\t * @returns the GC summary tree.\n\t */\n\tprivate buildGCSummaryTree(\n\t\tserializedGCState: string,\n\t\tserializedTombstones: string | undefined,\n\t\tserializedDeletedNodes: string | undefined,\n\t\ttrackState: boolean,\n\t): ISummaryTreeWithStats {\n\t\tconst gcStateBlobKey = `${gcBlobPrefix}_root`;\n\t\tconst builder = new SummaryTreeBuilder();\n\n\t\t// If the GC state hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {\n\t\t\tbuilder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcStateBlobKey, serializedGCState);\n\t\t}\n\n\t\t// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a\n\t\t// summary blob.\n\t\tif (serializedTombstones !== undefined) {\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData?.serializedTombstones === serializedTombstones &&\n\t\t\t\ttrackState\n\t\t\t) {\n\t\t\t\tbuilder.addHandle(\n\t\t\t\t\tgcTombstoneBlobKey,\n\t\t\t\t\tSummaryType.Blob,\n\t\t\t\t\t`/${gcTreeKey}/${gcTombstoneBlobKey}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tbuilder.addBlob(gcTombstoneBlobKey, serializedTombstones);\n\t\t\t}\n\t\t}\n\n\t\t// If there are no deleted nodes, return the summary tree.\n\t\tif (serializedDeletedNodes === undefined) {\n\t\t\treturn builder.getSummaryTree();\n\t\t}\n\n\t\t// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (\n\t\t\tthis.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&\n\t\t\ttrackState\n\t\t) {\n\t\t\tbuilder.addHandle(\n\t\t\t\tgcDeletedBlobKey,\n\t\t\t\tSummaryType.Blob,\n\t\t\t\t`/${gcTreeKey}/${gcDeletedBlobKey}`,\n\t\t\t);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcDeletedBlobKey, serializedDeletedNodes);\n\t\t}\n\t\treturn builder.getSummaryTree();\n\t}\n\n\t/**\n\t * Called to refresh the latest summary state. This happens when either a pending summary is acked or a snapshot\n\t * is downloaded and should be used to update the state.\n\t */\n\tpublic async refreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tresult: RefreshSummaryResult,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<IGarbageCollectionSnapshotData | undefined> {\n\t\t// If the latest summary was updated and the summary was tracked, this client is the one that generated this\n\t\t// summary. So, update wasGCRunInLatestSummary.\n\t\t// Note that this has to be updated if GC did not run too. Otherwise, `gcStateNeedsReset` will always return\n\t\t// true in scenarios where GC is disabled but enabled in the snapshot we loaded from.\n\t\tif (result.latestSummaryUpdated && result.wasSummaryTracked) {\n\t\t\tthis.wasGCRunInLatestSummary = this.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.shouldRunGC) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was tracked by this client, it was the one that generated the summary in the first place.\n\t\t// Update latest state from pending.\n\t\tif (result.wasSummaryTracked) {\n\t\t\tthis.latestSummaryGCVersion = this.currentGCVersion;\n\t\t\tif (this.trackGCState) {\n\t\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\t\tthis.pendingSummaryData = undefined;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was not tracked by this client, the state should be updated from the downloaded snapshot.\n\t\tconst snapshotTree = result.snapshotTree;\n\t\tconst metadataBlobId = snapshotTree.blobs[metadataBlobName];\n\t\tif (metadataBlobId) {\n\t\t\tconst metadata = await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId);\n\t\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\n\t\t}\n\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\t// If GC ran in the container that generated this snapshot, it will have a GC tree.\n\t\tthis.wasGCRunInLatestSummary = gcSnapshotTree !== undefined;\n\t\tlet latestGCData: IGarbageCollectionSnapshotData | undefined;\n\t\tif (gcSnapshotTree !== undefined) {\n\t\t\tlatestGCData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\t\t}\n\t\tthis.pendingSummaryData = undefined;\n\t\treturn latestGCData;\n\t}\n\n\t/**\n\t * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.\n\t * @param gcSnapshotData - The GC snapshot data to update state from.\n\t */\n\tpublic updateStateFromSnapshotData(gcSnapshotData: IGarbageCollectionSnapshotData | undefined) {\n\t\t// If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.\n\t\tif (gcSnapshotData === undefined) {\n\t\t\tthis.latestSummaryData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\t// If tracking state across summaries, update latest summary data from the snapshot's GC data.\n\t\tif (this.trackGCState) {\n\t\t\tthis.latestSummaryData = {\n\t\t\t\tserializedGCState: JSON.stringify(generateSortedGCState(gcSnapshotData.gcState)),\n\t\t\t\tserializedTombstones: JSON.stringify(gcSnapshotData.tombstones),\n\t\t\t\tserializedDeletedNodes: JSON.stringify(gcSnapshotData.deletedNodes),\n\t\t\t};\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"gcSummaryStateTracker.js","sourceRoot":"","sources":["../../src/gc/gcSummaryStateTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { getGCDataFromSnapshot } from \"@fluidframework/garbage-collector\";\nimport { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n\tmergeStats,\n\tReadAndParseBlob,\n\tRefreshSummaryResult,\n\tSummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName } from \"../summary\";\nimport {\n\tcurrentGCVersion,\n\tGCVersion,\n\tgcVersionUpgradeToV2Key,\n\tstableGCVersion,\n} from \"./gcDefinitions\";\nimport { generateSortedGCState, getGCVersion } from \"./gcHelpers\";\n\n/**\n * The GC data that is tracked for a summary.\n */\ninterface IGCSummaryTrackingData {\n\tserializedGCState: string | undefined;\n\tserializedTombstones: string | undefined;\n\tserializedDeletedNodes: string | undefined;\n}\n\n/**\n * Encapsulates the garbage collection state that is tracked across summaries.\n * It maintains the GC state as per the latest summary in by the server. It updates state when a summary tracked by this\n * client is acked by the server or from a snapshot is downloaded from the server.\n * On summarize, it decides whether to write new state or re-use previous summary's state.\n */\nexport class GCSummaryStateTracker {\n\t// The current version of GC running.\n\tpublic readonly currentGCVersion: GCVersion;\n\t// This is the version of GC data in the latest summary being tracked.\n\tprivate latestSummaryGCVersion: GCVersion;\n\n\t// Keeps track of the GC data from the latest summary successfully acked by the server.\n\tprivate latestSummaryData: IGCSummaryTrackingData | undefined;\n\t// Keeps track of the GC data from the last summary submitted to the server but not yet acked.\n\tprivate pendingSummaryData: IGCSummaryTrackingData | undefined;\n\n\t// Tracks whether there was GC was run in latest summary being tracked.\n\tprivate wasGCRunInLatestSummary: boolean;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly shouldRunGC: boolean,\n\t\t// Tells whether tombstone mode is enabled or not.\n\t\tprivate readonly tombstoneMode: boolean,\n\t\tprivate readonly mc: MonitoringContext,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t\t// The GC version in the base snapshot this container loaded from.\n\t\tgcVersionInBaseSnapshot: GCVersion | undefined,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\n\t\t// If version upgrade is not enabled, fall back to the stable GC version.\n\t\tthis.currentGCVersion =\n\t\t\tthis.mc.config.getBoolean(gcVersionUpgradeToV2Key) === true\n\t\t\t\t? currentGCVersion\n\t\t\t\t: stableGCVersion;\n\t\t// For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n\t\t// latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n\t\tthis.latestSummaryGCVersion = gcVersionInBaseSnapshot ?? this.currentGCVersion;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset. This can happen under 3 conditions:\n\t *\n\t * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n\t * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n\t *\n\t * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n\t * a document and the first time GC is enabled after is was disabled before.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * Note that the state will be reset only once for the first summary generated after this returns true. After that,\n\t * this will return false.\n\t */\n\tpublic doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.shouldRunGC;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n\t *\n\t * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n\t *\n\t * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * 4. The GC version in the latest summary is different from the current GC version. This can happen if:\n\t *\n\t * 4.1. The summary this client loaded with has data from a different GC version.\n\t *\n\t * 4.2. This client's latest summary was updated from a snapshot that has a different GC version.\n\t */\n\tpublic doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset() ||\n\t\t\t(this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion)\n\t\t);\n\t}\n\n\t/**\n\t * Summarizes three component of the GC data - GC state, tombstones and deleted nodes.\n\t * It does incremental summary, i.e., it writes summary tree / summary blob only for the component that changed.\n\t * For components that did not change, a summary handle is returned that points to the previous successful summary.\n\t * If none of the components changed, it returns a summary handle for the entire GC data.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\tgcState: IGarbageCollectionState,\n\t\tdeletedNodes: Set<string>,\n\t\ttombstones: string[],\n\t): ISummarizeResult | undefined {\n\t\tif (!this.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst serializedGCState = JSON.stringify(generateSortedGCState(gcState));\n\t\t// Serialize and write deleted nodes, if any. This is done irrespective of whether sweep is enabled or not so\n\t\t// to identify deleted nodes' usage.\n\t\tconst serializedDeletedNodes =\n\t\t\tdeletedNodes.size > 0 ? JSON.stringify(Array.from(deletedNodes).sort()) : undefined;\n\t\t// If running in tombstone mode, serialize and write tombstones, if any.\n\t\tconst serializedTombstones = this.tombstoneMode\n\t\t\t? tombstones.length > 0\n\t\t\t\t? JSON.stringify(tombstones.sort())\n\t\t\t\t: undefined\n\t\t\t: undefined;\n\n\t\t/**\n\t\t * Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,\n\t\t * write summary handle instead of summary tree for GC.\n\t\t * Otherwise, write the GC summary tree. In the tree, for each of these that changed, write a summary blob and\n\t\t * for each of these that did not change, write a summary handle.\n\t\t */\n\t\tthis.pendingSummaryData = {\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t};\n\n\t\tif (trackState && !fullTree && this.latestSummaryData !== undefined) {\n\t\t\t// If nothing changed since last summary, send a summary handle for the entire GC data.\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData.serializedGCState === serializedGCState &&\n\t\t\t\tthis.latestSummaryData.serializedTombstones === serializedTombstones\n\t\t\t) {\n\t\t\t\tconst stats = mergeStats();\n\t\t\t\tstats.handleNodeCount++;\n\t\t\t\treturn {\n\t\t\t\t\tsummary: {\n\t\t\t\t\t\ttype: SummaryType.Handle,\n\t\t\t\t\t\thandle: `/${gcTreeKey}`,\n\t\t\t\t\t\thandleType: SummaryType.Tree,\n\t\t\t\t\t},\n\t\t\t\t\tstats,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// If some state changed, build a GC summary tree.\n\t\t\treturn this.buildGCSummaryTree(\n\t\t\t\tserializedGCState,\n\t\t\t\tserializedTombstones,\n\t\t\t\tserializedDeletedNodes,\n\t\t\t\ttrue /* trackState */,\n\t\t\t);\n\t\t}\n\t\t// If not tracking GC state, build a GC summary tree without any summary handles.\n\t\treturn this.buildGCSummaryTree(\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t\tfalse /* trackState */,\n\t\t);\n\t}\n\n\t/**\n\t * Builds the GC summary tree which contains GC state, deleted nodes and tombstones.\n\t * If trackState is false, all of GC state, deleted nodes and tombstones are written as summary blobs.\n\t * If trackState is true, only states that changed are written. Rest are written as handles.\n\t * @param serializedGCState - The GC state serialized as string.\n\t * @param serializedTombstones - The tombstone state serialized as string.\n\t * @param serializedDeletedNodes - Deleted nodes serialized as string.\n\t * @param trackState - Whether we are tracking GC state across summaries.\n\t * @returns the GC summary tree.\n\t */\n\tprivate buildGCSummaryTree(\n\t\tserializedGCState: string,\n\t\tserializedTombstones: string | undefined,\n\t\tserializedDeletedNodes: string | undefined,\n\t\ttrackState: boolean,\n\t): ISummaryTreeWithStats {\n\t\tconst gcStateBlobKey = `${gcBlobPrefix}_root`;\n\t\tconst builder = new SummaryTreeBuilder();\n\n\t\t// If the GC state hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {\n\t\t\tbuilder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcStateBlobKey, serializedGCState);\n\t\t}\n\n\t\t// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a\n\t\t// summary blob.\n\t\tif (serializedTombstones !== undefined) {\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData?.serializedTombstones === serializedTombstones &&\n\t\t\t\ttrackState\n\t\t\t) {\n\t\t\t\tbuilder.addHandle(\n\t\t\t\t\tgcTombstoneBlobKey,\n\t\t\t\t\tSummaryType.Blob,\n\t\t\t\t\t`/${gcTreeKey}/${gcTombstoneBlobKey}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tbuilder.addBlob(gcTombstoneBlobKey, serializedTombstones);\n\t\t\t}\n\t\t}\n\n\t\t// If there are no deleted nodes, return the summary tree.\n\t\tif (serializedDeletedNodes === undefined) {\n\t\t\treturn builder.getSummaryTree();\n\t\t}\n\n\t\t// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (\n\t\t\tthis.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&\n\t\t\ttrackState\n\t\t) {\n\t\t\tbuilder.addHandle(\n\t\t\t\tgcDeletedBlobKey,\n\t\t\t\tSummaryType.Blob,\n\t\t\t\t`/${gcTreeKey}/${gcDeletedBlobKey}`,\n\t\t\t);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcDeletedBlobKey, serializedDeletedNodes);\n\t\t}\n\t\treturn builder.getSummaryTree();\n\t}\n\n\t/**\n\t * Called to refresh the latest summary state. This happens when either a pending summary is acked or a snapshot\n\t * is downloaded and should be used to update the state.\n\t */\n\tpublic async refreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tresult: RefreshSummaryResult,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<IGarbageCollectionSnapshotData | undefined> {\n\t\t// If the latest summary was updated and the summary was tracked, this client is the one that generated this\n\t\t// summary. So, update wasGCRunInLatestSummary.\n\t\t// Note that this has to be updated if GC did not run too. Otherwise, `gcStateNeedsReset` will always return\n\t\t// true in scenarios where GC is disabled but enabled in the snapshot we loaded from.\n\t\tif (result.latestSummaryUpdated && result.wasSummaryTracked) {\n\t\t\tthis.wasGCRunInLatestSummary = this.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.shouldRunGC) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was tracked by this client, it was the one that generated the summary in the first place.\n\t\t// Update latest state from pending.\n\t\tif (result.wasSummaryTracked) {\n\t\t\tthis.latestSummaryGCVersion = this.currentGCVersion;\n\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\tthis.pendingSummaryData = undefined;\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was not tracked by this client, the state should be updated from the downloaded snapshot.\n\t\tconst snapshotTree = result.snapshotTree;\n\t\tconst metadataBlobId = snapshotTree.blobs[metadataBlobName];\n\t\tif (metadataBlobId) {\n\t\t\tconst metadata = await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId);\n\t\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\n\t\t}\n\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\t// If GC ran in the container that generated this snapshot, it will have a GC tree.\n\t\tthis.wasGCRunInLatestSummary = gcSnapshotTree !== undefined;\n\t\tlet latestGCData: IGarbageCollectionSnapshotData | undefined;\n\t\tif (gcSnapshotTree !== undefined) {\n\t\t\tlatestGCData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\t\t}\n\t\tthis.pendingSummaryData = undefined;\n\t\treturn latestGCData;\n\t}\n\n\t/**\n\t * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.\n\t * @param gcSnapshotData - The GC snapshot data to update state from.\n\t */\n\tpublic updateStateFromSnapshotData(gcSnapshotData: IGarbageCollectionSnapshotData | undefined) {\n\t\t// If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.\n\t\tif (gcSnapshotData === undefined) {\n\t\t\tthis.latestSummaryData = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\t// If tracking state across summaries, update latest summary data from the snapshot's GC data.\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: JSON.stringify(generateSortedGCState(gcSnapshotData.gcState)),\n\t\t\tserializedTombstones: JSON.stringify(gcSnapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(gcSnapshotData.deletedNodes),\n\t\t};\n\t}\n}\n"]}
@@ -3,8 +3,9 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  export { GarbageCollector } from "./garbageCollection";
6
- export { currentGCVersion, defaultInactiveTimeoutMs, defaultSessionExpiryDurationMs, disableSweepLogKey, GCNodeType, gcTestModeKey, gcTombstoneGenerationOptionName, GCVersion, gcVersionUpgradeToV2Key, IGarbageCollectionRuntime, IGarbageCollector, IGarbageCollectorCreateParams, IGCMetadata, IGCStats, oneDayMs, runGCKey, runSessionExpiryKey, runSweepKey, stableGCVersion, sweepAttachmentBlobsKey, sweepDatastoresKey, throwOnTombstoneLoadKey, throwOnTombstoneUsageKey, UnreferencedState, } from "./gcDefinitions";
7
- export { sendGCUnexpectedUsageEvent, shouldAllowGcTombstoneEnforcement } from "./gcHelpers";
6
+ export { currentGCVersion, defaultInactiveTimeoutMs, defaultSessionExpiryDurationMs, disableSweepLogKey, GCNodeType, gcTestModeKey, gcTombstoneGenerationOptionName, GCVersion, gcVersionUpgradeToV2Key, IGarbageCollectionRuntime, // Deprecated
7
+ IGarbageCollector, IGarbageCollectorConfigs, IGarbageCollectorCreateParams, IGCMetadata, IGCRuntimeOptions, IGCStats, oneDayMs, runGCKey, runSessionExpiryKey, runSweepKey, stableGCVersion, sweepAttachmentBlobsKey, sweepDatastoresKey, throwOnTombstoneLoadKey, throwOnTombstoneUsageKey, UnreferencedState, } from "./gcDefinitions";
8
+ export { getSnapshotDataFromOldSnapshotFormat, sendGCUnexpectedUsageEvent, shouldAllowGcTombstoneEnforcement, } from "./gcHelpers";
8
9
  export { GCSummaryStateTracker } from "./gcSummaryStateTracker";
9
10
  export { skipClosureForXDaysKey, closuresMapLocalStorageKey, SweepReadyUsageDetectionHandler, } from "./gcSweepReadyUsageDetection";
10
11
  export { UnreferencedStateTracker } from "./gcUnreferencedStateTracker";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,+BAA+B,EAC/B,SAAS,EACT,uBAAuB,EACvB,yBAAyB,EACzB,iBAAiB,EACjB,6BAA6B,EAC7B,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,iCAAiC,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACN,sBAAsB,EACtB,0BAA0B,EAC1B,+BAA+B,GAC/B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,+BAA+B,EAC/B,SAAS,EACT,uBAAuB,EACvB,yBAAyB,EAAE,aAAa;AACxC,iBAAiB,EACjB,wBAAwB,EACxB,6BAA6B,EAC7B,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,oCAAoC,EACpC,0BAA0B,EAC1B,iCAAiC,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACN,sBAAsB,EACtB,0BAA0B,EAC1B,+BAA+B,GAC/B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/gc/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.UnreferencedStateTracker = exports.SweepReadyUsageDetectionHandler = exports.closuresMapLocalStorageKey = exports.skipClosureForXDaysKey = exports.GCSummaryStateTracker = exports.shouldAllowGcTombstoneEnforcement = exports.sendGCUnexpectedUsageEvent = exports.UnreferencedState = exports.throwOnTombstoneUsageKey = exports.throwOnTombstoneLoadKey = exports.sweepDatastoresKey = exports.sweepAttachmentBlobsKey = exports.stableGCVersion = exports.runSweepKey = exports.runSessionExpiryKey = exports.runGCKey = exports.oneDayMs = exports.gcVersionUpgradeToV2Key = exports.gcTombstoneGenerationOptionName = exports.gcTestModeKey = exports.GCNodeType = exports.disableSweepLogKey = exports.defaultSessionExpiryDurationMs = exports.defaultInactiveTimeoutMs = exports.currentGCVersion = exports.GarbageCollector = void 0;
7
+ exports.UnreferencedStateTracker = exports.SweepReadyUsageDetectionHandler = exports.closuresMapLocalStorageKey = exports.skipClosureForXDaysKey = exports.GCSummaryStateTracker = exports.shouldAllowGcTombstoneEnforcement = exports.sendGCUnexpectedUsageEvent = exports.getSnapshotDataFromOldSnapshotFormat = exports.UnreferencedState = exports.throwOnTombstoneUsageKey = exports.throwOnTombstoneLoadKey = exports.sweepDatastoresKey = exports.sweepAttachmentBlobsKey = exports.stableGCVersion = exports.runSweepKey = exports.runSessionExpiryKey = exports.runGCKey = exports.oneDayMs = exports.gcVersionUpgradeToV2Key = exports.gcTombstoneGenerationOptionName = exports.gcTestModeKey = exports.GCNodeType = exports.disableSweepLogKey = exports.defaultSessionExpiryDurationMs = exports.defaultInactiveTimeoutMs = exports.currentGCVersion = exports.GarbageCollector = void 0;
8
8
  var garbageCollection_1 = require("./garbageCollection");
9
9
  Object.defineProperty(exports, "GarbageCollector", { enumerable: true, get: function () { return garbageCollection_1.GarbageCollector; } });
10
10
  var gcDefinitions_1 = require("./gcDefinitions");
@@ -27,6 +27,7 @@ Object.defineProperty(exports, "throwOnTombstoneLoadKey", { enumerable: true, ge
27
27
  Object.defineProperty(exports, "throwOnTombstoneUsageKey", { enumerable: true, get: function () { return gcDefinitions_1.throwOnTombstoneUsageKey; } });
28
28
  Object.defineProperty(exports, "UnreferencedState", { enumerable: true, get: function () { return gcDefinitions_1.UnreferencedState; } });
29
29
  var gcHelpers_1 = require("./gcHelpers");
30
+ Object.defineProperty(exports, "getSnapshotDataFromOldSnapshotFormat", { enumerable: true, get: function () { return gcHelpers_1.getSnapshotDataFromOldSnapshotFormat; } });
30
31
  Object.defineProperty(exports, "sendGCUnexpectedUsageEvent", { enumerable: true, get: function () { return gcHelpers_1.sendGCUnexpectedUsageEvent; } });
31
32
  Object.defineProperty(exports, "shouldAllowGcTombstoneEnforcement", { enumerable: true, get: function () { return gcHelpers_1.shouldAllowGcTombstoneEnforcement; } });
32
33
  var gcSummaryStateTracker_1 = require("./gcSummaryStateTracker");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,iDAyByB;AAxBxB,iHAAA,gBAAgB,OAAA;AAChB,yHAAA,wBAAwB,OAAA;AACxB,+HAAA,8BAA8B,OAAA;AAC9B,mHAAA,kBAAkB,OAAA;AAClB,2GAAA,UAAU,OAAA;AACV,8GAAA,aAAa,OAAA;AACb,gIAAA,+BAA+B,OAAA;AAE/B,wHAAA,uBAAuB,OAAA;AAMvB,yGAAA,QAAQ,OAAA;AACR,yGAAA,QAAQ,OAAA;AACR,oHAAA,mBAAmB,OAAA;AACnB,4GAAA,WAAW,OAAA;AACX,gHAAA,eAAe,OAAA;AACf,wHAAA,uBAAuB,OAAA;AACvB,mHAAA,kBAAkB,OAAA;AAClB,wHAAA,uBAAuB,OAAA;AACvB,yHAAA,wBAAwB,OAAA;AACxB,kHAAA,iBAAiB,OAAA;AAElB,yCAA4F;AAAnF,uHAAA,0BAA0B,OAAA;AAAE,8HAAA,iCAAiC,OAAA;AACtE,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAC9B,2EAIsC;AAHrC,oIAAA,sBAAsB,OAAA;AACtB,wIAAA,0BAA0B,OAAA;AAC1B,6IAAA,+BAA+B,OAAA;AAEhC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { GarbageCollector } from \"./garbageCollection\";\nexport {\n\tcurrentGCVersion,\n\tdefaultInactiveTimeoutMs,\n\tdefaultSessionExpiryDurationMs,\n\tdisableSweepLogKey,\n\tGCNodeType,\n\tgcTestModeKey,\n\tgcTombstoneGenerationOptionName,\n\tGCVersion,\n\tgcVersionUpgradeToV2Key,\n\tIGarbageCollectionRuntime,\n\tIGarbageCollector,\n\tIGarbageCollectorCreateParams,\n\tIGCMetadata,\n\tIGCStats,\n\toneDayMs,\n\trunGCKey,\n\trunSessionExpiryKey,\n\trunSweepKey,\n\tstableGCVersion,\n\tsweepAttachmentBlobsKey,\n\tsweepDatastoresKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n\tUnreferencedState,\n} from \"./gcDefinitions\";\nexport { sendGCUnexpectedUsageEvent, shouldAllowGcTombstoneEnforcement } from \"./gcHelpers\";\nexport { GCSummaryStateTracker } from \"./gcSummaryStateTracker\";\nexport {\n\tskipClosureForXDaysKey,\n\tclosuresMapLocalStorageKey,\n\tSweepReadyUsageDetectionHandler,\n} from \"./gcSweepReadyUsageDetection\";\nexport { UnreferencedStateTracker } from \"./gcUnreferencedStateTracker\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,iDA2ByB;AA1BxB,iHAAA,gBAAgB,OAAA;AAChB,yHAAA,wBAAwB,OAAA;AACxB,+HAAA,8BAA8B,OAAA;AAC9B,mHAAA,kBAAkB,OAAA;AAClB,2GAAA,UAAU,OAAA;AACV,8GAAA,aAAa,OAAA;AACb,gIAAA,+BAA+B,OAAA;AAE/B,wHAAA,uBAAuB,OAAA;AAQvB,yGAAA,QAAQ,OAAA;AACR,yGAAA,QAAQ,OAAA;AACR,oHAAA,mBAAmB,OAAA;AACnB,4GAAA,WAAW,OAAA;AACX,gHAAA,eAAe,OAAA;AACf,wHAAA,uBAAuB,OAAA;AACvB,mHAAA,kBAAkB,OAAA;AAClB,wHAAA,uBAAuB,OAAA;AACvB,yHAAA,wBAAwB,OAAA;AACxB,kHAAA,iBAAiB,OAAA;AAElB,yCAIqB;AAHpB,iIAAA,oCAAoC,OAAA;AACpC,uHAAA,0BAA0B,OAAA;AAC1B,8HAAA,iCAAiC,OAAA;AAElC,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAC9B,2EAIsC;AAHrC,oIAAA,sBAAsB,OAAA;AACtB,wIAAA,0BAA0B,OAAA;AAC1B,6IAAA,+BAA+B,OAAA;AAEhC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { GarbageCollector } from \"./garbageCollection\";\nexport {\n\tcurrentGCVersion,\n\tdefaultInactiveTimeoutMs,\n\tdefaultSessionExpiryDurationMs,\n\tdisableSweepLogKey,\n\tGCNodeType,\n\tgcTestModeKey,\n\tgcTombstoneGenerationOptionName,\n\tGCVersion,\n\tgcVersionUpgradeToV2Key,\n\tIGarbageCollectionRuntime, // Deprecated\n\tIGarbageCollector,\n\tIGarbageCollectorConfigs,\n\tIGarbageCollectorCreateParams,\n\tIGCMetadata,\n\tIGCRuntimeOptions,\n\tIGCStats,\n\toneDayMs,\n\trunGCKey,\n\trunSessionExpiryKey,\n\trunSweepKey,\n\tstableGCVersion,\n\tsweepAttachmentBlobsKey,\n\tsweepDatastoresKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n\tUnreferencedState,\n} from \"./gcDefinitions\";\nexport {\n\tgetSnapshotDataFromOldSnapshotFormat,\n\tsendGCUnexpectedUsageEvent,\n\tshouldAllowGcTombstoneEnforcement,\n} from \"./gcHelpers\";\nexport { GCSummaryStateTracker } from \"./gcSummaryStateTracker\";\nexport {\n\tskipClosureForXDaysKey,\n\tclosuresMapLocalStorageKey,\n\tSweepReadyUsageDetectionHandler,\n} from \"./gcSweepReadyUsageDetection\";\nexport { UnreferencedStateTracker } from \"./gcUnreferencedStateTracker\";\n"]}
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { ContainerMessageType, ContainerRuntimeMessage, IGCRuntimeOptions, ISummaryRuntimeOptions, ISummaryBaseConfiguration, ISummaryConfigurationHeuristics, ISummaryConfigurationDisableSummarizer, ISummaryConfigurationDisableHeuristics, IContainerRuntimeOptions, IRootSummaryTreeWithStats, isRuntimeMessage, RuntimeMessage, agentSchedulerId, ContainerRuntime, RuntimeHeaders, AllowTombstoneRequestHeaderKey, TombstoneResponseHeaderKey, ISummaryConfiguration, DefaultSummaryConfiguration, ICompressionRuntimeOptions, CompressionAlgorithms, } from "./containerRuntime";
5
+ export { ContainerMessageType, ContainerRuntimeMessage, ISummaryRuntimeOptions, ISummaryBaseConfiguration, ISummaryConfigurationHeuristics, ISummaryConfigurationDisableSummarizer, ISummaryConfigurationDisableHeuristics, IContainerRuntimeOptions, IRootSummaryTreeWithStats, isRuntimeMessage, RuntimeMessage, agentSchedulerId, ContainerRuntime, RuntimeHeaders, AllowTombstoneRequestHeaderKey, TombstoneResponseHeaderKey, ISummaryConfiguration, DefaultSummaryConfiguration, ICompressionRuntimeOptions, CompressionAlgorithms, } from "./containerRuntime";
6
6
  export { FluidDataStoreRegistry } from "./dataStoreRegistry";
7
- export { IGCStats } from "./gc";
7
+ export { IGCRuntimeOptions, IGCStats } from "./gc";
8
8
  export { IPendingFlush, IPendingLocalState, IPendingMessage, IPendingState, } from "./pendingStateManager";
9
9
  export { IAckedSummary, ISummarizer, ISummarizeResults, ISummaryCancellationToken, neverCancelledSummaryToken, Summarizer, SummarizerStopReason, SummaryCollection, EnqueueSummarizeResult, IAckSummaryResult, IBaseSummarizeResult, IBroadcastSummaryResult, ICancellationToken, IConnectableRuntime, IEnqueueSummarizeOptions, IGenerateSummaryTreeResult, IGeneratedSummaryStats, INackSummaryResult, IOnDemandSummarizeOptions, IProvideSummarizer, IRefreshSummaryAckOptions, ISubmitSummaryOpResult, ISubmitSummaryOptions, ISummarizeOptions, ISummarizerEvents, ISummarizerInternalsProvider, ISummarizerRuntime, ISummarizingWarning, IUploadSummaryResult, SubmitSummaryResult, SummarizeResultPart, IClientSummaryWatcher, ISummary, ISummaryCollectionOpEvents, ISummaryAckMessage, ISummaryNackMessage, ISummaryOpMessage, OpActionEventListener, OpActionEventName, ICancellableSummarizerController, } from "./summary";
10
10
  export { IChunkedOp, unpackRuntimeMessage } from "./opLifecycle";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,yBAAyB,EACzB,+BAA+B,EAC/B,sCAAsC,EACtC,sCAAsC,EACtC,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,8BAA8B,EAC9B,0BAA0B,EAC1B,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,qBAAqB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EACN,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,aAAa,GACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,0BAA0B,EAC1B,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,EACzB,kBAAkB,EAClB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,QAAQ,EACR,0BAA0B,EAC1B,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,gCAAgC,GAChC,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,+BAA+B,EAC/B,sCAAsC,EACtC,sCAAsC,EACtC,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,8BAA8B,EAC9B,0BAA0B,EAC1B,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,qBAAqB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACnD,OAAO,EACN,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,aAAa,GACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,0BAA0B,EAC1B,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,EACzB,kBAAkB,EAClB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,QAAQ,EACR,0BAA0B,EAC1B,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,gCAAgC,GAChC,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAsB4B;AArB3B,wHAAA,oBAAoB,OAAA;AAUpB,oHAAA,gBAAgB,OAAA;AAChB,kHAAA,cAAc,OAAA;AACd,oHAAA,gBAAgB,OAAA;AAChB,oHAAA,gBAAgB,OAAA;AAChB,kHAAA,cAAc,OAAA;AACd,kIAAA,8BAA8B,OAAA;AAC9B,8HAAA,0BAA0B,OAAA;AAE1B,+HAAA,2BAA2B,OAAA;AAE3B,yHAAA,qBAAqB,OAAA;AAEtB,yDAA6D;AAApD,2HAAA,sBAAsB,OAAA;AAQ/B,qCAyCmB;AAvClB,sGAAA,WAAW,OAAA;AAGX,qHAAA,0BAA0B,OAAA;AAC1B,qGAAA,UAAU,OAAA;AAEV,4GAAA,iBAAiB,OAAA;AAkClB,6CAAiE;AAA5C,mHAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tContainerMessageType,\n\tContainerRuntimeMessage,\n\tIGCRuntimeOptions,\n\tISummaryRuntimeOptions,\n\tISummaryBaseConfiguration,\n\tISummaryConfigurationHeuristics,\n\tISummaryConfigurationDisableSummarizer,\n\tISummaryConfigurationDisableHeuristics,\n\tIContainerRuntimeOptions,\n\tIRootSummaryTreeWithStats,\n\tisRuntimeMessage,\n\tRuntimeMessage,\n\tagentSchedulerId,\n\tContainerRuntime,\n\tRuntimeHeaders,\n\tAllowTombstoneRequestHeaderKey,\n\tTombstoneResponseHeaderKey,\n\tISummaryConfiguration,\n\tDefaultSummaryConfiguration,\n\tICompressionRuntimeOptions,\n\tCompressionAlgorithms,\n} from \"./containerRuntime\";\nexport { FluidDataStoreRegistry } from \"./dataStoreRegistry\";\nexport { IGCStats } from \"./gc\";\nexport {\n\tIPendingFlush,\n\tIPendingLocalState,\n\tIPendingMessage,\n\tIPendingState,\n} from \"./pendingStateManager\";\nexport {\n\tIAckedSummary,\n\tISummarizer,\n\tISummarizeResults,\n\tISummaryCancellationToken,\n\tneverCancelledSummaryToken,\n\tSummarizer,\n\tSummarizerStopReason,\n\tSummaryCollection,\n\tEnqueueSummarizeResult,\n\tIAckSummaryResult,\n\tIBaseSummarizeResult,\n\tIBroadcastSummaryResult,\n\tICancellationToken,\n\tIConnectableRuntime,\n\tIEnqueueSummarizeOptions,\n\tIGenerateSummaryTreeResult,\n\tIGeneratedSummaryStats,\n\tINackSummaryResult,\n\tIOnDemandSummarizeOptions,\n\tIProvideSummarizer,\n\tIRefreshSummaryAckOptions,\n\tISubmitSummaryOpResult,\n\tISubmitSummaryOptions,\n\tISummarizeOptions,\n\tISummarizerEvents,\n\tISummarizerInternalsProvider,\n\tISummarizerRuntime,\n\tISummarizingWarning,\n\tIUploadSummaryResult,\n\tSubmitSummaryResult,\n\tSummarizeResultPart,\n\tIClientSummaryWatcher,\n\tISummary,\n\tISummaryCollectionOpEvents,\n\tISummaryAckMessage,\n\tISummaryNackMessage,\n\tISummaryOpMessage,\n\tOpActionEventListener,\n\tOpActionEventName,\n\tICancellableSummarizerController,\n} from \"./summary\";\nexport { IChunkedOp, unpackRuntimeMessage } from \"./opLifecycle\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAqB4B;AApB3B,wHAAA,oBAAoB,OAAA;AASpB,oHAAA,gBAAgB,OAAA;AAChB,kHAAA,cAAc,OAAA;AACd,oHAAA,gBAAgB,OAAA;AAChB,oHAAA,gBAAgB,OAAA;AAChB,kHAAA,cAAc,OAAA;AACd,kIAAA,8BAA8B,OAAA;AAC9B,8HAAA,0BAA0B,OAAA;AAE1B,+HAAA,2BAA2B,OAAA;AAE3B,yHAAA,qBAAqB,OAAA;AAEtB,yDAA6D;AAApD,2HAAA,sBAAsB,OAAA;AAQ/B,qCAyCmB;AAvClB,sGAAA,WAAW,OAAA;AAGX,qHAAA,0BAA0B,OAAA;AAC1B,qGAAA,UAAU,OAAA;AAEV,4GAAA,iBAAiB,OAAA;AAkClB,6CAAiE;AAA5C,mHAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tContainerMessageType,\n\tContainerRuntimeMessage,\n\tISummaryRuntimeOptions,\n\tISummaryBaseConfiguration,\n\tISummaryConfigurationHeuristics,\n\tISummaryConfigurationDisableSummarizer,\n\tISummaryConfigurationDisableHeuristics,\n\tIContainerRuntimeOptions,\n\tIRootSummaryTreeWithStats,\n\tisRuntimeMessage,\n\tRuntimeMessage,\n\tagentSchedulerId,\n\tContainerRuntime,\n\tRuntimeHeaders,\n\tAllowTombstoneRequestHeaderKey,\n\tTombstoneResponseHeaderKey,\n\tISummaryConfiguration,\n\tDefaultSummaryConfiguration,\n\tICompressionRuntimeOptions,\n\tCompressionAlgorithms,\n} from \"./containerRuntime\";\nexport { FluidDataStoreRegistry } from \"./dataStoreRegistry\";\nexport { IGCRuntimeOptions, IGCStats } from \"./gc\";\nexport {\n\tIPendingFlush,\n\tIPendingLocalState,\n\tIPendingMessage,\n\tIPendingState,\n} from \"./pendingStateManager\";\nexport {\n\tIAckedSummary,\n\tISummarizer,\n\tISummarizeResults,\n\tISummaryCancellationToken,\n\tneverCancelledSummaryToken,\n\tSummarizer,\n\tSummarizerStopReason,\n\tSummaryCollection,\n\tEnqueueSummarizeResult,\n\tIAckSummaryResult,\n\tIBaseSummarizeResult,\n\tIBroadcastSummaryResult,\n\tICancellationToken,\n\tIConnectableRuntime,\n\tIEnqueueSummarizeOptions,\n\tIGenerateSummaryTreeResult,\n\tIGeneratedSummaryStats,\n\tINackSummaryResult,\n\tIOnDemandSummarizeOptions,\n\tIProvideSummarizer,\n\tIRefreshSummaryAckOptions,\n\tISubmitSummaryOpResult,\n\tISubmitSummaryOptions,\n\tISummarizeOptions,\n\tISummarizerEvents,\n\tISummarizerInternalsProvider,\n\tISummarizerRuntime,\n\tISummarizingWarning,\n\tIUploadSummaryResult,\n\tSubmitSummaryResult,\n\tSummarizeResultPart,\n\tIClientSummaryWatcher,\n\tISummary,\n\tISummaryCollectionOpEvents,\n\tISummaryAckMessage,\n\tISummaryNackMessage,\n\tISummaryOpMessage,\n\tOpActionEventListener,\n\tOpActionEventName,\n\tICancellableSummarizerController,\n} from \"./summary\";\nexport { IChunkedOp, unpackRuntimeMessage } from \"./opLifecycle\";\n"]}
@@ -28,4 +28,13 @@ export declare class BatchManager {
28
28
  */
29
29
  checkpoint(): IBatchCheckpoint;
30
30
  }
31
+ /**
32
+ * Estimates the real size in bytes on the socket for a given batch. It assumes that
33
+ * the envelope size (and the size of an empty op) is 200 bytes, taking into account
34
+ * extra overhead from stringification.
35
+ *
36
+ * @param batch - the batch to inspect
37
+ * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire
38
+ */
39
+ export declare const estimateSocketSize: (batch: IBatch) => number;
31
40
  //# sourceMappingURL=batchManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;CACzD;AAED;;GAEG;AACH,qBAAa,YAAY;aAiBI,OAAO,EAAE,oBAAoB;IAhBzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAK;IAE7B,IAAW,MAAM,WAEhB;IACD,IAAW,kBAAkB,WAE5B;IAED,IAAW,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAIvD;gBAE2B,OAAO,EAAE,oBAAoB;IAElD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAiC3C,IAAW,KAAK,YAEf;IAEM,QAAQ,IAAI,MAAM;IAazB;;OAEG;IACI,UAAU,IAAI,gBAAgB;CAerC"}
1
+ {"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;CACzD;AAQD;;GAEG;AACH,qBAAa,YAAY;aAiBI,OAAO,EAAE,oBAAoB;IAhBzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAK;IAE7B,IAAW,MAAM,WAEhB;IACD,IAAW,kBAAkB,WAE5B;IAED,IAAW,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAIvD;gBAE2B,OAAO,EAAE,oBAAoB;IAElD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAiC3C,IAAW,KAAK,YAEf;IAEM,QAAQ,IAAI,MAAM;IAazB;;OAEG;IACI,UAAU,IAAI,gBAAgB;CAerC;AAiBD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAElD,CAAC"}
@@ -4,7 +4,12 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.BatchManager = void 0;
7
+ exports.estimateSocketSize = exports.BatchManager = void 0;
8
+ /**
9
+ * Estimated size of the stringification overhead for an op accumulated
10
+ * from runtime to loader to the service.
11
+ */
12
+ const opOverhead = 200;
8
13
  /**
9
14
  * Helper class that manages partial batch & rollback.
10
15
  */
@@ -34,7 +39,7 @@ class BatchManager {
34
39
  // Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.
35
40
  // Not taking it into account, as compression work should help there - compressed payload will be
36
41
  // initially stored as base64, and that requires only 2 extra escape characters.
37
- const socketMessageSize = contentSize + 200 * opCount;
42
+ const socketMessageSize = contentSize + opOverhead * opCount;
38
43
  // If we were provided soft limit, check for exceeding it.
39
44
  // But only if we have any ops, as the intention here is to flush existing ops (on exceeding this limit)
40
45
  // and start over. That's not an option if we have no ops.
@@ -92,4 +97,16 @@ const addBatchMetadata = (batch) => {
92
97
  }
93
98
  return batch;
94
99
  };
100
+ /**
101
+ * Estimates the real size in bytes on the socket for a given batch. It assumes that
102
+ * the envelope size (and the size of an empty op) is 200 bytes, taking into account
103
+ * extra overhead from stringification.
104
+ *
105
+ * @param batch - the batch to inspect
106
+ * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire
107
+ */
108
+ const estimateSocketSize = (batch) => {
109
+ return batch.contentSizeInBytes + opOverhead * batch.content.length;
110
+ };
111
+ exports.estimateSocketSize = estimateSocketSize;
95
112
  //# sourceMappingURL=batchManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly softLimit?: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n}\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: BatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\n\tpublic get length() {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes() {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: this.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(message: BatchMessage): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.contents?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + 200 * opCount;\n\n\t\t// If we were provided soft limit, check for exceeding it.\n\t\t// But only if we have any ops, as the intention here is to flush existing ops (on exceeding this limit)\n\t\t// and start over. That's not an option if we have no ops.\n\t\t// If compression is enabled, the soft and hard limit are ignored and the message will be pushed anyways.\n\t\t// Cases where the message is still too large will be handled by the maxConsecutiveReconnects path.\n\t\tif (\n\t\t\tthis.options.softLimit !== undefined &&\n\t\t\tthis.length > 0 &&\n\t\t\tsocketMessageSize >= this.options.softLimit\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty() {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\tpublic popBatch(): IBatch {\n\t\tconst batch: IBatch = {\n\t\t\tcontent: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\n\t\treturn addBatchMetadata(batch);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: BatchMessage) => void) => {\n\t\t\t\tfor (let i = this.pendingBatch.length; i > startPoint; ) {\n\t\t\t\t\ti--;\n\t\t\t\t\tconst message = this.pendingBatch[i];\n\t\t\t\t\tthis.batchContentSize -= message.contents?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\n\t\t\t\tthis.pendingBatch.length = startPoint;\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: IBatch): IBatch => {\n\tif (batch.content.length > 1) {\n\t\tbatch.content[0].metadata = {\n\t\t\t...batch.content[0].metadata,\n\t\t\tbatch: true,\n\t\t};\n\t\tbatch.content[batch.content.length - 1].metadata = {\n\t\t\t...batch.content[batch.content.length - 1].metadata,\n\t\t\tbatch: false,\n\t\t};\n\t}\n\n\treturn batch;\n};\n"]}
1
+ {"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly softLimit?: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n}\n\n/**\n * Estimated size of the stringification overhead for an op accumulated\n * from runtime to loader to the service.\n */\nconst opOverhead = 200;\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: BatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\n\tpublic get length() {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes() {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: this.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(message: BatchMessage): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.contents?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + opOverhead * opCount;\n\n\t\t// If we were provided soft limit, check for exceeding it.\n\t\t// But only if we have any ops, as the intention here is to flush existing ops (on exceeding this limit)\n\t\t// and start over. That's not an option if we have no ops.\n\t\t// If compression is enabled, the soft and hard limit are ignored and the message will be pushed anyways.\n\t\t// Cases where the message is still too large will be handled by the maxConsecutiveReconnects path.\n\t\tif (\n\t\t\tthis.options.softLimit !== undefined &&\n\t\t\tthis.length > 0 &&\n\t\t\tsocketMessageSize >= this.options.softLimit\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty() {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\tpublic popBatch(): IBatch {\n\t\tconst batch: IBatch = {\n\t\t\tcontent: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\n\t\treturn addBatchMetadata(batch);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: BatchMessage) => void) => {\n\t\t\t\tfor (let i = this.pendingBatch.length; i > startPoint; ) {\n\t\t\t\t\ti--;\n\t\t\t\t\tconst message = this.pendingBatch[i];\n\t\t\t\t\tthis.batchContentSize -= message.contents?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\n\t\t\t\tthis.pendingBatch.length = startPoint;\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: IBatch): IBatch => {\n\tif (batch.content.length > 1) {\n\t\tbatch.content[0].metadata = {\n\t\t\t...batch.content[0].metadata,\n\t\t\tbatch: true,\n\t\t};\n\t\tbatch.content[batch.content.length - 1].metadata = {\n\t\t\t...batch.content[batch.content.length - 1].metadata,\n\t\t\tbatch: false,\n\t\t};\n\t}\n\n\treturn batch;\n};\n\n/**\n * Estimates the real size in bytes on the socket for a given batch. It assumes that\n * the envelope size (and the size of an empty op) is 200 bytes, taking into account\n * extra overhead from stringification.\n *\n * @param batch - the batch to inspect\n * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire\n */\nexport const estimateSocketSize = (batch: IBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.content.length;\n};\n"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { BatchManager } from "./batchManager";
5
+ export { BatchManager, estimateSocketSize } from "./batchManager";
6
6
  export { BatchMessage, IBatch, IBatchCheckpoint, IChunkedOp, IMessageProcessingResult, } from "./definitions";
7
7
  export { Outbox } from "./outbox";
8
8
  export { OpCompressor } from "./opCompressor";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACN,YAAY,EACZ,MAAM,EACN,gBAAgB,EAChB,UAAU,EACV,wBAAwB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EACN,YAAY,EACZ,MAAM,EACN,gBAAgB,EAChB,UAAU,EACV,wBAAwB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -4,9 +4,10 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.unpackRuntimeMessage = exports.RemoteMessageProcessor = exports.splitOp = exports.OpSplitter = exports.OpDecompressor = exports.OpCompressor = exports.Outbox = exports.BatchManager = void 0;
7
+ exports.unpackRuntimeMessage = exports.RemoteMessageProcessor = exports.splitOp = exports.OpSplitter = exports.OpDecompressor = exports.OpCompressor = exports.Outbox = exports.estimateSocketSize = exports.BatchManager = void 0;
8
8
  var batchManager_1 = require("./batchManager");
9
9
  Object.defineProperty(exports, "BatchManager", { enumerable: true, get: function () { return batchManager_1.BatchManager; } });
10
+ Object.defineProperty(exports, "estimateSocketSize", { enumerable: true, get: function () { return batchManager_1.estimateSocketSize; } });
10
11
  var outbox_1 = require("./outbox");
11
12
  Object.defineProperty(exports, "Outbox", { enumerable: true, get: function () { return outbox_1.Outbox; } });
12
13
  var opCompressor_1 = require("./opCompressor");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAQrB,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,2CAAmD;AAA1C,wGAAA,UAAU,OAAA;AAAE,qGAAA,OAAO,OAAA;AAC5B,mEAAwF;AAA/E,gIAAA,sBAAsB,OAAA;AAAE,8HAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { BatchManager } from \"./batchManager\";\nexport {\n\tBatchMessage,\n\tIBatch,\n\tIBatchCheckpoint,\n\tIChunkedOp,\n\tIMessageProcessingResult,\n} from \"./definitions\";\nexport { Outbox } from \"./outbox\";\nexport { OpCompressor } from \"./opCompressor\";\nexport { OpDecompressor } from \"./opDecompressor\";\nexport { OpSplitter, splitOp } from \"./opSplitter\";\nexport { RemoteMessageProcessor, unpackRuntimeMessage } from \"./remoteMessageProcessor\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+CAAkE;AAAzD,4GAAA,YAAY,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAQzC,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,2CAAmD;AAA1C,wGAAA,UAAU,OAAA;AAAE,qGAAA,OAAO,OAAA;AAC5B,mEAAwF;AAA/E,gIAAA,sBAAsB,OAAA;AAAE,8HAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { BatchManager, estimateSocketSize } from \"./batchManager\";\nexport {\n\tBatchMessage,\n\tIBatch,\n\tIBatchCheckpoint,\n\tIChunkedOp,\n\tIMessageProcessingResult,\n} from \"./definitions\";\nexport { Outbox } from \"./outbox\";\nexport { OpCompressor } from \"./opCompressor\";\nexport { OpDecompressor } from \"./opDecompressor\";\nexport { OpSplitter, splitOp } from \"./opSplitter\";\nexport { RemoteMessageProcessor, unpackRuntimeMessage } from \"./remoteMessageProcessor\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"opCompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAMtE,OAAO,EAAE,MAAM,EAAgB,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAEZ,MAAM,EAAE,gBAAgB;IAI7B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAmC3C,OAAO,CAAC,cAAc;CAsBtB"}
1
+ {"version":3,"file":"opCompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAOtE,OAAO,EAAE,MAAM,EAAgB,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAEZ,MAAM,EAAE,gBAAgB;IAI7B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqD3C,OAAO,CAAC,cAAc;CAsBtB"}
@@ -10,6 +10,7 @@ const container_utils_1 = require("@fluidframework/container-utils");
10
10
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
11
11
  const lz4js_1 = require("lz4js");
12
12
  const containerRuntime_1 = require("../containerRuntime");
13
+ const batchManager_1 = require("./batchManager");
13
14
  /**
14
15
  * Compresses batches of ops. It generates a single compressed op that contains
15
16
  * the contents of each op in the batch. It then submits empty ops for each original
@@ -20,29 +21,42 @@ class OpCompressor {
20
21
  this.logger = telemetry_utils_1.ChildLogger.create(logger, "OpCompressor");
21
22
  }
22
23
  compressBatch(batch) {
24
+ (0, common_utils_1.assert)(batch.contentSizeInBytes > 0 && batch.content.length > 0, 0x5a4 /* Batch should not be empty */);
23
25
  const compressionStart = Date.now();
24
26
  const contentsAsBuffer = new TextEncoder().encode(this.serializeBatch(batch));
25
27
  const compressedContents = (0, lz4js_1.compress)(contentsAsBuffer);
26
28
  const compressedContent = common_utils_1.IsoBuffer.from(compressedContents).toString("base64");
27
29
  const duration = Date.now() - compressionStart;
28
- if (batch.contentSizeInBytes > 200000) {
29
- this.logger.sendPerformanceEvent({
30
- eventName: "CompressedBatch",
31
- duration,
32
- sizeBeforeCompression: batch.contentSizeInBytes,
33
- sizeAfterCompression: compressedContent.length,
34
- });
35
- }
36
30
  const messages = [];
37
31
  messages.push(Object.assign(Object.assign({}, batch.content[0]), { contents: JSON.stringify({ packedContents: compressedContent }), metadata: batch.content[0].metadata, compression: containerRuntime_1.CompressionAlgorithms.lz4 }));
32
+ // Add empty placeholder messages to reserve the sequence numbers
38
33
  for (const message of batch.content.slice(1)) {
39
- messages.push(Object.assign(Object.assign({}, message), { contents: undefined }));
34
+ messages.push({
35
+ deserializedContent: {
36
+ contents: undefined,
37
+ type: message.deserializedContent.type,
38
+ },
39
+ localOpMetadata: message.localOpMetadata,
40
+ metadata: message.metadata,
41
+ referenceSequenceNumber: message.referenceSequenceNumber,
42
+ });
40
43
  }
41
- return {
44
+ const compressedBatch = {
42
45
  contentSizeInBytes: compressedContent.length,
43
46
  content: messages,
44
47
  referenceSequenceNumber: batch.referenceSequenceNumber,
45
48
  };
49
+ if (batch.contentSizeInBytes > 200000) {
50
+ this.logger.sendPerformanceEvent({
51
+ eventName: "CompressedBatch",
52
+ duration,
53
+ sizeBeforeCompression: batch.contentSizeInBytes,
54
+ sizeAfterCompression: compressedBatch.contentSizeInBytes,
55
+ opCount: compressedBatch.content.length,
56
+ socketSize: (0, batchManager_1.estimateSocketSize)(compressedBatch),
57
+ });
58
+ }
59
+ return compressedBatch;
46
60
  }
47
61
  serializeBatch(batch) {
48
62
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"opCompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAyD;AACzD,qEAA6D;AAC7D,qEAA8D;AAC9D,iCAAiC;AACjC,0DAA4D;AAG5D;;;;GAIG;AACH,MAAa,YAAY;IAGxB,YAAY,MAAwB;QACnC,IAAI,CAAC,MAAM,GAAG,6BAAW,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1D,CAAC;IAEM,aAAa,CAAC,KAAa;QACjC,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,gBAAgB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9E,MAAM,kBAAkB,GAAG,IAAA,gBAAQ,EAAC,gBAAgB,CAAC,CAAC;QACtD,MAAM,iBAAiB,GAAG,wBAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC;QAE/C,IAAI,KAAK,CAAC,kBAAkB,GAAG,MAAM,EAAE;YACtC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,iBAAiB;gBAC5B,QAAQ;gBACR,qBAAqB,EAAE,KAAK,CAAC,kBAAkB;gBAC/C,oBAAoB,EAAE,iBAAiB,CAAC,MAAM;aAC9C,CAAC,CAAC;SACH;QAED,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,iCACT,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KACnB,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,EAC/D,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EACnC,WAAW,EAAE,wCAAqB,CAAC,GAAG,IACrC,CAAC;QAEH,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YAC7C,QAAQ,CAAC,IAAI,iCAAM,OAAO,KAAE,QAAQ,EAAE,SAAS,IAAG,CAAC;SACnD;QAED,OAAO;YACN,kBAAkB,EAAE,iBAAiB,CAAC,MAAM;YAC5C,OAAO,EAAE,QAAQ;YACjB,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;SACtD,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,KAAa;QACnC,IAAI;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;SACnF;QAAC,OAAO,CAAM,EAAE;YAChB,IAAI,CAAC,CAAC,OAAO,KAAK,uBAAuB,EAAE;gBAC1C,0CAA0C;gBAC1C,wCAAwC;gBACxC,MAAM,KAAK,GAAG,IAAI,4BAAU,CAAC,mBAAmB,CAAC,CAAC;gBAClD,IAAI,CAAC,MAAM,CAAC,cAAc,CACzB;oBACC,SAAS,EAAE,eAAe;oBAC1B,IAAI,EAAE,KAAK,CAAC,kBAAkB;oBAC9B,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;iBAC5B,EACD,KAAK,CACL,CAAC;gBACF,MAAM,KAAK,CAAC;aACZ;YAED,MAAM,CAAC,CAAC;SACR;IACF,CAAC;CACD;AAhED,oCAgEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { IsoBuffer } from \"@fluidframework/common-utils\";\nimport { UsageError } from \"@fluidframework/container-utils\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { compress } from \"lz4js\";\nimport { CompressionAlgorithms } from \"../containerRuntime\";\nimport { IBatch, BatchMessage } from \"./definitions\";\n\n/**\n * Compresses batches of ops. It generates a single compressed op that contains\n * the contents of each op in the batch. It then submits empty ops for each original\n * op to reserve sequence numbers.\n */\nexport class OpCompressor {\n\tprivate readonly logger;\n\n\tconstructor(logger: ITelemetryLogger) {\n\t\tthis.logger = ChildLogger.create(logger, \"OpCompressor\");\n\t}\n\n\tpublic compressBatch(batch: IBatch): IBatch {\n\t\tconst compressionStart = Date.now();\n\t\tconst contentsAsBuffer = new TextEncoder().encode(this.serializeBatch(batch));\n\t\tconst compressedContents = compress(contentsAsBuffer);\n\t\tconst compressedContent = IsoBuffer.from(compressedContents).toString(\"base64\");\n\t\tconst duration = Date.now() - compressionStart;\n\n\t\tif (batch.contentSizeInBytes > 200000) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"CompressedBatch\",\n\t\t\t\tduration,\n\t\t\t\tsizeBeforeCompression: batch.contentSizeInBytes,\n\t\t\t\tsizeAfterCompression: compressedContent.length,\n\t\t\t});\n\t\t}\n\n\t\tconst messages: BatchMessage[] = [];\n\t\tmessages.push({\n\t\t\t...batch.content[0],\n\t\t\tcontents: JSON.stringify({ packedContents: compressedContent }),\n\t\t\tmetadata: batch.content[0].metadata,\n\t\t\tcompression: CompressionAlgorithms.lz4,\n\t\t});\n\n\t\tfor (const message of batch.content.slice(1)) {\n\t\t\tmessages.push({ ...message, contents: undefined });\n\t\t}\n\n\t\treturn {\n\t\t\tcontentSizeInBytes: compressedContent.length,\n\t\t\tcontent: messages,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\t}\n\n\tprivate serializeBatch(batch: IBatch): string {\n\t\ttry {\n\t\t\treturn JSON.stringify(batch.content.map((message) => message.deserializedContent));\n\t\t} catch (e: any) {\n\t\t\tif (e.message === \"Invalid string length\") {\n\t\t\t\t// This is how JSON.stringify signals that\n\t\t\t\t// the content size exceeds its capacity\n\t\t\t\tconst error = new UsageError(\"Payload too large\");\n\t\t\t\tthis.logger.sendErrorEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"BatchTooLarge\",\n\t\t\t\t\t\tsize: batch.contentSizeInBytes,\n\t\t\t\t\t\tlength: batch.content.length,\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tthrow e;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"opCompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, IsoBuffer } from \"@fluidframework/common-utils\";\nimport { UsageError } from \"@fluidframework/container-utils\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { compress } from \"lz4js\";\nimport { CompressionAlgorithms } from \"../containerRuntime\";\nimport { estimateSocketSize } from \"./batchManager\";\nimport { IBatch, BatchMessage } from \"./definitions\";\n\n/**\n * Compresses batches of ops. It generates a single compressed op that contains\n * the contents of each op in the batch. It then submits empty ops for each original\n * op to reserve sequence numbers.\n */\nexport class OpCompressor {\n\tprivate readonly logger;\n\n\tconstructor(logger: ITelemetryLogger) {\n\t\tthis.logger = ChildLogger.create(logger, \"OpCompressor\");\n\t}\n\n\tpublic compressBatch(batch: IBatch): IBatch {\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.content.length > 0,\n\t\t\t0x5a4 /* Batch should not be empty */,\n\t\t);\n\n\t\tconst compressionStart = Date.now();\n\t\tconst contentsAsBuffer = new TextEncoder().encode(this.serializeBatch(batch));\n\t\tconst compressedContents = compress(contentsAsBuffer);\n\t\tconst compressedContent = IsoBuffer.from(compressedContents).toString(\"base64\");\n\t\tconst duration = Date.now() - compressionStart;\n\n\t\tconst messages: BatchMessage[] = [];\n\t\tmessages.push({\n\t\t\t...batch.content[0],\n\t\t\tcontents: JSON.stringify({ packedContents: compressedContent }),\n\t\t\tmetadata: batch.content[0].metadata,\n\t\t\tcompression: CompressionAlgorithms.lz4,\n\t\t});\n\n\t\t// Add empty placeholder messages to reserve the sequence numbers\n\t\tfor (const message of batch.content.slice(1)) {\n\t\t\tmessages.push({\n\t\t\t\tdeserializedContent: {\n\t\t\t\t\tcontents: undefined,\n\t\t\t\t\ttype: message.deserializedContent.type,\n\t\t\t\t},\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\tmetadata: message.metadata,\n\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t});\n\t\t}\n\n\t\tconst compressedBatch: IBatch = {\n\t\t\tcontentSizeInBytes: compressedContent.length,\n\t\t\tcontent: messages,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\n\t\tif (batch.contentSizeInBytes > 200000) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"CompressedBatch\",\n\t\t\t\tduration,\n\t\t\t\tsizeBeforeCompression: batch.contentSizeInBytes,\n\t\t\t\tsizeAfterCompression: compressedBatch.contentSizeInBytes,\n\t\t\t\topCount: compressedBatch.content.length,\n\t\t\t\tsocketSize: estimateSocketSize(compressedBatch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\tprivate serializeBatch(batch: IBatch): string {\n\t\ttry {\n\t\t\treturn JSON.stringify(batch.content.map((message) => message.deserializedContent));\n\t\t} catch (e: any) {\n\t\t\tif (e.message === \"Invalid string length\") {\n\t\t\t\t// This is how JSON.stringify signals that\n\t\t\t\t// the content size exceeds its capacity\n\t\t\t\tconst error = new UsageError(\"Payload too large\");\n\t\t\t\tthis.logger.sendErrorEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"BatchTooLarge\",\n\t\t\t\t\t\tsize: batch.contentSizeInBytes,\n\t\t\t\t\t\tlength: batch.content.length,\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tthrow e;\n\t\t}\n\t}\n}\n"]}
@@ -3,6 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
6
+ import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
7
  import { IMessageProcessingResult } from "./definitions";
7
8
  /**
8
9
  * State machine that "unrolls" contents of compressed batches of ops after decompressing them.
@@ -16,6 +17,9 @@ export declare class OpDecompressor {
16
17
  private activeBatch;
17
18
  private rootMessageContents;
18
19
  private processedCount;
20
+ private readonly logger;
21
+ constructor(logger: ITelemetryLogger);
19
22
  processMessage(message: ISequencedDocumentMessage): IMessageProcessingResult;
23
+ private isCompressed;
20
24
  }
21
25
  //# sourceMappingURL=opDecompressor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opDecompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opDecompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAGjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD;;;;;;;GAOG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,cAAc,CAAK;IAEpB,cAAc,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB;CAwFnF"}
1
+ {"version":3,"file":"opDecompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opDecompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAGjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD;;;;;;;GAOG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAEZ,MAAM,EAAE,gBAAgB;IAI7B,cAAc,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB;IAsFnF,OAAO,CAAC,YAAY;CAuCpB"}
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.OpDecompressor = void 0;
8
8
  const lz4js_1 = require("lz4js");
9
9
  const common_utils_1 = require("@fluidframework/common-utils");
10
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
10
11
  const containerRuntime_1 = require("../containerRuntime");
11
12
  /**
12
13
  * State machine that "unrolls" contents of compressed batches of ops after decompressing them.
@@ -17,14 +18,15 @@ const containerRuntime_1 = require("../containerRuntime");
17
18
  * 4. An individually compressed op will have undefined batch metadata and compression set to true
18
19
  */
19
20
  class OpDecompressor {
20
- constructor() {
21
+ constructor(logger) {
21
22
  this.activeBatch = false;
22
23
  this.processedCount = 0;
24
+ this.logger = telemetry_utils_1.ChildLogger.create(logger, "OpDecompressor");
23
25
  }
24
26
  processMessage(message) {
25
27
  var _a, _b, _c, _d;
26
28
  (0, common_utils_1.assert)(message.compression === undefined || message.compression === containerRuntime_1.CompressionAlgorithms.lz4, 0x511 /* Only lz4 compression is supported */);
27
- if (((_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch) === true && message.compression === containerRuntime_1.CompressionAlgorithms.lz4) {
29
+ if (((_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch) === true && this.isCompressed(message)) {
28
30
  // Beginning of a compressed batch
29
31
  (0, common_utils_1.assert)(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);
30
32
  if (message.compression) {
@@ -63,8 +65,7 @@ class OpDecompressor {
63
65
  state: "Processed",
64
66
  };
65
67
  }
66
- if (((_d = message.metadata) === null || _d === void 0 ? void 0 : _d.batch) === undefined &&
67
- message.compression === containerRuntime_1.CompressionAlgorithms.lz4) {
68
+ if (((_d = message.metadata) === null || _d === void 0 ? void 0 : _d.batch) === undefined && this.isCompressed(message)) {
68
69
  // Single compressed message
69
70
  (0, common_utils_1.assert)(this.activeBatch === false, 0x4ba /* shouldn't receive compressed message in middle of a batch */);
70
71
  const contents = common_utils_1.IsoBuffer.from(message.contents.packedContents, "base64");
@@ -81,6 +82,43 @@ class OpDecompressor {
81
82
  state: "Skipped",
82
83
  };
83
84
  }
85
+ isCompressed(message) {
86
+ var _a, _b, _c;
87
+ if (message.compression === containerRuntime_1.CompressionAlgorithms.lz4) {
88
+ return true;
89
+ }
90
+ /**
91
+ * Back-compat self healing mechanism for ADO:3538, as loaders from
92
+ * version client_v2.0.0-internal.1.2.0 to client_v2.0.0-internal.2.2.0 do not
93
+ * support adding the proper compression metadata to compressed messages submitted
94
+ * by the runtime. Should be removed after the loader reaches sufficient saturation
95
+ * for a version greater or equal than client_v2.0.0-internal.2.2.0.
96
+ *
97
+ * The condition holds true for compressed messages, regardless of metadata. We are ultimately
98
+ * looking for a message with a single property `packedContents` inside `contents`, of type 'string'
99
+ * with a base64 encoded value.
100
+ */
101
+ try {
102
+ if (typeof message.contents === "object" &&
103
+ Object.keys(message.contents).length === 1 &&
104
+ ((_a = message.contents) === null || _a === void 0 ? void 0 : _a.packedContents) !== undefined &&
105
+ typeof ((_b = message.contents) === null || _b === void 0 ? void 0 : _b.packedContents) === "string" &&
106
+ message.contents.packedContents.length > 0 &&
107
+ common_utils_1.IsoBuffer.from(message.contents.packedContents, "base64").toString("base64") ===
108
+ message.contents.packedContents) {
109
+ this.logger.sendTelemetryEvent({
110
+ eventName: "LegacyCompression",
111
+ type: message.type,
112
+ batch: (_c = message.metadata) === null || _c === void 0 ? void 0 : _c.batch,
113
+ });
114
+ return true;
115
+ }
116
+ }
117
+ catch (err) {
118
+ return false;
119
+ }
120
+ return false;
121
+ }
84
122
  }
85
123
  exports.OpDecompressor = OpDecompressor;
86
124
  // We should not be mutating the input message nor its metadata
@@ -1 +1 @@
1
- {"version":3,"file":"opDecompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opDecompressor.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { decompress } from \"lz4js\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { assert, IsoBuffer, Uint8ArrayToString } from \"@fluidframework/common-utils\";\nimport { CompressionAlgorithms } from \"../containerRuntime\";\nimport { IMessageProcessingResult } from \"./definitions\";\n\n/**\n * State machine that \"unrolls\" contents of compressed batches of ops after decompressing them.\n * This class relies on some implicit contracts defined below:\n * 1. A compressed batch will have its first message with batch metadata set to true and compressed set to true\n * 2. Messages in the middle of a compressed batch will have neither batch metadata nor the compression property set\n * 3. The final message of a batch will have batch metadata set to false\n * 4. An individually compressed op will have undefined batch metadata and compression set to true\n */\nexport class OpDecompressor {\n\tprivate activeBatch = false;\n\tprivate rootMessageContents: any | undefined;\n\tprivate processedCount = 0;\n\n\tpublic processMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tassert(\n\t\t\tmessage.compression === undefined || message.compression === CompressionAlgorithms.lz4,\n\t\t\t0x511 /* Only lz4 compression is supported */,\n\t\t);\n\n\t\tif (message.metadata?.batch === true && message.compression === CompressionAlgorithms.lz4) {\n\t\t\t// Beginning of a compressed batch\n\t\t\tassert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);\n\t\t\tif (message.compression) {\n\t\t\t\t// lz4 is the only supported compression algorithm for now\n\t\t\t\tassert(\n\t\t\t\t\tmessage.compression === CompressionAlgorithms.lz4,\n\t\t\t\t\t0x4b9 /* lz4 is currently the only supported compression algorithm */,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.activeBatch = true;\n\n\t\t\tconst contents = IsoBuffer.from(message.contents.packedContents, \"base64\");\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = Uint8ArrayToString(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\t\t\tthis.rootMessageContents = asObj;\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\tthis.rootMessageContents !== undefined &&\n\t\t\tmessage.metadata?.batch === undefined &&\n\t\t\tthis.activeBatch\n\t\t) {\n\t\t\tassert(message.contents === undefined, 0x512 /* Expecting empty message */);\n\n\t\t\t// Continuation of compressed batch\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (this.rootMessageContents !== undefined && message.metadata?.batch === false) {\n\t\t\t// End of compressed batch\n\t\t\tconst returnMessage = newMessage(\n\t\t\t\tmessage,\n\t\t\t\tthis.rootMessageContents[this.processedCount++],\n\t\t\t);\n\n\t\t\tthis.activeBatch = false;\n\t\t\tthis.rootMessageContents = undefined;\n\t\t\tthis.processedCount = 0;\n\n\t\t\treturn {\n\t\t\t\tmessage: returnMessage,\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\tmessage.metadata?.batch === undefined &&\n\t\t\tmessage.compression === CompressionAlgorithms.lz4\n\t\t) {\n\t\t\t// Single compressed message\n\t\t\tassert(\n\t\t\t\tthis.activeBatch === false,\n\t\t\t\t0x4ba /* shouldn't receive compressed message in middle of a batch */,\n\t\t\t);\n\n\t\t\tconst contents = IsoBuffer.from(message.contents.packedContents, \"base64\");\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = new TextDecoder().decode(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, asObj[0]),\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmessage,\n\t\t\tstate: \"Skipped\",\n\t\t};\n\t}\n}\n\n// We should not be mutating the input message nor its metadata\nconst newMessage = (\n\toriginalMessage: ISequencedDocumentMessage,\n\tcontents: any,\n): ISequencedDocumentMessage => ({\n\t...originalMessage,\n\tcontents,\n\tcompression: undefined,\n\tmetadata: { ...originalMessage.metadata },\n});\n"]}
1
+ {"version":3,"file":"opDecompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opDecompressor.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { decompress } from \"lz4js\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { assert, IsoBuffer, Uint8ArrayToString } from \"@fluidframework/common-utils\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { CompressionAlgorithms } from \"../containerRuntime\";\nimport { IMessageProcessingResult } from \"./definitions\";\n\n/**\n * State machine that \"unrolls\" contents of compressed batches of ops after decompressing them.\n * This class relies on some implicit contracts defined below:\n * 1. A compressed batch will have its first message with batch metadata set to true and compressed set to true\n * 2. Messages in the middle of a compressed batch will have neither batch metadata nor the compression property set\n * 3. The final message of a batch will have batch metadata set to false\n * 4. An individually compressed op will have undefined batch metadata and compression set to true\n */\nexport class OpDecompressor {\n\tprivate activeBatch = false;\n\tprivate rootMessageContents: any | undefined;\n\tprivate processedCount = 0;\n\tprivate readonly logger;\n\n\tconstructor(logger: ITelemetryLogger) {\n\t\tthis.logger = ChildLogger.create(logger, \"OpDecompressor\");\n\t}\n\n\tpublic processMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tassert(\n\t\t\tmessage.compression === undefined || message.compression === CompressionAlgorithms.lz4,\n\t\t\t0x511 /* Only lz4 compression is supported */,\n\t\t);\n\n\t\tif (message.metadata?.batch === true && this.isCompressed(message)) {\n\t\t\t// Beginning of a compressed batch\n\t\t\tassert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);\n\t\t\tif (message.compression) {\n\t\t\t\t// lz4 is the only supported compression algorithm for now\n\t\t\t\tassert(\n\t\t\t\t\tmessage.compression === CompressionAlgorithms.lz4,\n\t\t\t\t\t0x4b9 /* lz4 is currently the only supported compression algorithm */,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.activeBatch = true;\n\n\t\t\tconst contents = IsoBuffer.from(message.contents.packedContents, \"base64\");\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = Uint8ArrayToString(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\t\t\tthis.rootMessageContents = asObj;\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\tthis.rootMessageContents !== undefined &&\n\t\t\tmessage.metadata?.batch === undefined &&\n\t\t\tthis.activeBatch\n\t\t) {\n\t\t\tassert(message.contents === undefined, 0x512 /* Expecting empty message */);\n\n\t\t\t// Continuation of compressed batch\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (this.rootMessageContents !== undefined && message.metadata?.batch === false) {\n\t\t\t// End of compressed batch\n\t\t\tconst returnMessage = newMessage(\n\t\t\t\tmessage,\n\t\t\t\tthis.rootMessageContents[this.processedCount++],\n\t\t\t);\n\n\t\t\tthis.activeBatch = false;\n\t\t\tthis.rootMessageContents = undefined;\n\t\t\tthis.processedCount = 0;\n\n\t\t\treturn {\n\t\t\t\tmessage: returnMessage,\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\tif (message.metadata?.batch === undefined && this.isCompressed(message)) {\n\t\t\t// Single compressed message\n\t\t\tassert(\n\t\t\t\tthis.activeBatch === false,\n\t\t\t\t0x4ba /* shouldn't receive compressed message in middle of a batch */,\n\t\t\t);\n\n\t\t\tconst contents = IsoBuffer.from(message.contents.packedContents, \"base64\");\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = new TextDecoder().decode(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, asObj[0]),\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmessage,\n\t\t\tstate: \"Skipped\",\n\t\t};\n\t}\n\n\tprivate isCompressed(message: ISequencedDocumentMessage) {\n\t\tif (message.compression === CompressionAlgorithms.lz4) {\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * Back-compat self healing mechanism for ADO:3538, as loaders from\n\t\t * version client_v2.0.0-internal.1.2.0 to client_v2.0.0-internal.2.2.0 do not\n\t\t * support adding the proper compression metadata to compressed messages submitted\n\t\t * by the runtime. Should be removed after the loader reaches sufficient saturation\n\t\t * for a version greater or equal than client_v2.0.0-internal.2.2.0.\n\t\t *\n\t\t * The condition holds true for compressed messages, regardless of metadata. We are ultimately\n\t\t * looking for a message with a single property `packedContents` inside `contents`, of type 'string'\n\t\t * with a base64 encoded value.\n\t\t */\n\t\ttry {\n\t\t\tif (\n\t\t\t\ttypeof message.contents === \"object\" &&\n\t\t\t\tObject.keys(message.contents).length === 1 &&\n\t\t\t\tmessage.contents?.packedContents !== undefined &&\n\t\t\t\ttypeof message.contents?.packedContents === \"string\" &&\n\t\t\t\tmessage.contents.packedContents.length > 0 &&\n\t\t\t\tIsoBuffer.from(message.contents.packedContents, \"base64\").toString(\"base64\") ===\n\t\t\t\t\tmessage.contents.packedContents\n\t\t\t) {\n\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"LegacyCompression\",\n\t\t\t\t\ttype: message.type,\n\t\t\t\t\tbatch: message.metadata?.batch,\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n\n// We should not be mutating the input message nor its metadata\nconst newMessage = (\n\toriginalMessage: ISequencedDocumentMessage,\n\tcontents: any,\n): ISequencedDocumentMessage => ({\n\t...originalMessage,\n\tcontents,\n\tcompression: undefined,\n\tmetadata: { ...originalMessage.metadata },\n});\n"]}