@fluidframework/container-runtime 2.0.0-internal.4.2.1 → 2.0.0-internal.4.3.1

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 (131) hide show
  1. package/dist/connectionTelemetry.d.ts.map +1 -1
  2. package/dist/connectionTelemetry.js +1 -0
  3. package/dist/connectionTelemetry.js.map +1 -1
  4. package/dist/containerRuntime.d.ts.map +1 -1
  5. package/dist/containerRuntime.js +9 -6
  6. package/dist/containerRuntime.js.map +1 -1
  7. package/dist/dataStores.d.ts +5 -5
  8. package/dist/dataStores.d.ts.map +1 -1
  9. package/dist/dataStores.js +3 -6
  10. package/dist/dataStores.js.map +1 -1
  11. package/dist/gc/garbageCollection.d.ts +1 -27
  12. package/dist/gc/garbageCollection.d.ts.map +1 -1
  13. package/dist/gc/garbageCollection.js +30 -227
  14. package/dist/gc/garbageCollection.js.map +1 -1
  15. package/dist/gc/gcHelpers.d.ts +0 -10
  16. package/dist/gc/gcHelpers.d.ts.map +1 -1
  17. package/dist/gc/gcHelpers.js +1 -20
  18. package/dist/gc/gcHelpers.js.map +1 -1
  19. package/dist/gc/gcTelemetry.d.ts +91 -0
  20. package/dist/gc/gcTelemetry.d.ts.map +1 -0
  21. package/dist/gc/gcTelemetry.js +262 -0
  22. package/dist/gc/gcTelemetry.js.map +1 -0
  23. package/dist/gc/index.d.ts +2 -1
  24. package/dist/gc/index.d.ts.map +1 -1
  25. package/dist/gc/index.js +4 -2
  26. package/dist/gc/index.js.map +1 -1
  27. package/dist/opLifecycle/opGroupingManager.js +1 -1
  28. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  29. package/dist/opLifecycle/outbox.js +1 -1
  30. package/dist/opLifecycle/outbox.js.map +1 -1
  31. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  32. package/dist/opLifecycle/remoteMessageProcessor.js +25 -22
  33. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  34. package/dist/packageVersion.d.ts +1 -1
  35. package/dist/packageVersion.js +1 -1
  36. package/dist/packageVersion.js.map +1 -1
  37. package/dist/pendingStateManager.d.ts +1 -1
  38. package/dist/pendingStateManager.d.ts.map +1 -1
  39. package/dist/pendingStateManager.js.map +1 -1
  40. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  41. package/dist/summary/orderedClientElection.js +14 -17
  42. package/dist/summary/orderedClientElection.js.map +1 -1
  43. package/dist/summary/summarizer.d.ts +2 -0
  44. package/dist/summary/summarizer.d.ts.map +1 -1
  45. package/dist/summary/summarizer.js +9 -4
  46. package/dist/summary/summarizer.js.map +1 -1
  47. package/dist/summary/summarizerHeuristics.d.ts +8 -9
  48. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  49. package/dist/summary/summarizerHeuristics.js +15 -16
  50. package/dist/summary/summarizerHeuristics.js.map +1 -1
  51. package/dist/summary/summarizerTypes.d.ts +2 -0
  52. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  53. package/dist/summary/summarizerTypes.js.map +1 -1
  54. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  55. package/dist/summary/summaryGenerator.js +4 -3
  56. package/dist/summary/summaryGenerator.js.map +1 -1
  57. package/lib/connectionTelemetry.d.ts.map +1 -1
  58. package/lib/connectionTelemetry.js +1 -0
  59. package/lib/connectionTelemetry.js.map +1 -1
  60. package/lib/containerRuntime.d.ts.map +1 -1
  61. package/lib/containerRuntime.js +9 -6
  62. package/lib/containerRuntime.js.map +1 -1
  63. package/lib/dataStores.d.ts +5 -5
  64. package/lib/dataStores.d.ts.map +1 -1
  65. package/lib/dataStores.js +3 -6
  66. package/lib/dataStores.js.map +1 -1
  67. package/lib/gc/garbageCollection.d.ts +1 -27
  68. package/lib/gc/garbageCollection.d.ts.map +1 -1
  69. package/lib/gc/garbageCollection.js +34 -231
  70. package/lib/gc/garbageCollection.js.map +1 -1
  71. package/lib/gc/gcHelpers.d.ts +0 -10
  72. package/lib/gc/gcHelpers.d.ts.map +1 -1
  73. package/lib/gc/gcHelpers.js +0 -18
  74. package/lib/gc/gcHelpers.js.map +1 -1
  75. package/lib/gc/gcTelemetry.d.ts +91 -0
  76. package/lib/gc/gcTelemetry.d.ts.map +1 -0
  77. package/lib/gc/gcTelemetry.js +257 -0
  78. package/lib/gc/gcTelemetry.js.map +1 -0
  79. package/lib/gc/index.d.ts +2 -1
  80. package/lib/gc/index.d.ts.map +1 -1
  81. package/lib/gc/index.js +2 -1
  82. package/lib/gc/index.js.map +1 -1
  83. package/lib/opLifecycle/opGroupingManager.js +1 -1
  84. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  85. package/lib/opLifecycle/outbox.js +1 -1
  86. package/lib/opLifecycle/outbox.js.map +1 -1
  87. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  88. package/lib/opLifecycle/remoteMessageProcessor.js +25 -22
  89. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  90. package/lib/packageVersion.d.ts +1 -1
  91. package/lib/packageVersion.js +1 -1
  92. package/lib/packageVersion.js.map +1 -1
  93. package/lib/pendingStateManager.d.ts +1 -1
  94. package/lib/pendingStateManager.d.ts.map +1 -1
  95. package/lib/pendingStateManager.js.map +1 -1
  96. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  97. package/lib/summary/orderedClientElection.js +14 -17
  98. package/lib/summary/orderedClientElection.js.map +1 -1
  99. package/lib/summary/summarizer.d.ts +2 -0
  100. package/lib/summary/summarizer.d.ts.map +1 -1
  101. package/lib/summary/summarizer.js +9 -4
  102. package/lib/summary/summarizer.js.map +1 -1
  103. package/lib/summary/summarizerHeuristics.d.ts +8 -9
  104. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  105. package/lib/summary/summarizerHeuristics.js +15 -16
  106. package/lib/summary/summarizerHeuristics.js.map +1 -1
  107. package/lib/summary/summarizerTypes.d.ts +2 -0
  108. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  109. package/lib/summary/summarizerTypes.js.map +1 -1
  110. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  111. package/lib/summary/summaryGenerator.js +4 -3
  112. package/lib/summary/summaryGenerator.js.map +1 -1
  113. package/package.json +17 -17
  114. package/src/connectionTelemetry.ts +1 -0
  115. package/src/containerRuntime.ts +12 -11
  116. package/src/dataStores.ts +4 -7
  117. package/src/gc/garbageCollection.ts +53 -315
  118. package/src/gc/gcHelpers.ts +1 -38
  119. package/src/gc/gcTelemetry.ts +393 -0
  120. package/src/gc/index.ts +1 -1
  121. package/src/opLifecycle/README.md +13 -0
  122. package/src/opLifecycle/opGroupingManager.ts +1 -1
  123. package/src/opLifecycle/outbox.ts +2 -2
  124. package/src/opLifecycle/remoteMessageProcessor.ts +37 -28
  125. package/src/packageVersion.ts +1 -1
  126. package/src/pendingStateManager.ts +1 -4
  127. package/src/summary/orderedClientElection.ts +14 -17
  128. package/src/summary/summarizer.ts +17 -5
  129. package/src/summary/summarizerHeuristics.ts +15 -16
  130. package/src/summary/summarizerTypes.ts +2 -0
  131. package/src/summary/summaryGenerator.ts +5 -4
