@fluidframework/container-runtime 2.0.0-internal.5.4.0 → 2.0.0-internal.6.1.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 (223) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/dist/batchTracker.d.ts +2 -1
  3. package/dist/batchTracker.d.ts.map +1 -1
  4. package/dist/batchTracker.js.map +1 -1
  5. package/dist/blobManager.d.ts +4 -1
  6. package/dist/blobManager.d.ts.map +1 -1
  7. package/dist/blobManager.js +61 -26
  8. package/dist/blobManager.js.map +1 -1
  9. package/dist/connectionTelemetry.js +10 -2
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/containerRuntime.d.ts +26 -11
  12. package/dist/containerRuntime.d.ts.map +1 -1
  13. package/dist/containerRuntime.js +189 -131
  14. package/dist/containerRuntime.js.map +1 -1
  15. package/dist/dataStore.js +8 -2
  16. package/dist/dataStore.js.map +1 -1
  17. package/dist/dataStoreContext.d.ts.map +1 -1
  18. package/dist/dataStoreContext.js +24 -26
  19. package/dist/dataStoreContext.js.map +1 -1
  20. package/dist/dataStores.d.ts +20 -4
  21. package/dist/dataStores.d.ts.map +1 -1
  22. package/dist/dataStores.js +107 -53
  23. package/dist/dataStores.js.map +1 -1
  24. package/dist/deltaManagerProxyBase.d.ts +35 -0
  25. package/dist/deltaManagerProxyBase.d.ts.map +1 -0
  26. package/dist/deltaManagerProxyBase.js +77 -0
  27. package/dist/deltaManagerProxyBase.js.map +1 -0
  28. package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
  29. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  30. package/dist/deltaManagerSummarizerProxy.js +2 -2
  31. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  32. package/dist/gc/garbageCollection.js +17 -20
  33. package/dist/gc/garbageCollection.js.map +1 -1
  34. package/dist/gc/gcConfigs.js +13 -11
  35. package/dist/gc/gcConfigs.js.map +1 -1
  36. package/dist/gc/gcHelpers.js +4 -6
  37. package/dist/gc/gcHelpers.js.map +1 -1
  38. package/dist/gc/gcSummaryStateTracker.js +4 -6
  39. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  40. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  41. package/dist/gc/gcTelemetry.js +55 -37
  42. package/dist/gc/gcTelemetry.js.map +1 -1
  43. package/dist/id-compressor/idCompressor.js +49 -51
  44. package/dist/id-compressor/idCompressor.js.map +1 -1
  45. package/dist/id-compressor/idRange.js +2 -2
  46. package/dist/id-compressor/idRange.js.map +1 -1
  47. package/dist/id-compressor/sessionIdNormalizer.js +11 -16
  48. package/dist/id-compressor/sessionIdNormalizer.js.map +1 -1
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js.map +1 -1
  52. package/dist/opLifecycle/batchManager.js +10 -6
  53. package/dist/opLifecycle/batchManager.js.map +1 -1
  54. package/dist/opLifecycle/opCompressor.js +6 -1
  55. package/dist/opLifecycle/opCompressor.js.map +1 -1
  56. package/dist/opLifecycle/opDecompressor.js +11 -9
  57. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  58. package/dist/opLifecycle/opGroupingManager.js +13 -5
  59. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  60. package/dist/opLifecycle/opSplitter.js +10 -6
  61. package/dist/opLifecycle/opSplitter.js.map +1 -1
  62. package/dist/opLifecycle/outbox.js +1 -2
  63. package/dist/opLifecycle/outbox.js.map +1 -1
  64. package/dist/opLifecycle/remoteMessageProcessor.js +1 -1
  65. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  66. package/dist/opProperties.js +1 -2
  67. package/dist/opProperties.js.map +1 -1
  68. package/dist/packageVersion.d.ts +1 -1
  69. package/dist/packageVersion.js +1 -1
  70. package/dist/packageVersion.js.map +1 -1
  71. package/dist/pendingStateManager.d.ts +2 -2
  72. package/dist/pendingStateManager.d.ts.map +1 -1
  73. package/dist/pendingStateManager.js +22 -22
  74. package/dist/pendingStateManager.js.map +1 -1
  75. package/dist/scheduleManager.js +14 -10
  76. package/dist/scheduleManager.js.map +1 -1
  77. package/dist/summary/orderedClientElection.d.ts +2 -1
  78. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  79. package/dist/summary/orderedClientElection.js +17 -18
  80. package/dist/summary/orderedClientElection.js.map +1 -1
  81. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  82. package/dist/summary/runningSummarizer.js +35 -57
  83. package/dist/summary/runningSummarizer.js.map +1 -1
  84. package/dist/summary/summarizer.js +4 -7
  85. package/dist/summary/summarizer.js.map +1 -1
  86. package/dist/summary/summarizerClientElection.js +5 -9
  87. package/dist/summary/summarizerClientElection.js.map +1 -1
  88. package/dist/summary/summarizerHeuristics.js +8 -12
  89. package/dist/summary/summarizerHeuristics.js.map +1 -1
  90. package/dist/summary/summarizerNode/summarizerNode.js +22 -15
  91. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  92. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  93. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  94. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +17 -16
  95. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  96. package/dist/summary/summaryCollection.js +3 -5
  97. package/dist/summary/summaryCollection.js.map +1 -1
  98. package/dist/summary/summaryFormat.js +1 -2
  99. package/dist/summary/summaryFormat.js.map +1 -1
  100. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  101. package/dist/summary/summaryGenerator.js +62 -21
  102. package/dist/summary/summaryGenerator.js.map +1 -1
  103. package/dist/summary/summaryManager.js +3 -5
  104. package/dist/summary/summaryManager.js.map +1 -1
  105. package/lib/batchTracker.d.ts +2 -1
  106. package/lib/batchTracker.d.ts.map +1 -1
  107. package/lib/batchTracker.js.map +1 -1
  108. package/lib/blobManager.d.ts +4 -1
  109. package/lib/blobManager.d.ts.map +1 -1
  110. package/lib/blobManager.js +61 -26
  111. package/lib/blobManager.js.map +1 -1
  112. package/lib/connectionTelemetry.js +10 -2
  113. package/lib/connectionTelemetry.js.map +1 -1
  114. package/lib/containerRuntime.d.ts +26 -11
  115. package/lib/containerRuntime.d.ts.map +1 -1
  116. package/lib/containerRuntime.js +189 -131
  117. package/lib/containerRuntime.js.map +1 -1
  118. package/lib/dataStore.js +8 -2
  119. package/lib/dataStore.js.map +1 -1
  120. package/lib/dataStoreContext.d.ts.map +1 -1
  121. package/lib/dataStoreContext.js +24 -26
  122. package/lib/dataStoreContext.js.map +1 -1
  123. package/lib/dataStores.d.ts +20 -4
  124. package/lib/dataStores.d.ts.map +1 -1
  125. package/lib/dataStores.js +107 -53
  126. package/lib/dataStores.js.map +1 -1
  127. package/lib/deltaManagerProxyBase.d.ts +35 -0
  128. package/lib/deltaManagerProxyBase.d.ts.map +1 -0
  129. package/lib/deltaManagerProxyBase.js +73 -0
  130. package/lib/deltaManagerProxyBase.js.map +1 -0
  131. package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
  132. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  133. package/lib/deltaManagerSummarizerProxy.js +1 -1
  134. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  135. package/lib/gc/garbageCollection.js +17 -20
  136. package/lib/gc/garbageCollection.js.map +1 -1
  137. package/lib/gc/gcConfigs.js +13 -11
  138. package/lib/gc/gcConfigs.js.map +1 -1
  139. package/lib/gc/gcHelpers.js +4 -6
  140. package/lib/gc/gcHelpers.js.map +1 -1
  141. package/lib/gc/gcSummaryStateTracker.js +4 -6
  142. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  143. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  144. package/lib/gc/gcTelemetry.js +55 -37
  145. package/lib/gc/gcTelemetry.js.map +1 -1
  146. package/lib/id-compressor/idCompressor.js +49 -51
  147. package/lib/id-compressor/idCompressor.js.map +1 -1
  148. package/lib/id-compressor/idRange.js +2 -2
  149. package/lib/id-compressor/idRange.js.map +1 -1
  150. package/lib/id-compressor/sessionIdNormalizer.js +11 -16
  151. package/lib/id-compressor/sessionIdNormalizer.js.map +1 -1
  152. package/lib/index.d.ts +1 -1
  153. package/lib/index.d.ts.map +1 -1
  154. package/lib/index.js.map +1 -1
  155. package/lib/opLifecycle/batchManager.js +10 -6
  156. package/lib/opLifecycle/batchManager.js.map +1 -1
  157. package/lib/opLifecycle/opCompressor.js +6 -1
  158. package/lib/opLifecycle/opCompressor.js.map +1 -1
  159. package/lib/opLifecycle/opDecompressor.js +11 -9
  160. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  161. package/lib/opLifecycle/opGroupingManager.js +13 -5
  162. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  163. package/lib/opLifecycle/opSplitter.js +10 -6
  164. package/lib/opLifecycle/opSplitter.js.map +1 -1
  165. package/lib/opLifecycle/outbox.js +1 -2
  166. package/lib/opLifecycle/outbox.js.map +1 -1
  167. package/lib/opLifecycle/remoteMessageProcessor.js +1 -1
  168. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  169. package/lib/opProperties.js +1 -2
  170. package/lib/opProperties.js.map +1 -1
  171. package/lib/packageVersion.d.ts +1 -1
  172. package/lib/packageVersion.js +1 -1
  173. package/lib/packageVersion.js.map +1 -1
  174. package/lib/pendingStateManager.d.ts +2 -2
  175. package/lib/pendingStateManager.d.ts.map +1 -1
  176. package/lib/pendingStateManager.js +22 -22
  177. package/lib/pendingStateManager.js.map +1 -1
  178. package/lib/scheduleManager.js +14 -10
  179. package/lib/scheduleManager.js.map +1 -1
  180. package/lib/summary/orderedClientElection.d.ts +2 -1
  181. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  182. package/lib/summary/orderedClientElection.js +17 -18
  183. package/lib/summary/orderedClientElection.js.map +1 -1
  184. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  185. package/lib/summary/runningSummarizer.js +35 -57
  186. package/lib/summary/runningSummarizer.js.map +1 -1
  187. package/lib/summary/summarizer.js +4 -7
  188. package/lib/summary/summarizer.js.map +1 -1
  189. package/lib/summary/summarizerClientElection.js +5 -9
  190. package/lib/summary/summarizerClientElection.js.map +1 -1
  191. package/lib/summary/summarizerHeuristics.js +8 -12
  192. package/lib/summary/summarizerHeuristics.js.map +1 -1
  193. package/lib/summary/summarizerNode/summarizerNode.js +22 -15
  194. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  195. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  196. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  197. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +17 -16
  198. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  199. package/lib/summary/summaryCollection.js +3 -5
  200. package/lib/summary/summaryCollection.js.map +1 -1
  201. package/lib/summary/summaryFormat.js +1 -2
  202. package/lib/summary/summaryFormat.js.map +1 -1
  203. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  204. package/lib/summary/summaryGenerator.js +62 -21
  205. package/lib/summary/summaryGenerator.js.map +1 -1
  206. package/lib/summary/summaryManager.js +3 -5
  207. package/lib/summary/summaryManager.js.map +1 -1
  208. package/package.json +19 -19
  209. package/src/batchTracker.ts +2 -1
  210. package/src/blobManager.ts +43 -2
  211. package/src/containerRuntime.ts +95 -67
  212. package/src/dataStore.ts +7 -1
  213. package/src/dataStoreContext.ts +1 -2
  214. package/src/dataStores.ts +95 -55
  215. package/src/deltaManagerProxyBase.ts +111 -0
  216. package/src/deltaManagerSummarizerProxy.ts +2 -1
  217. package/src/gc/gcTelemetry.ts +1 -2
  218. package/src/index.ts +0 -1
  219. package/src/packageVersion.ts +1 -1
  220. package/src/pendingStateManager.ts +12 -15
  221. package/src/summary/orderedClientElection.ts +2 -1
  222. package/src/summary/runningSummarizer.ts +9 -31
  223. package/src/summary/summaryGenerator.ts +0 -1