@@ -1 +1 @@
1
- {"version":3,"file":"garbageCollection.js","sourceRoot":"","sources":["../../src/gc/garbageCollection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, LazyPromise, Timer } from \"@fluidframework/common-utils\";\nimport { ClientSessionExpiredError, DataProcessingError } from \"@fluidframework/container-utils\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport {\n\tgcTreeKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n\tISummarizeResult,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { packagePathToTelemetryProperty, ReadAndParseBlob } from \"@fluidframework/runtime-utils\";\nimport {\n\tChildLogger,\n\tgenerateStack,\n\tloggerToMonitoringContext,\n\tMonitoringContext,\n\tPerformanceEvent,\n\tTelemetryDataTag,\n} from \"@fluidframework/telemetry-utils\";\n\nimport { RuntimeHeaders } from \"../containerRuntime\";\nimport { ICreateContainerMetadata, RefreshSummaryResult } from \"../summary\";\nimport { generateGCConfigs } from \"./gcConfigs\";\nimport {\n\tdisableSweepLogKey,\n\tGCNodeType,\n\tIGarbageCollector,\n\tIGarbageCollectorCreateParams,\n\tIGarbageCollectionRuntime,\n\tIGCResult,\n\tIGCStats,\n\tUnreferencedState,\n\tIGCMetadata,\n\tIGarbageCollectorConfigs,\n} from \"./gcDefinitions\";\nimport {\n\tcloneGCData,\n\tconcatGarbageCollectionData,\n\tgetGCDataFromSnapshot,\n\tsendGCUnexpectedUsageEvent,\n} from \"./gcHelpers\";\nimport { runGarbageCollection } from \"./gcReferenceGraphAlgorithm\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { GCSummaryStateTracker } from \"./gcSummaryStateTracker\";\nimport { UnreferencedStateTracker } from \"./gcUnreferencedStateTracker\";\n\n/** The event that is logged when unreferenced node is used after a certain time. */\ninterface IUnreferencedEventProps {\n\tusageType: \"Changed\" | \"Loaded\" | \"Revived\";\n\tstate: UnreferencedState;\n\tid: string;\n\ttype: GCNodeType;\n\tunrefTime: number;\n\tage: number;\n\tcompletedGCRuns: number;\n\tfromId?: string;\n\ttimeout?: number;\n\tlastSummaryTime?: number;\n\tviaHandle?: boolean;\n}\n\n/**\n * The garbage collector for the container runtime. It consolidates the garbage collection functionality and maintains\n * its state across summaries.\n *\n * Node - represented as nodeId, it's a node on the GC graph\n *\n * Outbound Route - a path from one node to another node, think `nodeA` -\\> `nodeB`\n *\n * Graph - all nodes with their respective routes\n *\n * ```\n *\t\t\t GC Graph\n *\n *\t\t\t Node\n *\t\tNodeId = \"datastore1\"\n *\t\t /\t\t\t \\\\\n *\tOutboundRoute OutboundRoute\n *\t\t /\t\t\t\t \\\\\n *\t Node\t\t\t Node\n * NodeId = \"dds1\"\t NodeId = \"dds2\"\n * ```\n */\nexport class GarbageCollector implements IGarbageCollector {\n\tpublic static create(createParams: IGarbageCollectorCreateParams): IGarbageCollector {\n\t\treturn new GarbageCollector(createParams);\n\t}\n\n\tprivate readonly mc: MonitoringContext;\n\n\tprivate readonly configs: IGarbageCollectorConfigs;\n\n\tpublic get shouldRunGC(): boolean {\n\t\treturn this.configs.shouldRunGC;\n\t}\n\n\t// Keeps track of the GC state from the last run.\n\tprivate gcDataFromLastRun: IGarbageCollectionData | undefined;\n\t// Keeps a list of references (edges in the GC graph) between GC runs. Each entry has a node id and a list of\n\t// outbound routes from that node.\n\tprivate readonly newReferencesSinceLastRun: Map<string, string[]> = new Map();\n\t// A list of nodes that have been tombstoned.\n\tprivate tombstones: string[] = [];\n\t// A list of nodes that have been deleted during sweep phase.\n\tprivate deletedNodes: Set<string> = new Set();\n\n\t// Promise when resolved returns the GC data data in the base snapshot.\n\tprivate readonly baseSnapshotDataP: Promise<IGarbageCollectionSnapshotData | undefined>;\n\t// Promise when resolved initializes the GC state from the data in the base snapshot.\n\tprivate readonly initializeGCStateFromBaseSnapshotP: Promise<void>;\n\t// The GC details generated from the base snapshot.\n\tprivate readonly baseGCDetailsP: Promise<IGarbageCollectionDetailsBase>;\n\t// Map of node ids to their unreferenced state tracker.\n\tprivate readonly unreferencedNodesState: Map<string, UnreferencedStateTracker> = new Map();\n\t// The Timer responsible for closing the container when the session has expired\n\tprivate sessionExpiryTimer: Timer | undefined;\n\n\t// Keeps track of unreferenced events that are logged for a node. This is used to limit the log generation to one\n\t// per event per node.\n\tprivate readonly loggedUnreferencedEvents: Set<string> = new Set();\n\t// Queue for unreferenced events that should be logged the next time GC runs.\n\tprivate pendingEventsQueue: IUnreferencedEventProps[] = [];\n\n\t// The number of times GC has successfully completed on this instance of GarbageCollector.\n\tprivate completedRuns = 0;\n\n\tprivate readonly runtime: IGarbageCollectionRuntime;\n\tprivate readonly createContainerMetadata: ICreateContainerMetadata;\n\tprivate readonly isSummarizerClient: boolean;\n\n\tprivate readonly summaryStateTracker: GCSummaryStateTracker;\n\n\t/** For a given node path, returns the node's package path. */\n\tprivate readonly getNodePackagePath: (\n\t\tnodePath: string,\n\t) => Promise<readonly string[] | undefined>;\n\t/** Returns the timestamp of the last summary generated for this container. */\n\tprivate readonly getLastSummaryTimestampMs: () => number | undefined;\n\t/** Returns true if connection is active, i.e. it's \"write\" connection and the runtime is connected. */\n\tprivate readonly activeConnection: () => boolean;\n\n\tpublic get summaryStateNeedsReset(): boolean {\n\t\treturn this.summaryStateTracker.doesSummaryStateNeedReset;\n\t}\n\n\tprotected constructor(createParams: IGarbageCollectorCreateParams) {\n\t\tthis.runtime = createParams.runtime;\n\t\tthis.isSummarizerClient = createParams.isSummarizerClient;\n\t\tthis.createContainerMetadata = createParams.createContainerMetadata;\n\t\tthis.getNodePackagePath = createParams.getNodePackagePath;\n\t\tthis.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;\n\t\tthis.activeConnection = createParams.activeConnection;\n\n\t\tconst baseSnapshot = createParams.baseSnapshot;\n\t\tconst readAndParseBlob = createParams.readAndParseBlob;\n\n\t\tthis.mc = loggerToMonitoringContext(\n\t\t\tChildLogger.create(createParams.baseLogger, \"GarbageCollector\", {\n\t\t\t\tall: { completedGCRuns: () => this.completedRuns },\n\t\t\t}),\n\t\t);\n\n\t\tthis.configs = generateGCConfigs(this.mc, createParams);\n\n\t\t// If session expiry is enabled, we need to close the container when the session expiry timeout expires.\n\t\tif (this.configs.sessionExpiryTimeoutMs !== undefined) {\n\t\t\t// If Test Override config is set, override Session Expiry timeout.\n\t\t\tconst overrideSessionExpiryTimeoutMs = this.mc.config.getNumber(\n\t\t\t\t\"Fluid.GarbageCollection.TestOverride.SessionExpiryMs\",\n\t\t\t);\n\t\t\tconst timeoutMs = overrideSessionExpiryTimeoutMs ?? this.configs.sessionExpiryTimeoutMs;\n\n\t\t\tthis.sessionExpiryTimer = new Timer(timeoutMs, () => {\n\t\t\t\tthis.runtime.closeFn(\n\t\t\t\t\tnew ClientSessionExpiredError(`Client session expired.`, timeoutMs),\n\t\t\t\t);\n\t\t\t});\n\t\t\tthis.sessionExpiryTimer.start();\n\t\t}\n\n\t\tthis.summaryStateTracker = new GCSummaryStateTracker(\n\t\t\tthis.configs,\n\t\t\tbaseSnapshot?.trees[gcTreeKey] !== undefined /* wasGCRunInBaseSnapshot */,\n\t\t);\n\n\t\t// Get the GC data from the base snapshot. Use LazyPromise because we only want to do this once since it\n\t\t// it involves fetching blobs from storage which is expensive.\n\t\tthis.baseSnapshotDataP = new LazyPromise<IGarbageCollectionSnapshotData | undefined>(\n\t\t\tasync () => {\n\t\t\t\tif (baseSnapshot === undefined) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\t// For newer documents, GC data should be present in the GC tree in the root of the snapshot.\n\t\t\t\t\tconst gcSnapshotTree = baseSnapshot.trees[gcTreeKey];\n\t\t\t\t\tif (gcSnapshotTree === undefined) {\n\t\t\t\t\t\t// back-compat - Older documents get their gc data reset for simplicity as there are few of them\n\t\t\t\t\t\t// incremental gc summary will not work with older gc data as well\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst snapshotData = await getGCDataFromSnapshot(\n\t\t\t\t\t\tgcSnapshotTree,\n\t\t\t\t\t\treadAndParseBlob,\n\t\t\t\t\t);\n\n\t\t\t\t\t// If the GC version in base snapshot does not match the GC version currently in effect, the GC data\n\t\t\t\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for\n\t\t\t\t\t// deletedNodes because irrespective of GC versions, these nodes have been deleted and cannot be\n\t\t\t\t\t// brought back. The deletedNodes info is needed to identify when these nodes are used.\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.configs.gcVersionInBaseSnapshot !==\n\t\t\t\t\t\tthis.summaryStateTracker.currentGCVersion\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tgcState: undefined,\n\t\t\t\t\t\t\ttombstones: undefined,\n\t\t\t\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn snapshotData;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst dpe = DataProcessingError.wrapIfUnrecognized(\n\t\t\t\t\t\terror,\n\t\t\t\t\t\t\"FailedToInitializeGC\",\n\t\t\t\t\t);\n\t\t\t\t\tdpe.addTelemetryProperties({\n\t\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t\t});\n\t\t\t\t\tthrow dpe;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\t/**\n\t\t * Set up the initializer which initializes the GC state from the data in base snapshot. This is done when\n\t\t * connected in write mode or when GC runs the first time. It sets up all unreferenced nodes from the base\n\t\t * GC state and updates their inactive or sweep ready state.\n\t\t */\n\t\tthis.initializeGCStateFromBaseSnapshotP = new LazyPromise<void>(async () => {\n\t\t\t/**\n\t\t\t * If there is no current reference timestamp, skip initialization. We need the current timestamp to track\n\t\t\t * how long objects have been unreferenced and if they can be deleted.\n\t\t\t *\n\t\t\t * Note that the only scenario where there is no reference timestamp is when no ops have ever been processed\n\t\t\t * for this container and it is in read mode. In this scenario, there is no point in running GC anyway\n\t\t\t * because references in the container do not change without any ops, i.e., there is nothing to collect.\n\t\t\t */\n\t\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t\t// Log an event so we can evaluate how often we run into this scenario.\n\t\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"GarbageCollectorInitializedWithoutTimestamp\",\n\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t/**\n\t\t\t * The base snapshot data will not be present if the container is loaded from:\n\t\t\t * 1. The first summary created by the detached container.\n\t\t\t * 2. A summary that was generated with GC disabled.\n\t\t\t * 3. A summary that was generated before GC even existed.\n\t\t\t */\n\t\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t\tif (baseSnapshotData === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.updateStateFromSnapshotData(baseSnapshotData, currentReferenceTimestampMs);\n\t\t\tthis.summaryStateTracker.initializeBaseState(baseSnapshotData);\n\t\t});\n\n\t\t// Get the GC details from the GC state in the base summary. This is returned in getBaseGCDetails which is\n\t\t// used to initialize the GC state of all the nodes in the container.\n\t\tthis.baseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {\n\t\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t\tif (baseSnapshotData?.gcState === undefined) {\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\t\tfor (const [nodeId, nodeData] of Object.entries(baseSnapshotData.gcState.gcNodes)) {\n\t\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t\t}\n\t\t\t// Run GC on the nodes in the base summary to get the routes used in each node in the container.\n\t\t\t// This is an optimization for space (vs performance) wherein we don't need to store the used routes of\n\t\t\t// each node in the summary.\n\t\t\tconst usedRoutes = runGarbageCollection(gcNodes, [\"/\"]).referencedNodeIds;\n\n\t\t\treturn { gcData: { gcNodes }, usedRoutes };\n\t\t});\n\n\t\t// Log all the GC options and the state determined by the garbage collector. This is interesting only for the\n\t\t// summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.\n\t\tif (this.isSummarizerClient) {\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"GarbageCollectorLoaded\",\n\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\tgcOptions: JSON.stringify(createParams.gcOptions),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Called during container initialization. Initialize from the tombstone state in the base snapshot. This is done\n\t * during initialization so that deleted or tombstoned objects are marked as such before they are loaded or used.\n\t */\n\tpublic async initializeBaseState(): Promise<void> {\n\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t/**\n\t\t * The base snapshot data will not be present if the container is loaded from:\n\t\t * 1. The first summary created by the detached container.\n\t\t * 2. A summary that was generated with GC disabled.\n\t\t * 3. A summary that was generated before GC even existed.\n\t\t */\n\t\tif (baseSnapshotData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Initialize the deleted nodes from the snapshot. This is done irrespective of whether sweep is enabled or not\n\t\t// to identify deleted nodes' usage.\n\t\tif (baseSnapshotData.deletedNodes !== undefined) {\n\t\t\tthis.deletedNodes = new Set(baseSnapshotData.deletedNodes);\n\t\t}\n\n\t\t// If running in tombstone mode, initialize the tombstone state from the snapshot. Also, notify the runtime of\n\t\t// tombstone routes.\n\t\tif (this.configs.tombstoneMode && baseSnapshotData.tombstones !== undefined) {\n\t\t\t// Create a copy since we are writing from a source we don't control\n\t\t\tthis.tombstones = Array.from(baseSnapshotData.tombstones);\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\t}\n\n\t/**\n\t * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.\n\t * All current tracking is reset and updated from the data in the snapshot.\n\t * @param snapshotData - The snapshot data to update state from. If this is undefined, all GC state and tracking\n\t * is reset.\n\t * @param currentReferenceTimestampMs - The current reference timestamp for marking unreferenced nodes' unreferenced\n\t * timestamp.\n\t */\n\tprivate updateStateFromSnapshotData(\n\t\tsnapshotData: IGarbageCollectionSnapshotData | undefined,\n\t\tcurrentReferenceTimestampMs: number,\n\t) {\n\t\t/**\n\t\t * Note: \"newReferencesSinceLastRun\" is not reset here. This is done because there may be references since the\n\t\t * snapshot that we are updating state from. For example, this client may have processed ops till seq#1000 and\n\t\t * its refreshing state from a summary that happened at seq#900. In this case, there may be references between\n\t\t * seq#901 and seq#1000 that we don't want to reset.\n\t\t * Unfortunately, there is no way to track the seq# of ops that add references, so we choose to not reset any\n\t\t * references here. This should be fine because, in the worst case, we may end up updating the unreferenced\n\t\t * timestamp of a node which will delay its deletion. Although not ideal, this will only happen in rare\n\t\t * scenarios, so it should be okay.\n\t\t */\n\n\t\t// Clear all existing unreferenced state tracking.\n\t\tfor (const [, nodeStateTracker] of this.unreferencedNodesState) {\n\t\t\tnodeStateTracker.stopTracking();\n\t\t}\n\t\tthis.unreferencedNodesState.clear();\n\n\t\t// If running sweep, the tombstone state represents the list of nodes that have been deleted during sweep.\n\t\t// If running in tombstone mode, the tombstone state represents the list of nodes that have been marked as\n\t\t// tombstones.\n\t\t// If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state\n\t\t// in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.\n\t\tif (this.configs.shouldRunSweep) {\n\t\t\tconst snapshotDeletedNodes = snapshotData?.deletedNodes\n\t\t\t\t? new Set(snapshotData.deletedNodes)\n\t\t\t\t: undefined;\n\t\t\t// If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to\n\t\t\t// delete them.\n\t\t\tif (snapshotDeletedNodes !== undefined) {\n\t\t\t\tconst newDeletedNodes: string[] = [];\n\t\t\t\tfor (const nodeId of snapshotDeletedNodes) {\n\t\t\t\t\tif (!this.deletedNodes.has(nodeId)) {\n\t\t\t\t\t\tnewDeletedNodes.push(nodeId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (newDeletedNodes.length > 0) {\n\t\t\t\t\t// Call container runtime to delete these nodes and add deleted nodes to this.deletedNodes.\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.configs.tombstoneMode) {\n\t\t\t// The snapshot may contain more or fewer tombstone nodes than this client. Update tombstone state and\n\t\t\t// notify the runtime to update its state as well.\n\t\t\tthis.tombstones = snapshotData?.tombstones ? Array.from(snapshotData.tombstones) : [];\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\n\t\t// If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.\n\t\tif (snapshotData?.gcState === undefined) {\n\t\t\tthis.gcDataFromLastRun = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\t// Update unreferenced state tracking as per the GC state in the snapshot data and update gcDataFromLastRun\n\t\t// to the GC data from the snapshot data.\n\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\tfor (const [nodeId, nodeData] of Object.entries(snapshotData.gcState.gcNodes)) {\n\t\t\tif (nodeData.unreferencedTimestampMs !== undefined) {\n\t\t\t\tthis.unreferencedNodesState.set(\n\t\t\t\t\tnodeId,\n\t\t\t\t\tnew UnreferencedStateTracker(\n\t\t\t\t\t\tnodeData.unreferencedTimestampMs,\n\t\t\t\t\t\tthis.configs.inactiveTimeoutMs,\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.sweepTimeoutMs,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t}\n\t\tthis.gcDataFromLastRun = { gcNodes };\n\t}\n\n\t/**\n\t * Called when the connection state of the runtime changes, i.e., it connects or disconnects. GC subscribes to this\n\t * to initialize the base state for non-summarizer clients so that they can track inactive / sweep ready nodes.\n\t * @param connected - Whether the runtime connected / disconnected.\n\t * @param clientId - The clientId of this runtime.\n\t */\n\tpublic setConnectionState(connected: boolean, clientId?: string | undefined): void {\n\t\t/**\n\t\t * For all clients, initialize the base state when the container becomes active, i.e., it transitions\n\t\t * to \"write\" mode. This will ensure that the container's own join op is processed and there is a recent\n\t\t * reference timestamp that will be used to update the state of unreferenced nodes. Also, all trailing ops which\n\t\t * could affect the GC state will have been processed.\n\t\t *\n\t\t * If GC is up-to-date for the client and the summarizing client, there will be an doubling of both\n\t\t * InactiveObject_Loaded and SweepReady_Loaded errors, as there will be one from the sending client and one from\n\t\t * the receiving summarizer client.\n\t\t *\n\t\t * Ideally, this initialization should only be done for summarizer client. However, we are currently rolling out\n\t\t * sweep in phases and we want to track when inactive and sweep ready objects are used in any client.\n\t\t */\n\t\tif (this.activeConnection() && this.configs.shouldRunGC) {\n\t\t\tthis.initializeGCStateFromBaseSnapshotP.catch((error) => {});\n\t\t}\n\t}\n\n\t/**\n\t * Runs garbage collection and updates the reference / used state of the nodes in the container.\n\t * @returns stats of the GC run or undefined if GC did not run.\n\t */\n\tpublic async collectGarbage(\n\t\toptions: {\n\t\t\t/** Logger to use for logging GC events */\n\t\t\tlogger?: ITelemetryLogger;\n\t\t\t/** True to run GC sweep phase after the mark phase */\n\t\t\trunSweep?: boolean;\n\t\t\t/** True to generate full GC data */\n\t\t\tfullGC?: boolean;\n\t\t},\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<IGCStats | undefined> {\n\t\tconst fullGC =\n\t\t\toptions.fullGC ??\n\t\t\t(this.configs.runFullGC === true || this.summaryStateTracker.doesSummaryStateNeedReset);\n\n\t\t// Add the options that are used to run GC to the telemetry context.\n\t\ttelemetryContext?.setMultiple(\"fluid_GC\", \"Options\", {\n\t\t\tfullGC,\n\t\t\trunSweep: options.runSweep,\n\t\t});\n\n\t\tconst logger = options.logger\n\t\t\t? ChildLogger.create(options.logger, undefined, {\n\t\t\t\t\tall: { completedGCRuns: () => this.completedRuns },\n\t\t\t })\n\t\t\t: this.mc.logger;\n\n\t\t/**\n\t\t * If there is no current reference timestamp, skip running GC. We need the current timestamp to track\n\t\t * how long objects have been unreferenced and if they should be deleted.\n\t\t *\n\t\t * Note that the only scenario where GC is called and there is no reference timestamp is when no ops have ever\n\t\t * been processed for this container and it is in read mode. In this scenario, there is no point in running GC\n\t\t * anyway because references in the container do not change without any ops, i.e., there is nothing to collect.\n\t\t */\n\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t// Log an event so we can evaluate how often we run into this scenario.\n\t\t\tlogger.sendErrorEvent({\n\t\t\t\teventName: \"CollectGarbageCalledWithoutTimestamp\",\n\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tlogger,\n\t\t\t{ eventName: \"GarbageCollection\" },\n\t\t\tasync (event) => {\n\t\t\t\tawait this.runPreGCSteps();\n\n\t\t\t\t// Get the runtime's GC data and run GC on the reference graph in it.\n\t\t\t\tconst gcData = await this.runtime.getGCData(fullGC);\n\t\t\t\tconst gcResult = runGarbageCollection(gcData.gcNodes, [\"/\"]);\n\n\t\t\t\tconst gcStats = await this.runPostGCSteps(\n\t\t\t\t\tgcData,\n\t\t\t\t\tgcResult,\n\t\t\t\t\tlogger,\n\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t);\n\t\t\t\tevent.end({ ...gcStats, timestamp: currentReferenceTimestampMs });\n\t\t\t\tthis.completedRuns++;\n\t\t\t\treturn gcStats;\n\t\t\t},\n\t\t\t{ end: true, cancel: \"error\" },\n\t\t);\n\t}\n\n\tprivate async runPreGCSteps() {\n\t\t// Ensure that state has been initialized from the base snapshot data.\n\t\tawait this.initializeGCStateFromBaseSnapshotP;\n\t\t// Let the runtime update its pending state before GC runs.\n\t\tawait this.runtime.updateStateBeforeGC();\n\t}\n\n\tprivate async runPostGCSteps(\n\t\tgcData: IGarbageCollectionData,\n\t\tgcResult: IGCResult,\n\t\tlogger: ITelemetryLogger,\n\t\tcurrentReferenceTimestampMs: number,\n\t): Promise<IGCStats> {\n\t\t// Generate statistics from the current run. This is done before updating the current state because it\n\t\t// generates some of its data based on previous state of the system.\n\t\tconst gcStats = this.generateStats(gcResult);\n\n\t\t// Update the current mark state and update the runtime of all used routes or ids that used as per the GC run.\n\t\tconst sweepReadyNodes = this.updateMarkPhase(\n\t\t\tgcData,\n\t\t\tgcResult,\n\t\t\tcurrentReferenceTimestampMs,\n\t\t\tlogger,\n\t\t);\n\t\tthis.runtime.updateUsedRoutes(gcResult.referencedNodeIds);\n\n\t\t// Log events for objects that are ready to be deleted by sweep. When we have sweep enabled, we will\n\t\t// delete these objects here instead.\n\t\tthis.logSweepEvents(logger, currentReferenceTimestampMs);\n\n\t\tlet updatedGCData: IGarbageCollectionData = gcData;\n\n\t\tif (this.configs.shouldRunSweep) {\n\t\t\tupdatedGCData = this.runSweepPhase(sweepReadyNodes, gcData);\n\t\t} else if (this.configs.testMode) {\n\t\t\t// If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios\n\t\t\t// involving access to deleted data.\n\t\t\tthis.runtime.updateUnusedRoutes(gcResult.deletedNodeIds);\n\t\t} else if (this.configs.tombstoneMode) {\n\t\t\tthis.tombstones = sweepReadyNodes;\n\t\t\t// If we are running in GC tombstone mode, update tombstoned routes. This enables testing scenarios\n\t\t\t// involving access to \"deleted\" data without actually deleting the data from summaries.\n\t\t\t// Note: we will not tombstone in test mode.\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\n\t\tthis.gcDataFromLastRun = cloneGCData(updatedGCData);\n\n\t\t// Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and\n\t\t// updates its state so that we don't send false positives based on intermediate state. For example, we may get\n\t\t// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.\n\t\tawait this.logUnreferencedEvents(logger);\n\n\t\treturn gcStats;\n\t}\n\n\t/**\n\t * Summarizes the GC data and returns it as a summary tree.\n\t * We current write the entire GC state in a single blob. This can be modified later to write multiple\n\t * blobs. All the blob keys should start with `gcBlobPrefix`.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): ISummarizeResult | undefined {\n\t\tif (!this.configs.shouldRunGC || this.gcDataFromLastRun === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst gcState: IGarbageCollectionState = { gcNodes: {} };\n\t\tfor (const [nodeId, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n\t\t\tgcState.gcNodes[nodeId] = {\n\t\t\t\toutboundRoutes,\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tthis.unreferencedNodesState.get(nodeId)?.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\n\t\treturn this.summaryStateTracker.summarize(\n\t\t\tfullTree,\n\t\t\ttrackState,\n\t\t\tgcState,\n\t\t\tthis.deletedNodes,\n\t\t\tthis.tombstones,\n\t\t);\n\t}\n\n\tpublic getMetadata(): IGCMetadata {\n\t\treturn {\n\t\t\t/**\n\t\t\t * If GC is enabled, the GC data is written using the current GC version and that is the gcFeature that goes\n\t\t\t * into the metadata blob. If GC is disabled, the gcFeature is 0.\n\t\t\t */\n\t\t\tgcFeature: this.configs.gcEnabled ? this.summaryStateTracker.currentGCVersion : 0,\n\t\t\tgcFeatureMatrix: this.configs.persistedGcFeatureMatrix,\n\t\t\tsessionExpiryTimeoutMs: this.configs.sessionExpiryTimeoutMs,\n\t\t\tsweepEnabled: false, // DEPRECATED - to be removed\n\t\t\tsweepTimeoutMs: this.configs.sweepTimeoutMs,\n\t\t};\n\t}\n\n\t/**\n\t * Returns a the GC details generated from the base summary. This is used to initialize the GC state of the nodes\n\t * in the container.\n\t */\n\tpublic async getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase> {\n\t\treturn this.baseGCDetailsP;\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<void> {\n\t\tconst latestSnapshotData = await this.summaryStateTracker.refreshLatestSummary(\n\t\t\tproposalHandle,\n\t\t\tresult,\n\t\t\treadAndParseBlob,\n\t\t);\n\n\t\t// If the latest summary was updated but it was not tracked by this client, our state needs to be updated from\n\t\t// this snapshot data.\n\t\tif (this.shouldRunGC && result.latestSummaryUpdated && !result.wasSummaryTracked) {\n\t\t\t// The current reference timestamp should be available if we are refreshing state from a snapshot. There has\n\t\t\t// to be at least one op (summary op / ack, if nothing else) if a snapshot was taken.\n\t\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"No reference timestamp when updating GC state from snapshot\",\n\t\t\t\t\t\"refreshLatestSummary\",\n\t\t\t\t\tundefined,\n\t\t\t\t\t{\n\t\t\t\t\t\tproposalHandle,\n\t\t\t\t\t\tsummaryRefSeq: result.summaryRefSeq,\n\t\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.updateStateFromSnapshotData(latestSnapshotData, currentReferenceTimestampMs);\n\t\t}\n\t}\n\n\t/**\n\t * Called when a node with the given id is updated. If the node is inactive, log an error.\n\t * @param nodePath - The id of the node that changed.\n\t * @param reason - Whether the node was loaded or changed.\n\t * @param timestampMs - The timestamp when the node changed.\n\t * @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.\n\t * @param requestHeaders - If the node was loaded via request path, the headers in the request.\n\t */\n\tpublic nodeUpdated(\n\t\tnodePath: string,\n\t\treason: \"Loaded\" | \"Changed\",\n\t\ttimestampMs?: number,\n\t\tpackagePath?: readonly string[],\n\t\trequestHeaders?: IRequestHeader,\n\t) {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodePath);\n\t\tif (nodeStateTracker && nodeStateTracker.state !== UnreferencedState.Active) {\n\t\t\tthis.inactiveNodeUsed(\n\t\t\t\treason,\n\t\t\t\tnodePath,\n\t\t\t\tnodeStateTracker,\n\t\t\t\tundefined /* fromNodeId */,\n\t\t\t\tpackagePath,\n\t\t\t\ttimestampMs,\n\t\t\t\trequestHeaders,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Called when an outbound reference is added to a node. This is used to identify all nodes that have been\n\t * referenced between summaries so that their unreferenced timestamp can be reset.\n\t *\n\t * @param fromNodePath - The node from which the reference is added.\n\t * @param toNodePath - The node to which the reference is added.\n\t */\n\tpublic addedOutboundReference(fromNodePath: string, toNodePath: string) {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst outboundRoutes = this.newReferencesSinceLastRun.get(fromNodePath) ?? [];\n\t\toutboundRoutes.push(toNodePath);\n\t\tthis.newReferencesSinceLastRun.set(fromNodePath, outboundRoutes);\n\n\t\tconst nodeStateTracker = this.unreferencedNodesState.get(toNodePath);\n\t\tif (nodeStateTracker && nodeStateTracker.state !== UnreferencedState.Active) {\n\t\t\tthis.inactiveNodeUsed(\"Revived\", toNodePath, nodeStateTracker, fromNodePath);\n\t\t}\n\n\t\tif (this.tombstones.includes(toNodePath)) {\n\t\t\tconst nodeType = this.runtime.getNodeType(toNodePath);\n\n\t\t\tlet eventName = \"GC_Tombstone_SubDatastore_Revived\";\n\t\t\tif (nodeType === GCNodeType.DataStore) {\n\t\t\t\teventName = \"GC_Tombstone_Datastore_Revived\";\n\t\t\t} else if (nodeType === GCNodeType.Blob) {\n\t\t\t\teventName = \"GC_Tombstone_Blob_Revived\";\n\t\t\t}\n\n\t\t\tsendGCUnexpectedUsageEvent(\n\t\t\t\tthis.mc,\n\t\t\t\t{\n\t\t\t\t\teventName,\n\t\t\t\t\tcategory: \"generic\",\n\t\t\t\t\turl: toNodePath,\n\t\t\t\t\tnodeType,\n\t\t\t\t\tgcTombstoneEnforcementAllowed: this.runtime.gcTombstoneEnforcementAllowed,\n\t\t\t\t},\n\t\t\t\tundefined /* packagePath */,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether a node with the given path has been deleted or not. This can be used by the runtime to identify\n\t * cases where objects are used after they are deleted and throw / log errors accordingly.\n\t */\n\tpublic isNodeDeleted(nodePath: string): boolean {\n\t\treturn this.deletedNodes.has(nodePath);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.sessionExpiryTimer?.clear();\n\t\tthis.sessionExpiryTimer = undefined;\n\t}\n\n\t/**\n\t * Updates the state of the system as per the current GC run. It does the following:\n\t * 1. Sets up the current GC state as per the gcData.\n\t * 2. Starts tracking for nodes that have become unreferenced in this run.\n\t * 3. Clears tracking for nodes that were unreferenced but became referenced in this run.\n\t * @param gcData - The data representing the reference graph on which GC is run.\n\t * @param gcResult - The result of the GC run on the gcData.\n\t * @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.\n\t * @returns - A list of sweep ready nodes. (Nodes ready to be deleted)\n\t */\n\tprivate updateMarkPhase(\n\t\tgcData: IGarbageCollectionData,\n\t\tgcResult: IGCResult,\n\t\tcurrentReferenceTimestampMs: number,\n\t\tlogger: ITelemetryLogger,\n\t) {\n\t\t// Get references from the current GC run + references between previous and current run and then update each\n\t\t// node's state\n\t\tconst allNodesReferencedBetweenGCs =\n\t\t\tthis.findAllNodesReferencedBetweenGCs(gcData, this.gcDataFromLastRun, logger) ??\n\t\t\tgcResult.referencedNodeIds;\n\t\tthis.newReferencesSinceLastRun.clear();\n\n\t\t// Iterate through the referenced nodes and stop tracking if they were unreferenced before.\n\t\tfor (const nodeId of allNodesReferencedBetweenGCs) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\tif (nodeStateTracker !== undefined) {\n\t\t\t\t// Stop tracking so as to clear out any running timers.\n\t\t\t\tnodeStateTracker.stopTracking();\n\t\t\t\t// Delete the node as we don't need to track it any more.\n\t\t\t\tthis.unreferencedNodesState.delete(nodeId);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * If a node became unreferenced in this run, start tracking it.\n\t\t * If a node was already unreferenced, update its tracking information. Since the current reference time is\n\t\t * from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.\n\t\t *\n\t\t * If a node is sweep ready, store and then return it.\n\t\t */\n\t\tconst sweepReadyNodes: string[] = [];\n\t\tfor (const nodeId of gcResult.deletedNodeIds) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\tif (nodeStateTracker === undefined) {\n\t\t\t\tthis.unreferencedNodesState.set(\n\t\t\t\t\tnodeId,\n\t\t\t\t\tnew UnreferencedStateTracker(\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.inactiveTimeoutMs,\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.sweepTimeoutMs,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tnodeStateTracker.updateTracking(currentReferenceTimestampMs);\n\t\t\t\tif (nodeStateTracker.state === UnreferencedState.SweepReady) {\n\t\t\t\t\tsweepReadyNodes.push(nodeId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn sweepReadyNodes;\n\t}\n\n\t/**\n\t * Deletes nodes from both the runtime and garbage collection\n\t * @param sweepReadyNodes - nodes that are ready to be deleted\n\t */\n\tprivate runSweepPhase(sweepReadyNodes: string[], gcData: IGarbageCollectionData) {\n\t\t// TODO: GC:Validation - validate that removed routes are not double deleted\n\t\t// TODO: GC:Validation - validate that the child routes of removed routes are deleted as well\n\t\tconst sweptRoutes = this.runtime.deleteSweepReadyNodes(sweepReadyNodes);\n\t\tconst updatedGCData = this.deleteSweptRoutes(sweptRoutes, gcData);\n\n\t\tfor (const nodeId of sweptRoutes) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\t// TODO: GC:Validation - assert that the nodeStateTracker is defined\n\t\t\tif (nodeStateTracker !== undefined) {\n\t\t\t\t// Stop tracking so as to clear out any running timers.\n\t\t\t\tnodeStateTracker.stopTracking();\n\t\t\t\t// Delete the node as we don't need to track it any more.\n\t\t\t\tthis.unreferencedNodesState.delete(nodeId);\n\t\t\t}\n\t\t\t// TODO: GC:Validation - assert that the deleted node is not a duplicate\n\t\t\tthis.deletedNodes.add(nodeId);\n\t\t}\n\n\t\treturn updatedGCData;\n\t}\n\n\t/**\n\t * @returns IGarbageCollectionData after deleting the sweptRoutes from the gcData\n\t */\n\tprivate deleteSweptRoutes(\n\t\tsweptRoutes: string[],\n\t\tgcData: IGarbageCollectionData,\n\t): IGarbageCollectionData {\n\t\tconst sweptRoutesSet = new Set<string>(sweptRoutes);\n\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\t\tif (!sweptRoutesSet.has(id)) {\n\t\t\t\tgcNodes[id] = Array.from(outboundRoutes);\n\t\t\t}\n\t\t}\n\n\t\t// TODO: GC:Validation - assert that the nodeId is in gcData\n\n\t\treturn {\n\t\t\tgcNodes,\n\t\t};\n\t}\n\n\t/**\n\t * Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in\n\t * time. There can be nodes that were referenced in between two runs and their unreferenced state needs to be\n\t * updated. For example, in the following scenarios not updating the unreferenced timestamp can lead to deletion of\n\t * these objects while there can be in-memory referenced to it:\n\t * 1. A node transitions from `unreferenced -> referenced -> unreferenced` between two runs. When the reference is\n\t * added, the object may have been accessed and in-memory reference to it added.\n\t * 2. A reference is added from one unreferenced node to one or more unreferenced nodes. Even though the node[s] were\n\t * unreferenced, they could have been accessed and in-memory reference to them added.\n\t *\n\t * This function identifies nodes that were referenced since the last run.\n\t * If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.\n\t *\n\t * @returns - a list of all nodes referenced from the last local summary until now.\n\t */\n\tprivate findAllNodesReferencedBetweenGCs(\n\t\tcurrentGCData: IGarbageCollectionData,\n\t\tpreviousGCData: IGarbageCollectionData | undefined,\n\t\tlogger: ITelemetryLogger,\n\t): string[] | undefined {\n\t\t// If we haven't run GC before there is nothing to do.\n\t\t// No previousGCData, means nothing is unreferenced, and there are no reference state trackers to clear\n\t\tif (previousGCData === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Find any references that haven't been identified correctly.\n\t\tconst missingExplicitReferences = this.findMissingExplicitReferences(\n\t\t\tcurrentGCData,\n\t\t\tpreviousGCData,\n\t\t\tthis.newReferencesSinceLastRun,\n\t\t);\n\n\t\tif (missingExplicitReferences.length > 0) {\n\t\t\tmissingExplicitReferences.forEach((missingExplicitReference) => {\n\t\t\t\tlogger.sendErrorEvent({\n\t\t\t\t\teventName: \"gcUnknownOutboundReferences\",\n\t\t\t\t\tgcNodeId: missingExplicitReference[0],\n\t\t\t\t\tgcRoutes: JSON.stringify(missingExplicitReference[1]),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// No references were added since the last run so we don't have to update reference states of any unreferenced\n\t\t// nodes. There is no in between state at this point.\n\t\tif (this.newReferencesSinceLastRun.size === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t/**\n\t\t * Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and\n\t\t * edges that have been added since then. To do this, combine the GC data from the last run and the current\n\t\t * run, and then add the references since last run.\n\t\t *\n\t\t * Note on why we need to combine the data from previous run, current run and all references in between -\n\t\t * 1. We need data from last run because some of its references may have been deleted since then. If those\n\t\t * references added new outbound references before they were deleted, we need to detect them.\n\t\t *\n\t\t * 2. We need new outbound references since last run because some of them may have been deleted later. If those\n\t\t * references added new outbound references before they were deleted, we need to detect them.\n\t\t *\n\t\t * 3. We need data from the current run because currently we may not detect when DDSes are referenced:\n\t\t * - We don't require DDSes handles to be stored in a referenced DDS.\n\t\t * - A new data store may have \"root\" DDSes already created and we don't detect them today.\n\t\t */\n\t\tconst gcDataSuperSet = concatGarbageCollectionData(previousGCData, currentGCData);\n\t\tconst newOutboundRoutesSinceLastRun: string[] = [];\n\t\tthis.newReferencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {\n\t\t\tif (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {\n\t\t\t\tgcDataSuperSet.gcNodes[sourceNodeId] = outboundRoutes;\n\t\t\t} else {\n\t\t\t\tgcDataSuperSet.gcNodes[sourceNodeId].push(...outboundRoutes);\n\t\t\t}\n\t\t\tnewOutboundRoutesSinceLastRun.push(...outboundRoutes);\n\t\t});\n\n\t\t/**\n\t\t * Run GC on the above reference graph starting with root and all new outbound routes. This will generate a\n\t\t * list of all nodes that could have been referenced since the last run. If any of these nodes are unreferenced,\n\t\t * unreferenced, stop tracking them and remove from unreferenced list.\n\t\t * Note that some of these nodes may be unreferenced now and if so, the current run will mark them as\n\t\t * unreferenced and add unreferenced state.\n\t\t */\n\t\tconst gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, [\n\t\t\t\"/\",\n\t\t\t...newOutboundRoutesSinceLastRun,\n\t\t]);\n\t\treturn gcResult.referencedNodeIds;\n\t}\n\n\t/**\n\t * Finds all new references or outbound routes in the current graph that haven't been explicitly notified to GC.\n\t * The principle is that every new reference or outbound route must be notified to GC via the\n\t * addedOutboundReference method. It it hasn't, its a bug and we want to identify these scenarios.\n\t *\n\t * In more simple terms:\n\t * Missing Explicit References = Current References - Previous References - Explicitly Added References;\n\t *\n\t * @param currentGCData - The GC data (reference graph) from the current GC run.\n\t * @param previousGCData - The GC data (reference graph) from the previous GC run.\n\t * @param explicitReferences - New references added explicity between the previous and the current run.\n\t * @returns - a list of missing explicit references\n\t */\n\tprivate findMissingExplicitReferences(\n\t\tcurrentGCData: IGarbageCollectionData,\n\t\tpreviousGCData: IGarbageCollectionData,\n\t\texplicitReferences: Map<string, string[]>,\n\t): [string, string[]][] {\n\t\tassert(\n\t\t\tpreviousGCData !== undefined,\n\t\t\t0x2b7 /* \"Can't validate correctness without GC data from last run\" */,\n\t\t);\n\n\t\tconst currentGraph = Object.entries(currentGCData.gcNodes);\n\t\tconst missingExplicitReferences: [string, string[]][] = [];\n\t\tcurrentGraph.forEach(([nodeId, currentOutboundRoutes]) => {\n\t\t\tconst previousRoutes = previousGCData.gcNodes[nodeId] ?? [];\n\t\t\tconst explicitRoutes = explicitReferences.get(nodeId) ?? [];\n\t\t\tconst missingExplicitRoutes: string[] = [];\n\n\t\t\t/**\n\t\t\t * 1. For routes in the current GC data, routes that were not present in previous GC data and did not have\n\t\t\t * explicit references should be added to missing explicit routes list.\n\t\t\t * 2. Only include data store and blob routes since GC only works for these two.\n\t\t\t * Note: Due to a bug with de-duped blobs, only adding data store routes for now.\n\t\t\t * 3. Ignore DDS routes to their parent datastores since those were added implicitly. So, there won't be\n\t\t\t * explicit routes to them.\n\t\t\t */\n\t\t\tcurrentOutboundRoutes.forEach((route) => {\n\t\t\t\tconst nodeType = this.runtime.getNodeType(route);\n\t\t\t\tif (\n\t\t\t\t\t(nodeType === GCNodeType.DataStore || nodeType === GCNodeType.Blob) &&\n\t\t\t\t\t!nodeId.startsWith(route) &&\n\t\t\t\t\t!previousRoutes.includes(route) &&\n\t\t\t\t\t!explicitRoutes.includes(route)\n\t\t\t\t) {\n\t\t\t\t\tmissingExplicitRoutes.push(route);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (missingExplicitRoutes.length > 0) {\n\t\t\t\tmissingExplicitReferences.push([nodeId, missingExplicitRoutes]);\n\t\t\t}\n\t\t});\n\n\t\t// Ideally missingExplicitReferences should always have a size 0\n\t\treturn missingExplicitReferences;\n\t}\n\n\t/**\n\t * Generates the stats of a garbage collection run from the given results of the run.\n\t * @param gcResult - The result of a GC run.\n\t * @returns the GC stats of the GC run.\n\t */\n\tprivate generateStats(gcResult: IGCResult): IGCStats {\n\t\tconst gcStats: IGCStats = {\n\t\t\tnodeCount: 0,\n\t\t\tdataStoreCount: 0,\n\t\t\tattachmentBlobCount: 0,\n\t\t\tunrefNodeCount: 0,\n\t\t\tunrefDataStoreCount: 0,\n\t\t\tunrefAttachmentBlobCount: 0,\n\t\t\tupdatedNodeCount: 0,\n\t\t\tupdatedDataStoreCount: 0,\n\t\t\tupdatedAttachmentBlobCount: 0,\n\t\t};\n\n\t\tconst updateNodeStats = (nodeId: string, referenced: boolean) => {\n\t\t\tgcStats.nodeCount++;\n\t\t\t// If there is no previous GC data, every node's state is generated and is considered as updated.\n\t\t\t// Otherwise, find out if any node went from referenced to unreferenced or vice-versa.\n\t\t\tconst stateUpdated =\n\t\t\t\tthis.gcDataFromLastRun === undefined ||\n\t\t\t\tthis.unreferencedNodesState.has(nodeId) === referenced;\n\t\t\tif (stateUpdated) {\n\t\t\t\tgcStats.updatedNodeCount++;\n\t\t\t}\n\t\t\tif (!referenced) {\n\t\t\t\tgcStats.unrefNodeCount++;\n\t\t\t}\n\n\t\t\tif (this.runtime.getNodeType(nodeId) === GCNodeType.DataStore) {\n\t\t\t\tgcStats.dataStoreCount++;\n\t\t\t\tif (stateUpdated) {\n\t\t\t\t\tgcStats.updatedDataStoreCount++;\n\t\t\t\t}\n\t\t\t\tif (!referenced) {\n\t\t\t\t\tgcStats.unrefDataStoreCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.runtime.getNodeType(nodeId) === GCNodeType.Blob) {\n\t\t\t\tgcStats.attachmentBlobCount++;\n\t\t\t\tif (stateUpdated) {\n\t\t\t\t\tgcStats.updatedAttachmentBlobCount++;\n\t\t\t\t}\n\t\t\t\tif (!referenced) {\n\t\t\t\t\tgcStats.unrefAttachmentBlobCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor (const nodeId of gcResult.referencedNodeIds) {\n\t\t\tupdateNodeStats(nodeId, true /* referenced */);\n\t\t}\n\n\t\tfor (const nodeId of gcResult.deletedNodeIds) {\n\t\t\tupdateNodeStats(nodeId, false /* referenced */);\n\t\t}\n\n\t\treturn gcStats;\n\t}\n\n\t/**\n\t * For nodes that are ready to sweep, log an event for now. Until we start running sweep which deletes objects,\n\t * this will give us a view into how much deleted content a container has.\n\t */\n\tprivate logSweepEvents(logger: ITelemetryLogger, currentReferenceTimestampMs: number) {\n\t\tif (\n\t\t\tthis.mc.config.getBoolean(disableSweepLogKey) === true ||\n\t\t\tthis.configs.sweepTimeoutMs === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.unreferencedNodesState.forEach((nodeStateTracker, nodeId) => {\n\t\t\tif (nodeStateTracker.state !== UnreferencedState.SweepReady) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst nodeType = this.runtime.getNodeType(nodeId);\n\t\t\tif (nodeType !== GCNodeType.DataStore && nodeType !== GCNodeType.Blob) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Log deleted event for each node only once to reduce noise in telemetry.\n\t\t\tconst uniqueEventId = `Deleted-${nodeId}`;\n\t\t\tif (this.loggedUnreferencedEvents.has(uniqueEventId)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.loggedUnreferencedEvents.add(uniqueEventId);\n\t\t\tlogger.sendTelemetryEvent({\n\t\t\t\teventName: \"GCObjectDeleted\",\n\t\t\t\tid: nodeId,\n\t\t\t\ttype: nodeType,\n\t\t\t\tage: currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs,\n\t\t\t\ttimeout: this.configs.sweepTimeoutMs,\n\t\t\t\tcompletedGCRuns: this.completedRuns,\n\t\t\t\tlastSummaryTime: this.getLastSummaryTimestampMs(),\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Called when an inactive node is used after. Queue up an event that will be logged next time GC runs.\n\t */\n\tprivate inactiveNodeUsed(\n\t\tusageType: \"Changed\" | \"Loaded\" | \"Revived\",\n\t\tnodeId: string,\n\t\tnodeStateTracker: UnreferencedStateTracker,\n\t\tfromNodeId?: string,\n\t\tpackagePath?: readonly string[],\n\t\tcurrentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(),\n\t\trequestHeaders?: IRequestHeader,\n\t) {\n\t\t// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip\n\t\t// logging as nothing interesting would have happened worth logging.\n\t\t// If the node is active, skip logging.\n\t\tif (\n\t\t\tcurrentReferenceTimestampMs === undefined ||\n\t\t\tnodeStateTracker.state === UnreferencedState.Active\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We only care about data stores and attachment blobs for this telemetry since GC only marks these objects\n\t\t// as unreferenced. Also, if an inactive DDS is used, the corresponding data store store will also be used.\n\t\tconst nodeType = this.runtime.getNodeType(nodeId);\n\t\tif (nodeType !== GCNodeType.DataStore && nodeType !== GCNodeType.Blob) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst state = nodeStateTracker.state;\n\t\tconst uniqueEventId = `${state}-${nodeId}-${usageType}`;\n\t\tif (this.loggedUnreferencedEvents.has(uniqueEventId)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.loggedUnreferencedEvents.add(uniqueEventId);\n\n\t\tconst propsToLog = {\n\t\t\tid: nodeId,\n\t\t\ttype: nodeType,\n\t\t\tunrefTime: nodeStateTracker.unreferencedTimestampMs,\n\t\t\tage: currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs,\n\t\t\ttimeout:\n\t\t\t\tnodeStateTracker.state === UnreferencedState.Inactive\n\t\t\t\t\t? this.configs.inactiveTimeoutMs\n\t\t\t\t\t: this.configs.sweepTimeoutMs,\n\t\t\tcompletedGCRuns: this.completedRuns,\n\t\t\tlastSummaryTime: this.getLastSummaryTimestampMs(),\n\t\t\t...this.createContainerMetadata,\n\t\t\tviaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],\n\t\t\tfromId: fromNodeId,\n\t\t};\n\n\t\t// For summarizer client, queue the event so it is logged the next time GC runs if the event is still valid.\n\t\t// For non-summarizer client, log the event now since GC won't run on it. This may result in false positives\n\t\t// but it's a good signal nonetheless and we can consume it with a grain of salt.\n\t\t// Inactive errors are usages of Objects that are unreferenced for at least a period of 7 days.\n\t\t// SweepReady errors are usages of Objects that will be deleted by GC Sweep!\n\t\tif (this.isSummarizerClient) {\n\t\t\tthis.pendingEventsQueue.push({ ...propsToLog, usageType, state });\n\t\t} else {\n\t\t\t// For non-summarizer clients, only log \"Loaded\" type events since these objects may not be loaded in the\n\t\t\t// summarizer clients if they are based off of user actions (such as scrolling to content for these objects)\n\t\t\t// Events generated:\n\t\t\t// InactiveObject_Loaded, SweepReadyObject_Loaded\n\t\t\tif (usageType === \"Loaded\") {\n\t\t\t\tconst event = {\n\t\t\t\t\t...propsToLog,\n\t\t\t\t\teventName: `${state}Object_${usageType}`,\n\t\t\t\t\tpkg: packagePathToTelemetryProperty(packagePath),\n\t\t\t\t\tstack: generateStack(),\n\t\t\t\t};\n\n\t\t\t\t// Do not log the inactive object x events as error events as they are not the best signal for\n\t\t\t\t// detecting something wrong with GC either from the partner or from the runtime itself.\n\t\t\t\tif (state === UnreferencedState.Inactive) {\n\t\t\t\t\tthis.mc.logger.sendTelemetryEvent(event);\n\t\t\t\t} else {\n\t\t\t\t\tthis.mc.logger.sendErrorEvent(event);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async logUnreferencedEvents(logger: ITelemetryLogger) {\n\t\t// Events sent come only from the summarizer client. In between summaries, events are pushed to a queue and at\n\t\t// summary time they are then logged.\n\t\t// Events generated:\n\t\t// InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived\n\t\t// SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived\n\t\tfor (const eventProps of this.pendingEventsQueue) {\n\t\t\tconst { usageType, state, ...propsToLog } = eventProps;\n\t\t\t/**\n\t\t\t * Revived event is logged only if the node is active. If the node is not active, the reference to it was\n\t\t\t * from another unreferenced node and this scenario is not interesting to log.\n\t\t\t * Loaded and Changed events are logged only if the node is not active. If the node is active, it was\n\t\t\t * revived and a Revived event will be logged for it.\n\t\t\t */\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(eventProps.id);\n\t\t\tconst active =\n\t\t\t\tnodeStateTracker === undefined ||\n\t\t\t\tnodeStateTracker.state === UnreferencedState.Active;\n\t\t\tif ((usageType === \"Revived\") === active) {\n\t\t\t\tconst pkg = await this.getNodePackagePath(eventProps.id);\n\t\t\t\tconst fromPkg = eventProps.fromId\n\t\t\t\t\t? await this.getNodePackagePath(eventProps.fromId)\n\t\t\t\t\t: undefined;\n\t\t\t\tconst event = {\n\t\t\t\t\t...propsToLog,\n\t\t\t\t\teventName: `${state}Object_${usageType}`,\n\t\t\t\t\tpkg: pkg\n\t\t\t\t\t\t? { value: pkg.join(\"/\"), tag: TelemetryDataTag.CodeArtifact }\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tfromPkg: fromPkg\n\t\t\t\t\t\t? { value: fromPkg.join(\"/\"), tag: TelemetryDataTag.CodeArtifact }\n\t\t\t\t\t\t: undefined,\n\t\t\t\t};\n\n\t\t\t\tif (state === UnreferencedState.Inactive) {\n\t\t\t\t\tlogger.sendTelemetryEvent(event);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.sendErrorEvent(event);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.pendingEventsQueue = [];\n\t}\n}\n"]}
1
+ {"version":3,"file":"garbageCollection.js","sourceRoot":"","sources":["../../src/gc/garbageCollection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEjG,OAAO,EACN,SAAS,GAKT,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,WAAW,EACX,yBAAyB,EAEzB,gBAAgB,GAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACN,UAAU,EAMV,iBAAiB,GAGjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,gBAAgB;IAwD5B,YAAsB,YAA2C;QAzCjE,6GAA6G;QAC7G,kCAAkC;QACjB,8BAAyB,GAA0B,IAAI,GAAG,EAAE,CAAC;QAC9E,6CAA6C;QACrC,eAAU,GAAa,EAAE,CAAC;QAClC,6DAA6D;QACrD,iBAAY,GAAgB,IAAI,GAAG,EAAE,CAAC;QAQ9C,uDAAuD;QACtC,2BAAsB,GAA0C,IAAI,GAAG,EAAE,CAAC;QAI3F,0FAA0F;QAClF,kBAAa,GAAG,CAAC,CAAC;QAsBzB,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;QACpC,IAAI,CAAC,kBAAkB,GAAG,YAAY,CAAC,kBAAkB,CAAC;QAC1D,IAAI,CAAC,kBAAkB,GAAG,YAAY,CAAC,kBAAkB,CAAC;QAC1D,IAAI,CAAC,yBAAyB,GAAG,YAAY,CAAC,yBAAyB,CAAC;QACxE,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAC;QAEtD,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,CAAC;QAC/C,MAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAC;QAEvD,IAAI,CAAC,EAAE,GAAG,yBAAyB,CAClC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,kBAAkB,EAAE;YAC/D,GAAG,EAAE,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;SAClD,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAExD,wGAAwG;QACxG,IAAI,IAAI,CAAC,OAAO,CAAC,sBAAsB,KAAK,SAAS,EAAE;YACtD,mEAAmE;YACnE,MAAM,8BAA8B,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAC9D,sDAAsD,CACtD,CAAC;YACF,MAAM,SAAS,GAAG,8BAA8B,aAA9B,8BAA8B,cAA9B,8BAA8B,GAAI,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC;YAExF,IAAI,CAAC,kBAAkB,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE;gBACnD,IAAI,CAAC,OAAO,CAAC,OAAO,CACnB,IAAI,yBAAyB,CAAC,yBAAyB,EAAE,SAAS,CAAC,CACnE,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;SAChC;QAED,IAAI,CAAC,mBAAmB,GAAG,IAAI,qBAAqB,CACnD,IAAI,CAAC,OAAO,EACZ,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,KAAK,CAAC,SAAS,CAAC,MAAK,SAAS,CAAC,4BAA4B,CACzE,CAAC;QAEF,IAAI,CAAC,gBAAgB,GAAG,IAAI,kBAAkB,CAC7C,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,kBAAkB,EACvB,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAC1C,YAAY,CAAC,uBAAuB,EACpC,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EACpD,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,EAC3D,IAAI,CAAC,kBAAkB,CACvB,CAAC;QAEF,wGAAwG;QACxG,8DAA8D;QAC9D,IAAI,CAAC,iBAAiB,GAAG,IAAI,WAAW,CACvC,KAAK,IAAI,EAAE;YACV,IAAI,YAAY,KAAK,SAAS,EAAE;gBAC/B,OAAO,SAAS,CAAC;aACjB;YAED,IAAI;gBACH,6FAA6F;gBAC7F,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACrD,IAAI,cAAc,KAAK,SAAS,EAAE;oBACjC,gGAAgG;oBAChG,kEAAkE;oBAClE,OAAO,SAAS,CAAC;iBACjB;gBAED,MAAM,YAAY,GAAG,MAAM,qBAAqB,CAC/C,cAAc,EACd,gBAAgB,CAChB,CAAC;gBAEF,oGAAoG;gBACpG,0FAA0F;gBAC1F,gGAAgG;gBAChG,uFAAuF;gBACvF,IACC,IAAI,CAAC,OAAO,CAAC,uBAAuB;oBACpC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,EACxC;oBACD,OAAO;wBACN,OAAO,EAAE,SAAS;wBAClB,UAAU,EAAE,SAAS;wBACrB,YAAY,EAAE,YAAY,CAAC,YAAY;qBACvC,CAAC;iBACF;gBACD,OAAO,YAAY,CAAC;aACpB;YAAC,OAAO,KAAK,EAAE;gBACf,MAAM,GAAG,GAAG,mBAAmB,CAAC,kBAAkB,CACjD,KAAK,EACL,sBAAsB,CACtB,CAAC;gBACF,GAAG,CAAC,sBAAsB,CAAC;oBAC1B,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;iBACvC,CAAC,CAAC;gBACH,MAAM,GAAG,CAAC;aACV;QACF,CAAC,CACD,CAAC;QAEF;;;;WAIG;QACH,IAAI,CAAC,kCAAkC,GAAG,IAAI,WAAW,CAAO,KAAK,IAAI,EAAE;YAC1E;;;;;;;eAOG;YACH,MAAM,2BAA2B,GAAG,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE,CAAC;YAClF,IAAI,2BAA2B,KAAK,SAAS,EAAE;gBAC9C,uEAAuE;gBACvE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;oBAC7B,SAAS,EAAE,6CAA6C;oBACxD,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;iBACvC,CAAC,CAAC;gBACH,OAAO;aACP;YACD;;;;;eAKG;YACH,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC;YACtD,IAAI,gBAAgB,KAAK,SAAS,EAAE;gBACnC,OAAO;aACP;YACD,IAAI,CAAC,2BAA2B,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,CAAC;YAChF,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,0GAA0G;QAC1G,qEAAqE;QACrE,IAAI,CAAC,cAAc,GAAG,IAAI,WAAW,CAAgC,KAAK,IAAI,EAAE;YAC/E,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC;YACtD,IAAI,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,OAAO,MAAK,SAAS,EAAE;gBAC5C,OAAO,EAAE,CAAC;aACV;YAED,MAAM,OAAO,GAA+B,EAAE,CAAC;YAC/C,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;gBAClF,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;aACtD;YACD,gGAAgG;YAChG,uGAAuG;YACvG,4BAA4B;YAC5B,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAE1E,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,6GAA6G;QAC7G,wGAAwG;QACxG,IAAI,IAAI,CAAC,kBAAkB,EAAE;YAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBACjC,SAAS,EAAE,wBAAwB;gBACnC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;gBACvC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC;aACjD,CAAC,CAAC;SACH;IACF,CAAC;IA7NM,MAAM,CAAC,MAAM,CAAC,YAA2C;QAC/D,OAAO,IAAI,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC;IAMD,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;IACjC,CAAC;IAyCD,IAAW,sBAAsB;QAChC,OAAO,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,CAAC;IAC3D,CAAC;IA0KD;;;OAGG;IACI,KAAK,CAAC,mBAAmB;QAC/B,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC;QACtD;;;;;WAKG;QACH,IAAI,gBAAgB,KAAK,SAAS,EAAE;YACnC,OAAO;SACP;QAED,+GAA+G;QAC/G,oCAAoC;QACpC,IAAI,gBAAgB,CAAC,YAAY,KAAK,SAAS,EAAE;YAChD,IAAI,CAAC,YAAY,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;SAC3D;QAED,8GAA8G;QAC9G,oBAAoB;QACpB,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,gBAAgB,CAAC,UAAU,KAAK,SAAS,EAAE;YAC5E,oEAAoE;YACpE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAC1D,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACrD;IACF,CAAC;IAED;;;;;;;OAOG;IACK,2BAA2B,CAClC,YAAwD,EACxD,2BAAmC;QAEnC;;;;;;;;;WASG;QAEH,kDAAkD;QAClD,KAAK,MAAM,CAAC,EAAE,gBAAgB,CAAC,IAAI,IAAI,CAAC,sBAAsB,EAAE;YAC/D,gBAAgB,CAAC,YAAY,EAAE,CAAC;SAChC;QACD,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,CAAC;QAEpC,0GAA0G;QAC1G,0GAA0G;QAC1G,cAAc;QACd,0GAA0G;QAC1G,yGAAyG;QACzG,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;YAChC,MAAM,oBAAoB,GAAG,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,YAAY;gBACtD,CAAC,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,YAAY,CAAC;gBACpC,CAAC,CAAC,SAAS,CAAC;YACb,qGAAqG;YACrG,eAAe;YACf,IAAI,oBAAoB,KAAK,SAAS,EAAE;gBACvC,MAAM,eAAe,GAAa,EAAE,CAAC;gBACrC,KAAK,MAAM,MAAM,IAAI,oBAAoB,EAAE;oBAC1C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;wBACnC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;qBAC7B;iBACD;gBACD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE;oBAC/B,2FAA2F;iBAC3F;aACD;SACD;aAAM,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,sGAAsG;YACtG,kDAAkD;YAClD,IAAI,CAAC,UAAU,GAAG,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,UAAU,EAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACrD;QAED,2GAA2G;QAC3G,IAAI,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,OAAO,MAAK,SAAS,EAAE;YACxC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;YACnC,OAAO;SACP;QAED,2GAA2G;QAC3G,yCAAyC;QACzC,MAAM,OAAO,GAA+B,EAAE,CAAC;QAC/C,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YAC9E,IAAI,QAAQ,CAAC,uBAAuB,KAAK,SAAS,EAAE;gBACnD,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAC9B,MAAM,EACN,IAAI,wBAAwB,CAC3B,QAAQ,CAAC,uBAAuB,EAChC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAC9B,2BAA2B,EAC3B,IAAI,CAAC,OAAO,CAAC,cAAc,CAC3B,CACD,CAAC;aACF;YACD,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;SACtD;QACD,IAAI,CAAC,iBAAiB,GAAG,EAAE,OAAO,EAAE,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACI,kBAAkB,CAAC,SAAkB,EAAE,QAA6B;QAC1E;;;;;;;;;;;;WAYG;QACH,IAAI,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YACxD,IAAI,CAAC,kCAAkC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,GAAE,CAAC,CAAC,CAAC;SAC7D;IACF,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,cAAc,CAC1B,OAOC,EACD,gBAAoC;;QAEpC,MAAM,MAAM,GACX,MAAA,OAAO,CAAC,MAAM,mCACd,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,CAAC,CAAC;QAEzF,oEAAoE;QACpE,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE;YACpD,MAAM;YACN,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC1B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;YAC5B,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;gBAC9C,GAAG,EAAE,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;aACjD,CAAC;YACJ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;QAElB;;;;;;;WAOG;QACH,MAAM,2BAA2B,GAAG,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE,CAAC;QAClF,IAAI,2BAA2B,KAAK,SAAS,EAAE;YAC9C,uEAAuE;YACvE,MAAM,CAAC,cAAc,CAAC;gBACrB,SAAS,EAAE,sCAAsC;gBACjD,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;aACvC,CAAC,CAAC;YACH,OAAO,SAAS,CAAC;SACjB;QAED,OAAO,gBAAgB,CAAC,cAAc,CACrC,MAAM,EACN,EAAE,SAAS,EAAE,mBAAmB,EAAE,EAClC,KAAK,EAAE,KAAK,EAAE,EAAE;YACf,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAE3B,qEAAqE;YACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAE7D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CACxC,MAAM,EACN,QAAQ,EACR,MAAM,EACN,2BAA2B,CAC3B,CAAC;YACF,KAAK,CAAC,GAAG,iCAAM,OAAO,KAAE,SAAS,EAAE,2BAA2B,IAAG,CAAC;YAClE,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO,OAAO,CAAC;QAChB,CAAC,EACD,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAC9B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa;QAC1B,sEAAsE;QACtE,MAAM,IAAI,CAAC,kCAAkC,CAAC;QAC9C,2DAA2D;QAC3D,MAAM,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,cAAc,CAC3B,MAA8B,EAC9B,QAAmB,EACnB,MAAwB,EACxB,2BAAmC;QAEnC,sGAAsG;QACtG,oEAAoE;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAE7C,8GAA8G;QAC9G,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAC3C,MAAM,EACN,QAAQ,EACR,2BAA2B,EAC3B,MAAM,CACN,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QAE1D,gEAAgE;QAChE,IAAI,CAAC,gBAAgB,CAAC,cAAc,CACnC,MAAM,EACN,2BAA2B,EAC3B,IAAI,CAAC,sBAAsB,EAC3B,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,yBAAyB,EAAE,CAChC,CAAC;QAEF,IAAI,aAAa,GAA2B,MAAM,CAAC;QAEnD,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;YAChC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;SAC5D;aAAM,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;YACjC,sGAAsG;YACtG,oCAAoC;YACpC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;SACzD;aAAM,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC;YAClC,mGAAmG;YACnG,wFAAwF;YACxF,4CAA4C;YAC5C,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACrD;QAED,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;QAEpD,2GAA2G;QAC3G,+GAA+G;QAC/G,wGAAwG;QACxG,MAAM,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAErD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACI,SAAS,CACf,QAAiB,EACjB,UAAmB,EACnB,gBAAoC;;QAEpC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE;YACtE,OAAO;SACP;QAED,MAAM,OAAO,GAA4B,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzD,KAAK,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE;YACtF,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG;gBACzB,cAAc;gBACd,uBAAuB,EACtB,MAAA,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,0CAAE,uBAAuB;aACjE,CAAC;SACF;QAED,OAAO,IAAI,CAAC,mBAAmB,CAAC,SAAS,CACxC,QAAQ,EACR,UAAU,EACV,OAAO,EACP,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,UAAU,CACf,CAAC;IACH,CAAC;IAEM,WAAW;QACjB,OAAO;YACN;;;eAGG;YACH,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;YACjF,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,wBAAwB;YACtD,sBAAsB,EAAE,IAAI,CAAC,OAAO,CAAC,sBAAsB;YAC3D,YAAY,EAAE,KAAK;YACnB,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;SAC3C,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,gBAAgB;QAC5B,OAAO,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,oBAAoB,CAChC,cAAkC,EAClC,MAA4B,EAC5B,gBAAkC;QAElC,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,oBAAoB,CAC7E,cAAc,EACd,MAAM,EACN,gBAAgB,CAChB,CAAC;QAEF,8GAA8G;QAC9G,sBAAsB;QACtB,IAAI,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,oBAAoB,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;YACjF,4GAA4G;YAC5G,qFAAqF;YACrF,MAAM,2BAA2B,GAAG,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE,CAAC;YAClF,IAAI,2BAA2B,KAAK,SAAS,EAAE;gBAC9C,MAAM,mBAAmB,CAAC,MAAM,CAC/B,6DAA6D,EAC7D,sBAAsB,EACtB,SAAS,EACT;oBACC,cAAc;oBACd,aAAa,EAAE,MAAM,CAAC,aAAa;oBACnC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;iBACvC,CACD,CAAC;aACF;YACD,IAAI,CAAC,2BAA2B,CAAC,kBAAkB,EAAE,2BAA2B,CAAC,CAAC;SAClF;IACF,CAAC;IAED;;;;;;;OAOG;IACI,WAAW,CACjB,QAAgB,EAChB,MAA4B,EAC5B,WAAoB,EACpB,WAA+B,EAC/B,cAA+B;QAE/B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YAC9B,OAAO;SACP;QAED,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YAC9B,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,MAAM;YACjB,2BAA2B,EAC1B,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE;YAC7D,WAAW;YACX,eAAe,EAAE,IAAI,CAAC,aAAa;YACnC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAChD,eAAe,EAAE,IAAI,CAAC,yBAAyB,EAAE;YACjD,SAAS,EAAE,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAG,cAAc,CAAC,SAAS,CAAC;SACrD,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,sBAAsB,CAAC,YAAoB,EAAE,UAAkB;;QACrE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YAC9B,OAAO;SACP;QAED,MAAM,cAAc,GAAG,MAAA,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,YAAY,CAAC,mCAAI,EAAE,CAAC;QAC9E,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QAEjE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YAC9B,MAAM,EAAE,UAAU;YAClB,SAAS,EAAE,SAAS;YACpB,2BAA2B,EAAE,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE;YAC1E,WAAW,EAAE,SAAS;YACtB,eAAe,EAAE,IAAI,CAAC,aAAa;YACnC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC;YAClD,eAAe,EAAE,IAAI,CAAC,yBAAyB,EAAE;YACjD,MAAM,EAAE,YAAY;SACpB,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,aAAa,CAAC,QAAgB;QACpC,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAEM,OAAO;;QACb,MAAA,IAAI,CAAC,kBAAkB,0CAAE,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,kBAAkB,GAAG,SAAS,CAAC;IACrC,CAAC;IAED;;;;;;;;;OASG;IACK,eAAe,CACtB,MAA8B,EAC9B,QAAmB,EACnB,2BAAmC,EACnC,MAAwB;;QAExB,4GAA4G;QAC5G,eAAe;QACf,MAAM,4BAA4B,GACjC,MAAA,IAAI,CAAC,gCAAgC,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,mCAC7E,QAAQ,CAAC,iBAAiB,CAAC;QAC5B,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,CAAC;QAEvC,2FAA2F;QAC3F,KAAK,MAAM,MAAM,IAAI,4BAA4B,EAAE;YAClD,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,gBAAgB,KAAK,SAAS,EAAE;gBACnC,uDAAuD;gBACvD,gBAAgB,CAAC,YAAY,EAAE,CAAC;gBAChC,yDAAyD;gBACzD,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;aAC3C;SACD;QAED;;;;;;WAMG;QACH,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE;YAC7C,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,gBAAgB,KAAK,SAAS,EAAE;gBACnC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAC9B,MAAM,EACN,IAAI,wBAAwB,CAC3B,2BAA2B,EAC3B,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAC9B,2BAA2B,EAC3B,IAAI,CAAC,OAAO,CAAC,cAAc,CAC3B,CACD,CAAC;aACF;iBAAM;gBACN,gBAAgB,CAAC,cAAc,CAAC,2BAA2B,CAAC,CAAC;gBAC7D,IAAI,gBAAgB,CAAC,KAAK,KAAK,iBAAiB,CAAC,UAAU,EAAE;oBAC5D,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;iBAC7B;aACD;SACD;QAED,OAAO,eAAe,CAAC;IACxB,CAAC;IAED;;;OAGG;IACK,aAAa,CAAC,eAAyB,EAAE,MAA8B;QAC9E,4EAA4E;QAC5E,6FAA6F;QAC7F,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,eAAe,CAAC,CAAC;QACxE,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAElE,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE;YACjC,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjE,oEAAoE;YACpE,IAAI,gBAAgB,KAAK,SAAS,EAAE;gBACnC,uDAAuD;gBACvD,gBAAgB,CAAC,YAAY,EAAE,CAAC;gBAChC,yDAAyD;gBACzD,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;aAC3C;YACD,wEAAwE;YACxE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC9B;QAED,OAAO,aAAa,CAAC;IACtB,CAAC;IAED;;OAEG;IACK,iBAAiB,CACxB,WAAqB,EACrB,MAA8B;QAE9B,MAAM,cAAc,GAAG,IAAI,GAAG,CAAS,WAAW,CAAC,CAAC;QACpD,MAAM,OAAO,GAA+B,EAAE,CAAC;QAC/C,KAAK,MAAM,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;YAClE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBAC5B,OAAO,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;aACzC;SACD;QAED,4DAA4D;QAE5D,OAAO;YACN,OAAO;SACP,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACK,gCAAgC,CACvC,aAAqC,EACrC,cAAkD,EAClD,MAAwB;QAExB,sDAAsD;QACtD,uGAAuG;QACvG,IAAI,cAAc,KAAK,SAAS,EAAE;YACjC,OAAO,SAAS,CAAC;SACjB;QAED;;;WAGG;QACH,IAAI,CAAC,gBAAgB,CAAC,8BAA8B,CACnD,aAAa,EACb,cAAc,EACd,IAAI,CAAC,yBAAyB,EAC9B,MAAM,CACN,CAAC;QAEF,8GAA8G;QAC9G,qDAAqD;QACrD,IAAI,IAAI,CAAC,yBAAyB,CAAC,IAAI,KAAK,CAAC,EAAE;YAC9C,OAAO,SAAS,CAAC;SACjB;QAED;;;;;;;;;;;;;;;WAeG;QACH,MAAM,cAAc,GAAG,2BAA2B,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;QAClF,MAAM,6BAA6B,GAAa,EAAE,CAAC;QACnD,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC,cAAwB,EAAE,YAAoB,EAAE,EAAE;YACzF,IAAI,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,SAAS,EAAE;gBACvD,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,cAAc,CAAC;aACtD;iBAAM;gBACN,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;aAC7D;YACD,6BAA6B,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH;;;;;;WAMG;QACH,MAAM,QAAQ,GAAG,oBAAoB,CAAC,cAAc,CAAC,OAAO,EAAE;YAC7D,GAAG;YACH,GAAG,6BAA6B;SAChC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,iBAAiB,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACK,aAAa,CAAC,QAAmB;QACxC,MAAM,OAAO,GAAa;YACzB,SAAS,EAAE,CAAC;YACZ,cAAc,EAAE,CAAC;YACjB,mBAAmB,EAAE,CAAC;YACtB,cAAc,EAAE,CAAC;YACjB,mBAAmB,EAAE,CAAC;YACtB,wBAAwB,EAAE,CAAC;YAC3B,gBAAgB,EAAE,CAAC;YACnB,qBAAqB,EAAE,CAAC;YACxB,0BAA0B,EAAE,CAAC;SAC7B,CAAC;QAEF,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,UAAmB,EAAE,EAAE;YAC/D,OAAO,CAAC,SAAS,EAAE,CAAC;YACpB,iGAAiG;YACjG,sFAAsF;YACtF,MAAM,YAAY,GACjB,IAAI,CAAC,iBAAiB,KAAK,SAAS;gBACpC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC;YACxD,IAAI,YAAY,EAAE;gBACjB,OAAO,CAAC,gBAAgB,EAAE,CAAC;aAC3B;YACD,IAAI,CAAC,UAAU,EAAE;gBAChB,OAAO,CAAC,cAAc,EAAE,CAAC;aACzB;YAED,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,SAAS,EAAE;gBAC9D,OAAO,CAAC,cAAc,EAAE,CAAC;gBACzB,IAAI,YAAY,EAAE;oBACjB,OAAO,CAAC,qBAAqB,EAAE,CAAC;iBAChC;gBACD,IAAI,CAAC,UAAU,EAAE;oBAChB,OAAO,CAAC,mBAAmB,EAAE,CAAC;iBAC9B;aACD;YACD,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,IAAI,EAAE;gBACzD,OAAO,CAAC,mBAAmB,EAAE,CAAC;gBAC9B,IAAI,YAAY,EAAE;oBACjB,OAAO,CAAC,0BAA0B,EAAE,CAAC;iBACrC;gBACD,IAAI,CAAC,UAAU,EAAE;oBAChB,OAAO,CAAC,wBAAwB,EAAE,CAAC;iBACnC;aACD;QACF,CAAC,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,iBAAiB,EAAE;YAChD,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;SAC/C;QAED,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE;YAC7C,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;SAChD;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { LazyPromise, Timer } from \"@fluidframework/common-utils\";\nimport { ClientSessionExpiredError, DataProcessingError } from \"@fluidframework/container-utils\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport {\n\tgcTreeKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n\tISummarizeResult,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"@fluidframework/runtime-utils\";\nimport {\n\tChildLogger,\n\tloggerToMonitoringContext,\n\tMonitoringContext,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils\";\n\nimport { RuntimeHeaders } from \"../containerRuntime\";\nimport { RefreshSummaryResult } from \"../summary\";\nimport { generateGCConfigs } from \"./gcConfigs\";\nimport {\n\tGCNodeType,\n\tIGarbageCollector,\n\tIGarbageCollectorCreateParams,\n\tIGarbageCollectionRuntime,\n\tIGCResult,\n\tIGCStats,\n\tUnreferencedState,\n\tIGCMetadata,\n\tIGarbageCollectorConfigs,\n} from \"./gcDefinitions\";\nimport { cloneGCData, concatGarbageCollectionData, getGCDataFromSnapshot } from \"./gcHelpers\";\nimport { runGarbageCollection } from \"./gcReferenceGraphAlgorithm\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { GCSummaryStateTracker } from \"./gcSummaryStateTracker\";\nimport { UnreferencedStateTracker } from \"./gcUnreferencedStateTracker\";\nimport { GCTelemetryTracker } from \"./gcTelemetry\";\n\n/**\n * The garbage collector for the container runtime. It consolidates the garbage collection functionality and maintains\n * its state across summaries.\n *\n * Node - represented as nodeId, it's a node on the GC graph\n *\n * Outbound Route - a path from one node to another node, think `nodeA` -\\> `nodeB`\n *\n * Graph - all nodes with their respective routes\n *\n * ```\n *\t\t\t GC Graph\n *\n *\t\t\t Node\n *\t\tNodeId = \"datastore1\"\n *\t\t /\t\t\t \\\\\n *\tOutboundRoute OutboundRoute\n *\t\t /\t\t\t\t \\\\\n *\t Node\t\t\t Node\n * NodeId = \"dds1\"\t NodeId = \"dds2\"\n * ```\n */\nexport class GarbageCollector implements IGarbageCollector {\n\tpublic static create(createParams: IGarbageCollectorCreateParams): IGarbageCollector {\n\t\treturn new GarbageCollector(createParams);\n\t}\n\n\tprivate readonly mc: MonitoringContext;\n\n\tprivate readonly configs: IGarbageCollectorConfigs;\n\n\tpublic get shouldRunGC(): boolean {\n\t\treturn this.configs.shouldRunGC;\n\t}\n\n\t// Keeps track of the GC state from the last run.\n\tprivate gcDataFromLastRun: IGarbageCollectionData | undefined;\n\t// Keeps a list of references (edges in the GC graph) between GC runs. Each entry has a node id and a list of\n\t// outbound routes from that node.\n\tprivate readonly newReferencesSinceLastRun: Map<string, string[]> = new Map();\n\t// A list of nodes that have been tombstoned.\n\tprivate tombstones: string[] = [];\n\t// A list of nodes that have been deleted during sweep phase.\n\tprivate deletedNodes: Set<string> = new Set();\n\n\t// Promise when resolved returns the GC data data in the base snapshot.\n\tprivate readonly baseSnapshotDataP: Promise<IGarbageCollectionSnapshotData | undefined>;\n\t// Promise when resolved initializes the GC state from the data in the base snapshot.\n\tprivate readonly initializeGCStateFromBaseSnapshotP: Promise<void>;\n\t// The GC details generated from the base snapshot.\n\tprivate readonly baseGCDetailsP: Promise<IGarbageCollectionDetailsBase>;\n\t// Map of node ids to their unreferenced state tracker.\n\tprivate readonly unreferencedNodesState: Map<string, UnreferencedStateTracker> = new Map();\n\t// The Timer responsible for closing the container when the session has expired\n\tprivate sessionExpiryTimer: Timer | undefined;\n\n\t// The number of times GC has successfully completed on this instance of GarbageCollector.\n\tprivate completedRuns = 0;\n\n\tprivate readonly runtime: IGarbageCollectionRuntime;\n\tprivate readonly isSummarizerClient: boolean;\n\n\tprivate readonly summaryStateTracker: GCSummaryStateTracker;\n\tprivate readonly telemetryTracker: GCTelemetryTracker;\n\n\t/** For a given node path, returns the node's package path. */\n\tprivate readonly getNodePackagePath: (\n\t\tnodePath: string,\n\t) => Promise<readonly string[] | undefined>;\n\t/** Returns the timestamp of the last summary generated for this container. */\n\tprivate readonly getLastSummaryTimestampMs: () => number | undefined;\n\t/** Returns true if connection is active, i.e. it's \"write\" connection and the runtime is connected. */\n\tprivate readonly activeConnection: () => boolean;\n\n\tpublic get summaryStateNeedsReset(): boolean {\n\t\treturn this.summaryStateTracker.doesSummaryStateNeedReset;\n\t}\n\n\tprotected constructor(createParams: IGarbageCollectorCreateParams) {\n\t\tthis.runtime = createParams.runtime;\n\t\tthis.isSummarizerClient = createParams.isSummarizerClient;\n\t\tthis.getNodePackagePath = createParams.getNodePackagePath;\n\t\tthis.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;\n\t\tthis.activeConnection = createParams.activeConnection;\n\n\t\tconst baseSnapshot = createParams.baseSnapshot;\n\t\tconst readAndParseBlob = createParams.readAndParseBlob;\n\n\t\tthis.mc = loggerToMonitoringContext(\n\t\t\tChildLogger.create(createParams.baseLogger, \"GarbageCollector\", {\n\t\t\t\tall: { completedGCRuns: () => this.completedRuns },\n\t\t\t}),\n\t\t);\n\n\t\tthis.configs = generateGCConfigs(this.mc, createParams);\n\n\t\t// If session expiry is enabled, we need to close the container when the session expiry timeout expires.\n\t\tif (this.configs.sessionExpiryTimeoutMs !== undefined) {\n\t\t\t// If Test Override config is set, override Session Expiry timeout.\n\t\t\tconst overrideSessionExpiryTimeoutMs = this.mc.config.getNumber(\n\t\t\t\t\"Fluid.GarbageCollection.TestOverride.SessionExpiryMs\",\n\t\t\t);\n\t\t\tconst timeoutMs = overrideSessionExpiryTimeoutMs ?? this.configs.sessionExpiryTimeoutMs;\n\n\t\t\tthis.sessionExpiryTimer = new Timer(timeoutMs, () => {\n\t\t\t\tthis.runtime.closeFn(\n\t\t\t\t\tnew ClientSessionExpiredError(`Client session expired.`, timeoutMs),\n\t\t\t\t);\n\t\t\t});\n\t\t\tthis.sessionExpiryTimer.start();\n\t\t}\n\n\t\tthis.summaryStateTracker = new GCSummaryStateTracker(\n\t\t\tthis.configs,\n\t\t\tbaseSnapshot?.trees[gcTreeKey] !== undefined /* wasGCRunInBaseSnapshot */,\n\t\t);\n\n\t\tthis.telemetryTracker = new GCTelemetryTracker(\n\t\t\tthis.mc,\n\t\t\tthis.configs,\n\t\t\tthis.isSummarizerClient,\n\t\t\tthis.runtime.gcTombstoneEnforcementAllowed,\n\t\t\tcreateParams.createContainerMetadata,\n\t\t\t(nodeId: string) => this.runtime.getNodeType(nodeId),\n\t\t\t(nodeId: string) => this.unreferencedNodesState.get(nodeId),\n\t\t\tthis.getNodePackagePath,\n\t\t);\n\n\t\t// Get the GC data from the base snapshot. Use LazyPromise because we only want to do this once since it\n\t\t// it involves fetching blobs from storage which is expensive.\n\t\tthis.baseSnapshotDataP = new LazyPromise<IGarbageCollectionSnapshotData | undefined>(\n\t\t\tasync () => {\n\t\t\t\tif (baseSnapshot === undefined) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\t// For newer documents, GC data should be present in the GC tree in the root of the snapshot.\n\t\t\t\t\tconst gcSnapshotTree = baseSnapshot.trees[gcTreeKey];\n\t\t\t\t\tif (gcSnapshotTree === undefined) {\n\t\t\t\t\t\t// back-compat - Older documents get their gc data reset for simplicity as there are few of them\n\t\t\t\t\t\t// incremental gc summary will not work with older gc data as well\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst snapshotData = await getGCDataFromSnapshot(\n\t\t\t\t\t\tgcSnapshotTree,\n\t\t\t\t\t\treadAndParseBlob,\n\t\t\t\t\t);\n\n\t\t\t\t\t// If the GC version in base snapshot does not match the GC version currently in effect, the GC data\n\t\t\t\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for\n\t\t\t\t\t// deletedNodes because irrespective of GC versions, these nodes have been deleted and cannot be\n\t\t\t\t\t// brought back. The deletedNodes info is needed to identify when these nodes are used.\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.configs.gcVersionInBaseSnapshot !==\n\t\t\t\t\t\tthis.summaryStateTracker.currentGCVersion\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tgcState: undefined,\n\t\t\t\t\t\t\ttombstones: undefined,\n\t\t\t\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn snapshotData;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst dpe = DataProcessingError.wrapIfUnrecognized(\n\t\t\t\t\t\terror,\n\t\t\t\t\t\t\"FailedToInitializeGC\",\n\t\t\t\t\t);\n\t\t\t\t\tdpe.addTelemetryProperties({\n\t\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t\t});\n\t\t\t\t\tthrow dpe;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\t/**\n\t\t * Set up the initializer which initializes the GC state from the data in base snapshot. This is done when\n\t\t * connected in write mode or when GC runs the first time. It sets up all unreferenced nodes from the base\n\t\t * GC state and updates their inactive or sweep ready state.\n\t\t */\n\t\tthis.initializeGCStateFromBaseSnapshotP = new LazyPromise<void>(async () => {\n\t\t\t/**\n\t\t\t * If there is no current reference timestamp, skip initialization. We need the current timestamp to track\n\t\t\t * how long objects have been unreferenced and if they can be deleted.\n\t\t\t *\n\t\t\t * Note that the only scenario where there is no reference timestamp is when no ops have ever been processed\n\t\t\t * for this container and it is in read mode. In this scenario, there is no point in running GC anyway\n\t\t\t * because references in the container do not change without any ops, i.e., there is nothing to collect.\n\t\t\t */\n\t\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t\t// Log an event so we can evaluate how often we run into this scenario.\n\t\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"GarbageCollectorInitializedWithoutTimestamp\",\n\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t/**\n\t\t\t * The base snapshot data will not be present if the container is loaded from:\n\t\t\t * 1. The first summary created by the detached container.\n\t\t\t * 2. A summary that was generated with GC disabled.\n\t\t\t * 3. A summary that was generated before GC even existed.\n\t\t\t */\n\t\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t\tif (baseSnapshotData === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.updateStateFromSnapshotData(baseSnapshotData, currentReferenceTimestampMs);\n\t\t\tthis.summaryStateTracker.initializeBaseState(baseSnapshotData);\n\t\t});\n\n\t\t// Get the GC details from the GC state in the base summary. This is returned in getBaseGCDetails which is\n\t\t// used to initialize the GC state of all the nodes in the container.\n\t\tthis.baseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {\n\t\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t\tif (baseSnapshotData?.gcState === undefined) {\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\t\tfor (const [nodeId, nodeData] of Object.entries(baseSnapshotData.gcState.gcNodes)) {\n\t\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t\t}\n\t\t\t// Run GC on the nodes in the base summary to get the routes used in each node in the container.\n\t\t\t// This is an optimization for space (vs performance) wherein we don't need to store the used routes of\n\t\t\t// each node in the summary.\n\t\t\tconst usedRoutes = runGarbageCollection(gcNodes, [\"/\"]).referencedNodeIds;\n\n\t\t\treturn { gcData: { gcNodes }, usedRoutes };\n\t\t});\n\n\t\t// Log all the GC options and the state determined by the garbage collector. This is interesting only for the\n\t\t// summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.\n\t\tif (this.isSummarizerClient) {\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"GarbageCollectorLoaded\",\n\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\tgcOptions: JSON.stringify(createParams.gcOptions),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Called during container initialization. Initialize from the tombstone state in the base snapshot. This is done\n\t * during initialization so that deleted or tombstoned objects are marked as such before they are loaded or used.\n\t */\n\tpublic async initializeBaseState(): Promise<void> {\n\t\tconst baseSnapshotData = await this.baseSnapshotDataP;\n\t\t/**\n\t\t * The base snapshot data will not be present if the container is loaded from:\n\t\t * 1. The first summary created by the detached container.\n\t\t * 2. A summary that was generated with GC disabled.\n\t\t * 3. A summary that was generated before GC even existed.\n\t\t */\n\t\tif (baseSnapshotData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Initialize the deleted nodes from the snapshot. This is done irrespective of whether sweep is enabled or not\n\t\t// to identify deleted nodes' usage.\n\t\tif (baseSnapshotData.deletedNodes !== undefined) {\n\t\t\tthis.deletedNodes = new Set(baseSnapshotData.deletedNodes);\n\t\t}\n\n\t\t// If running in tombstone mode, initialize the tombstone state from the snapshot. Also, notify the runtime of\n\t\t// tombstone routes.\n\t\tif (this.configs.tombstoneMode && baseSnapshotData.tombstones !== undefined) {\n\t\t\t// Create a copy since we are writing from a source we don't control\n\t\t\tthis.tombstones = Array.from(baseSnapshotData.tombstones);\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\t}\n\n\t/**\n\t * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.\n\t * All current tracking is reset and updated from the data in the snapshot.\n\t * @param snapshotData - The snapshot data to update state from. If this is undefined, all GC state and tracking\n\t * is reset.\n\t * @param currentReferenceTimestampMs - The current reference timestamp for marking unreferenced nodes' unreferenced\n\t * timestamp.\n\t */\n\tprivate updateStateFromSnapshotData(\n\t\tsnapshotData: IGarbageCollectionSnapshotData | undefined,\n\t\tcurrentReferenceTimestampMs: number,\n\t) {\n\t\t/**\n\t\t * Note: \"newReferencesSinceLastRun\" is not reset here. This is done because there may be references since the\n\t\t * snapshot that we are updating state from. For example, this client may have processed ops till seq#1000 and\n\t\t * its refreshing state from a summary that happened at seq#900. In this case, there may be references between\n\t\t * seq#901 and seq#1000 that we don't want to reset.\n\t\t * Unfortunately, there is no way to track the seq# of ops that add references, so we choose to not reset any\n\t\t * references here. This should be fine because, in the worst case, we may end up updating the unreferenced\n\t\t * timestamp of a node which will delay its deletion. Although not ideal, this will only happen in rare\n\t\t * scenarios, so it should be okay.\n\t\t */\n\n\t\t// Clear all existing unreferenced state tracking.\n\t\tfor (const [, nodeStateTracker] of this.unreferencedNodesState) {\n\t\t\tnodeStateTracker.stopTracking();\n\t\t}\n\t\tthis.unreferencedNodesState.clear();\n\n\t\t// If running sweep, the tombstone state represents the list of nodes that have been deleted during sweep.\n\t\t// If running in tombstone mode, the tombstone state represents the list of nodes that have been marked as\n\t\t// tombstones.\n\t\t// If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state\n\t\t// in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.\n\t\tif (this.configs.shouldRunSweep) {\n\t\t\tconst snapshotDeletedNodes = snapshotData?.deletedNodes\n\t\t\t\t? new Set(snapshotData.deletedNodes)\n\t\t\t\t: undefined;\n\t\t\t// If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to\n\t\t\t// delete them.\n\t\t\tif (snapshotDeletedNodes !== undefined) {\n\t\t\t\tconst newDeletedNodes: string[] = [];\n\t\t\t\tfor (const nodeId of snapshotDeletedNodes) {\n\t\t\t\t\tif (!this.deletedNodes.has(nodeId)) {\n\t\t\t\t\t\tnewDeletedNodes.push(nodeId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (newDeletedNodes.length > 0) {\n\t\t\t\t\t// Call container runtime to delete these nodes and add deleted nodes to this.deletedNodes.\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.configs.tombstoneMode) {\n\t\t\t// The snapshot may contain more or fewer tombstone nodes than this client. Update tombstone state and\n\t\t\t// notify the runtime to update its state as well.\n\t\t\tthis.tombstones = snapshotData?.tombstones ? Array.from(snapshotData.tombstones) : [];\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\n\t\t// If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.\n\t\tif (snapshotData?.gcState === undefined) {\n\t\t\tthis.gcDataFromLastRun = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\t// Update unreferenced state tracking as per the GC state in the snapshot data and update gcDataFromLastRun\n\t\t// to the GC data from the snapshot data.\n\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\tfor (const [nodeId, nodeData] of Object.entries(snapshotData.gcState.gcNodes)) {\n\t\t\tif (nodeData.unreferencedTimestampMs !== undefined) {\n\t\t\t\tthis.unreferencedNodesState.set(\n\t\t\t\t\tnodeId,\n\t\t\t\t\tnew UnreferencedStateTracker(\n\t\t\t\t\t\tnodeData.unreferencedTimestampMs,\n\t\t\t\t\t\tthis.configs.inactiveTimeoutMs,\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.sweepTimeoutMs,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t}\n\t\tthis.gcDataFromLastRun = { gcNodes };\n\t}\n\n\t/**\n\t * Called when the connection state of the runtime changes, i.e., it connects or disconnects. GC subscribes to this\n\t * to initialize the base state for non-summarizer clients so that they can track inactive / sweep ready nodes.\n\t * @param connected - Whether the runtime connected / disconnected.\n\t * @param clientId - The clientId of this runtime.\n\t */\n\tpublic setConnectionState(connected: boolean, clientId?: string | undefined): void {\n\t\t/**\n\t\t * For all clients, initialize the base state when the container becomes active, i.e., it transitions\n\t\t * to \"write\" mode. This will ensure that the container's own join op is processed and there is a recent\n\t\t * reference timestamp that will be used to update the state of unreferenced nodes. Also, all trailing ops which\n\t\t * could affect the GC state will have been processed.\n\t\t *\n\t\t * If GC is up-to-date for the client and the summarizing client, there will be an doubling of both\n\t\t * InactiveObject_Loaded and SweepReady_Loaded errors, as there will be one from the sending client and one from\n\t\t * the receiving summarizer client.\n\t\t *\n\t\t * Ideally, this initialization should only be done for summarizer client. However, we are currently rolling out\n\t\t * sweep in phases and we want to track when inactive and sweep ready objects are used in any client.\n\t\t */\n\t\tif (this.activeConnection() && this.configs.shouldRunGC) {\n\t\t\tthis.initializeGCStateFromBaseSnapshotP.catch((error) => {});\n\t\t}\n\t}\n\n\t/**\n\t * Runs garbage collection and updates the reference / used state of the nodes in the container.\n\t * @returns stats of the GC run or undefined if GC did not run.\n\t */\n\tpublic async collectGarbage(\n\t\toptions: {\n\t\t\t/** Logger to use for logging GC events */\n\t\t\tlogger?: ITelemetryLogger;\n\t\t\t/** True to run GC sweep phase after the mark phase */\n\t\t\trunSweep?: boolean;\n\t\t\t/** True to generate full GC data */\n\t\t\tfullGC?: boolean;\n\t\t},\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<IGCStats | undefined> {\n\t\tconst fullGC =\n\t\t\toptions.fullGC ??\n\t\t\t(this.configs.runFullGC === true || this.summaryStateTracker.doesSummaryStateNeedReset);\n\n\t\t// Add the options that are used to run GC to the telemetry context.\n\t\ttelemetryContext?.setMultiple(\"fluid_GC\", \"Options\", {\n\t\t\tfullGC,\n\t\t\trunSweep: options.runSweep,\n\t\t});\n\n\t\tconst logger = options.logger\n\t\t\t? ChildLogger.create(options.logger, undefined, {\n\t\t\t\t\tall: { completedGCRuns: () => this.completedRuns },\n\t\t\t })\n\t\t\t: this.mc.logger;\n\n\t\t/**\n\t\t * If there is no current reference timestamp, skip running GC. We need the current timestamp to track\n\t\t * how long objects have been unreferenced and if they should be deleted.\n\t\t *\n\t\t * Note that the only scenario where GC is called and there is no reference timestamp is when no ops have ever\n\t\t * been processed for this container and it is in read mode. In this scenario, there is no point in running GC\n\t\t * anyway because references in the container do not change without any ops, i.e., there is nothing to collect.\n\t\t */\n\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t// Log an event so we can evaluate how often we run into this scenario.\n\t\t\tlogger.sendErrorEvent({\n\t\t\t\teventName: \"CollectGarbageCalledWithoutTimestamp\",\n\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tlogger,\n\t\t\t{ eventName: \"GarbageCollection\" },\n\t\t\tasync (event) => {\n\t\t\t\tawait this.runPreGCSteps();\n\n\t\t\t\t// Get the runtime's GC data and run GC on the reference graph in it.\n\t\t\t\tconst gcData = await this.runtime.getGCData(fullGC);\n\t\t\t\tconst gcResult = runGarbageCollection(gcData.gcNodes, [\"/\"]);\n\n\t\t\t\tconst gcStats = await this.runPostGCSteps(\n\t\t\t\t\tgcData,\n\t\t\t\t\tgcResult,\n\t\t\t\t\tlogger,\n\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t);\n\t\t\t\tevent.end({ ...gcStats, timestamp: currentReferenceTimestampMs });\n\t\t\t\tthis.completedRuns++;\n\t\t\t\treturn gcStats;\n\t\t\t},\n\t\t\t{ end: true, cancel: \"error\" },\n\t\t);\n\t}\n\n\tprivate async runPreGCSteps() {\n\t\t// Ensure that state has been initialized from the base snapshot data.\n\t\tawait this.initializeGCStateFromBaseSnapshotP;\n\t\t// Let the runtime update its pending state before GC runs.\n\t\tawait this.runtime.updateStateBeforeGC();\n\t}\n\n\tprivate async runPostGCSteps(\n\t\tgcData: IGarbageCollectionData,\n\t\tgcResult: IGCResult,\n\t\tlogger: ITelemetryLogger,\n\t\tcurrentReferenceTimestampMs: number,\n\t): Promise<IGCStats> {\n\t\t// Generate statistics from the current run. This is done before updating the current state because it\n\t\t// generates some of its data based on previous state of the system.\n\t\tconst gcStats = this.generateStats(gcResult);\n\n\t\t// Update the current mark state and update the runtime of all used routes or ids that used as per the GC run.\n\t\tconst sweepReadyNodes = this.updateMarkPhase(\n\t\t\tgcData,\n\t\t\tgcResult,\n\t\t\tcurrentReferenceTimestampMs,\n\t\t\tlogger,\n\t\t);\n\t\tthis.runtime.updateUsedRoutes(gcResult.referencedNodeIds);\n\n\t\t// Log events for objects that are ready to be deleted by sweep.\n\t\tthis.telemetryTracker.logSweepEvents(\n\t\t\tlogger,\n\t\t\tcurrentReferenceTimestampMs,\n\t\t\tthis.unreferencedNodesState,\n\t\t\tthis.completedRuns,\n\t\t\tthis.getLastSummaryTimestampMs(),\n\t\t);\n\n\t\tlet updatedGCData: IGarbageCollectionData = gcData;\n\n\t\tif (this.configs.shouldRunSweep) {\n\t\t\tupdatedGCData = this.runSweepPhase(sweepReadyNodes, gcData);\n\t\t} else if (this.configs.testMode) {\n\t\t\t// If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios\n\t\t\t// involving access to deleted data.\n\t\t\tthis.runtime.updateUnusedRoutes(gcResult.deletedNodeIds);\n\t\t} else if (this.configs.tombstoneMode) {\n\t\t\tthis.tombstones = sweepReadyNodes;\n\t\t\t// If we are running in GC tombstone mode, update tombstoned routes. This enables testing scenarios\n\t\t\t// involving access to \"deleted\" data without actually deleting the data from summaries.\n\t\t\t// Note: we will not tombstone in test mode.\n\t\t\tthis.runtime.updateTombstonedRoutes(this.tombstones);\n\t\t}\n\n\t\tthis.gcDataFromLastRun = cloneGCData(updatedGCData);\n\n\t\t// Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and\n\t\t// updates its state so that we don't send false positives based on intermediate state. For example, we may get\n\t\t// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.\n\t\tawait this.telemetryTracker.logPendingEvents(logger);\n\n\t\treturn gcStats;\n\t}\n\n\t/**\n\t * Summarizes the GC data and returns it as a summary tree.\n\t * We current write the entire GC state in a single blob. This can be modified later to write multiple\n\t * blobs. All the blob keys should start with `gcBlobPrefix`.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): ISummarizeResult | undefined {\n\t\tif (!this.configs.shouldRunGC || this.gcDataFromLastRun === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst gcState: IGarbageCollectionState = { gcNodes: {} };\n\t\tfor (const [nodeId, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n\t\t\tgcState.gcNodes[nodeId] = {\n\t\t\t\toutboundRoutes,\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tthis.unreferencedNodesState.get(nodeId)?.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\n\t\treturn this.summaryStateTracker.summarize(\n\t\t\tfullTree,\n\t\t\ttrackState,\n\t\t\tgcState,\n\t\t\tthis.deletedNodes,\n\t\t\tthis.tombstones,\n\t\t);\n\t}\n\n\tpublic getMetadata(): IGCMetadata {\n\t\treturn {\n\t\t\t/**\n\t\t\t * If GC is enabled, the GC data is written using the current GC version and that is the gcFeature that goes\n\t\t\t * into the metadata blob. If GC is disabled, the gcFeature is 0.\n\t\t\t */\n\t\t\tgcFeature: this.configs.gcEnabled ? this.summaryStateTracker.currentGCVersion : 0,\n\t\t\tgcFeatureMatrix: this.configs.persistedGcFeatureMatrix,\n\t\t\tsessionExpiryTimeoutMs: this.configs.sessionExpiryTimeoutMs,\n\t\t\tsweepEnabled: false, // DEPRECATED - to be removed\n\t\t\tsweepTimeoutMs: this.configs.sweepTimeoutMs,\n\t\t};\n\t}\n\n\t/**\n\t * Returns a the GC details generated from the base summary. This is used to initialize the GC state of the nodes\n\t * in the container.\n\t */\n\tpublic async getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase> {\n\t\treturn this.baseGCDetailsP;\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<void> {\n\t\tconst latestSnapshotData = await this.summaryStateTracker.refreshLatestSummary(\n\t\t\tproposalHandle,\n\t\t\tresult,\n\t\t\treadAndParseBlob,\n\t\t);\n\n\t\t// If the latest summary was updated but it was not tracked by this client, our state needs to be updated from\n\t\t// this snapshot data.\n\t\tif (this.shouldRunGC && result.latestSummaryUpdated && !result.wasSummaryTracked) {\n\t\t\t// The current reference timestamp should be available if we are refreshing state from a snapshot. There has\n\t\t\t// to be at least one op (summary op / ack, if nothing else) if a snapshot was taken.\n\t\t\tconst currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n\t\t\tif (currentReferenceTimestampMs === undefined) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"No reference timestamp when updating GC state from snapshot\",\n\t\t\t\t\t\"refreshLatestSummary\",\n\t\t\t\t\tundefined,\n\t\t\t\t\t{\n\t\t\t\t\t\tproposalHandle,\n\t\t\t\t\t\tsummaryRefSeq: result.summaryRefSeq,\n\t\t\t\t\t\tgcConfigs: JSON.stringify(this.configs),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.updateStateFromSnapshotData(latestSnapshotData, currentReferenceTimestampMs);\n\t\t}\n\t}\n\n\t/**\n\t * Called when a node with the given id is updated. If the node is inactive, log an error.\n\t * @param nodePath - The id of the node that changed.\n\t * @param reason - Whether the node was loaded or changed.\n\t * @param timestampMs - The timestamp when the node changed.\n\t * @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.\n\t * @param requestHeaders - If the node was loaded via request path, the headers in the request.\n\t */\n\tpublic nodeUpdated(\n\t\tnodePath: string,\n\t\treason: \"Loaded\" | \"Changed\",\n\t\ttimestampMs?: number,\n\t\tpackagePath?: readonly string[],\n\t\trequestHeaders?: IRequestHeader,\n\t) {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.telemetryTracker.nodeUsed({\n\t\t\tnodeId: nodePath,\n\t\t\tusageType: reason,\n\t\t\tcurrentReferenceTimestampMs:\n\t\t\t\ttimestampMs ?? this.runtime.getCurrentReferenceTimestampMs(),\n\t\t\tpackagePath,\n\t\t\tcompletedGCRuns: this.completedRuns,\n\t\t\tisTombstoned: this.tombstones.includes(nodePath),\n\t\t\tlastSummaryTime: this.getLastSummaryTimestampMs(),\n\t\t\tviaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],\n\t\t});\n\t}\n\n\t/**\n\t * Called when an outbound reference is added to a node. This is used to identify all nodes that have been\n\t * referenced between summaries so that their unreferenced timestamp can be reset.\n\t *\n\t * @param fromNodePath - The node from which the reference is added.\n\t * @param toNodePath - The node to which the reference is added.\n\t */\n\tpublic addedOutboundReference(fromNodePath: string, toNodePath: string) {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst outboundRoutes = this.newReferencesSinceLastRun.get(fromNodePath) ?? [];\n\t\toutboundRoutes.push(toNodePath);\n\t\tthis.newReferencesSinceLastRun.set(fromNodePath, outboundRoutes);\n\n\t\tthis.telemetryTracker.nodeUsed({\n\t\t\tnodeId: toNodePath,\n\t\t\tusageType: \"Revived\",\n\t\t\tcurrentReferenceTimestampMs: this.runtime.getCurrentReferenceTimestampMs(),\n\t\t\tpackagePath: undefined,\n\t\t\tcompletedGCRuns: this.completedRuns,\n\t\t\tisTombstoned: this.tombstones.includes(toNodePath),\n\t\t\tlastSummaryTime: this.getLastSummaryTimestampMs(),\n\t\t\tfromId: fromNodePath,\n\t\t});\n\t}\n\n\t/**\n\t * Returns whether a node with the given path has been deleted or not. This can be used by the runtime to identify\n\t * cases where objects are used after they are deleted and throw / log errors accordingly.\n\t */\n\tpublic isNodeDeleted(nodePath: string): boolean {\n\t\treturn this.deletedNodes.has(nodePath);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.sessionExpiryTimer?.clear();\n\t\tthis.sessionExpiryTimer = undefined;\n\t}\n\n\t/**\n\t * Updates the state of the system as per the current GC run. It does the following:\n\t * 1. Sets up the current GC state as per the gcData.\n\t * 2. Starts tracking for nodes that have become unreferenced in this run.\n\t * 3. Clears tracking for nodes that were unreferenced but became referenced in this run.\n\t * @param gcData - The data representing the reference graph on which GC is run.\n\t * @param gcResult - The result of the GC run on the gcData.\n\t * @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.\n\t * @returns - A list of sweep ready nodes. (Nodes ready to be deleted)\n\t */\n\tprivate updateMarkPhase(\n\t\tgcData: IGarbageCollectionData,\n\t\tgcResult: IGCResult,\n\t\tcurrentReferenceTimestampMs: number,\n\t\tlogger: ITelemetryLogger,\n\t) {\n\t\t// Get references from the current GC run + references between previous and current run and then update each\n\t\t// node's state\n\t\tconst allNodesReferencedBetweenGCs =\n\t\t\tthis.findAllNodesReferencedBetweenGCs(gcData, this.gcDataFromLastRun, logger) ??\n\t\t\tgcResult.referencedNodeIds;\n\t\tthis.newReferencesSinceLastRun.clear();\n\n\t\t// Iterate through the referenced nodes and stop tracking if they were unreferenced before.\n\t\tfor (const nodeId of allNodesReferencedBetweenGCs) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\tif (nodeStateTracker !== undefined) {\n\t\t\t\t// Stop tracking so as to clear out any running timers.\n\t\t\t\tnodeStateTracker.stopTracking();\n\t\t\t\t// Delete the node as we don't need to track it any more.\n\t\t\t\tthis.unreferencedNodesState.delete(nodeId);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * If a node became unreferenced in this run, start tracking it.\n\t\t * If a node was already unreferenced, update its tracking information. Since the current reference time is\n\t\t * from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.\n\t\t *\n\t\t * If a node is sweep ready, store and then return it.\n\t\t */\n\t\tconst sweepReadyNodes: string[] = [];\n\t\tfor (const nodeId of gcResult.deletedNodeIds) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\tif (nodeStateTracker === undefined) {\n\t\t\t\tthis.unreferencedNodesState.set(\n\t\t\t\t\tnodeId,\n\t\t\t\t\tnew UnreferencedStateTracker(\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.inactiveTimeoutMs,\n\t\t\t\t\t\tcurrentReferenceTimestampMs,\n\t\t\t\t\t\tthis.configs.sweepTimeoutMs,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tnodeStateTracker.updateTracking(currentReferenceTimestampMs);\n\t\t\t\tif (nodeStateTracker.state === UnreferencedState.SweepReady) {\n\t\t\t\t\tsweepReadyNodes.push(nodeId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn sweepReadyNodes;\n\t}\n\n\t/**\n\t * Deletes nodes from both the runtime and garbage collection\n\t * @param sweepReadyNodes - nodes that are ready to be deleted\n\t */\n\tprivate runSweepPhase(sweepReadyNodes: string[], gcData: IGarbageCollectionData) {\n\t\t// TODO: GC:Validation - validate that removed routes are not double deleted\n\t\t// TODO: GC:Validation - validate that the child routes of removed routes are deleted as well\n\t\tconst sweptRoutes = this.runtime.deleteSweepReadyNodes(sweepReadyNodes);\n\t\tconst updatedGCData = this.deleteSweptRoutes(sweptRoutes, gcData);\n\n\t\tfor (const nodeId of sweptRoutes) {\n\t\t\tconst nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n\t\t\t// TODO: GC:Validation - assert that the nodeStateTracker is defined\n\t\t\tif (nodeStateTracker !== undefined) {\n\t\t\t\t// Stop tracking so as to clear out any running timers.\n\t\t\t\tnodeStateTracker.stopTracking();\n\t\t\t\t// Delete the node as we don't need to track it any more.\n\t\t\t\tthis.unreferencedNodesState.delete(nodeId);\n\t\t\t}\n\t\t\t// TODO: GC:Validation - assert that the deleted node is not a duplicate\n\t\t\tthis.deletedNodes.add(nodeId);\n\t\t}\n\n\t\treturn updatedGCData;\n\t}\n\n\t/**\n\t * @returns IGarbageCollectionData after deleting the sweptRoutes from the gcData\n\t */\n\tprivate deleteSweptRoutes(\n\t\tsweptRoutes: string[],\n\t\tgcData: IGarbageCollectionData,\n\t): IGarbageCollectionData {\n\t\tconst sweptRoutesSet = new Set<string>(sweptRoutes);\n\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\t\tif (!sweptRoutesSet.has(id)) {\n\t\t\t\tgcNodes[id] = Array.from(outboundRoutes);\n\t\t\t}\n\t\t}\n\n\t\t// TODO: GC:Validation - assert that the nodeId is in gcData\n\n\t\treturn {\n\t\t\tgcNodes,\n\t\t};\n\t}\n\n\t/**\n\t * Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in\n\t * time. There can be nodes that were referenced in between two runs and their unreferenced state needs to be\n\t * updated. For example, in the following scenarios not updating the unreferenced timestamp can lead to deletion of\n\t * these objects while there can be in-memory referenced to it:\n\t * 1. A node transitions from `unreferenced -> referenced -> unreferenced` between two runs. When the reference is\n\t * added, the object may have been accessed and in-memory reference to it added.\n\t * 2. A reference is added from one unreferenced node to one or more unreferenced nodes. Even though the node[s] were\n\t * unreferenced, they could have been accessed and in-memory reference to them added.\n\t *\n\t * This function identifies nodes that were referenced since the last run.\n\t * If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.\n\t *\n\t * @returns - a list of all nodes referenced from the last local summary until now.\n\t */\n\tprivate findAllNodesReferencedBetweenGCs(\n\t\tcurrentGCData: IGarbageCollectionData,\n\t\tpreviousGCData: IGarbageCollectionData | undefined,\n\t\tlogger: ITelemetryLogger,\n\t): string[] | undefined {\n\t\t// If we haven't run GC before there is nothing to do.\n\t\t// No previousGCData, means nothing is unreferenced, and there are no reference state trackers to clear\n\t\tif (previousGCData === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t/**\n\t\t * If there are references that were not explicitly notified to GC, log an error because this should never happen.\n\t\t * If it does, this may result in the unreferenced timestamps of these nodes not updated when they were referenced.\n\t\t */\n\t\tthis.telemetryTracker.logIfMissingExplicitReferences(\n\t\t\tcurrentGCData,\n\t\t\tpreviousGCData,\n\t\t\tthis.newReferencesSinceLastRun,\n\t\t\tlogger,\n\t\t);\n\n\t\t// No references were added since the last run so we don't have to update reference states of any unreferenced\n\t\t// nodes. There is no in between state at this point.\n\t\tif (this.newReferencesSinceLastRun.size === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t/**\n\t\t * Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and\n\t\t * edges that have been added since then. To do this, combine the GC data from the last run and the current\n\t\t * run, and then add the references since last run.\n\t\t *\n\t\t * Note on why we need to combine the data from previous run, current run and all references in between -\n\t\t * 1. We need data from last run because some of its references may have been deleted since then. If those\n\t\t * references added new outbound references before they were deleted, we need to detect them.\n\t\t *\n\t\t * 2. We need new outbound references since last run because some of them may have been deleted later. If those\n\t\t * references added new outbound references before they were deleted, we need to detect them.\n\t\t *\n\t\t * 3. We need data from the current run because currently we may not detect when DDSes are referenced:\n\t\t * - We don't require DDSes handles to be stored in a referenced DDS.\n\t\t * - A new data store may have \"root\" DDSes already created and we don't detect them today.\n\t\t */\n\t\tconst gcDataSuperSet = concatGarbageCollectionData(previousGCData, currentGCData);\n\t\tconst newOutboundRoutesSinceLastRun: string[] = [];\n\t\tthis.newReferencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {\n\t\t\tif (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {\n\t\t\t\tgcDataSuperSet.gcNodes[sourceNodeId] = outboundRoutes;\n\t\t\t} else {\n\t\t\t\tgcDataSuperSet.gcNodes[sourceNodeId].push(...outboundRoutes);\n\t\t\t}\n\t\t\tnewOutboundRoutesSinceLastRun.push(...outboundRoutes);\n\t\t});\n\n\t\t/**\n\t\t * Run GC on the above reference graph starting with root and all new outbound routes. This will generate a\n\t\t * list of all nodes that could have been referenced since the last run. If any of these nodes are unreferenced,\n\t\t * unreferenced, stop tracking them and remove from unreferenced list.\n\t\t * Note that some of these nodes may be unreferenced now and if so, the current run will mark them as\n\t\t * unreferenced and add unreferenced state.\n\t\t */\n\t\tconst gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, [\n\t\t\t\"/\",\n\t\t\t...newOutboundRoutesSinceLastRun,\n\t\t]);\n\t\treturn gcResult.referencedNodeIds;\n\t}\n\n\t/**\n\t * Generates the stats of a garbage collection run from the given results of the run.\n\t * @param gcResult - The result of a GC run.\n\t * @returns the GC stats of the GC run.\n\t */\n\tprivate generateStats(gcResult: IGCResult): IGCStats {\n\t\tconst gcStats: IGCStats = {\n\t\t\tnodeCount: 0,\n\t\t\tdataStoreCount: 0,\n\t\t\tattachmentBlobCount: 0,\n\t\t\tunrefNodeCount: 0,\n\t\t\tunrefDataStoreCount: 0,\n\t\t\tunrefAttachmentBlobCount: 0,\n\t\t\tupdatedNodeCount: 0,\n\t\t\tupdatedDataStoreCount: 0,\n\t\t\tupdatedAttachmentBlobCount: 0,\n\t\t};\n\n\t\tconst updateNodeStats = (nodeId: string, referenced: boolean) => {\n\t\t\tgcStats.nodeCount++;\n\t\t\t// If there is no previous GC data, every node's state is generated and is considered as updated.\n\t\t\t// Otherwise, find out if any node went from referenced to unreferenced or vice-versa.\n\t\t\tconst stateUpdated =\n\t\t\t\tthis.gcDataFromLastRun === undefined ||\n\t\t\t\tthis.unreferencedNodesState.has(nodeId) === referenced;\n\t\t\tif (stateUpdated) {\n\t\t\t\tgcStats.updatedNodeCount++;\n\t\t\t}\n\t\t\tif (!referenced) {\n\t\t\t\tgcStats.unrefNodeCount++;\n\t\t\t}\n\n\t\t\tif (this.runtime.getNodeType(nodeId) === GCNodeType.DataStore) {\n\t\t\t\tgcStats.dataStoreCount++;\n\t\t\t\tif (stateUpdated) {\n\t\t\t\t\tgcStats.updatedDataStoreCount++;\n\t\t\t\t}\n\t\t\t\tif (!referenced) {\n\t\t\t\t\tgcStats.unrefDataStoreCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.runtime.getNodeType(nodeId) === GCNodeType.Blob) {\n\t\t\t\tgcStats.attachmentBlobCount++;\n\t\t\t\tif (stateUpdated) {\n\t\t\t\t\tgcStats.updatedAttachmentBlobCount++;\n\t\t\t\t}\n\t\t\t\tif (!referenced) {\n\t\t\t\t\tgcStats.unrefAttachmentBlobCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor (const nodeId of gcResult.referencedNodeIds) {\n\t\t\tupdateNodeStats(nodeId, true /* referenced */);\n\t\t}\n\n\t\tfor (const nodeId of gcResult.deletedNodeIds) {\n\t\t\tupdateNodeStats(nodeId, false /* referenced */);\n\t\t}\n\n\t\treturn gcStats;\n\t}\n}\n"]}
@@ -2,21 +2,11 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ITelemetryGenericEvent } from "@fluidframework/common-definitions";
6
5
  import { ISnapshotTree } from "@fluidframework/protocol-definitions";
7
6
  import { IGarbageCollectionData, IGarbageCollectionDetailsBase } from "@fluidframework/runtime-definitions";
8
- import { MonitoringContext } from "@fluidframework/telemetry-utils";
9
7
  import { GCFeatureMatrix, GCVersion, IGCMetadata } from "./gcDefinitions";
10
8
  import { IGarbageCollectionSnapshotData, IGarbageCollectionState } from "./gcSummaryDefinitions";
11
9
  export declare function getGCVersion(metadata?: IGCMetadata): GCVersion;
12
- /**
13
- * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a
14
- * tombstoned or deleted object is loaded.
15
- */
16
- export declare function sendGCUnexpectedUsageEvent(mc: MonitoringContext, event: ITelemetryGenericEvent & {
17
- category: "error" | "generic";
18
- gcTombstoneEnforcementAllowed: boolean | undefined;
19
- }, packagePath: readonly string[] | undefined, error?: unknown): void;
20
10
  /**
21
11
  * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted
22
12
  * TombstoneGeneration values
@@ -1 +1 @@
1
- {"version":3,"file":"gcHelpers.d.ts","sourceRoot":"","sources":["../../src/gc/gcHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAIN,sBAAsB,EACtB,6BAA6B,EAC7B,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAEN,eAAe,EACf,SAAS,EACT,WAAW,EAIX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEN,8BAA8B,EAC9B,uBAAuB,EACvB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,SAAS,CAM9D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,sBAAsB,GAAG;IAC/B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,6BAA6B,EAAE,OAAO,GAAG,SAAS,CAAC;CACnD,EACD,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC1C,KAAK,CAAC,EAAE,OAAO,QAaf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAChD,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAMT;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CACjC,oBAAoB,EAAE,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,qBAAqB,CAAC,EACtF,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAgBT;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAS/F;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,uBAAuB,GAC/B,uBAAuB,CAsCzB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,CAQlF;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,0BAY/B;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAC1C,cAAc,EAAE,aAAa,EAC7B,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,8BAA8B,CAAC,CAgCzC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,6BAA6B,8CA0DjF;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,UAExD"}
1
+ {"version":3,"file":"gcHelpers.d.ts","sourceRoot":"","sources":["../../src/gc/gcHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAIN,sBAAsB,EACtB,6BAA6B,EAC7B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAEN,8BAA8B,EAC9B,uBAAuB,EACvB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,SAAS,CAM9D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAChD,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAMT;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CACjC,oBAAoB,EAAE,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,qBAAqB,CAAC,EACtF,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAgBT;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAS/F;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,uBAAuB,GAC/B,uBAAuB,CAsCzB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,CAQlF;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,0BAY/B;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAC1C,cAAc,EAAE,aAAa,EAC7B,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,8BAA8B,CAAC,CAgCzC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,6BAA6B,8CA0DjF;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,UAExD"}
@@ -4,8 +4,6 @@
4
4
  */