@@ -15,7 +15,6 @@ import { getGCVersion, shouldAllowGcSweep } from "./gcHelpers";
15
15
  * @returns The garbage collector configurations.
16
16
  */
17
17
  export function generateGCConfigs(mc, createParams) {
18
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
19
18
  let gcEnabled;
20
19
  let sessionExpiryTimeoutMs;
21
20
  let sweepTimeoutMs;
@@ -33,10 +32,10 @@ export function generateGCConfigs(mc, createParams) {
33
32
  // Existing documents which did not have createParams.metadata blob or had GC disabled have version as 0. For all
34
33
  // other existing documents, GC is enabled.
35
34
  gcEnabled = gcVersionInBaseSnapshot > 0;
36
- sessionExpiryTimeoutMs = (_a = createParams.metadata) === null || _a === void 0 ? void 0 : _a.sessionExpiryTimeoutMs;
35
+ sessionExpiryTimeoutMs = createParams.metadata?.sessionExpiryTimeoutMs;
37
36
  sweepTimeoutMs =
38
- (_c = (_b = createParams.metadata) === null || _b === void 0 ? void 0 : _b.sweepTimeoutMs) !== null && _c !== void 0 ? _c : computeSweepTimeout(sessionExpiryTimeoutMs); // Backfill old documents that didn't persist this
39
- persistedGcFeatureMatrix = (_d = createParams.metadata) === null || _d === void 0 ? void 0 : _d.gcFeatureMatrix;
37
+ createParams.metadata?.sweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs); // Backfill old documents that didn't persist this
38
+ persistedGcFeatureMatrix = createParams.metadata?.gcFeatureMatrix;
40
39
  }