5
5
  import { assert } from "@fluidframework/common-utils";
6
6
  import { gcBlobPrefix, gcDeletedBlobKey, gcTombstoneBlobKey, } from "@fluidframework/runtime-definitions";
7
- import { packagePathToTelemetryProperty } from "@fluidframework/runtime-utils";
8
- import { disableTombstoneKey, runSweepKey, throwOnTombstoneLoadKey, throwOnTombstoneUsageKey, } from "./gcDefinitions";
9
7
  export function getGCVersion(metadata) {
10
8
  var _a;
11
9
  if (!metadata) {
@@ -14,22 +12,6 @@ export function getGCVersion(metadata) {
14
12
  }
15
13
  return (_a = metadata.gcFeature) !== null && _a !== void 0 ? _a : 0;
16
14
  }
17
- /**
18
- * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a
19
- * tombstoned or deleted object is loaded.
20
- */
21
- export function sendGCUnexpectedUsageEvent(mc, event, packagePath, error) {
22
- event.pkg = packagePathToTelemetryProperty(packagePath);
23
- event.tombstoneFlags = JSON.stringify({
24
- DisableTombstone: mc.config.getBoolean(disableTombstoneKey),
25
- ThrowOnTombstoneUsage: mc.config.getBoolean(throwOnTombstoneUsageKey),
26
- ThrowOnTombstoneLoad: mc.config.getBoolean(throwOnTombstoneLoadKey),
27
- });
28
- event.sweepFlags = JSON.stringify({
29
- EnableSweepFlag: mc.config.getBoolean(runSweepKey),
30
- });
31
- mc.logger.sendTelemetryEvent(event, error);
32
- }
33
15
  /**
34
16
  * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted
35
17
  * TombstoneGeneration values
@@ -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 { ITelemetryGenericEvent } from \"@fluidframework/common-definitions\";\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 { packagePathToTelemetryProperty } from \"@fluidframework/runtime-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport {\n\tdisableTombstoneKey,\n\tGCFeatureMatrix,\n\tGCVersion,\n\tIGCMetadata,\n\trunSweepKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n} 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 * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a\n * tombstoned or deleted object is loaded.\n */\nexport function sendGCUnexpectedUsageEvent(\n\tmc: MonitoringContext,\n\tevent: ITelemetryGenericEvent & {\n\t\tcategory: \"error\" | \"generic\";\n\t\tgcTombstoneEnforcementAllowed: boolean | undefined;\n\t},\n\tpackagePath: readonly string[] | undefined,\n\terror?: unknown,\n) {\n\tevent.pkg = packagePathToTelemetryProperty(packagePath);\n\tevent.tombstoneFlags = JSON.stringify({\n\t\tDisableTombstone: mc.config.getBoolean(disableTombstoneKey),\n\t\tThrowOnTombstoneUsage: mc.config.getBoolean(throwOnTombstoneUsageKey),\n\t\tThrowOnTombstoneLoad: mc.config.getBoolean(throwOnTombstoneLoadKey),\n\t});\n\tevent.sweepFlags = JSON.stringify({\n\t\tEnableSweepFlag: mc.config.getBoolean(runSweepKey),\n\t});\n\n\tmc.logger.sendTelemetryEvent(event, error);\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 * @returns a clone of the given GC data.\n */\nexport function cloneGCData(gcData: IGarbageCollectionData): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\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"]}
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 { 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 * @returns a clone of the given GC data.\n */\nexport function cloneGCData(gcData: IGarbageCollectionData): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\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"]}
@@ -0,0 +1,91 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
6
+ import { IGarbageCollectionData } from "@fluidframework/runtime-definitions";
7
+ import { MonitoringContext } from "@fluidframework/telemetry-utils";
8
+ import { ICreateContainerMetadata } from "../summary";
9
+ import { GCNodeType, IGarbageCollectorConfigs } from "./gcDefinitions";
10
+ import { UnreferencedStateTracker } from "./gcUnreferencedStateTracker";
11
+ declare type NodeUsageType = "Changed" | "Loaded" | "Revived";
12
+ /** Properties that are common to IUnreferencedEventProps and INodeUsageProps */
13
+ interface ICommonProps {
14
+ usageType: NodeUsageType;
15
+ completedGCRuns: number;
16
+ isTombstoned: boolean;
17
+ lastSummaryTime?: number;
18
+ fromId?: string;
19
+ viaHandle?: boolean;
20
+ }
21
+ /** Properties passed to nodeUsed function when a node is used. */
22
+ interface INodeUsageProps extends ICommonProps {
23
+ nodeId: string;
24
+ currentReferenceTimestampMs: number | undefined;
25
+ packagePath: readonly string[] | undefined;
26
+ }
27
+ /**
28
+ * Encapsulates the logic that tracks the various telemetry logged by the Garbage Collector. There are 4 types of
29
+ * telemetry logged:
30
+ * 1. inactiveObject telemetry - When an inactive node is used - A node that has been unreferenced for inactiveTimeoutMs.
31
+ * 2. sweepReadyObject telemetry - When a sweep ready node is used - A node that has been unreferenced for sweepTimeoutMs.
32
+ * 3. Tombstone telemetry - When a tombstoned node is used - A node that that has been marked as tombstone.
33
+ * 4. Sweep / deleted telemetry - When a node is detected as sweep ready in the sweep phase.
34
+ * 5. Unknown outbound reference telemetry - When a node is referenced but GC is not explicitly notified of it.
35
+ */
36
+ export declare class GCTelemetryTracker {
37
+ private readonly mc;
38
+ private readonly configs;
39
+ private readonly isSummarizerClient;
40
+ private readonly gcTombstoneEnforcementAllowed;
41
+ private readonly createContainerMetadata;
42
+ private readonly getNodeType;
43
+ private readonly getNodeStateTracker;
44
+ private readonly getNodePackagePath;
45
+ private readonly loggedUnreferencedEvents;
46
+ private pendingEventsQueue;
47
+ constructor(mc: MonitoringContext, configs: Pick<IGarbageCollectorConfigs, "inactiveTimeoutMs" | "sweepTimeoutMs">, isSummarizerClient: boolean, gcTombstoneEnforcementAllowed: boolean, createContainerMetadata: ICreateContainerMetadata, getNodeType: (nodeId: string) => GCNodeType, getNodeStateTracker: (nodeId: string) => UnreferencedStateTracker | undefined, getNodePackagePath: (nodePath: string) => Promise<readonly string[] | undefined>);
48
+ /**
49
+ * Returns whether an event should be logged for a node that isn't active anymore. Some scenarios where we won't log:
50
+ * 1. When a DDS is changed or loaded. The corresponding data store's event will be logged instead.
51
+ * 2. An event is logged only once per container instance per event per node.
52
+ */
53
+ private shouldLogNonActiveEvent;
54
+ /**
55
+ * Called when a node is used. If the node is not active, log an event indicating object is used when its not active.
56
+ */
57
+ nodeUsed(nodeUsageProps: INodeUsageProps): void;
58
+ /**
59
+ * Log all new references or outbound routes in the current graph that haven't been explicitly notified to GC.
60
+ * The principle is that every new reference or outbound route must be notified to GC via the
61
+ * addedOutboundReference method. It it hasn't, its a bug and we want to identify these scenarios.
62
+ *
63
+ * In more simple terms:
64
+ * Missing Explicit References = Current References - Previous References - Explicitly Added References;
65
+ *
66
+ * @param currentGCData - The GC data (reference graph) from the current GC run.
67
+ * @param previousGCData - The GC data (reference graph) from the previous GC run.
68
+ * @param explicitReferences - New references added explicity between the previous and the current run.
69
+ */
70
+ logIfMissingExplicitReferences(currentGCData: IGarbageCollectionData, previousGCData: IGarbageCollectionData, explicitReferences: Map<string, string[]>, logger: ITelemetryLogger): void;
71
+ /**
72
+ * Log events that are pending in pendingEventsQueue. This is called after GC runs in the summarizer client
73
+ * so that the state of an unreferenced node is updated.
74
+ */
75
+ logPendingEvents(logger: ITelemetryLogger): Promise<void>;
76
+ /**
77
+ * For nodes that are ready to sweep, log an event for now. Until we start running sweep which deletes objects,
78
+ * this will give us a view into how much deleted content a container has.
79
+ */
80
+ logSweepEvents(logger: ITelemetryLogger, currentReferenceTimestampMs: number, unreferencedNodesState: Map<string, UnreferencedStateTracker>, completedGCRuns: number, lastSummaryTime?: number): void;
81
+ }
82
+ /**
83
+ * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a
84
+ * tombstoned or deleted object is loaded.
85
+ */
86
+ export declare function sendGCUnexpectedUsageEvent(mc: MonitoringContext, event: ITelemetryGenericEvent & {
87
+ category: "error" | "generic";
88
+ gcTombstoneEnforcementAllowed: boolean | undefined;
89
+ }, packagePath: readonly string[] | undefined, error?: unknown): void;
90
+ export {};
91
+ //# sourceMappingURL=gcTelemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcTelemetry.d.ts","sourceRoot":"","sources":["../../src/gc/gcTelemetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAEN,iBAAiB,EAEjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAEN,UAAU,EAEV,wBAAwB,EAKxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,aAAK,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtD,gFAAgF;AAChF,UAAU,YAAY;IACrB,SAAS,EAAE,aAAa,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAYD,kEAAkE;AAClE,UAAU,eAAgB,SAAQ,YAAY;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAQ7B,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAIxB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,6BAA6B;IAC9C,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAGpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAjBpC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA0B;IAEnE,OAAO,CAAC,kBAAkB,CAAiC;gBAGzC,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE,IAAI,CAC7B,wBAAwB,EACxB,mBAAmB,GAAG,gBAAgB,CACtC,EACgB,kBAAkB,EAAE,OAAO,EAC3B,6BAA6B,EAAE,OAAO,EACtC,uBAAuB,EAAE,wBAAwB,EACjD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,EAC3C,mBAAmB,EAAE,CACrC,MAAM,EAAE,MAAM,KACV,wBAAwB,GAAG,SAAS,EACxB,kBAAkB,EAAE,CACpC,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAG5C;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACI,QAAQ,CAAC,cAAc,EAAE,eAAe;IAgG/C;;;;;;;;;;;OAWG;IACI,8BAA8B,CACpC,aAAa,EAAE,sBAAsB,EACrC,cAAc,EAAE,sBAAsB,EACtC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACzC,MAAM,EAAE,gBAAgB;IAqCzB;;;OAGG;IACU,gBAAgB,CAAC,MAAM,EAAE,gBAAgB;IA4CtD;;;OAGG;IACI,cAAc,CACpB,MAAM,EAAE,gBAAgB,EACxB,2BAA2B,EAAE,MAAM,EACnC,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,EAC7D,eAAe,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,MAAM;CAqCzB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,sBAAsB,GAAG;IAC/B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,6BAA6B,EAAE,OAAO,GAAG,SAAS,CAAC;CACnD,EACD,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC1C,KAAK,CAAC,EAAE,OAAO,QAaf"}