41
40
  else {
42
41
  const tombstoneGeneration = createParams.gcOptions[gcTombstoneGenerationOptionName];
@@ -53,9 +52,9 @@ export function generateGCConfigs(mc, createParams) {
53
52
  // Set the Session Expiry if GC is enabled and session expiry flag isn't explicitly set to false.
54
53
  if (gcEnabled && mc.config.getBoolean(runSessionExpiryKey) !== false) {
55
54
  sessionExpiryTimeoutMs =
56
- (_e = createParams.gcOptions.sessionExpiryTimeoutMs) !== null && _e !== void 0 ? _e : defaultSessionExpiryDurationMs;
55
+ createParams.gcOptions.sessionExpiryTimeoutMs ?? defaultSessionExpiryDurationMs;
57
56
  }
58
- sweepTimeoutMs = testOverrideSweepTimeoutMs !== null && testOverrideSweepTimeoutMs !== void 0 ? testOverrideSweepTimeoutMs : computeSweepTimeout(sessionExpiryTimeoutMs);
57
+ sweepTimeoutMs = testOverrideSweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs);
59
58
  if (tombstoneGeneration !== undefined || sweepGeneration !== undefined) {
60
59
  persistedGcFeatureMatrix = {
61
60
  tombstoneGeneration,
@@ -64,7 +63,7 @@ export function generateGCConfigs(mc, createParams) {
64
63
  }
65
64
  }
66
65
  // Is sweepEnabled for this document?
67
- const sweepEnabled = shouldAllowGcSweep(persistedGcFeatureMatrix !== null && persistedGcFeatureMatrix !== void 0 ? persistedGcFeatureMatrix : {} /* persistedGenerations */, createParams.gcOptions[gcSweepGenerationOptionName] /* currentGeneration */);
66
+ const sweepEnabled = shouldAllowGcSweep(persistedGcFeatureMatrix ?? {} /* persistedGenerations */, createParams.gcOptions[gcSweepGenerationOptionName] /* currentGeneration */);
68
67
  // If version upgrade is not enabled, fall back to the stable GC version.
69
68
  const gcVersionInEffect = mc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;
70
69
  // The GC version is up-to-date if the GC version in effect is at least equal to the GC version in base snapshot.
@@ -78,7 +77,8 @@ export function generateGCConfigs(mc, createParams) {
78
77
  * 3. The current GC version should be greater of equal to the GC version in the base snapshot.
79
78
  * These conditions can be overridden via runGCKey feature flag.
80
79
  */
81
- const shouldRunGC = (_f = mc.config.getBoolean(runGCKey)) !== null && _f !== void 0 ? _f : (gcEnabled && !createParams.gcOptions.disableGC && isGCVersionUpToDate);
80
+ const shouldRunGC = mc.config.getBoolean(runGCKey) ??
81
+ (gcEnabled && !createParams.gcOptions.disableGC && isGCVersionUpToDate);
82
82
  /**
83
83
  * Whether sweep should run or not. The following conditions have to be met to run sweep:
84
84
  *
@@ -91,15 +91,17 @@ export function generateGCConfigs(mc, createParams) {
91
91
  */
92
92
  const shouldRunSweep = shouldRunGC &&
93
93
  sweepTimeoutMs !== undefined &&
94
- ((_g = mc.config.getBoolean(runSweepKey)) !== null && _g !== void 0 ? _g : sweepEnabled);
94
+ (mc.config.getBoolean(runSweepKey) ?? sweepEnabled);
95
95
  // Override inactive timeout if test config or gc options to override it is set.
96
- const inactiveTimeoutMs = (_j = (_h = mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _h !== void 0 ? _h : createParams.gcOptions.inactiveTimeoutMs) !== null && _j !== void 0 ? _j : defaultInactiveTimeoutMs;
96
+ const inactiveTimeoutMs = mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs") ??
97
+ createParams.gcOptions.inactiveTimeoutMs ??
98
+ defaultInactiveTimeoutMs;
97
99
  // Inactive timeout must be greater than sweep timeout since a node goes from active -> inactive -> sweep ready.
98
100
  if (sweepTimeoutMs !== undefined && inactiveTimeoutMs > sweepTimeoutMs) {
99
101
  throw new UsageError("inactive timeout should not be greater than the sweep timeout");
100
102
  }
101
103
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
102
- const testMode = (_k = mc.config.getBoolean(gcTestModeKey)) !== null && _k !== void 0 ? _k : createParams.gcOptions.runGCInTestMode === true;
104
+ const testMode = mc.config.getBoolean(gcTestModeKey) ?? createParams.gcOptions.runGCInTestMode === true;
103
105
  // Whether we are running in tombstone mode. This is enabled by default if sweep won't run. It can be disabled
104
106
  // via feature flags.
105
107
  const tombstoneMode = !shouldRunSweep && mc.config.getBoolean(disableTombstoneKey) !== true;
@@ -1 +1 @@
1
- {"version":3,"file":"gcConfigs.js","sourceRoot":"","sources":["../../src/gc/gcConfigs.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 { UsageError } from \"@fluidframework/container-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport { IContainerRuntimeMetadata } from \"../summary\";\nimport {\n\tcurrentGCVersion,\n\tdefaultInactiveTimeoutMs,\n\tdefaultSessionExpiryDurationMs,\n\tdisableTombstoneKey,\n\tGCFeatureMatrix,\n\tgcSweepGenerationOptionName,\n\tgcTestModeKey,\n\tgcTombstoneGenerationOptionName,\n\tGCVersion,\n\tgcVersionUpgradeToV3Key,\n\tIGarbageCollectorConfigs,\n\tIGCRuntimeOptions,\n\tmaxSnapshotCacheExpiryMs,\n\toneDayMs,\n\trunGCKey,\n\trunSessionExpiryKey,\n\trunSweepKey,\n\tstableGCVersion,\n} from \"./gcDefinitions\";\nimport { getGCVersion, shouldAllowGcSweep } from \"./gcHelpers\";\n\n/**\n * Generates configurations for the Garbage Collector that it uses to determine what to run and how.\n * @param mc - The monitoring context for reading configs from the config provider.\n * @param createParams - The creation params:\n * gcOptions - The garbage collector runtime options.\n * metadata - The container runtime's createParams.metadata.\n * existing - Whether the container is new or an existing one.\n * @returns The garbage collector configurations.\n */\nexport function generateGCConfigs(\n\tmc: MonitoringContext,\n\tcreateParams: {\n\t\tgcOptions: IGCRuntimeOptions;\n\t\tmetadata: IContainerRuntimeMetadata | undefined;\n\t\texisting: boolean;\n\t},\n): IGarbageCollectorConfigs {\n\tlet gcEnabled: boolean;\n\tlet sessionExpiryTimeoutMs: number | undefined;\n\tlet sweepTimeoutMs: number | undefined;\n\tlet persistedGcFeatureMatrix: GCFeatureMatrix | undefined;\n\tlet gcVersionInBaseSnapshot: GCVersion | undefined;\n\n\t/**\n\t * The following GC state is enabled during container creation and cannot be changed throughout its lifetime:\n\t * 1. Whether running GC mark phase is allowed or not.\n\t * 2. Whether running GC sweep phase is allowed or not.\n\t * 3. Whether GC session expiry is enabled or not.\n\t * For existing containers, we get this information from the createParams.metadata blob of its summary.\n\t */\n\tif (createParams.existing) {\n\t\tgcVersionInBaseSnapshot = getGCVersion(createParams.metadata);\n\t\t// Existing documents which did not have createParams.metadata blob or had GC disabled have version as 0. For all\n\t\t// other existing documents, GC is enabled.\n\t\tgcEnabled = gcVersionInBaseSnapshot > 0;\n\t\tsessionExpiryTimeoutMs = createParams.metadata?.sessionExpiryTimeoutMs;\n\t\tsweepTimeoutMs =\n\t\t\tcreateParams.metadata?.sweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs); // Backfill old documents that didn't persist this\n\t\tpersistedGcFeatureMatrix = createParams.metadata?.gcFeatureMatrix;\n\t} else {\n\t\tconst tombstoneGeneration = createParams.gcOptions[gcTombstoneGenerationOptionName];\n\t\tconst sweepGeneration = createParams.gcOptions[gcSweepGenerationOptionName];\n\n\t\t// Sweep should not be enabled (via sweepGeneration value) without enabling GC mark phase.\n\t\tif (sweepGeneration !== undefined && createParams.gcOptions.gcAllowed === false) {\n\t\t\tthrow new UsageError(\"GC sweep phase cannot be enabled without enabling GC mark phase\");\n\t\t}\n\n\t\t// This Test Override only applies for new containers\n\t\tconst testOverrideSweepTimeoutMs = mc.config.getNumber(\n\t\t\t\"Fluid.GarbageCollection.TestOverride.SweepTimeoutMs\",\n\t\t);\n\n\t\t// For new documents, GC is enabled by default. It can be explicitly disabled by setting the gcAllowed\n\t\t// flag in GC options to false.\n\t\tgcEnabled = createParams.gcOptions.gcAllowed !== false;\n\n\t\t// Set the Session Expiry if GC is enabled and session expiry flag isn't explicitly set to false.\n\t\tif (gcEnabled && mc.config.getBoolean(runSessionExpiryKey) !== false) {\n\t\t\tsessionExpiryTimeoutMs =\n\t\t\t\tcreateParams.gcOptions.sessionExpiryTimeoutMs ?? defaultSessionExpiryDurationMs;\n\t\t}\n\t\tsweepTimeoutMs = testOverrideSweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs);\n\n\t\tif (tombstoneGeneration !== undefined || sweepGeneration !== undefined) {\n\t\t\tpersistedGcFeatureMatrix = {\n\t\t\t\ttombstoneGeneration,\n\t\t\t\tsweepGeneration,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Is sweepEnabled for this document?\n\tconst sweepEnabled = shouldAllowGcSweep(\n\t\tpersistedGcFeatureMatrix ?? {} /* persistedGenerations */,\n\t\tcreateParams.gcOptions[gcSweepGenerationOptionName] /* currentGeneration */,\n\t);\n\n\t// If version upgrade is not enabled, fall back to the stable GC version.\n\tconst gcVersionInEffect =\n\t\tmc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;\n\n\t// The GC version is up-to-date if the GC version in effect is at least equal to the GC version in base snapshot.\n\t// If it is not up-to-date, there is a newer version of GC out there which is more reliable than this. So, GC\n\t// should not run as it may produce incorrect / unreliable state.\n\tconst isGCVersionUpToDate =\n\t\tgcVersionInBaseSnapshot === undefined || gcVersionInEffect >= gcVersionInBaseSnapshot;\n\n\t/**\n\t * Whether GC should run or not. The following conditions have to be met to run sweep:\n\t * 1. GC should be enabled for this container.\n\t * 2. GC should not be disabled via disableGC GC option.\n\t * 3. The current GC version should be greater of equal to the GC version in the base snapshot.\n\t * These conditions can be overridden via runGCKey feature flag.\n\t */\n\tconst shouldRunGC =\n\t\tmc.config.getBoolean(runGCKey) ??\n\t\t(gcEnabled && !createParams.gcOptions.disableGC && isGCVersionUpToDate);\n\n\t/**\n\t * Whether sweep should run or not. The following conditions have to be met to run sweep:\n\t *\n\t * 1. Overall GC or mark phase must be enabled (this.configs.shouldRunGC).\n\t * 2. Sweep timeout should be available. Without this, we wouldn't know when an object should be deleted.\n\t * 3. The driver must implement the policy limiting the age of snapshots used for loading. Otherwise\n\t * the Sweep Timeout calculation is not valid. We use the persisted value to ensure consistency over time.\n\t * 4. Sweep should be enabled for this container. This can be overridden via runSweep\n\t * feature flag.\n\t */\n\tconst shouldRunSweep =\n\t\tshouldRunGC &&\n\t\tsweepTimeoutMs !== undefined &&\n\t\t(mc.config.getBoolean(runSweepKey) ?? sweepEnabled);\n\n\t// Override inactive timeout if test config or gc options to override it is set.\n\tconst inactiveTimeoutMs =\n\t\tmc.config.getNumber(\"Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs\") ??\n\t\tcreateParams.gcOptions.inactiveTimeoutMs ??\n\t\tdefaultInactiveTimeoutMs;\n\n\t// Inactive timeout must be greater than sweep timeout since a node goes from active -> inactive -> sweep ready.\n\tif (sweepTimeoutMs !== undefined && inactiveTimeoutMs > sweepTimeoutMs) {\n\t\tthrow new UsageError(\"inactive timeout should not be greater than the sweep timeout\");\n\t}\n\n\t// Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.\n\tconst testMode =\n\t\tmc.config.getBoolean(gcTestModeKey) ?? createParams.gcOptions.runGCInTestMode === true;\n\t// Whether we are running in tombstone mode. This is enabled by default if sweep won't run. It can be disabled\n\t// via feature flags.\n\tconst tombstoneMode = !shouldRunSweep && mc.config.getBoolean(disableTombstoneKey) !== true;\n\tconst runFullGC = createParams.gcOptions.runFullGC;\n\n\treturn {\n\t\tgcEnabled,\n\t\tsweepEnabled,\n\t\tshouldRunGC,\n\t\tshouldRunSweep,\n\t\trunFullGC,\n\t\ttestMode,\n\t\ttombstoneMode,\n\t\tsessionExpiryTimeoutMs,\n\t\tsweepTimeoutMs,\n\t\tinactiveTimeoutMs,\n\t\tpersistedGcFeatureMatrix,\n\t\tgcVersionInBaseSnapshot,\n\t\tgcVersionInEffect,\n\t};\n}\n\n/**\n * Sweep timeout is the time after which unreferenced content can be swept.\n * Sweep timeout = session expiry timeout + snapshot cache expiry timeout + one day buffer.\n *\n * The snapshot cache expiry timeout cannot be known precisely but the upper bound is 5 days.\n * The buffer is added to account for any clock skew or other edge cases.\n * We use server timestamps throughout so the skew should be minimal but make it 1 day to be safe.\n */\nfunction computeSweepTimeout(sessionExpiryTimeoutMs: number | undefined): number | undefined {\n\tconst bufferMs = oneDayMs;\n\treturn sessionExpiryTimeoutMs && sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs;\n}\n"]}
1
+ {"version":3,"file":"gcConfigs.js","sourceRoot":"","sources":["../../src/gc/gcConfigs.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 { UsageError } from \"@fluidframework/container-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport { IContainerRuntimeMetadata } from \"../summary\";\nimport {\n\tcurrentGCVersion,\n\tdefaultInactiveTimeoutMs,\n\tdefaultSessionExpiryDurationMs,\n\tdisableTombstoneKey,\n\tGCFeatureMatrix,\n\tgcSweepGenerationOptionName,\n\tgcTestModeKey,\n\tgcTombstoneGenerationOptionName,\n\tGCVersion,\n\tgcVersionUpgradeToV3Key,\n\tIGarbageCollectorConfigs,\n\tIGCRuntimeOptions,\n\tmaxSnapshotCacheExpiryMs,\n\toneDayMs,\n\trunGCKey,\n\trunSessionExpiryKey,\n\trunSweepKey,\n\tstableGCVersion,\n} from \"./gcDefinitions\";\nimport { getGCVersion, shouldAllowGcSweep } from \"./gcHelpers\";\n\n/**\n * Generates configurations for the Garbage Collector that it uses to determine what to run and how.\n * @param mc - The monitoring context for reading configs from the config provider.\n * @param createParams - The creation params:\n * gcOptions - The garbage collector runtime options.\n * metadata - The container runtime's createParams.metadata.\n * existing - Whether the container is new or an existing one.\n * @returns The garbage collector configurations.\n */\nexport function generateGCConfigs(\n\tmc: MonitoringContext,\n\tcreateParams: {\n\t\tgcOptions: IGCRuntimeOptions;\n\t\tmetadata: IContainerRuntimeMetadata | undefined;\n\t\texisting: boolean;\n\t},\n): IGarbageCollectorConfigs {\n\tlet gcEnabled: boolean;\n\tlet sessionExpiryTimeoutMs: number | undefined;\n\tlet sweepTimeoutMs: number | undefined;\n\tlet persistedGcFeatureMatrix: GCFeatureMatrix | undefined;\n\tlet gcVersionInBaseSnapshot: GCVersion | undefined;\n\n\t/**\n\t * The following GC state is enabled during container creation and cannot be changed throughout its lifetime:\n\t * 1. Whether running GC mark phase is allowed or not.\n\t * 2. Whether running GC sweep phase is allowed or not.\n\t * 3. Whether GC session expiry is enabled or not.\n\t * For existing containers, we get this information from the createParams.metadata blob of its summary.\n\t */\n\tif (createParams.existing) {\n\t\tgcVersionInBaseSnapshot = getGCVersion(createParams.metadata);\n\t\t// Existing documents which did not have createParams.metadata blob or had GC disabled have version as 0. For all\n\t\t// other existing documents, GC is enabled.\n\t\tgcEnabled = gcVersionInBaseSnapshot > 0;\n\t\tsessionExpiryTimeoutMs = createParams.metadata?.sessionExpiryTimeoutMs;\n\t\tsweepTimeoutMs =\n\t\t\tcreateParams.metadata?.sweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs); // Backfill old documents that didn't persist this\n\t\tpersistedGcFeatureMatrix = createParams.metadata?.gcFeatureMatrix;\n\t} else {\n\t\tconst tombstoneGeneration = createParams.gcOptions[gcTombstoneGenerationOptionName];\n\t\tconst sweepGeneration = createParams.gcOptions[gcSweepGenerationOptionName];\n\n\t\t// Sweep should not be enabled (via sweepGeneration value) without enabling GC mark phase.\n\t\tif (sweepGeneration !== undefined && createParams.gcOptions.gcAllowed === false) {\n\t\t\tthrow new UsageError(\"GC sweep phase cannot be enabled without enabling GC mark phase\");\n\t\t}\n\n\t\t// This Test Override only applies for new containers\n\t\tconst testOverrideSweepTimeoutMs = mc.config.getNumber(\n\t\t\t\"Fluid.GarbageCollection.TestOverride.SweepTimeoutMs\",\n\t\t);\n\n\t\t// For new documents, GC is enabled by default. It can be explicitly disabled by setting the gcAllowed\n\t\t// flag in GC options to false.\n\t\tgcEnabled = createParams.gcOptions.gcAllowed !== false;\n\n\t\t// Set the Session Expiry if GC is enabled and session expiry flag isn't explicitly set to false.\n\t\tif (gcEnabled && mc.config.getBoolean(runSessionExpiryKey) !== false) {\n\t\t\tsessionExpiryTimeoutMs =\n\t\t\t\tcreateParams.gcOptions.sessionExpiryTimeoutMs ?? defaultSessionExpiryDurationMs;\n\t\t}\n\t\tsweepTimeoutMs = testOverrideSweepTimeoutMs ?? computeSweepTimeout(sessionExpiryTimeoutMs);\n\n\t\tif (tombstoneGeneration !== undefined || sweepGeneration !== undefined) {\n\t\t\tpersistedGcFeatureMatrix = {\n\t\t\t\ttombstoneGeneration,\n\t\t\t\tsweepGeneration,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Is sweepEnabled for this document?\n\tconst sweepEnabled = shouldAllowGcSweep(\n\t\tpersistedGcFeatureMatrix ?? {} /* persistedGenerations */,\n\t\tcreateParams.gcOptions[gcSweepGenerationOptionName] /* currentGeneration */,\n\t);\n\n\t// If version upgrade is not enabled, fall back to the stable GC version.\n\tconst gcVersionInEffect =\n\t\tmc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;\n\n\t// The GC version is up-to-date if the GC version in effect is at least equal to the GC version in base snapshot.\n\t// If it is not up-to-date, there is a newer version of GC out there which is more reliable than this. So, GC\n\t// should not run as it may produce incorrect / unreliable state.\n\tconst isGCVersionUpToDate =\n\t\tgcVersionInBaseSnapshot === undefined || gcVersionInEffect >= gcVersionInBaseSnapshot;\n\n\t/**\n\t * Whether GC should run or not. The following conditions have to be met to run sweep:\n\t * 1. GC should be enabled for this container.\n\t * 2. GC should not be disabled via disableGC GC option.\n\t * 3. The current GC version should be greater of equal to the GC version in the base snapshot.\n\t * These conditions can be overridden via runGCKey feature flag.\n\t */\n\tconst shouldRunGC =\n\t\tmc.config.getBoolean(runGCKey) ??\n\t\t(gcEnabled && !createParams.gcOptions.disableGC && isGCVersionUpToDate);\n\n\t/**\n\t * Whether sweep should run or not. The following conditions have to be met to run sweep:\n\t *\n\t * 1. Overall GC or mark phase must be enabled (this.configs.shouldRunGC).\n\t * 2. Sweep timeout should be available. Without this, we wouldn't know when an object should be deleted.\n\t * 3. The driver must implement the policy limiting the age of snapshots used for loading. Otherwise\n\t * the Sweep Timeout calculation is not valid. We use the persisted value to ensure consistency over time.\n\t * 4. Sweep should be enabled for this container. This can be overridden via runSweep\n\t * feature flag.\n\t */\n\tconst shouldRunSweep =\n\t\tshouldRunGC &&\n\t\tsweepTimeoutMs !== undefined &&\n\t\t(mc.config.getBoolean(runSweepKey) ?? sweepEnabled);\n\n\t// Override inactive timeout if test config or gc options to override it is set.\n\tconst inactiveTimeoutMs =\n\t\tmc.config.getNumber(\"Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs\") ??\n\t\tcreateParams.gcOptions.inactiveTimeoutMs ??\n\t\tdefaultInactiveTimeoutMs;\n\n\t// Inactive timeout must be greater than sweep timeout since a node goes from active -> inactive -> sweep ready.\n\tif (sweepTimeoutMs !== undefined && inactiveTimeoutMs > sweepTimeoutMs) {\n\t\tthrow new UsageError(\"inactive timeout should not be greater than the sweep timeout\");\n\t}\n\n\t// Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.\n\tconst testMode =\n\t\tmc.config.getBoolean(gcTestModeKey) ?? createParams.gcOptions.runGCInTestMode === true;\n\t// Whether we are running in tombstone mode. This is enabled by default if sweep won't run. It can be disabled\n\t// via feature flags.\n\tconst tombstoneMode = !shouldRunSweep && mc.config.getBoolean(disableTombstoneKey) !== true;\n\tconst runFullGC = createParams.gcOptions.runFullGC;\n\n\treturn {\n\t\tgcEnabled,\n\t\tsweepEnabled,\n\t\tshouldRunGC,\n\t\tshouldRunSweep,\n\t\trunFullGC,\n\t\ttestMode,\n\t\ttombstoneMode,\n\t\tsessionExpiryTimeoutMs,\n\t\tsweepTimeoutMs,\n\t\tinactiveTimeoutMs,\n\t\tpersistedGcFeatureMatrix,\n\t\tgcVersionInBaseSnapshot,\n\t\tgcVersionInEffect,\n\t};\n}\n\n/**\n * Sweep timeout is the time after which unreferenced content can be swept.\n * Sweep timeout = session expiry timeout + snapshot cache expiry timeout + one day buffer.\n *\n * The snapshot cache expiry timeout cannot be known precisely but the upper bound is 5 days.\n * The buffer is added to account for any clock skew or other edge cases.\n * We use server timestamps throughout so the skew should be minimal but make it 1 day to be safe.\n */\nfunction computeSweepTimeout(sessionExpiryTimeoutMs: number | undefined): number | undefined {\n\tconst bufferMs = oneDayMs;\n\treturn sessionExpiryTimeoutMs && sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs;\n}\n"]}
@@ -6,12 +6,11 @@ import { assert } from "@fluidframework/common-utils";
6
6
  import { gcBlobPrefix, gcDeletedBlobKey, gcTombstoneBlobKey, } from "@fluidframework/runtime-definitions";
7
7
  import { TelemetryDataTag } from "@fluidframework/telemetry-utils";
8
8
  export function getGCVersion(metadata) {
9
- var _a;
10
9
  if (!metadata) {
11
10
  // Force to 0/disallowed in prior versions
12
11
  return 0;
13
12
  }
14
- return (_a = metadata.gcFeature) !== null && _a !== void 0 ? _a : 0;
13
+ return metadata.gcFeature ?? 0;
15
14
  }
16
15
  /**
17
16
  * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted
@@ -79,7 +78,6 @@ export function generateSortedGCState(gcState) {
79
78
  * Concatenates the given GC states and returns the concatenated GC state.
80
79
  */
81
80
  export function concatGarbageCollectionStates(gcState1, gcState2) {
82
- var _a;
83
81
  const combinedGCNodes = {};
84
82
  for (const [nodeId, nodeData] of Object.entries(gcState1.gcNodes)) {
85
83
  combinedGCNodes[nodeId] = {
@@ -105,7 +103,7 @@ export function concatGarbageCollectionStates(gcState1, gcState2) {
105
103
  outboundRoutes: [
106
104
  ...new Set([...nodeData.outboundRoutes, ...combineNodeData.outboundRoutes]),
107
105
  ],
108
- unreferencedTimestampMs: (_a = nodeData.unreferencedTimestampMs) !== null && _a !== void 0 ? _a : combineNodeData.unreferencedTimestampMs,
106
+ unreferencedTimestampMs: nodeData.unreferencedTimestampMs ?? combineNodeData.unreferencedTimestampMs,
109
107
  };
110
108
  }
111
109
  combinedGCNodes[nodeId] = combineNodeData;
@@ -122,7 +120,7 @@ export function concatGarbageCollectionStates(gcState1, gcState2) {
122
120
  export function cloneGCData(gcData, filter) {
123
121
  const clonedGCNodes = {};
124
122
  for (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {
125
- if ((filter === null || filter === void 0 ? void 0 : filter(id)) !== true) {
123
+ if (filter?.(id) !== true) {
126
124
  clonedGCNodes[id] = Array.from(outboundRoutes);
127
125
  }
128
126
  }
@@ -224,7 +222,7 @@ export function unpackChildNodesGCDetails(gcDetails) {
224
222
  const childId = route.split("/")[1];
225
223
  const childUsedRoute = route.slice(childId.length + 1);
226
224
  const childGCDetails = childGCDetailsMap.get(childId);
227
- assert((childGCDetails === null || childGCDetails === void 0 ? void 0 : childGCDetails.usedRoutes) !== undefined, 0x5dc /* This should have be initialized when generate GC nodes above */);
225
+ assert(childGCDetails?.usedRoutes !== undefined, 0x5dc /* This should have be initialized when generate GC nodes above */);
228
226
  childGCDetails.usedRoutes.push(childUsedRoute);
229
227
  childGCDetailsMap.set(childId, childGCDetails);
230
228
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gcHelpers.js","sourceRoot":"","sources":["../../src/gc/gcHelpers.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 { assert } from \"@fluidframework/common-utils\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n} from \"@fluidframework/runtime-definitions\";\nimport { TelemetryDataTag } from \"@fluidframework/telemetry-utils\";\nimport { GCFeatureMatrix, GCVersion, IGCMetadata } from \"./gcDefinitions\";\nimport {\n\tIGarbageCollectionNodeData,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n} from \"./gcSummaryDefinitions\";\n\nexport function getGCVersion(metadata?: IGCMetadata): GCVersion {\n\tif (!metadata) {\n\t\t// Force to 0/disallowed in prior versions\n\t\treturn 0;\n\t}\n\treturn metadata.gcFeature ?? 0;\n}\n\n/**\n * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted\n * TombstoneGeneration values\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Tombstone (Failing on Tombstone load/usage) would cause legitimate data loss,\n * the container author may increment the generation value for Tombstone such that containers created\n * with a different value will not be subjected to GC enforcement.\n *\n * If no generation is provided at runtime, this defaults to return true to maintain expected default behavior\n *\n * @param persistedGeneration - The persisted tombstoneGeneration value\n * @param currentGeneration - The current app-provided tombstoneGeneration value\n * @returns true if GC Tombstone enforcement (Fail on Tombstone load/usage) should be allowed for this document\n */\nexport function shouldAllowGcTombstoneEnforcement(\n\tpersistedGeneration: number | undefined,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, then we should default to letting Tombstone feature behave as intended.\n\tif (currentGeneration === undefined) {\n\t\treturn true;\n\t}\n\treturn persistedGeneration === currentGeneration;\n}\n\n/**\n * Indicates whether Sweep is allowed for this document based on the GC Feature Matrix and current SweepGeneration\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Sweep would cause legitimate data loss, the container author may increment the generation value for Sweep\n * such that containers created with a different value will not be subjected to GC Sweep.\n *\n * If no generation is provided, Sweep will be disabled.\n * Passing 0 is a special case: Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.\n *\n * @param persistedGenerations - The persisted sweep/tombstone generations from the GC Feature Matrix\n * @param currentGeneration - The current app-provided sweepGeneration value\n * @returns true if GC Sweep should be allowed for this document\n */\nexport function shouldAllowGcSweep(\n\tpersistedGenerations: Pick<GCFeatureMatrix, \"sweepGeneration\" | \"tombstoneGeneration\">,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, default to false\n\tif (currentGeneration === undefined) {\n\t\treturn false;\n\t}\n\n\t// 0 is a special case: It matches both SweepGeneration and TombstoneGeneration\n\t// This is an optimistic measure to maximize coverage of GC Sweep if no bumps to TombstoneGeneration are needed before enabling Sweep.\n\tif (currentGeneration === 0) {\n\t\treturn (\n\t\t\tpersistedGenerations.sweepGeneration === 0 ||\n\t\t\tpersistedGenerations.tombstoneGeneration === 0\n\t\t);\n\t}\n\n\treturn persistedGenerations.sweepGeneration === currentGeneration;\n}\n\n/**\n * Sorts the given GC state as per the id of the GC nodes. It also sorts the outbound routes array of each node.\n */\nexport function generateSortedGCState(gcState: IGarbageCollectionState): IGarbageCollectionState {\n\tconst sortableArray: [string, IGarbageCollectionNodeData][] = Object.entries(gcState.gcNodes);\n\tsortableArray.sort(([a], [b]) => a.localeCompare(b));\n\tconst sortedGCState: IGarbageCollectionState = { gcNodes: {} };\n\tfor (const [nodeId, nodeData] of sortableArray) {\n\t\tnodeData.outboundRoutes.sort();\n\t\tsortedGCState.gcNodes[nodeId] = nodeData;\n\t}\n\treturn sortedGCState;\n}\n\n/**\n * Concatenates the given GC states and returns the concatenated GC state.\n */\nexport function concatGarbageCollectionStates(\n\tgcState1: IGarbageCollectionState,\n\tgcState2: IGarbageCollectionState,\n): IGarbageCollectionState {\n\tconst combinedGCNodes: { [id: string]: IGarbageCollectionNodeData } = {};\n\tfor (const [nodeId, nodeData] of Object.entries(gcState1.gcNodes)) {\n\t\tcombinedGCNodes[nodeId] = {\n\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t};\n\t}\n\n\tfor (const [nodeId, nodeData] of Object.entries(gcState2.gcNodes)) {\n\t\tlet combineNodeData = combinedGCNodes[nodeId];\n\t\tif (combineNodeData === undefined) {\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t} else {\n\t\t\t// Validate that same node doesn't have different unreferenced timestamp.\n\t\t\tif (\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined &&\n\t\t\t\tcombineNodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tassert(\n\t\t\t\t\tnodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,\n\t\t\t\t\t0x5d7 /* Two entries for the same GC node with different unreferenced timestamp */,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: [\n\t\t\t\t\t...new Set([...nodeData.outboundRoutes, ...combineNodeData.outboundRoutes]),\n\t\t\t\t],\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tnodeData.unreferencedTimestampMs ?? combineNodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\t\tcombinedGCNodes[nodeId] = combineNodeData;\n\t}\n\treturn { gcNodes: combinedGCNodes };\n}\n\n/**\n * Helper function that clones the GC data.\n * @param gcData - The GC data to clone.\n * @param filter - Optional function to filter out node ids not to be included in the cloned GC data. Returns\n * true to filter out nodes.\n * @returns a clone of the given GC data.\n */\nexport function cloneGCData(\n\tgcData: IGarbageCollectionData,\n\tfilter?: (id: string) => boolean,\n): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tif (filter?.(id) !== true) {\n\t\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\n\t\t}\n\t}\n\treturn {\n\t\tgcNodes: clonedGCNodes,\n\t};\n}\n\n/**\n * Concatenates the given GC data and returns the concatenated GC data.\n */\nexport function concatGarbageCollectionData(\n\tgcData1: IGarbageCollectionData,\n\tgcData2: IGarbageCollectionData,\n) {\n\tconst combinedGCData: IGarbageCollectionData = cloneGCData(gcData1);\n\tfor (const [id, routes] of Object.entries(gcData2.gcNodes)) {\n\t\tif (combinedGCData.gcNodes[id] === undefined) {\n\t\t\tcombinedGCData.gcNodes[id] = Array.from(routes);\n\t\t} else {\n\t\t\tconst combinedRoutes = [...routes, ...combinedGCData.gcNodes[id]];\n\t\t\tcombinedGCData.gcNodes[id] = [...new Set(combinedRoutes)];\n\t\t}\n\t}\n\treturn combinedGCData;\n}\n\n/**\n * Gets the base garbage collection state from the given snapshot tree. It contains GC state, deleted nodes and\n * tombstones. The GC state may be written into multiple blobs. Merge the GC state from all such blobs into one.\n */\nexport async function getGCDataFromSnapshot(\n\tgcSnapshotTree: ISnapshotTree,\n\treadAndParseBlob: <T>(id: string) => Promise<T>,\n): Promise<IGarbageCollectionSnapshotData> {\n\tlet rootGCState: IGarbageCollectionState = { gcNodes: {} };\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const key of Object.keys(gcSnapshotTree.blobs)) {\n\t\t// Update deleted nodes blob.\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update tombstone blob.\n\t\tif (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip blobs that do not start with the GC prefix.\n\t\tif (!key.startsWith(gcBlobPrefix)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst blobId = gcSnapshotTree.blobs[key];\n\t\tif (blobId === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n\t\tassert(gcState !== undefined, 0x5d8 /* GC blob missing from snapshot */);\n\t\t// Merge the GC state of this blob into the root GC state.\n\t\trootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n\t}\n\treturn { gcState: rootGCState, tombstones, deletedNodes };\n}\n\n/**\n * Helper function that unpacks the GC details of the children from a given node's GC details.\n * @param gcDetails - The GC details of a node.\n * @returns A map of GC details of each children of the the given node.\n */\nexport function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBase) {\n\tconst childGCDetailsMap: Map<string, IGarbageCollectionDetailsBase> = new Map();\n\n\t// If GC data is not available, bail out.\n\tif (gcDetails.gcData === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\tconst gcNodes = gcDetails.gcData.gcNodes;\n\tfor (const [id, outboundRoutes] of Object.entries(gcNodes)) {\n\t\t// Skip self-node since only children GC data is to be generated.\n\t\tif (id === \"/\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tassert(id.startsWith(\"/\"), 0x5d9 /* node id should always be an absolute route */);\n\t\tconst childId = id.split(\"/\")[1];\n\t\tlet childGCNodeId = id.slice(childId.length + 1);\n\t\t// GC node id always begins with \"/\". Handle the special case where a child's id in the parent's GC nodes is\n\t\t// of format `/root`. In this case, the childId is root and childGCNodeId is \"\". Make childGCNodeId = \"/\".\n\t\tif (childGCNodeId === \"\") {\n\t\t\tchildGCNodeId = \"/\";\n\t\t}\n\n\t\tlet childGCDetails = childGCDetailsMap.get(childId);\n\t\tif (childGCDetails === undefined) {\n\t\t\tchildGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };\n\t\t}\n\t\t// gcData should not undefined as its always at least initialized as empty above.\n\t\tassert(\n\t\t\tchildGCDetails.gcData !== undefined,\n\t\t\t0x5da /* Child GC data should have been initialized */,\n\t\t);\n\t\tchildGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\n\tif (gcDetails.usedRoutes === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\t// Remove the node's self used route, if any, and generate the children used routes.\n\tconst usedRoutes = gcDetails.usedRoutes.filter((route) => route !== \"\" && route !== \"/\");\n\tfor (const route of usedRoutes) {\n\t\tassert(route.startsWith(\"/\"), 0x5db /* Used route should always be an absolute route */);\n\t\tconst childId = route.split(\"/\")[1];\n\t\tconst childUsedRoute = route.slice(childId.length + 1);\n\n\t\tconst childGCDetails = childGCDetailsMap.get(childId);\n\t\tassert(\n\t\t\tchildGCDetails?.usedRoutes !== undefined,\n\t\t\t0x5dc /* This should have be initialized when generate GC nodes above */,\n\t\t);\n\n\t\tchildGCDetails.usedRoutes.push(childUsedRoute);\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\treturn childGCDetailsMap;\n}\n\n/**\n * Trims the leading and trailing slashes from the given string.\n * @param str - A string that may contain leading and / or trailing slashes.\n * @returns A new string without leading and trailing slashes.\n */\nexport function trimLeadingAndTrailingSlashes(str: string) {\n\treturn str.replace(/^\\/+|\\/+$/g, \"\");\n}\n\n/**\n * Tags the passed value as a CodeArtifact and returns the tagged value.\n * @deprecated - Use telemetry-utils tagCodeArtifacts instead\n */\nexport function tagAsCodeArtifact(value: string) {\n\treturn {\n\t\tvalue,\n\t\ttag: TelemetryDataTag.CodeArtifact,\n\t};\n}\n"]}
1
+ {"version":3,"file":"gcHelpers.js","sourceRoot":"","sources":["../../src/gc/gcHelpers.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 { assert } from \"@fluidframework/common-utils\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n} from \"@fluidframework/runtime-definitions\";\nimport { TelemetryDataTag } from \"@fluidframework/telemetry-utils\";\nimport { GCFeatureMatrix, GCVersion, IGCMetadata } from \"./gcDefinitions\";\nimport {\n\tIGarbageCollectionNodeData,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n} from \"./gcSummaryDefinitions\";\n\nexport function getGCVersion(metadata?: IGCMetadata): GCVersion {\n\tif (!metadata) {\n\t\t// Force to 0/disallowed in prior versions\n\t\treturn 0;\n\t}\n\treturn metadata.gcFeature ?? 0;\n}\n\n/**\n * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted\n * TombstoneGeneration values\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Tombstone (Failing on Tombstone load/usage) would cause legitimate data loss,\n * the container author may increment the generation value for Tombstone such that containers created\n * with a different value will not be subjected to GC enforcement.\n *\n * If no generation is provided at runtime, this defaults to return true to maintain expected default behavior\n *\n * @param persistedGeneration - The persisted tombstoneGeneration value\n * @param currentGeneration - The current app-provided tombstoneGeneration value\n * @returns true if GC Tombstone enforcement (Fail on Tombstone load/usage) should be allowed for this document\n */\nexport function shouldAllowGcTombstoneEnforcement(\n\tpersistedGeneration: number | undefined,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, then we should default to letting Tombstone feature behave as intended.\n\tif (currentGeneration === undefined) {\n\t\treturn true;\n\t}\n\treturn persistedGeneration === currentGeneration;\n}\n\n/**\n * Indicates whether Sweep is allowed for this document based on the GC Feature Matrix and current SweepGeneration\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Sweep would cause legitimate data loss, the container author may increment the generation value for Sweep\n * such that containers created with a different value will not be subjected to GC Sweep.\n *\n * If no generation is provided, Sweep will be disabled.\n * Passing 0 is a special case: Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.\n *\n * @param persistedGenerations - The persisted sweep/tombstone generations from the GC Feature Matrix\n * @param currentGeneration - The current app-provided sweepGeneration value\n * @returns true if GC Sweep should be allowed for this document\n */\nexport function shouldAllowGcSweep(\n\tpersistedGenerations: Pick<GCFeatureMatrix, \"sweepGeneration\" | \"tombstoneGeneration\">,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, default to false\n\tif (currentGeneration === undefined) {\n\t\treturn false;\n\t}\n\n\t// 0 is a special case: It matches both SweepGeneration and TombstoneGeneration\n\t// This is an optimistic measure to maximize coverage of GC Sweep if no bumps to TombstoneGeneration are needed before enabling Sweep.\n\tif (currentGeneration === 0) {\n\t\treturn (\n\t\t\tpersistedGenerations.sweepGeneration === 0 ||\n\t\t\tpersistedGenerations.tombstoneGeneration === 0\n\t\t);\n\t}\n\n\treturn persistedGenerations.sweepGeneration === currentGeneration;\n}\n\n/**\n * Sorts the given GC state as per the id of the GC nodes. It also sorts the outbound routes array of each node.\n */\nexport function generateSortedGCState(gcState: IGarbageCollectionState): IGarbageCollectionState {\n\tconst sortableArray: [string, IGarbageCollectionNodeData][] = Object.entries(gcState.gcNodes);\n\tsortableArray.sort(([a], [b]) => a.localeCompare(b));\n\tconst sortedGCState: IGarbageCollectionState = { gcNodes: {} };\n\tfor (const [nodeId, nodeData] of sortableArray) {\n\t\tnodeData.outboundRoutes.sort();\n\t\tsortedGCState.gcNodes[nodeId] = nodeData;\n\t}\n\treturn sortedGCState;\n}\n\n/**\n * Concatenates the given GC states and returns the concatenated GC state.\n */\nexport function concatGarbageCollectionStates(\n\tgcState1: IGarbageCollectionState,\n\tgcState2: IGarbageCollectionState,\n): IGarbageCollectionState {\n\tconst combinedGCNodes: { [id: string]: IGarbageCollectionNodeData } = {};\n\tfor (const [nodeId, nodeData] of Object.entries(gcState1.gcNodes)) {\n\t\tcombinedGCNodes[nodeId] = {\n\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t};\n\t}\n\n\tfor (const [nodeId, nodeData] of Object.entries(gcState2.gcNodes)) {\n\t\tlet combineNodeData = combinedGCNodes[nodeId];\n\t\tif (combineNodeData === undefined) {\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t} else {\n\t\t\t// Validate that same node doesn't have different unreferenced timestamp.\n\t\t\tif (\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined &&\n\t\t\t\tcombineNodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tassert(\n\t\t\t\t\tnodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,\n\t\t\t\t\t0x5d7 /* Two entries for the same GC node with different unreferenced timestamp */,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: [\n\t\t\t\t\t...new Set([...nodeData.outboundRoutes, ...combineNodeData.outboundRoutes]),\n\t\t\t\t],\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tnodeData.unreferencedTimestampMs ?? combineNodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\t\tcombinedGCNodes[nodeId] = combineNodeData;\n\t}\n\treturn { gcNodes: combinedGCNodes };\n}\n\n/**\n * Helper function that clones the GC data.\n * @param gcData - The GC data to clone.\n * @param filter - Optional function to filter out node ids not to be included in the cloned GC data. Returns\n * true to filter out nodes.\n * @returns a clone of the given GC data.\n */\nexport function cloneGCData(\n\tgcData: IGarbageCollectionData,\n\tfilter?: (id: string) => boolean,\n): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tif (filter?.(id) !== true) {\n\t\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\n\t\t}\n\t}\n\treturn {\n\t\tgcNodes: clonedGCNodes,\n\t};\n}\n\n/**\n * Concatenates the given GC data and returns the concatenated GC data.\n */\nexport function concatGarbageCollectionData(\n\tgcData1: IGarbageCollectionData,\n\tgcData2: IGarbageCollectionData,\n) {\n\tconst combinedGCData: IGarbageCollectionData = cloneGCData(gcData1);\n\tfor (const [id, routes] of Object.entries(gcData2.gcNodes)) {\n\t\tif (combinedGCData.gcNodes[id] === undefined) {\n\t\t\tcombinedGCData.gcNodes[id] = Array.from(routes);\n\t\t} else {\n\t\t\tconst combinedRoutes = [...routes, ...combinedGCData.gcNodes[id]];\n\t\t\tcombinedGCData.gcNodes[id] = [...new Set(combinedRoutes)];\n\t\t}\n\t}\n\treturn combinedGCData;\n}\n\n/**\n * Gets the base garbage collection state from the given snapshot tree. It contains GC state, deleted nodes and\n * tombstones. The GC state may be written into multiple blobs. Merge the GC state from all such blobs into one.\n */\nexport async function getGCDataFromSnapshot(\n\tgcSnapshotTree: ISnapshotTree,\n\treadAndParseBlob: <T>(id: string) => Promise<T>,\n): Promise<IGarbageCollectionSnapshotData> {\n\tlet rootGCState: IGarbageCollectionState = { gcNodes: {} };\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const key of Object.keys(gcSnapshotTree.blobs)) {\n\t\t// Update deleted nodes blob.\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update tombstone blob.\n\t\tif (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip blobs that do not start with the GC prefix.\n\t\tif (!key.startsWith(gcBlobPrefix)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst blobId = gcSnapshotTree.blobs[key];\n\t\tif (blobId === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n\t\tassert(gcState !== undefined, 0x5d8 /* GC blob missing from snapshot */);\n\t\t// Merge the GC state of this blob into the root GC state.\n\t\trootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n\t}\n\treturn { gcState: rootGCState, tombstones, deletedNodes };\n}\n\n/**\n * Helper function that unpacks the GC details of the children from a given node's GC details.\n * @param gcDetails - The GC details of a node.\n * @returns A map of GC details of each children of the the given node.\n */\nexport function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBase) {\n\tconst childGCDetailsMap: Map<string, IGarbageCollectionDetailsBase> = new Map();\n\n\t// If GC data is not available, bail out.\n\tif (gcDetails.gcData === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\tconst gcNodes = gcDetails.gcData.gcNodes;\n\tfor (const [id, outboundRoutes] of Object.entries(gcNodes)) {\n\t\t// Skip self-node since only children GC data is to be generated.\n\t\tif (id === \"/\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tassert(id.startsWith(\"/\"), 0x5d9 /* node id should always be an absolute route */);\n\t\tconst childId = id.split(\"/\")[1];\n\t\tlet childGCNodeId = id.slice(childId.length + 1);\n\t\t// GC node id always begins with \"/\". Handle the special case where a child's id in the parent's GC nodes is\n\t\t// of format `/root`. In this case, the childId is root and childGCNodeId is \"\". Make childGCNodeId = \"/\".\n\t\tif (childGCNodeId === \"\") {\n\t\t\tchildGCNodeId = \"/\";\n\t\t}\n\n\t\tlet childGCDetails = childGCDetailsMap.get(childId);\n\t\tif (childGCDetails === undefined) {\n\t\t\tchildGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };\n\t\t}\n\t\t// gcData should not undefined as its always at least initialized as empty above.\n\t\tassert(\n\t\t\tchildGCDetails.gcData !== undefined,\n\t\t\t0x5da /* Child GC data should have been initialized */,\n\t\t);\n\t\tchildGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\n\tif (gcDetails.usedRoutes === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\t// Remove the node's self used route, if any, and generate the children used routes.\n\tconst usedRoutes = gcDetails.usedRoutes.filter((route) => route !== \"\" && route !== \"/\");\n\tfor (const route of usedRoutes) {\n\t\tassert(route.startsWith(\"/\"), 0x5db /* Used route should always be an absolute route */);\n\t\tconst childId = route.split(\"/\")[1];\n\t\tconst childUsedRoute = route.slice(childId.length + 1);\n\n\t\tconst childGCDetails = childGCDetailsMap.get(childId);\n\t\tassert(\n\t\t\tchildGCDetails?.usedRoutes !== undefined,\n\t\t\t0x5dc /* This should have be initialized when generate GC nodes above */,\n\t\t);\n\n\t\tchildGCDetails.usedRoutes.push(childUsedRoute);\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\treturn childGCDetailsMap;\n}\n\n/**\n * Trims the leading and trailing slashes from the given string.\n * @param str - A string that may contain leading and / or trailing slashes.\n * @returns A new string without leading and trailing slashes.\n */\nexport function trimLeadingAndTrailingSlashes(str: string) {\n\treturn str.replace(/^\\/+|\\/+$/g, \"\");\n}\n\n/**\n * Tags the passed value as a CodeArtifact and returns the tagged value.\n * @deprecated - Use telemetry-utils tagCodeArtifacts instead\n */\nexport function tagAsCodeArtifact(value: string) {\n\treturn {\n\t\tvalue,\n\t\ttag: TelemetryDataTag.CodeArtifact,\n\t};\n}\n"]}
@@ -20,7 +20,6 @@ export class GCSummaryStateTracker {
20
20
  configs,
21
21
  // Tells whether GC was run in the base snapshot this container loaded from.
22
22
  wasGCRunInBaseSnapshot) {
23
- var _a;
24
23
  this.configs = configs;
25
24
  // Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced
26
25
  // to unreferenced or vice-versa.
@@ -29,7 +28,7 @@ export class GCSummaryStateTracker {
29
28
  // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the
30
29
  // latest tracked GC version. For new documents, we will be writing the first summary with the current version.
31
30
  this.latestSummaryGCVersion =
32
- (_a = this.configs.gcVersionInBaseSnapshot) !== null && _a !== void 0 ? _a : this.configs.gcVersionInEffect;
31
+ this.configs.gcVersionInBaseSnapshot ?? this.configs.gcVersionInEffect;
33
32
  }
34
33
  /**
35
34
  * Tells whether the GC state needs to be reset. This can happen under 3 conditions:
@@ -145,10 +144,9 @@ export class GCSummaryStateTracker {
145
144
  * @returns the GC summary tree.
146
145
  */
147
146
  buildGCSummaryTree(serializedGCState, serializedTombstones, serializedDeletedNodes, trackState) {
148
- var _a, _b, _c;
149
147
  const builder = new SummaryTreeBuilder();
150
148
  // If the GC state hasn't changed, write a summary handle, else write a summary blob for it.
151
- if (((_a = this.latestSummaryData) === null || _a === void 0 ? void 0 : _a.serializedGCState) === serializedGCState && trackState) {
149
+ if (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {
152
150
  builder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);
153
151
  }
154
152
  else {
@@ -157,7 +155,7 @@ export class GCSummaryStateTracker {
157
155
  // If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a
158
156
  // summary blob.
159
157
  if (serializedTombstones !== undefined) {
160
- if (((_b = this.latestSummaryData) === null || _b === void 0 ? void 0 : _b.serializedTombstones) === serializedTombstones &&
158
+ if (this.latestSummaryData?.serializedTombstones === serializedTombstones &&
161
159
  trackState) {
162
160
  builder.addHandle(gcTombstoneBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcTombstoneBlobKey}`);
163
161
  }
@@ -170,7 +168,7 @@ export class GCSummaryStateTracker {
170
168
  return builder.getSummaryTree();
171
169
  }
172
170
  // If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.
173
- if (((_c = this.latestSummaryData) === null || _c === void 0 ? void 0 : _c.serializedDeletedNodes) === serializedDeletedNodes &&
171
+ if (this.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&
174
172
  trackState) {
175
173
  builder.addHandle(gcDeletedBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcDeletedBlobKey}`);
176
174
  }
@@ -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 { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport { mergeStats, ReadAndParseBlob, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName, RefreshSummaryResult } from \"../summary\";\nimport { GCVersion, IGCStats } from \"./gcDefinitions\";\nimport { getGCDataFromSnapshot, generateSortedGCState, getGCVersion } from \"./gcHelpers\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { IGarbageCollectorConfigs } from \".\";\n\nexport const gcStateBlobKey = `${gcBlobPrefix}_root`;\n\n/**\n * The GC data that is tracked for a summary.\n */\nexport interface 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// 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\t// Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced\n\t// to unreferenced or vice-versa.\n\tpublic updatedDSCountSinceLastSummary: number = 0;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly configs: Pick<\n\t\t\tIGarbageCollectorConfigs,\n\t\t\t\"shouldRunGC\" | \"tombstoneMode\" | \"gcVersionInBaseSnapshot\" | \"gcVersionInEffect\"\n\t\t>,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\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 =\n\t\t\tthis.configs.gcVersionInBaseSnapshot ?? this.configs.gcVersionInEffect;\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 get doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.configs.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 get doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset ||\n\t\t\t(this.configs.shouldRunGC &&\n\t\t\t\tthis.latestSummaryGCVersion !== this.configs.gcVersionInEffect)\n\t\t);\n\t}\n\n\t/**\n\t * Called during GC initialization. Initialize the latest summary data from the base snapshot data.\n\t */\n\tpublic initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData) {\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: baseSnapshotData.gcState\n\t\t\t\t? JSON.stringify(generateSortedGCState(baseSnapshotData.gcState))\n\t\t\t\t: undefined,\n\t\t\tserializedTombstones: JSON.stringify(baseSnapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(baseSnapshotData.deletedNodes),\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.configs.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.configs.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\tthis.latestSummaryData.serializedDeletedNodes === serializedDeletedNodes\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 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.configs.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.configs.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.configs.gcVersionInEffect;\n\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\tthis.pendingSummaryData = undefined;\n\t\t\tthis.updatedDSCountSinceLastSummary = 0;\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\tconst metadata = metadataBlobId\n\t\t\t? await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId)\n\t\t\t: undefined;\n\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\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\n\t\tif (gcSnapshotTree === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet snapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t// If the GC version in the snapshot does not match the GC version currently in effect, the GC data\n\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes\n\t\t// because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The\n\t\t// deletedNodes info is needed to identify when these nodes are used.\n\t\tif (getGCVersion(metadata) !== this.configs.gcVersionInEffect) {\n\t\t\tsnapshotData = {\n\t\t\t\tgcState: undefined,\n\t\t\t\ttombstones: undefined,\n\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t};\n\t\t}\n\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: JSON.stringify(snapshotData.gcState),\n\t\t\tserializedTombstones: JSON.stringify(snapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(snapshotData.deletedNodes),\n\t\t};\n\t\treturn snapshotData;\n\t}\n\n\t/**\n\t * Called to update the state from a GC run's stats. Used to update the count of data stores whose state updated.\n\t */\n\tpublic updateStateFromGCRunStats(stats: IGCStats) {\n\t\tthis.updatedDSCountSinceLastSummary += stats.updatedDataStoreCount;\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 { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport { mergeStats, ReadAndParseBlob, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName, RefreshSummaryResult } from \"../summary\";\nimport { GCVersion, IGCStats } from \"./gcDefinitions\";\nimport { getGCDataFromSnapshot, generateSortedGCState, getGCVersion } from \"./gcHelpers\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { IGarbageCollectorConfigs } from \".\";\n\nexport const gcStateBlobKey = `${gcBlobPrefix}_root`;\n\n/**\n * The GC data that is tracked for a summary.\n */\nexport interface 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// 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\t// Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced\n\t// to unreferenced or vice-versa.\n\tpublic updatedDSCountSinceLastSummary: number = 0;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly configs: Pick<\n\t\t\tIGarbageCollectorConfigs,\n\t\t\t\"shouldRunGC\" | \"tombstoneMode\" | \"gcVersionInBaseSnapshot\" | \"gcVersionInEffect\"\n\t\t>,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\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 =\n\t\t\tthis.configs.gcVersionInBaseSnapshot ?? this.configs.gcVersionInEffect;\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 get doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.configs.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 get doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset ||\n\t\t\t(this.configs.shouldRunGC &&\n\t\t\t\tthis.latestSummaryGCVersion !== this.configs.gcVersionInEffect)\n\t\t);\n\t}\n\n\t/**\n\t * Called during GC initialization. Initialize the latest summary data from the base snapshot data.\n\t */\n\tpublic initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData) {\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: baseSnapshotData.gcState\n\t\t\t\t? JSON.stringify(generateSortedGCState(baseSnapshotData.gcState))\n\t\t\t\t: undefined,\n\t\t\tserializedTombstones: JSON.stringify(baseSnapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(baseSnapshotData.deletedNodes),\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.configs.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.configs.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\tthis.latestSummaryData.serializedDeletedNodes === serializedDeletedNodes\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 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.configs.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.configs.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.configs.gcVersionInEffect;\n\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\tthis.pendingSummaryData = undefined;\n\t\t\tthis.updatedDSCountSinceLastSummary = 0;\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\tconst metadata = metadataBlobId\n\t\t\t? await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId)\n\t\t\t: undefined;\n\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\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\n\t\tif (gcSnapshotTree === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet snapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t// If the GC version in the snapshot does not match the GC version currently in effect, the GC data\n\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes\n\t\t// because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The\n\t\t// deletedNodes info is needed to identify when these nodes are used.\n\t\tif (getGCVersion(metadata) !== this.configs.gcVersionInEffect) {\n\t\t\tsnapshotData = {\n\t\t\t\tgcState: undefined,\n\t\t\t\ttombstones: undefined,\n\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t};\n\t\t}\n\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: JSON.stringify(snapshotData.gcState),\n\t\t\tserializedTombstones: JSON.stringify(snapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(snapshotData.deletedNodes),\n\t\t};\n\t\treturn snapshotData;\n\t}\n\n\t/**\n\t * Called to update the state from a GC run's stats. Used to update the count of data stores whose state updated.\n\t */\n\tpublic updateStateFromGCRunStats(stats: IGCStats) {\n\t\tthis.updatedDSCountSinceLastSummary += stats.updatedDataStoreCount;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"gcTelemetry.d.ts","sourceRoot":"","sources":["../../src/gc/gcTelemetry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gcTelemetry.d.ts","sourceRoot":"","sources":["../../src/gc/gcTelemetry.ts"],"names":[],"mappings":"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"}
@@ -2,18 +2,6 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- var __rest = (this && this.__rest) || function (s, e) {
6
- var t = {};
7
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
8
- t[p] = s[p];
9
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
10
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
11
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
12
- t[p[i]] = s[p[i]];
13
- }
14
- return t;
15
- };
16
- import { packagePathToTelemetryProperty } from "@fluidframework/runtime-utils";
17
5
  import { generateStack, tagCodeArtifacts, } from "@fluidframework/telemetry-utils";
18
6
  import { disableSweepLogKey, GCNodeType, UnreferencedState, disableTombstoneKey, throwOnTombstoneUsageKey, throwOnTombstoneLoadKey, runSweepKey, } from "./gcDefinitions";
19
7
  import { tagAsCodeArtifact } from "./gcHelpers";
@@ -85,11 +73,19 @@ export class GCTelemetryTracker {
85
73
  // Add the unique event id so that we don't generate a log for this event again in this session..
86
74
  this.loggedUnreferencedEvents.add(uniqueEventId);
87
75
  const state = nodeStateTracker.state;
88
- const { usageType, currentReferenceTimestampMs, packagePath, id, fromId } = nodeUsageProps, propsToLog = __rest(nodeUsageProps, ["usageType", "currentReferenceTimestampMs", "packagePath", "id", "fromId"]);
89
- const eventProps = Object.assign(Object.assign(Object.assign({ type: nodeType, unrefTime: nodeStateTracker.unreferencedTimestampMs, age: nodeUsageProps.currentReferenceTimestampMs -
90
- nodeStateTracker.unreferencedTimestampMs, timeout: state === UnreferencedState.Inactive
76
+ const { usageType, currentReferenceTimestampMs, packagePath, id, fromId, ...propsToLog } = nodeUsageProps;
77
+ const eventProps = {
78
+ type: nodeType,
79
+ unrefTime: nodeStateTracker.unreferencedTimestampMs,
80
+ age: nodeUsageProps.currentReferenceTimestampMs -
81
+ nodeStateTracker.unreferencedTimestampMs,
82
+ timeout: state === UnreferencedState.Inactive
91
83
  ? this.configs.inactiveTimeoutMs
92
- : this.configs.sweepTimeoutMs }, tagCodeArtifacts({ id, fromId })), propsToLog), this.createContainerMetadata);
84
+ : this.configs.sweepTimeoutMs,
85
+ ...tagCodeArtifacts({ id, fromId }),
86
+ ...propsToLog,
87
+ ...this.createContainerMetadata,
88
+ };
93
89
  // This will log the following events:
94
90
  // GC_Tombstone_DataStore_Revived, GC_Tombstone_SubDataStore_Revived, GC_Tombstone_Blob_Revived
95
91
  if (nodeUsageProps.usageType === "Revived" && nodeUsageProps.isTombstoned) {
@@ -106,7 +102,11 @@ export class GCTelemetryTracker {
106
102
  // Inactive errors are usages of Objects that are unreferenced for at least a period of 7 days.
107
103
  // SweepReady errors are usages of Objects that will be deleted by GC Sweep!
108
104
  if (this.isSummarizerClient) {
109
- this.pendingEventsQueue.push(Object.assign(Object.assign({}, eventProps), { usageType: nodeUsageProps.usageType, state }));
105
+ this.pendingEventsQueue.push({
106
+ ...eventProps,
107
+ usageType: nodeUsageProps.usageType,
108
+ state,
109
+ });
110
110
  }
111
111
  else {
112
112
  // For non-summarizer clients, only log "Loaded" type events since these objects may not be loaded in the
@@ -114,14 +114,16 @@ export class GCTelemetryTracker {
114
114
  // Events generated:
115
115
  // InactiveObject_Loaded, SweepReadyObject_Loaded
116
116
  if (nodeUsageProps.usageType === "Loaded") {
117
- const { id: taggedId, fromId: taggedFromId } = eventProps, otherProps = __rest(eventProps, ["id", "fromId"]);
117
+ const { id: taggedId, fromId: taggedFromId, ...otherProps } = eventProps;
118
118
  const event = {
119
119
  eventName: `${state}Object_${nodeUsageProps.usageType}`,
120
- pkg: packagePathToTelemetryProperty(nodeUsageProps.packagePath),
120
+ pkg: tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }).pkg,
121
121
  stack: generateStack(),
122
122
  id: taggedId,
123
123
  fromId: taggedFromId,
124
- details: JSON.stringify(Object.assign({}, otherProps)),
124
+ details: JSON.stringify({
125
+ ...otherProps,
126
+ }),
125
127
  };
126
128
  // Do not log the inactive object x events as error events as they are not the best signal for
127
129
  // detecting something wrong with GC either from the partner or from the runtime itself.
@@ -147,10 +149,9 @@ export class GCTelemetryTracker {
147
149
  * @param explicitReferences - New references added explicity between the previous and the current run.
148
150
  */
149
151
  logIfMissingExplicitReferences(currentGCData, previousGCData, explicitReferences, logger) {
150
- var _a, _b;
151
152
  for (const [nodeId, currentOutboundRoutes] of Object.entries(currentGCData.gcNodes)) {
152
- const previousRoutes = (_a = previousGCData.gcNodes[nodeId]) !== null && _a !== void 0 ? _a : [];
153
- const explicitRoutes = (_b = explicitReferences.get(nodeId)) !== null && _b !== void 0 ? _b : [];
153
+ const previousRoutes = previousGCData.gcNodes[nodeId] ?? [];
154
+ const explicitRoutes = explicitReferences.get(nodeId) ?? [];
154
155
  /**
155
156
  * 1. For routes in the current GC data, routes that were not present in previous GC data and did not have
156
157
  * explicit references should be added to missing explicit routes list.
@@ -170,10 +171,13 @@ export class GCTelemetryTracker {
170
171
  }
171
172
  }
172
173
  if (missingExplicitRoutes.length > 0) {
173
- logger.sendErrorEvent(Object.assign({ eventName: "gcUnknownOutboundReferences" }, tagCodeArtifacts({
174
- id: nodeId,
175
- routes: JSON.stringify(missingExplicitRoutes),
176
- })));
174
+ logger.sendErrorEvent({
175
+ eventName: "gcUnknownOutboundReferences",
176
+ ...tagCodeArtifacts({
177
+ id: nodeId,
178
+ routes: JSON.stringify(missingExplicitRoutes),
179
+ }),
180
+ });
177
181
  }
178
182
  }
179
183
  }
@@ -188,7 +192,7 @@ export class GCTelemetryTracker {
188
192
  // InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
189
193
  // SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
190
194
  for (const eventProps of this.pendingEventsQueue) {
191
- const { usageType, state, id, fromId } = eventProps, propsToLog = __rest(eventProps, ["usageType", "state", "id", "fromId"]);
195
+ const { usageType, state, id, fromId, ...propsToLog } = eventProps;
192
196
  /**
193
197
  * Revived event is logged only if the node is active. If the node is not active, the reference to it was
194
198
  * from another unreferenced node and this scenario is not interesting to log.
@@ -203,11 +207,18 @@ export class GCTelemetryTracker {
203
207
  const fromPkg = eventProps.fromId
204
208
  ? await this.getNodePackagePath(eventProps.fromId.value)
205
209
  : undefined;
206
- const event = Object.assign({ eventName: `${state}Object_${usageType}`, details: JSON.stringify(Object.assign({}, propsToLog)), id,
207
- fromId }, tagCodeArtifacts({
208
- pkg: pkg === null || pkg === void 0 ? void 0 : pkg.join("/"),
209
- fromPkg: fromPkg === null || fromPkg === void 0 ? void 0 : fromPkg.join("/"),
210
- }));
210
+ const event = {
211
+ eventName: `${state}Object_${usageType}`,
212
+ details: JSON.stringify({
213
+ ...propsToLog,
214
+ }),
215
+ id,
216
+ fromId,
217
+ ...tagCodeArtifacts({
218
+ pkg: pkg?.join("/"),
219
+ fromPkg: fromPkg?.join("/"),
220
+ }),
221
+ };
211
222
  if (state === UnreferencedState.Inactive) {
212
223
  logger.sendTelemetryEvent(event);
213
224
  }
@@ -245,8 +256,16 @@ export class GCTelemetryTracker {
245
256
  deletedNodeIds.push(nodeId);
246
257
  }
247
258
  if (deletedNodeIds.length > 0) {
248
- logger.sendTelemetryEvent(Object.assign({ eventName: "GC_SweepReadyObjects_Delete", details: JSON.stringify(Object.assign({ timeout: this.configs.sweepTimeoutMs, completedGCRuns,
249
- lastSummaryTime }, this.createContainerMetadata)) }, tagCodeArtifacts({ id: JSON.stringify(deletedNodeIds) })));
259
+ logger.sendTelemetryEvent({
260
+ eventName: "GC_SweepReadyObjects_Delete",
261
+ details: JSON.stringify({
262
+ timeout: this.configs.sweepTimeoutMs,
263
+ completedGCRuns,
264
+ lastSummaryTime,
265
+ ...this.createContainerMetadata,
266
+ }),
267
+ ...tagCodeArtifacts({ id: JSON.stringify(deletedNodeIds) }),
268
+ });
250
269
  }
251
270
  }
252
271
  }
@@ -255,8 +274,7 @@ export class GCTelemetryTracker {
255
274
  * tombstoned or deleted object is loaded.
256
275
  */
257
276
  export function sendGCUnexpectedUsageEvent(mc, event, packagePath, error) {
258
- var _a;
259
- event.pkg = (_a = tagCodeArtifacts({ pkg: packagePath === null || packagePath === void 0 ? void 0 : packagePath.join("/") })) === null || _a === void 0 ? void 0 : _a.pkg;
277
+ event.pkg = tagCodeArtifacts({ pkg: packagePath?.join("/") })?.pkg;
260
278
  event.tombstoneFlags = JSON.stringify({
261
279
  DisableTombstone: mc.config.getBoolean(disableTombstoneKey),
262
280
  ThrowOnTombstoneUsage: mc.config.getBoolean(throwOnTombstoneUsageKey),