@fluidframework/container-runtime 0.59.1000-61898 → 0.59.1001

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 (62) hide show
  1. package/dist/containerRuntime.d.ts +2 -2
  2. package/dist/containerRuntime.d.ts.map +1 -1
  3. package/dist/containerRuntime.js +12 -13
  4. package/dist/containerRuntime.js.map +1 -1
  5. package/dist/dataStores.d.ts +4 -2
  6. package/dist/dataStores.d.ts.map +1 -1
  7. package/dist/dataStores.js +12 -5
  8. package/dist/dataStores.js.map +1 -1
  9. package/dist/garbageCollection.d.ts +1 -0
  10. package/dist/garbageCollection.d.ts.map +1 -1
  11. package/dist/garbageCollection.js +3 -1
  12. package/dist/garbageCollection.js.map +1 -1
  13. package/dist/orderedClientElection.d.ts +6 -57
  14. package/dist/orderedClientElection.d.ts.map +1 -1
  15. package/dist/orderedClientElection.js +25 -140
  16. package/dist/orderedClientElection.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.d.ts.map +1 -1
  19. package/dist/packageVersion.js +1 -1
  20. package/dist/packageVersion.js.map +1 -1
  21. package/dist/summarizerClientElection.d.ts +0 -2
  22. package/dist/summarizerClientElection.d.ts.map +1 -1
  23. package/dist/summarizerClientElection.js +2 -7
  24. package/dist/summarizerClientElection.js.map +1 -1
  25. package/dist/summaryManager.d.ts.map +1 -1
  26. package/dist/summaryManager.js +3 -14
  27. package/dist/summaryManager.js.map +1 -1
  28. package/lib/containerRuntime.d.ts +2 -2
  29. package/lib/containerRuntime.d.ts.map +1 -1
  30. package/lib/containerRuntime.js +12 -13
  31. package/lib/containerRuntime.js.map +1 -1
  32. package/lib/dataStores.d.ts +4 -2
  33. package/lib/dataStores.d.ts.map +1 -1
  34. package/lib/dataStores.js +12 -5
  35. package/lib/dataStores.js.map +1 -1
  36. package/lib/garbageCollection.d.ts +1 -0
  37. package/lib/garbageCollection.d.ts.map +1 -1
  38. package/lib/garbageCollection.js +3 -1
  39. package/lib/garbageCollection.js.map +1 -1
  40. package/lib/orderedClientElection.d.ts +6 -57
  41. package/lib/orderedClientElection.d.ts.map +1 -1
  42. package/lib/orderedClientElection.js +25 -140
  43. package/lib/orderedClientElection.js.map +1 -1
  44. package/lib/packageVersion.d.ts +1 -1
  45. package/lib/packageVersion.d.ts.map +1 -1
  46. package/lib/packageVersion.js +1 -1
  47. package/lib/packageVersion.js.map +1 -1
  48. package/lib/summarizerClientElection.d.ts +0 -2
  49. package/lib/summarizerClientElection.d.ts.map +1 -1
  50. package/lib/summarizerClientElection.js +2 -7
  51. package/lib/summarizerClientElection.js.map +1 -1
  52. package/lib/summaryManager.d.ts.map +1 -1
  53. package/lib/summaryManager.js +3 -14
  54. package/lib/summaryManager.js.map +1 -1
  55. package/package.json +17 -17
  56. package/src/containerRuntime.ts +11 -13
  57. package/src/dataStores.ts +13 -5
  58. package/src/garbageCollection.ts +3 -1
  59. package/src/orderedClientElection.ts +25 -154
  60. package/src/packageVersion.ts +1 -1
  61. package/src/summarizerClientElection.ts +2 -7
  62. package/src/summaryManager.ts +4 -15
@@ -1 +1 @@
1
- {"version":3,"file":"garbageCollection.js","sourceRoot":"","sources":["../src/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 { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { ClientSessionExpiredError, DataProcessingError } from \"@fluidframework/container-utils\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport {\n cloneGCData,\n concatGarbageCollectionStates,\n concatGarbageCollectionData,\n IGCResult,\n runGarbageCollection,\n unpackChildNodesGCDetails,\n} from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionState,\n IGarbageCollectionDetailsBase,\n ISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n ReadAndParseBlob,\n RefreshSummaryResult,\n SummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport {\n ChildLogger,\n loggerToMonitoringContext,\n MonitoringContext,\n PerformanceEvent,\n TelemetryDataTag,\n} from \"@fluidframework/telemetry-utils\";\n\nimport { IGCRuntimeOptions, RuntimeHeaders } from \"./containerRuntime\";\nimport { getSummaryForDatastores } from \"./dataStores\";\nimport {\n getGCVersion,\n GCVersion,\n IContainerRuntimeMetadata,\n metadataBlobName,\n ReadFluidDataStoreAttributes,\n dataStoreAttributesBlobName,\n} from \"./summaryFormat\";\n\n/** This is the current version of garbage collection. */\nconst GCVersion = 1;\n\n// The key for the GC tree in summary.\nexport const gcTreeKey = \"gc\";\n// They prefix for GC blobs in the GC tree in summary.\nexport const gcBlobPrefix = \"__gc\";\n\n// Feature gate key to turn GC on / off.\nconst runGCKey = \"Fluid.GarbageCollection.RunGC\";\n// Feature gate key to turn GC test mode on / off.\nconst gcTestModeKey = \"Fluid.GarbageCollection.GCTestMode\";\n// Feature gate key to turn GC sweep on / off.\nconst runSweepKey = \"Fluid.GarbageCollection.RunSweep\";\n// Feature gate key to write GC data at the root of the summary tree.\nconst writeAtRootKey = \"Fluid.GarbageCollection.WriteDataAtRoot\";\n// Feature gate key to expire a session after a set period of time.\nconst runSessionExpiry = \"Fluid.GarbageCollection.RunSessionExpiry\";\n\nconst defaultDeleteTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days\nexport const defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days\n\n/** The statistics of the system state after a garbage collection run. */\nexport interface IGCStats {\n /** The number of nodes in the container. */\n nodeCount: number;\n /** The number of data stores in the container. */\n dataStoreCount: number;\n /** The number of attachment blobs in the container. */\n attachmentBlobCount: number;\n /** The number of unreferenced nodes in the container. */\n unrefNodeCount: number;\n /** The number of unreferenced data stores in the container. */\n unrefDataStoreCount: number;\n /** The number of unreferenced attachment blobs in the container. */\n unrefAttachmentBlobCount: number;\n /** The number of nodes whose reference state updated since last GC run. */\n updatedNodeCount: number;\n /** The number of data stores whose reference state updated since last GC run. */\n updatedDataStoreCount: number;\n /** The number of attachment blobs whose reference state updated since last GC run. */\n updatedAttachmentBlobCount: number;\n}\n\n/** The types of GC nodes in the GC reference graph. */\nexport const GCNodeType = {\n // Nodes that are for data stores.\n DataStore: \"DataStore\",\n // Nodes that are for attachment blobs, i.e., blobs uploaded via BlobManager.\n Blob: \"Blob\",\n // Nodes that are neither data store not blobs. For example, root node and DDS nodes.\n Other: \"Other\",\n};\nexport type GCNodeType = typeof GCNodeType[keyof typeof GCNodeType];\n\n/** The event that is logged when unreferenced node is used after a certain time. */\ninterface IUnreferencedEvent {\n eventName: string;\n id: string;\n age: number;\n timeout: number;\n lastSummaryTime?: number;\n externalRequest?: boolean;\n viaHandle?: boolean;\n}\n\n/** Defines the APIs for the runtime object to be passed to the garbage collector. */\nexport interface IGarbageCollectionRuntime {\n /** Before GC runs, called to notify the runtime to update any pending GC state. */\n updateStateBeforeGC(): Promise<void>;\n /** Returns the garbage collection data of the runtime. */\n getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;\n /** After GC has run, called to notify the runtime of routes that are used in it. */\n updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): void;\n /** After GC has run, called to delete objects in the runtime whose routes are unused. */\n deleteUnusedRoutes(unusedRoutes: string[]): void;\n /** Returns a referenced timestamp to be used to track unreferenced nodes. */\n getCurrentReferenceTimestampMs(): number | undefined;\n /** Returns the type of the GC node. */\n getNodeType(nodePath: string): GCNodeType;\n /** Called when the runtime should close because of an error. */\n closeFn(error?: ICriticalContainerError): void;\n}\n\n/** Defines the contract for the garbage collector. */\nexport interface IGarbageCollector {\n /** Tells whether GC should run or not. */\n readonly shouldRunGC: boolean;\n /** The time in ms to expire a session for a client for gc. */\n readonly sessionExpiryTimeoutMs: number | undefined;\n /**\n * This tracks two things:\n * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.\n * 2. If GC is enabled, the version of GC used to generate the GC data written in a summary.\n */\n readonly gcSummaryFeatureVersion: number;\n /** Tells whether the GC state in summary needs to be reset in the next summary. */\n readonly summaryStateNeedsReset: boolean;\n /** Tells whether GC data should be written to the root of the summary tree. */\n readonly writeDataAtRoot: boolean;\n /** Run garbage collection and update the reference / used state of the system. */\n collectGarbage(\n options: { logger?: ITelemetryLogger, runGC?: boolean, runSweep?: boolean, fullGC?: boolean },\n ): Promise<IGCStats>;\n /** Summarizes the GC data and returns it as a summary tree. */\n summarize(): ISummaryTreeWithStats | undefined;\n /** Returns a map of each node id to its base GC details in the base summary. */\n getBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>>;\n /** Called when the latest summary of the system has been refreshed. */\n latestSummaryStateRefreshed(result: RefreshSummaryResult, readAndParseBlob: ReadAndParseBlob): Promise<void>;\n /** Called when a node is updated. Used to detect and log when an inactive node is changed or loaded. */\n nodeUpdated(\n nodePath: string,\n reason: \"Loaded\" | \"Changed\",\n timestampMs?: number,\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ): void;\n /** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */\n addedOutboundReference(fromNodePath: string, toNodePath: string): void;\n dispose(): void;\n}\n\n/**\n * Helper class that tracks the state of an unreferenced node such as the time it was unreferenced. It also sets\n * the node's state to inactive if it remains unreferenced for a given amount of time (inactiveTimeoutMs).\n */\nclass UnreferencedStateTracker {\n private _inactive: boolean = false;\n public get inactive(): boolean {\n return this._inactive;\n }\n\n private timer: Timer | undefined;\n\n constructor(\n public readonly unreferencedTimestampMs: number,\n private readonly inactiveTimeoutMs: number,\n currentReferenceTimestampMs?: number,\n ) {\n // If there is no current reference timestamp, don't track the node's inactive state. This will happen later\n // when updateTracking is called with a reference timestamp.\n if (currentReferenceTimestampMs !== undefined) {\n this.updateTracking(currentReferenceTimestampMs);\n }\n }\n\n /**\n * Updates the tracking state based on the provided timestamp.\n */\n public updateTracking(currentReferenceTimestampMs: number) {\n const unreferencedDurationMs = currentReferenceTimestampMs - this.unreferencedTimestampMs;\n // If the timeout has already expired, the node has become inactive.\n if (unreferencedDurationMs > this.inactiveTimeoutMs) {\n this._inactive = true;\n this.timer?.clear();\n return;\n }\n\n // The node isn't inactive yet. Restart a timer for the duration remaining for it to become inactive.\n const remainingDurationMs = this.inactiveTimeoutMs - unreferencedDurationMs;\n if (this.timer === undefined) {\n this.timer = new Timer(remainingDurationMs, () => { this._inactive = true; });\n }\n this.timer.restart(remainingDurationMs);\n }\n\n /**\n * Stop tracking this node. Reset the unreferenced timer, if any, and reset inactive state.\n */\n public stopTracking() {\n this.timer?.clear();\n this._inactive = false;\n }\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 */\nexport class GarbageCollector implements IGarbageCollector {\n public static create(\n provider: IGarbageCollectionRuntime,\n gcOptions: IGCRuntimeOptions,\n getNodePackagePath: (nodePath: string) => readonly string[] | undefined,\n getLastSummaryTimestampMs: () => number | undefined,\n baseSnapshot: ISnapshotTree | undefined,\n readAndParseBlob: ReadAndParseBlob,\n baseLogger: ITelemetryLogger,\n existing: boolean,\n metadata?: IContainerRuntimeMetadata,\n ): IGarbageCollector {\n return new GarbageCollector(\n provider,\n gcOptions,\n getNodePackagePath,\n getLastSummaryTimestampMs,\n baseSnapshot,\n readAndParseBlob,\n baseLogger,\n existing,\n metadata,\n );\n }\n\n /**\n * Tells whether GC should be run based on the GC options and local storage flags.\n */\n public readonly shouldRunGC: boolean;\n\n /**\n * The time in ms to expire a session for a client for gc.\n */\n public readonly sessionExpiryTimeoutMs: number | undefined;\n\n /**\n * This tracks two things:\n * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.\n * 2. If GC is enabled, the version of GC used to generate the GC data written in a summary.\n */\n public get gcSummaryFeatureVersion(): number {\n return this.gcEnabled ? this.currentGCVersion : 0;\n }\n\n /**\n * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n * 3. The GC version in the latest summary is different from the current GC version. This can happen if:\n * 3.1. The summary this client loaded with has data from a different GC version.\n * 3.2. This client's latest summary was updated from a snapshot that has a different GC version.\n */\n public get summaryStateNeedsReset(): boolean {\n return this.initialStateNeedsReset ||\n (this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion);\n }\n\n /**\n * Tracks if GC is enabled for this document. This is specified during document creation and doesn't change\n * throughout its lifetime.\n */\n private readonly gcEnabled: boolean;\n private readonly shouldRunSweep: boolean;\n private readonly testMode: boolean;\n private readonly mc: MonitoringContext;\n\n /**\n * Tells whether the GC data should be written to the root of the summary tree.\n */\n private _writeDataAtRoot: boolean = false;\n public get writeDataAtRoot(): boolean {\n return this._writeDataAtRoot;\n }\n\n /**\n * Tells whether the initial GC state needs to be reset. This can happen under 2 conditions:\n * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n * a document and the first time GC is enabled after is was disabled before.\n *\n * Note that the state needs reset only for the very first time summary is generated by this client. After that, the\n * state will be up-to-date and this flag will be reset.\n */\n private initialStateNeedsReset: boolean = false;\n\n // The current GC version that this container is running.\n private readonly currentGCVersion = GCVersion;\n // This is the version of GC data in the latest summary being tracked.\n private latestSummaryGCVersion: GCVersion;\n\n // Keeps track of the GC state from the last run.\n private gcDataFromLastRun: IGarbageCollectionData | undefined;\n // Keeps a list of references (edges in the GC graph) between GC runs. Each entry has a node id and a list of\n // outbound routes from that node.\n private readonly referencesSinceLastRun: Map<string, string[]> = new Map();\n\n // Promise when resolved initializes the base state of the nodes from the base summary state.\n private readonly initializeBaseStateP: Promise<void>;\n // The map of data store ids to their GC details in the base summary returned in getDataStoreGCDetails().\n private readonly baseGCDetailsP: Promise<Map<string, IGarbageCollectionDetailsBase>>;\n // The time after which an unreferenced node can be deleted. Currently, we only set the node's state to expired.\n private readonly deleteTimeoutMs: number;\n // Map of node ids to their unreferenced state tracker.\n private readonly unreferencedNodesState: Map<string, UnreferencedStateTracker> = new Map();\n // The timeout responsible for closing the container when the session has expired\n private sessionExpiryTimer?: ReturnType<typeof setTimeout>;\n\n // Keeps track of unreferenced events that are logged for a node. This is used to limit the log generation to one\n // per event per node.\n private readonly loggedUnreferencedEvents: Set<string> = new Set();\n // Queue for unreferenced events that should be logged the next time GC runs.\n private readonly pendingEventsQueue: IUnreferencedEvent[] = [];\n\n protected constructor(\n private readonly runtime: IGarbageCollectionRuntime,\n private readonly gcOptions: IGCRuntimeOptions,\n /** For a given node path, returns the node's package path. */\n private readonly getNodePackagePath: (nodePath: string) => readonly string[] | undefined,\n /** Returns the timestamp of the last summary generated for this container. */\n private readonly getLastSummaryTimestampMs: () => number | undefined,\n baseSnapshot: ISnapshotTree | undefined,\n readAndParseBlob: ReadAndParseBlob,\n baseLogger: ITelemetryLogger,\n existing: boolean,\n metadata?: IContainerRuntimeMetadata,\n ) {\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(baseLogger, \"GarbageCollector\"));\n\n this.deleteTimeoutMs = this.gcOptions.deleteTimeoutMs ?? defaultDeleteTimeoutMs;\n\n let prevSummaryGCVersion: number | undefined;\n\n // GC can only be enabled during creation. After that, it can never be enabled again. So, for existing\n // documents, we get this information from the metadata blob. Similarly the session timeout should be\n // consistent across all clients, thus we grab it as well from the metadata blob, and set it once on creation.\n if (existing) {\n prevSummaryGCVersion = getGCVersion(metadata);\n // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all\n // other existing documents, GC is enabled.\n this.gcEnabled = prevSummaryGCVersion > 0;\n this.sessionExpiryTimeoutMs = metadata?.sessionExpiryTimeoutMs;\n } else {\n // For new documents, GC has to be explicitly enabled via the gcAllowed flag in GC options.\n this.gcEnabled = gcOptions.gcAllowed === true;\n // Set the Session Expiry only if the flag is enabled or the test option is set.\n if (this.mc.config.getBoolean(runSessionExpiry) && this.gcEnabled) {\n this.sessionExpiryTimeoutMs = defaultSessionExpiryDurationMs;\n }\n }\n\n // If session expiry is enabled, we need to close the container when the timeout expires\n if (this.sessionExpiryTimeoutMs !== undefined) {\n const timeoutMs = this.sessionExpiryTimeoutMs;\n setLongTimeout(timeoutMs,\n () => {\n this.runtime.closeFn(new ClientSessionExpiredError(`Client session expired.`, timeoutMs));\n },\n (timer) => {\n this.sessionExpiryTimer = timer;\n });\n }\n\n // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n // latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n this.latestSummaryGCVersion = prevSummaryGCVersion ?? this.currentGCVersion;\n\n // Whether GC should run or not. Can override with localStorage flag.\n this.shouldRunGC = this.mc.config.getBoolean(runGCKey) ?? (\n // GC must be enabled for the document.\n this.gcEnabled\n // GC must not be disabled via GC options.\n && !gcOptions.disableGC\n );\n\n // Whether GC sweep phase should run or not. If this is false, only GC mark phase is run. Can override with\n // localStorage flag.\n this.shouldRunSweep = this.shouldRunGC &&\n (this.mc.config.getBoolean(runSweepKey) ?? gcOptions.runSweep === true)\n && this.sessionExpiryTimer !== undefined;\n\n // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.\n this.testMode = this.mc.config.getBoolean(gcTestModeKey) ?? gcOptions.runGCInTestMode === true;\n\n /**\n * Enable resetting initial state once the following issue is resolved:\n * https://github.com/microsoft/FluidFramework/issues/8878.\n * Currently, the GC tree is not written at root, so we don't know if the base snapshot contains GC tree or not.\n */\n // The GC state needs to be reset if the base snapshot contains GC tree and GC is disabled or it doesn't contain\n // GC tree and GC is enabled.\n // const gcTreePresent = baseSnapshot?.trees[gcTreeKey] !== undefined;\n // this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;\n\n // If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that\n // the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.\n this._writeDataAtRoot = this.mc.config.getBoolean(writeAtRootKey) ?? this.gcOptions.writeDataAtRoot === true;\n\n // Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do\n // this once since it involves fetching blobs from storage which is expensive.\n const baseSummaryStateP = new LazyPromise<IGarbageCollectionState | undefined>(async () => {\n if (baseSnapshot === undefined) {\n return undefined;\n }\n\n // For newer documents, GC data should be present in the GC tree in the root of the snapshot.\n const gcSnapshotTree = baseSnapshot.trees[gcTreeKey];\n if (gcSnapshotTree !== undefined) {\n // If the GC tree is written at root, we should also do the same.\n this._writeDataAtRoot = true;\n return getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);\n }\n\n // back-compat - Older documents will have the GC blobs in each data store's summary tree. Get them and\n // consolidate into IGarbageCollectionState format.\n // Add a node for the root node that is not present in older snapshot format.\n const gcState: IGarbageCollectionState = { gcNodes: { \"/\": { outboundRoutes: [] } } };\n const dataStoreSnapshotTree = getSummaryForDatastores(baseSnapshot, metadata);\n assert(dataStoreSnapshotTree !== undefined,\n 0x2a8 /* \"Expected data store snapshot tree in base snapshot\" */);\n for (const [dsId, dsSnapshotTree] of Object.entries(dataStoreSnapshotTree.trees)) {\n const blobId = dsSnapshotTree.blobs[gcBlobKey];\n if (blobId === undefined) {\n continue;\n }\n\n const gcSummaryDetails = await readAndParseBlob<IGarbageCollectionDetailsBase>(blobId);\n // If there are no nodes for this data store, skip it.\n if (gcSummaryDetails.gcData?.gcNodes === undefined) {\n continue;\n }\n\n const dsRootId = `/${dsId}`;\n // Since we used to write GC data at data store level, we won't have an entry for the root (\"/\").\n // Construct that entry by adding root data store ids to its outbound routes.\n const initialSnapshotDetails = await readAndParseBlob<ReadFluidDataStoreAttributes>(\n dsSnapshotTree.blobs[dataStoreAttributesBlobName],\n );\n if (initialSnapshotDetails.isRootDataStore) {\n gcState.gcNodes[\"/\"].outboundRoutes.push(dsRootId);\n }\n\n for (const [id, outboundRoutes] of Object.entries(gcSummaryDetails.gcData.gcNodes)) {\n // Prefix the data store id to the GC node ids to make them relative to the root from being\n // relative to the data store. Similar to how its done in DataStore::getGCData.\n const rootId = id === \"/\" ? dsRootId : `${dsRootId}${id}`;\n gcState.gcNodes[rootId] = { outboundRoutes: Array.from(outboundRoutes) };\n }\n assert(gcState.gcNodes[dsRootId] !== undefined,\n 0x2a9 /* `GC nodes for data store ${dsId} not in GC blob` */);\n gcState.gcNodes[dsRootId].unreferencedTimestampMs = gcSummaryDetails.unrefTimestamp;\n }\n\n // If there is only one node (root node just added above), either GC is disabled or we are loading from the\n // very first summary generated by detached container. In both cases, GC was not run - return undefined.\n return Object.keys(gcState.gcNodes).length === 1 ? undefined : gcState;\n });\n\n /**\n * Set up the initializer which initializes the base GC state from the base snapshot. Note that the reference\n * timestamp maybe from old ops which were not summarized and stored in the file. So, the unreferenced state\n * may be out of date. This is fine because the state is updated every time GC runs based on the time then.\n */\n this.initializeBaseStateP = new LazyPromise<void>(async () => {\n const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n const baseState = await baseSummaryStateP;\n if (baseState === undefined) {\n return;\n }\n\n const gcNodes: { [ id: string ]: string[] } = {};\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n if (nodeData.unreferencedTimestampMs !== undefined) {\n this.unreferencedNodesState.set(\n nodeId,\n new UnreferencedStateTracker(\n nodeData.unreferencedTimestampMs,\n this.deleteTimeoutMs,\n currentReferenceTimestampMs,\n ),\n );\n }\n gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n }\n this.gcDataFromLastRun = { gcNodes };\n });\n\n // Get the GC details for each node from the GC state in the base summary. This is returned in getBaseGCDetails\n // which the caller uses to initialize each node's GC state.\n this.baseGCDetailsP = new LazyPromise<Map<string, IGarbageCollectionDetailsBase>>(async () => {\n const baseState = await baseSummaryStateP;\n if (baseState === undefined) {\n return new Map();\n }\n\n const gcNodes: { [ id: string ]: string[] } = {};\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n }\n // Run GC on the nodes in the base summary to get the routes used in each node in the container.\n // This is an optimization for space (vs performance) wherein we don't need to store the used routes of\n // each node in the summary.\n const usedRoutes = runGarbageCollection(\n gcNodes,\n [ \"/\" ],\n this.mc.logger,\n ).referencedNodeIds;\n\n const baseGCDetailsMap = unpackChildNodesGCDetails({ gcData: { gcNodes }, usedRoutes });\n // Currently, the nodes may write the GC data. So, we need to update it's base GC details with the\n // unreferenced timestamp. Once we start writing the GC data here, we won't need to do this anymore.\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n if (nodeData.unreferencedTimestampMs !== undefined) {\n const dataStoreGCDetails = baseGCDetailsMap.get(nodeId.slice(1));\n if (dataStoreGCDetails !== undefined) {\n dataStoreGCDetails.unrefTimestamp = nodeData.unreferencedTimestampMs;\n }\n }\n }\n return baseGCDetailsMap;\n });\n\n // Initialize the base state. The base GC data is used to detect and log when inactive / deleted objects are\n // used in the container.\n if (this.shouldRunGC) {\n this.initializeBaseStateP.catch((error) => {\n const dpe = DataProcessingError.wrapIfUnrecognized(\n error,\n \"FailedToInitializeGC\",\n );\n dpe.addTelemetryProperties({\n gcEnabled: this.gcEnabled,\n runSweep: this.shouldRunSweep,\n writeAtRoot: this._writeDataAtRoot,\n testMode: this.testMode,\n sessionExpiry: this.sessionExpiryTimeoutMs,\n });\n throw dpe;\n });\n }\n }\n\n /**\n * Runs garbage collection and updates the reference / used state of the nodes in the container.\n * @returns the number of data stores that have been marked as unreferenced.\n */\n public async collectGarbage(\n options: {\n /** Logger to use for logging GC events */\n logger?: ITelemetryLogger,\n /** True to run GC sweep phase after the mark phase */\n runSweep?: boolean,\n /** True to generate full GC data */\n fullGC?: boolean,\n },\n ): Promise<IGCStats> {\n const {\n logger = this.mc.logger,\n runSweep = this.shouldRunSweep,\n fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset,\n } = options;\n\n return PerformanceEvent.timedExecAsync(logger, { eventName: \"GarbageCollection\" }, async (event) => {\n await this.initializeBaseStateP;\n\n // Let the runtime update its pending state before GC runs.\n await this.runtime.updateStateBeforeGC();\n\n // Get the runtime's GC data and run GC on the reference graph in it.\n const gcData = await this.runtime.getGCData(fullGC);\n const gcResult = runGarbageCollection(\n gcData.gcNodes,\n [ \"/\" ],\n logger,\n );\n const gcStats = this.generateStatsAndLogEvents(gcResult);\n\n // Update the state since the last GC run. There can be nodes that were referenced between the last and\n // the current run. We need to identify than and update their unreferenced state if needed.\n this.updateStateSinceLastRun(gcData);\n\n // Update the current state of the system based on the GC run.\n const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n this.updateCurrentState(gcData, gcResult, currentReferenceTimestampMs);\n\n this.runtime.updateUsedRoutes(gcResult.referencedNodeIds, currentReferenceTimestampMs);\n\n if (runSweep) {\n // Placeholder for running sweep logic.\n }\n\n // If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios\n // involving access to deleted data.\n if (this.testMode) {\n this.runtime.deleteUnusedRoutes(gcResult.deletedNodeIds);\n }\n event.end({ ...gcStats });\n return gcStats;\n },\n { end: true, cancel: \"error\" });\n }\n\n /**\n * Summarizes the GC data and returns it as a summary tree.\n * We current write the entire GC state in a single blob. This can be modified later to write multiple\n * blobs. All the blob keys should start with `gcBlobPrefix`.\n */\n public summarize(): ISummaryTreeWithStats | undefined {\n if (!this.shouldRunGC || this.gcDataFromLastRun === undefined) {\n return;\n }\n\n const gcState: IGarbageCollectionState = { gcNodes: {} };\n for (const [nodeId, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n gcState.gcNodes[nodeId] = {\n outboundRoutes,\n unreferencedTimestampMs: this.unreferencedNodesState.get(nodeId)?.unreferencedTimestampMs,\n };\n }\n\n const builder = new SummaryTreeBuilder();\n builder.addBlob(`${gcBlobPrefix}_root`, JSON.stringify(gcState));\n return builder.getSummaryTree();\n }\n\n /**\n * Returns a map of node ids to their base GC details generated from the base summary. This is used by the caller\n * to initialize the GC state of the nodes.\n */\n public async getBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>> {\n return this.baseGCDetailsP;\n }\n\n /**\n * Called when the latest summary of the system has been refreshed. This will be used to update the state of the\n * latest summary tracked.\n */\n public async latestSummaryStateRefreshed(\n result: RefreshSummaryResult,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // After a summary is successfully submitted and ack'd by this client, the GC state should have been reset in\n // the summary and doesn't need to be reset anymore.\n this.initialStateNeedsReset = false;\n\n if (!this.shouldRunGC || !result.latestSummaryUpdated) {\n return;\n }\n\n // If the summary was tracked by this client, it was the one that generated the summary in the first place.\n // Basically, it was written in the current GC version.\n if (result.wasSummaryTracked) {\n this.latestSummaryGCVersion = this.currentGCVersion;\n return;\n }\n // If the summary was not tracked by this client, update latest GC version from the snapshot in the result as\n // that is now the latest summary.\n await this.updateSummaryGCVersionFromSnapshot(result.snapshot, readAndParseBlob);\n }\n\n /**\n * Called when a node with the given id is updated. If the node is inactive, log an error.\n * @param nodePath - The id of the node that changed.\n * @param reason - Whether the node was loaded or changed.\n * @param timestampMs - The timestamp when the node changed.\n * @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.\n * @param requestHeaders - If the node was loaded via request path, the headers in the request.\n */\n public nodeUpdated(\n nodePath: string,\n reason: \"Loaded\" | \"Changed\",\n timestampMs?: number,\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ) {\n if (!this.shouldRunGC) {\n return;\n }\n\n this.logIfInactive(\n reason,\n nodePath,\n timestampMs,\n packagePath,\n requestHeaders,\n );\n }\n\n /**\n * Called when an outbound reference is added to a node. This is used to identify all nodes that have been\n * referenced between summaries so that their unreferenced timestamp can be reset.\n *\n * @param fromNodePath - The node from which the reference is added.\n * @param toNodePath - The node to which the reference is added.\n */\n public addedOutboundReference(fromNodePath: string, toNodePath: string) {\n if (!this.shouldRunGC) {\n return;\n }\n\n const outboundRoutes = this.referencesSinceLastRun.get(fromNodePath) ?? [];\n outboundRoutes.push(toNodePath);\n this.referencesSinceLastRun.set(fromNodePath, outboundRoutes);\n\n // If the node that got referenced is inactive, log an event as that may indicate use-after-delete.\n this.logIfInactive(\n \"Revived\",\n toNodePath,\n );\n }\n\n public dispose(): void {\n if (this.sessionExpiryTimer !== undefined) {\n clearTimeout(this.sessionExpiryTimer);\n this.sessionExpiryTimer = undefined;\n }\n }\n\n /**\n * Update the latest summary GC version from the metadata blob in the given snapshot.\n */\n private async updateSummaryGCVersionFromSnapshot(snapshot: ISnapshotTree, readAndParseBlob: ReadAndParseBlob) {\n const metadataBlobId = snapshot.blobs[metadataBlobName];\n if (metadataBlobId) {\n const metadata = await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId);\n this.latestSummaryGCVersion = getGCVersion(metadata);\n }\n }\n\n /**\n * Updates the state of the system as per the current GC run. It does the following:\n * 1. Sets up the current GC state as per the gcData.\n * 2. Starts tracking for nodes that have become unreferenced in this run.\n * 3. Clears tracking for nodes that were unreferenced but became referenced in this run.\n * @param gcData - The data representing the reference graph on which GC is run.\n * @param gcResult - The result of the GC run on the gcData.\n * @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.\n */\n private updateCurrentState(\n gcData: IGarbageCollectionData,\n gcResult: IGCResult,\n currentReferenceTimestampMs?: number,\n ) {\n this.gcDataFromLastRun = cloneGCData(gcData);\n this.referencesSinceLastRun.clear();\n\n // Iterate through the referenced nodes and stop tracking if they were unreferenced before.\n for (const nodeId of gcResult.referencedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker !== undefined) {\n // Stop tracking so as to clear out any running timers.\n nodeStateTracker.stopTracking();\n // Delete the node as we don't need to track it any more.\n this.unreferencedNodesState.delete(nodeId);\n }\n }\n\n /**\n * If there is no current reference time, skip tracking when a node becomes unreferenced. This would happen\n * if no ops have been processed ever and we still try to run GC. If so, there is nothing interesting to track\n * anyway.\n */\n if (currentReferenceTimestampMs === undefined) {\n return;\n }\n\n /**\n * If a node became unreferenced in this run, start tracking it.\n * If a node was already unreferenced, update its tracking information. Since the current reference time is\n * from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.\n */\n for (const nodeId of gcResult.deletedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker === undefined) {\n this.unreferencedNodesState.set(\n nodeId,\n new UnreferencedStateTracker(\n currentReferenceTimestampMs,\n this.deleteTimeoutMs,\n currentReferenceTimestampMs,\n ),\n );\n } else {\n nodeStateTracker.updateTracking(currentReferenceTimestampMs);\n }\n }\n }\n\n /**\n * Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in\n * time. It's possible that nodes transition from `unreferenced -> referenced -> unreferenced` between two runs. The\n * unreferenced timestamp of such nodes needs to be reset as they may have been accessed when they were referenced.\n *\n * This function identifies nodes that were referenced since last run and removes their unreferenced state, if any.\n * If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.\n */\n private updateStateSinceLastRun(currentGCData: IGarbageCollectionData) {\n // If we haven't run GC before or no references were added since the last run, there is nothing to do.\n if (this.gcDataFromLastRun === undefined || this.referencesSinceLastRun.size === 0) {\n return;\n }\n\n // Validate that we have identified all references correctly.\n this.validateReferenceCorrectness(currentGCData);\n\n /**\n * Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and\n * edges that have been added since then. To do this, combine the GC data from the last run and the current\n * run, and then add the references since last run.\n *\n * Note on why we need to combine the data from previous run, current run and all references in between -\n * 1. We need data from last run because some of its references may have been deleted since then. If those\n * references added new outbound references before getting deleted, we need to detect them.\n * 2. We need new outbound references since last run because some of them may have been deleted later. If those\n * references added new outbound references before getting deleted, we need to detect them.\n * 3. We need data from the current run because currently we may not detect when DDSs are referenced:\n * - We don't require DDSs handles to be stored in a referenced DDS. For this, we need GC at DDS level\n * which is tracked by https://github.com/microsoft/FluidFramework/issues/8470.\n * - A new data store may have \"root\" DDSs already created and we don't detect them today.\n */\n const gcDataSuperSet = concatGarbageCollectionData(this.gcDataFromLastRun, currentGCData);\n this.referencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {\n if (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {\n gcDataSuperSet.gcNodes[sourceNodeId] = outboundRoutes;\n } else {\n gcDataSuperSet.gcNodes[sourceNodeId].push(...outboundRoutes);\n }\n });\n\n /**\n * Run GC on the above reference graph to find all nodes that are referenced. For each one, if they are\n * unreferenced, stop tracking them and remove from unreferenced list.\n * Some of these nodes may be unreferenced now and if so, the current run will add unreferenced state for them.\n */\n const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, [\"/\"], this.mc.logger);\n for (const nodeId of gcResult.referencedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker !== undefined) {\n // Stop tracking so as to clear out any running timers.\n nodeStateTracker.stopTracking();\n // Delete the node as we don't need to track it any more.\n this.unreferencedNodesState.delete(nodeId);\n }\n }\n }\n\n /**\n * Validates that all new references are correctly identified and processed. The basic principle for validation is\n * that we should not have new references in the reference graph (GC data) that have not been notified to the\n * garbage collector via `referenceAdded`.\n * We validate that the references in the current reference graph should be a subset of the references in the last\n * run's reference graph + references since the last run.\n * @param currentGCData - The GC data (reference graph) from the current GC run.\n */\n private validateReferenceCorrectness(currentGCData: IGarbageCollectionData) {\n assert(\n this.gcDataFromLastRun !== undefined,\n 0x2b7, /* \"Can't validate correctness without GC data from last run\" */\n );\n\n // Get a list of all the outbound routes (or references) in the current GC data.\n const currentReferences: string[] = [];\n for (const [nodeId, outboundRoutes] of Object.entries(currentGCData.gcNodes)) {\n /**\n * Remove routes from a child node to its parent which is added implicitly by the runtime. For instance,\n * each adds its data store as an outbound route to mark it as referenced if the DDS is referenced.\n * We won't get any explicit notification for these references so they must be removed before validation.\n */\n const explicitRoutes = outboundRoutes.filter((route) => !nodeId.startsWith(route));\n currentReferences.push(...explicitRoutes);\n }\n\n // Get a list of outbound routes (or references) from the last run's GC data plus references added since the\n // last run that were notified via `referenceAdded`.\n const explicitReferences: string[] = [];\n for (const [, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n explicitReferences.push(...outboundRoutes);\n }\n this.referencesSinceLastRun.forEach((outboundRoutes: string[]) => {\n explicitReferences.push(...outboundRoutes);\n });\n\n // Validate that the current reference graph doesn't have references that we are not already aware of. If this\n // happens, it might indicate data corruption since we may delete objects prematurely.\n currentReferences.forEach((route: string) => {\n // Validate references for data stores only. Currently, layers below data stores don't have GC implemented\n // so there is no guarantee their references will be notified.\n if (this.runtime.getNodeType(route) === GCNodeType.DataStore && !explicitReferences.includes(route)) {\n /**\n * The following log will be enabled once this issue is resolved:\n * https://github.com/microsoft/FluidFramework/issues/8878.\n */\n // We should ideally throw a data corruption error here. However, send an error for now until we have\n // implemented sweep and have reasonable confidence in the sweep process.\n // this.mc.logger.sendErrorEvent({\n // eventName: \"gcUnknownOutboundRoute\",\n // route,\n // });\n }\n });\n }\n\n /**\n * Generates the stats of a garbage collection run from the given results of the run. Also, logs any pending events\n * in the pendingEventsQueue. This should be called before updating the current state because it generates stats\n * based on previous state of the system.\n * @param gcResult - The result of a GC run.\n * @returns the GC stats of the GC run.\n */\n private generateStatsAndLogEvents(gcResult: IGCResult): IGCStats {\n // Log pending events for unreferenced nodes after GC has run. We should have the package data available for\n // them now since the GC run should have loaded these nodes.\n let event = this.pendingEventsQueue.shift();\n while (event !== undefined) {\n const pkg = this.getNodePackagePath(event.id);\n this.mc.logger.sendErrorEvent({\n ...event,\n pkg: pkg ? { value: `/${pkg.join(\"/\")}`, tag: TelemetryDataTag.PackageData } : undefined,\n });\n event = this.pendingEventsQueue.shift();\n }\n\n const gcStats: IGCStats = {\n nodeCount: 0,\n dataStoreCount: 0,\n attachmentBlobCount: 0,\n unrefNodeCount: 0,\n unrefDataStoreCount: 0,\n unrefAttachmentBlobCount: 0,\n updatedNodeCount: 0,\n updatedDataStoreCount: 0,\n updatedAttachmentBlobCount: 0,\n };\n\n const updateNodeStats = (nodeId: string, referenced: boolean) => {\n gcStats.nodeCount++;\n /**\n * `this.unreferencedNodesState` has the previous unreferenced state of all nodes. `referenced` flag passed\n * here is current state of the give node. Check if the reference state of the changed.\n */\n const stateUpdated = this.unreferencedNodesState.has(nodeId) ? referenced : !referenced;\n if (stateUpdated) {\n gcStats.updatedNodeCount++;\n }\n if (!referenced) {\n gcStats.unrefNodeCount++;\n }\n\n if (this.runtime.getNodeType(nodeId) === GCNodeType.DataStore) {\n gcStats.dataStoreCount++;\n if (stateUpdated) {\n gcStats.updatedDataStoreCount++;\n }\n if (!referenced) {\n gcStats.unrefDataStoreCount++;\n }\n }\n if (this.runtime.getNodeType(nodeId) === GCNodeType.Blob) {\n gcStats.attachmentBlobCount++;\n if (stateUpdated) {\n gcStats.updatedAttachmentBlobCount++;\n }\n if (!referenced) {\n gcStats.unrefAttachmentBlobCount++;\n }\n }\n };\n\n for (const nodeId of gcResult.referencedNodeIds) {\n updateNodeStats(nodeId, true /* referenced */);\n }\n\n for (const nodeId of gcResult.deletedNodeIds) {\n updateNodeStats(nodeId, false /* referenced */);\n }\n\n return gcStats;\n }\n\n /**\n * Logs an event if a node is inactive and is used.\n */\n private logIfInactive(\n eventSuffix: \"Changed\" | \"Loaded\" | \"Revived\",\n nodeId: string,\n currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(),\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ) {\n // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip\n // logging as nothing interesting would have happened worth logging.\n if (currentReferenceTimestampMs === undefined) {\n return;\n }\n\n const eventName = `inactiveObject_${eventSuffix}`;\n // We log a particular event for a given node only once so that it is not too noisy.\n const uniqueEventId = `${nodeId}-${eventName}`;\n const nodeState = this.unreferencedNodesState.get(nodeId);\n if (nodeState?.inactive && !this.loggedUnreferencedEvents.has(uniqueEventId)) {\n this.loggedUnreferencedEvents.add(uniqueEventId);\n const event: IUnreferencedEvent = {\n eventName,\n id: nodeId,\n age: currentReferenceTimestampMs - nodeState.unreferencedTimestampMs,\n timeout: this.deleteTimeoutMs,\n lastSummaryTime: this.getLastSummaryTimestampMs(),\n externalRequest: requestHeaders?.[RuntimeHeaders.externalRequest],\n viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],\n };\n\n // If the package data for the node exists, log immediately. Otherwise, queue it and it will be logged the\n // next time GC runs as the package data should be available then.\n const pkg = packagePath ?? this.getNodePackagePath(nodeId);\n if (pkg !== undefined) {\n this.mc.logger.sendErrorEvent({\n ...event,\n pkg: { value: `/${pkg.join(\"/\")}`, tag: TelemetryDataTag.PackageData },\n });\n } else {\n this.pendingEventsQueue.push(event);\n }\n }\n }\n}\n\n/**\n * Gets the garbage collection state from the given snapshot tree. The GC state may be written into multiple blobs.\n * Merge the GC state from all such blobs and return the merged GC state.\n */\nasync function getGCStateFromSnapshot(\n gcSnapshotTree: ISnapshotTree,\n readAndParseBlob: ReadAndParseBlob,\n): Promise<IGarbageCollectionState> {\n let rootGCState: IGarbageCollectionState = { gcNodes: {} };\n for (const key of Object.keys(gcSnapshotTree.blobs)) {\n // Skip blobs that do not start with the GC prefix.\n if (!key.startsWith(gcBlobPrefix)) {\n continue;\n }\n\n const blobId = gcSnapshotTree.blobs[key];\n if (blobId === undefined) {\n continue;\n }\n const gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n assert(gcState !== undefined, 0x2ad /* \"GC blob missing from snapshot\" */);\n // Merge the GC state of this blob into the root GC state.\n rootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n }\n return rootGCState;\n}\n\n/**\n * setLongTimeout is used for timeouts longer than setTimeout's ~24.8 day max\n * @param timeoutMs - the total time the timeout needs to last in ms\n * @param timeoutFn - the function to execute when the timer ends\n * @param setTimerFn - the function used to update your timer variable\n */\nfunction setLongTimeout(\n timeoutMs: number,\n timeoutFn: () => void,\n setTimerFn: (timer: ReturnType<typeof setTimeout>) => void,\n) {\n // The setTimeout max is 24.8 days before looping occurs.\n const maxTimeout = 2147483647;\n let timer: ReturnType<typeof setTimeout>;\n if (timeoutMs > maxTimeout) {\n const newTimeoutMs = timeoutMs - maxTimeout;\n timer = setTimeout(() => setLongTimeout(newTimeoutMs, timeoutFn, setTimerFn), maxTimeout);\n } else {\n timer = setTimeout(() => timeoutFn(), timeoutMs);\n }\n setTimerFn(timer);\n}\n"]}
1
+ {"version":3,"file":"garbageCollection.js","sourceRoot":"","sources":["../src/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 { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { ClientSessionExpiredError, DataProcessingError } from \"@fluidframework/container-utils\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport {\n cloneGCData,\n concatGarbageCollectionStates,\n concatGarbageCollectionData,\n IGCResult,\n runGarbageCollection,\n unpackChildNodesGCDetails,\n} from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionState,\n IGarbageCollectionDetailsBase,\n ISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n ReadAndParseBlob,\n RefreshSummaryResult,\n SummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport {\n ChildLogger,\n loggerToMonitoringContext,\n MonitoringContext,\n PerformanceEvent,\n TelemetryDataTag,\n} from \"@fluidframework/telemetry-utils\";\n\nimport { IGCRuntimeOptions, RuntimeHeaders } from \"./containerRuntime\";\nimport { getSummaryForDatastores } from \"./dataStores\";\nimport {\n getGCVersion,\n GCVersion,\n IContainerRuntimeMetadata,\n metadataBlobName,\n ReadFluidDataStoreAttributes,\n dataStoreAttributesBlobName,\n} from \"./summaryFormat\";\n\n/** This is the current version of garbage collection. */\nconst GCVersion = 1;\n\n// The key for the GC tree in summary.\nexport const gcTreeKey = \"gc\";\n// They prefix for GC blobs in the GC tree in summary.\nexport const gcBlobPrefix = \"__gc\";\n\n// Feature gate key to turn GC on / off.\nconst runGCKey = \"Fluid.GarbageCollection.RunGC\";\n// Feature gate key to turn GC test mode on / off.\nconst gcTestModeKey = \"Fluid.GarbageCollection.GCTestMode\";\n// Feature gate key to turn GC sweep on / off.\nconst runSweepKey = \"Fluid.GarbageCollection.RunSweep\";\n// Feature gate key to write GC data at the root of the summary tree.\nconst writeAtRootKey = \"Fluid.GarbageCollection.WriteDataAtRoot\";\n// Feature gate key to expire a session after a set period of time.\nconst runSessionExpiry = \"Fluid.GarbageCollection.RunSessionExpiry\";\n\nconst defaultDeleteTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days\nexport const defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days\n\n/** The statistics of the system state after a garbage collection run. */\nexport interface IGCStats {\n /** The number of nodes in the container. */\n nodeCount: number;\n /** The number of data stores in the container. */\n dataStoreCount: number;\n /** The number of attachment blobs in the container. */\n attachmentBlobCount: number;\n /** The number of unreferenced nodes in the container. */\n unrefNodeCount: number;\n /** The number of unreferenced data stores in the container. */\n unrefDataStoreCount: number;\n /** The number of unreferenced attachment blobs in the container. */\n unrefAttachmentBlobCount: number;\n /** The number of nodes whose reference state updated since last GC run. */\n updatedNodeCount: number;\n /** The number of data stores whose reference state updated since last GC run. */\n updatedDataStoreCount: number;\n /** The number of attachment blobs whose reference state updated since last GC run. */\n updatedAttachmentBlobCount: number;\n}\n\n/** The types of GC nodes in the GC reference graph. */\nexport const GCNodeType = {\n // Nodes that are for data stores.\n DataStore: \"DataStore\",\n // Nodes that are within a data store. For example, DDS nodes.\n SubDataStore: \"SubDataStore\",\n // Nodes that are for attachment blobs, i.e., blobs uploaded via BlobManager.\n Blob: \"Blob\",\n // Nodes that are neither of the above. For example, root node.\n Other: \"Other\",\n};\nexport type GCNodeType = typeof GCNodeType[keyof typeof GCNodeType];\n\n/** The event that is logged when unreferenced node is used after a certain time. */\ninterface IUnreferencedEvent {\n eventName: string;\n id: string;\n age: number;\n timeout: number;\n lastSummaryTime?: number;\n externalRequest?: boolean;\n viaHandle?: boolean;\n}\n\n/** Defines the APIs for the runtime object to be passed to the garbage collector. */\nexport interface IGarbageCollectionRuntime {\n /** Before GC runs, called to notify the runtime to update any pending GC state. */\n updateStateBeforeGC(): Promise<void>;\n /** Returns the garbage collection data of the runtime. */\n getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;\n /** After GC has run, called to notify the runtime of routes that are used in it. */\n updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): void;\n /** After GC has run, called to delete objects in the runtime whose routes are unused. */\n deleteUnusedRoutes(unusedRoutes: string[]): void;\n /** Returns a referenced timestamp to be used to track unreferenced nodes. */\n getCurrentReferenceTimestampMs(): number | undefined;\n /** Returns the type of the GC node. */\n getNodeType(nodePath: string): GCNodeType;\n /** Called when the runtime should close because of an error. */\n closeFn(error?: ICriticalContainerError): void;\n}\n\n/** Defines the contract for the garbage collector. */\nexport interface IGarbageCollector {\n /** Tells whether GC should run or not. */\n readonly shouldRunGC: boolean;\n /** The time in ms to expire a session for a client for gc. */\n readonly sessionExpiryTimeoutMs: number | undefined;\n /**\n * This tracks two things:\n * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.\n * 2. If GC is enabled, the version of GC used to generate the GC data written in a summary.\n */\n readonly gcSummaryFeatureVersion: number;\n /** Tells whether the GC state in summary needs to be reset in the next summary. */\n readonly summaryStateNeedsReset: boolean;\n /** Tells whether GC data should be written to the root of the summary tree. */\n readonly writeDataAtRoot: boolean;\n /** Run garbage collection and update the reference / used state of the system. */\n collectGarbage(\n options: { logger?: ITelemetryLogger, runGC?: boolean, runSweep?: boolean, fullGC?: boolean },\n ): Promise<IGCStats>;\n /** Summarizes the GC data and returns it as a summary tree. */\n summarize(): ISummaryTreeWithStats | undefined;\n /** Returns a map of each node id to its base GC details in the base summary. */\n getBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>>;\n /** Called when the latest summary of the system has been refreshed. */\n latestSummaryStateRefreshed(result: RefreshSummaryResult, readAndParseBlob: ReadAndParseBlob): Promise<void>;\n /** Called when a node is updated. Used to detect and log when an inactive node is changed or loaded. */\n nodeUpdated(\n nodePath: string,\n reason: \"Loaded\" | \"Changed\",\n timestampMs?: number,\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ): void;\n /** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */\n addedOutboundReference(fromNodePath: string, toNodePath: string): void;\n dispose(): void;\n}\n\n/**\n * Helper class that tracks the state of an unreferenced node such as the time it was unreferenced. It also sets\n * the node's state to inactive if it remains unreferenced for a given amount of time (inactiveTimeoutMs).\n */\nclass UnreferencedStateTracker {\n private _inactive: boolean = false;\n public get inactive(): boolean {\n return this._inactive;\n }\n\n private timer: Timer | undefined;\n\n constructor(\n public readonly unreferencedTimestampMs: number,\n private readonly inactiveTimeoutMs: number,\n currentReferenceTimestampMs?: number,\n ) {\n // If there is no current reference timestamp, don't track the node's inactive state. This will happen later\n // when updateTracking is called with a reference timestamp.\n if (currentReferenceTimestampMs !== undefined) {\n this.updateTracking(currentReferenceTimestampMs);\n }\n }\n\n /**\n * Updates the tracking state based on the provided timestamp.\n */\n public updateTracking(currentReferenceTimestampMs: number) {\n const unreferencedDurationMs = currentReferenceTimestampMs - this.unreferencedTimestampMs;\n // If the timeout has already expired, the node has become inactive.\n if (unreferencedDurationMs > this.inactiveTimeoutMs) {\n this._inactive = true;\n this.timer?.clear();\n return;\n }\n\n // The node isn't inactive yet. Restart a timer for the duration remaining for it to become inactive.\n const remainingDurationMs = this.inactiveTimeoutMs - unreferencedDurationMs;\n if (this.timer === undefined) {\n this.timer = new Timer(remainingDurationMs, () => { this._inactive = true; });\n }\n this.timer.restart(remainingDurationMs);\n }\n\n /**\n * Stop tracking this node. Reset the unreferenced timer, if any, and reset inactive state.\n */\n public stopTracking() {\n this.timer?.clear();\n this._inactive = false;\n }\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 */\nexport class GarbageCollector implements IGarbageCollector {\n public static create(\n provider: IGarbageCollectionRuntime,\n gcOptions: IGCRuntimeOptions,\n getNodePackagePath: (nodePath: string) => readonly string[] | undefined,\n getLastSummaryTimestampMs: () => number | undefined,\n baseSnapshot: ISnapshotTree | undefined,\n readAndParseBlob: ReadAndParseBlob,\n baseLogger: ITelemetryLogger,\n existing: boolean,\n metadata?: IContainerRuntimeMetadata,\n ): IGarbageCollector {\n return new GarbageCollector(\n provider,\n gcOptions,\n getNodePackagePath,\n getLastSummaryTimestampMs,\n baseSnapshot,\n readAndParseBlob,\n baseLogger,\n existing,\n metadata,\n );\n }\n\n /**\n * Tells whether GC should be run based on the GC options and local storage flags.\n */\n public readonly shouldRunGC: boolean;\n\n /**\n * The time in ms to expire a session for a client for gc.\n */\n public readonly sessionExpiryTimeoutMs: number | undefined;\n\n /**\n * This tracks two things:\n * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.\n * 2. If GC is enabled, the version of GC used to generate the GC data written in a summary.\n */\n public get gcSummaryFeatureVersion(): number {\n return this.gcEnabled ? this.currentGCVersion : 0;\n }\n\n /**\n * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n * 3. The GC version in the latest summary is different from the current GC version. This can happen if:\n * 3.1. The summary this client loaded with has data from a different GC version.\n * 3.2. This client's latest summary was updated from a snapshot that has a different GC version.\n */\n public get summaryStateNeedsReset(): boolean {\n return this.initialStateNeedsReset ||\n (this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion);\n }\n\n /**\n * Tracks if GC is enabled for this document. This is specified during document creation and doesn't change\n * throughout its lifetime.\n */\n private readonly gcEnabled: boolean;\n private readonly shouldRunSweep: boolean;\n private readonly testMode: boolean;\n private readonly mc: MonitoringContext;\n\n /**\n * Tells whether the GC data should be written to the root of the summary tree.\n */\n private _writeDataAtRoot: boolean = false;\n public get writeDataAtRoot(): boolean {\n return this._writeDataAtRoot;\n }\n\n /**\n * Tells whether the initial GC state needs to be reset. This can happen under 2 conditions:\n * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n * a document and the first time GC is enabled after is was disabled before.\n *\n * Note that the state needs reset only for the very first time summary is generated by this client. After that, the\n * state will be up-to-date and this flag will be reset.\n */\n private initialStateNeedsReset: boolean = false;\n\n // The current GC version that this container is running.\n private readonly currentGCVersion = GCVersion;\n // This is the version of GC data in the latest summary being tracked.\n private latestSummaryGCVersion: GCVersion;\n\n // Keeps track of the GC state from the last run.\n private gcDataFromLastRun: IGarbageCollectionData | undefined;\n // Keeps a list of references (edges in the GC graph) between GC runs. Each entry has a node id and a list of\n // outbound routes from that node.\n private readonly referencesSinceLastRun: Map<string, string[]> = new Map();\n\n // Promise when resolved initializes the base state of the nodes from the base summary state.\n private readonly initializeBaseStateP: Promise<void>;\n // The map of data store ids to their GC details in the base summary returned in getDataStoreGCDetails().\n private readonly baseGCDetailsP: Promise<Map<string, IGarbageCollectionDetailsBase>>;\n // The time after which an unreferenced node can be deleted. Currently, we only set the node's state to expired.\n private readonly deleteTimeoutMs: number;\n // Map of node ids to their unreferenced state tracker.\n private readonly unreferencedNodesState: Map<string, UnreferencedStateTracker> = new Map();\n // The timeout responsible for closing the container when the session has expired\n private sessionExpiryTimer?: ReturnType<typeof setTimeout>;\n\n // Keeps track of unreferenced events that are logged for a node. This is used to limit the log generation to one\n // per event per node.\n private readonly loggedUnreferencedEvents: Set<string> = new Set();\n // Queue for unreferenced events that should be logged the next time GC runs.\n private readonly pendingEventsQueue: IUnreferencedEvent[] = [];\n\n protected constructor(\n private readonly runtime: IGarbageCollectionRuntime,\n private readonly gcOptions: IGCRuntimeOptions,\n /** For a given node path, returns the node's package path. */\n private readonly getNodePackagePath: (nodePath: string) => readonly string[] | undefined,\n /** Returns the timestamp of the last summary generated for this container. */\n private readonly getLastSummaryTimestampMs: () => number | undefined,\n baseSnapshot: ISnapshotTree | undefined,\n readAndParseBlob: ReadAndParseBlob,\n baseLogger: ITelemetryLogger,\n existing: boolean,\n metadata?: IContainerRuntimeMetadata,\n ) {\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(baseLogger, \"GarbageCollector\"));\n\n this.deleteTimeoutMs = this.gcOptions.deleteTimeoutMs ?? defaultDeleteTimeoutMs;\n\n let prevSummaryGCVersion: number | undefined;\n\n // GC can only be enabled during creation. After that, it can never be enabled again. So, for existing\n // documents, we get this information from the metadata blob. Similarly the session timeout should be\n // consistent across all clients, thus we grab it as well from the metadata blob, and set it once on creation.\n if (existing) {\n prevSummaryGCVersion = getGCVersion(metadata);\n // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all\n // other existing documents, GC is enabled.\n this.gcEnabled = prevSummaryGCVersion > 0;\n this.sessionExpiryTimeoutMs = metadata?.sessionExpiryTimeoutMs;\n } else {\n // For new documents, GC has to be explicitly enabled via the gcAllowed flag in GC options.\n this.gcEnabled = gcOptions.gcAllowed === true;\n // Set the Session Expiry only if the flag is enabled or the test option is set.\n if (this.mc.config.getBoolean(runSessionExpiry) && this.gcEnabled) {\n this.sessionExpiryTimeoutMs = defaultSessionExpiryDurationMs;\n }\n }\n\n // If session expiry is enabled, we need to close the container when the timeout expires\n if (this.sessionExpiryTimeoutMs !== undefined) {\n const timeoutMs = this.sessionExpiryTimeoutMs;\n setLongTimeout(timeoutMs,\n () => {\n this.runtime.closeFn(new ClientSessionExpiredError(`Client session expired.`, timeoutMs));\n },\n (timer) => {\n this.sessionExpiryTimer = timer;\n });\n }\n\n // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n // latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n this.latestSummaryGCVersion = prevSummaryGCVersion ?? this.currentGCVersion;\n\n // Whether GC should run or not. Can override with localStorage flag.\n this.shouldRunGC = this.mc.config.getBoolean(runGCKey) ?? (\n // GC must be enabled for the document.\n this.gcEnabled\n // GC must not be disabled via GC options.\n && !gcOptions.disableGC\n );\n\n // Whether GC sweep phase should run or not. If this is false, only GC mark phase is run. Can override with\n // localStorage flag.\n this.shouldRunSweep = this.shouldRunGC &&\n (this.mc.config.getBoolean(runSweepKey) ?? gcOptions.runSweep === true)\n && this.sessionExpiryTimer !== undefined;\n\n // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.\n this.testMode = this.mc.config.getBoolean(gcTestModeKey) ?? gcOptions.runGCInTestMode === true;\n\n /**\n * Enable resetting initial state once the following issue is resolved:\n * https://github.com/microsoft/FluidFramework/issues/8878.\n * Currently, the GC tree is not written at root, so we don't know if the base snapshot contains GC tree or not.\n */\n // The GC state needs to be reset if the base snapshot contains GC tree and GC is disabled or it doesn't contain\n // GC tree and GC is enabled.\n // const gcTreePresent = baseSnapshot?.trees[gcTreeKey] !== undefined;\n // this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;\n\n // If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that\n // the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.\n this._writeDataAtRoot = this.mc.config.getBoolean(writeAtRootKey) ?? this.gcOptions.writeDataAtRoot === true;\n\n // Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do\n // this once since it involves fetching blobs from storage which is expensive.\n const baseSummaryStateP = new LazyPromise<IGarbageCollectionState | undefined>(async () => {\n if (baseSnapshot === undefined) {\n return undefined;\n }\n\n // For newer documents, GC data should be present in the GC tree in the root of the snapshot.\n const gcSnapshotTree = baseSnapshot.trees[gcTreeKey];\n if (gcSnapshotTree !== undefined) {\n // If the GC tree is written at root, we should also do the same.\n this._writeDataAtRoot = true;\n return getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);\n }\n\n // back-compat - Older documents will have the GC blobs in each data store's summary tree. Get them and\n // consolidate into IGarbageCollectionState format.\n // Add a node for the root node that is not present in older snapshot format.\n const gcState: IGarbageCollectionState = { gcNodes: { \"/\": { outboundRoutes: [] } } };\n const dataStoreSnapshotTree = getSummaryForDatastores(baseSnapshot, metadata);\n assert(dataStoreSnapshotTree !== undefined,\n 0x2a8 /* \"Expected data store snapshot tree in base snapshot\" */);\n for (const [dsId, dsSnapshotTree] of Object.entries(dataStoreSnapshotTree.trees)) {\n const blobId = dsSnapshotTree.blobs[gcBlobKey];\n if (blobId === undefined) {\n continue;\n }\n\n const gcSummaryDetails = await readAndParseBlob<IGarbageCollectionDetailsBase>(blobId);\n // If there are no nodes for this data store, skip it.\n if (gcSummaryDetails.gcData?.gcNodes === undefined) {\n continue;\n }\n\n const dsRootId = `/${dsId}`;\n // Since we used to write GC data at data store level, we won't have an entry for the root (\"/\").\n // Construct that entry by adding root data store ids to its outbound routes.\n const initialSnapshotDetails = await readAndParseBlob<ReadFluidDataStoreAttributes>(\n dsSnapshotTree.blobs[dataStoreAttributesBlobName],\n );\n if (initialSnapshotDetails.isRootDataStore) {\n gcState.gcNodes[\"/\"].outboundRoutes.push(dsRootId);\n }\n\n for (const [id, outboundRoutes] of Object.entries(gcSummaryDetails.gcData.gcNodes)) {\n // Prefix the data store id to the GC node ids to make them relative to the root from being\n // relative to the data store. Similar to how its done in DataStore::getGCData.\n const rootId = id === \"/\" ? dsRootId : `${dsRootId}${id}`;\n gcState.gcNodes[rootId] = { outboundRoutes: Array.from(outboundRoutes) };\n }\n assert(gcState.gcNodes[dsRootId] !== undefined,\n 0x2a9 /* `GC nodes for data store ${dsId} not in GC blob` */);\n gcState.gcNodes[dsRootId].unreferencedTimestampMs = gcSummaryDetails.unrefTimestamp;\n }\n\n // If there is only one node (root node just added above), either GC is disabled or we are loading from the\n // very first summary generated by detached container. In both cases, GC was not run - return undefined.\n return Object.keys(gcState.gcNodes).length === 1 ? undefined : gcState;\n });\n\n /**\n * Set up the initializer which initializes the base GC state from the base snapshot. Note that the reference\n * timestamp maybe from old ops which were not summarized and stored in the file. So, the unreferenced state\n * may be out of date. This is fine because the state is updated every time GC runs based on the time then.\n */\n this.initializeBaseStateP = new LazyPromise<void>(async () => {\n const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n const baseState = await baseSummaryStateP;\n if (baseState === undefined) {\n return;\n }\n\n const gcNodes: { [ id: string ]: string[] } = {};\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n if (nodeData.unreferencedTimestampMs !== undefined) {\n this.unreferencedNodesState.set(\n nodeId,\n new UnreferencedStateTracker(\n nodeData.unreferencedTimestampMs,\n this.deleteTimeoutMs,\n currentReferenceTimestampMs,\n ),\n );\n }\n gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n }\n this.gcDataFromLastRun = { gcNodes };\n });\n\n // Get the GC details for each node from the GC state in the base summary. This is returned in getBaseGCDetails\n // which the caller uses to initialize each node's GC state.\n this.baseGCDetailsP = new LazyPromise<Map<string, IGarbageCollectionDetailsBase>>(async () => {\n const baseState = await baseSummaryStateP;\n if (baseState === undefined) {\n return new Map();\n }\n\n const gcNodes: { [ id: string ]: string[] } = {};\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n }\n // Run GC on the nodes in the base summary to get the routes used in each node in the container.\n // This is an optimization for space (vs performance) wherein we don't need to store the used routes of\n // each node in the summary.\n const usedRoutes = runGarbageCollection(\n gcNodes,\n [ \"/\" ],\n this.mc.logger,\n ).referencedNodeIds;\n\n const baseGCDetailsMap = unpackChildNodesGCDetails({ gcData: { gcNodes }, usedRoutes });\n // Currently, the nodes may write the GC data. So, we need to update it's base GC details with the\n // unreferenced timestamp. Once we start writing the GC data here, we won't need to do this anymore.\n for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {\n if (nodeData.unreferencedTimestampMs !== undefined) {\n const dataStoreGCDetails = baseGCDetailsMap.get(nodeId.slice(1));\n if (dataStoreGCDetails !== undefined) {\n dataStoreGCDetails.unrefTimestamp = nodeData.unreferencedTimestampMs;\n }\n }\n }\n return baseGCDetailsMap;\n });\n\n // Initialize the base state. The base GC data is used to detect and log when inactive / deleted objects are\n // used in the container.\n if (this.shouldRunGC) {\n this.initializeBaseStateP.catch((error) => {\n const dpe = DataProcessingError.wrapIfUnrecognized(\n error,\n \"FailedToInitializeGC\",\n );\n dpe.addTelemetryProperties({\n gcEnabled: this.gcEnabled,\n runSweep: this.shouldRunSweep,\n writeAtRoot: this._writeDataAtRoot,\n testMode: this.testMode,\n sessionExpiry: this.sessionExpiryTimeoutMs,\n });\n throw dpe;\n });\n }\n }\n\n /**\n * Runs garbage collection and updates the reference / used state of the nodes in the container.\n * @returns the number of data stores that have been marked as unreferenced.\n */\n public async collectGarbage(\n options: {\n /** Logger to use for logging GC events */\n logger?: ITelemetryLogger,\n /** True to run GC sweep phase after the mark phase */\n runSweep?: boolean,\n /** True to generate full GC data */\n fullGC?: boolean,\n },\n ): Promise<IGCStats> {\n const {\n logger = this.mc.logger,\n runSweep = this.shouldRunSweep,\n fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset,\n } = options;\n\n return PerformanceEvent.timedExecAsync(logger, { eventName: \"GarbageCollection\" }, async (event) => {\n await this.initializeBaseStateP;\n\n // Let the runtime update its pending state before GC runs.\n await this.runtime.updateStateBeforeGC();\n\n // Get the runtime's GC data and run GC on the reference graph in it.\n const gcData = await this.runtime.getGCData(fullGC);\n const gcResult = runGarbageCollection(\n gcData.gcNodes,\n [ \"/\" ],\n logger,\n );\n const gcStats = this.generateStatsAndLogEvents(gcResult);\n\n // Update the state since the last GC run. There can be nodes that were referenced between the last and\n // the current run. We need to identify than and update their unreferenced state if needed.\n this.updateStateSinceLastRun(gcData);\n\n // Update the current state of the system based on the GC run.\n const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();\n this.updateCurrentState(gcData, gcResult, currentReferenceTimestampMs);\n\n this.runtime.updateUsedRoutes(gcResult.referencedNodeIds, currentReferenceTimestampMs);\n\n if (runSweep) {\n // Placeholder for running sweep logic.\n }\n\n // If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios\n // involving access to deleted data.\n if (this.testMode) {\n this.runtime.deleteUnusedRoutes(gcResult.deletedNodeIds);\n }\n event.end({ ...gcStats });\n return gcStats;\n },\n { end: true, cancel: \"error\" });\n }\n\n /**\n * Summarizes the GC data and returns it as a summary tree.\n * We current write the entire GC state in a single blob. This can be modified later to write multiple\n * blobs. All the blob keys should start with `gcBlobPrefix`.\n */\n public summarize(): ISummaryTreeWithStats | undefined {\n if (!this.shouldRunGC || this.gcDataFromLastRun === undefined) {\n return;\n }\n\n const gcState: IGarbageCollectionState = { gcNodes: {} };\n for (const [nodeId, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n gcState.gcNodes[nodeId] = {\n outboundRoutes,\n unreferencedTimestampMs: this.unreferencedNodesState.get(nodeId)?.unreferencedTimestampMs,\n };\n }\n\n const builder = new SummaryTreeBuilder();\n builder.addBlob(`${gcBlobPrefix}_root`, JSON.stringify(gcState));\n return builder.getSummaryTree();\n }\n\n /**\n * Returns a map of node ids to their base GC details generated from the base summary. This is used by the caller\n * to initialize the GC state of the nodes.\n */\n public async getBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>> {\n return this.baseGCDetailsP;\n }\n\n /**\n * Called when the latest summary of the system has been refreshed. This will be used to update the state of the\n * latest summary tracked.\n */\n public async latestSummaryStateRefreshed(\n result: RefreshSummaryResult,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // After a summary is successfully submitted and ack'd by this client, the GC state should have been reset in\n // the summary and doesn't need to be reset anymore.\n this.initialStateNeedsReset = false;\n\n if (!this.shouldRunGC || !result.latestSummaryUpdated) {\n return;\n }\n\n // If the summary was tracked by this client, it was the one that generated the summary in the first place.\n // Basically, it was written in the current GC version.\n if (result.wasSummaryTracked) {\n this.latestSummaryGCVersion = this.currentGCVersion;\n return;\n }\n // If the summary was not tracked by this client, update latest GC version from the snapshot in the result as\n // that is now the latest summary.\n await this.updateSummaryGCVersionFromSnapshot(result.snapshot, readAndParseBlob);\n }\n\n /**\n * Called when a node with the given id is updated. If the node is inactive, log an error.\n * @param nodePath - The id of the node that changed.\n * @param reason - Whether the node was loaded or changed.\n * @param timestampMs - The timestamp when the node changed.\n * @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.\n * @param requestHeaders - If the node was loaded via request path, the headers in the request.\n */\n public nodeUpdated(\n nodePath: string,\n reason: \"Loaded\" | \"Changed\",\n timestampMs?: number,\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ) {\n if (!this.shouldRunGC) {\n return;\n }\n\n this.logIfInactive(\n reason,\n nodePath,\n timestampMs,\n packagePath,\n requestHeaders,\n );\n }\n\n /**\n * Called when an outbound reference is added to a node. This is used to identify all nodes that have been\n * referenced between summaries so that their unreferenced timestamp can be reset.\n *\n * @param fromNodePath - The node from which the reference is added.\n * @param toNodePath - The node to which the reference is added.\n */\n public addedOutboundReference(fromNodePath: string, toNodePath: string) {\n if (!this.shouldRunGC) {\n return;\n }\n\n const outboundRoutes = this.referencesSinceLastRun.get(fromNodePath) ?? [];\n outboundRoutes.push(toNodePath);\n this.referencesSinceLastRun.set(fromNodePath, outboundRoutes);\n\n // If the node that got referenced is inactive, log an event as that may indicate use-after-delete.\n this.logIfInactive(\n \"Revived\",\n toNodePath,\n );\n }\n\n public dispose(): void {\n if (this.sessionExpiryTimer !== undefined) {\n clearTimeout(this.sessionExpiryTimer);\n this.sessionExpiryTimer = undefined;\n }\n }\n\n /**\n * Update the latest summary GC version from the metadata blob in the given snapshot.\n */\n private async updateSummaryGCVersionFromSnapshot(snapshot: ISnapshotTree, readAndParseBlob: ReadAndParseBlob) {\n const metadataBlobId = snapshot.blobs[metadataBlobName];\n if (metadataBlobId) {\n const metadata = await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId);\n this.latestSummaryGCVersion = getGCVersion(metadata);\n }\n }\n\n /**\n * Updates the state of the system as per the current GC run. It does the following:\n * 1. Sets up the current GC state as per the gcData.\n * 2. Starts tracking for nodes that have become unreferenced in this run.\n * 3. Clears tracking for nodes that were unreferenced but became referenced in this run.\n * @param gcData - The data representing the reference graph on which GC is run.\n * @param gcResult - The result of the GC run on the gcData.\n * @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.\n */\n private updateCurrentState(\n gcData: IGarbageCollectionData,\n gcResult: IGCResult,\n currentReferenceTimestampMs?: number,\n ) {\n this.gcDataFromLastRun = cloneGCData(gcData);\n this.referencesSinceLastRun.clear();\n\n // Iterate through the referenced nodes and stop tracking if they were unreferenced before.\n for (const nodeId of gcResult.referencedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker !== undefined) {\n // Stop tracking so as to clear out any running timers.\n nodeStateTracker.stopTracking();\n // Delete the node as we don't need to track it any more.\n this.unreferencedNodesState.delete(nodeId);\n }\n }\n\n /**\n * If there is no current reference time, skip tracking when a node becomes unreferenced. This would happen\n * if no ops have been processed ever and we still try to run GC. If so, there is nothing interesting to track\n * anyway.\n */\n if (currentReferenceTimestampMs === undefined) {\n return;\n }\n\n /**\n * If a node became unreferenced in this run, start tracking it.\n * If a node was already unreferenced, update its tracking information. Since the current reference time is\n * from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.\n */\n for (const nodeId of gcResult.deletedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker === undefined) {\n this.unreferencedNodesState.set(\n nodeId,\n new UnreferencedStateTracker(\n currentReferenceTimestampMs,\n this.deleteTimeoutMs,\n currentReferenceTimestampMs,\n ),\n );\n } else {\n nodeStateTracker.updateTracking(currentReferenceTimestampMs);\n }\n }\n }\n\n /**\n * Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in\n * time. It's possible that nodes transition from `unreferenced -> referenced -> unreferenced` between two runs. The\n * unreferenced timestamp of such nodes needs to be reset as they may have been accessed when they were referenced.\n *\n * This function identifies nodes that were referenced since last run and removes their unreferenced state, if any.\n * If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.\n */\n private updateStateSinceLastRun(currentGCData: IGarbageCollectionData) {\n // If we haven't run GC before or no references were added since the last run, there is nothing to do.\n if (this.gcDataFromLastRun === undefined || this.referencesSinceLastRun.size === 0) {\n return;\n }\n\n // Validate that we have identified all references correctly.\n this.validateReferenceCorrectness(currentGCData);\n\n /**\n * Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and\n * edges that have been added since then. To do this, combine the GC data from the last run and the current\n * run, and then add the references since last run.\n *\n * Note on why we need to combine the data from previous run, current run and all references in between -\n * 1. We need data from last run because some of its references may have been deleted since then. If those\n * references added new outbound references before getting deleted, we need to detect them.\n * 2. We need new outbound references since last run because some of them may have been deleted later. If those\n * references added new outbound references before getting deleted, we need to detect them.\n * 3. We need data from the current run because currently we may not detect when DDSs are referenced:\n * - We don't require DDSs handles to be stored in a referenced DDS. For this, we need GC at DDS level\n * which is tracked by https://github.com/microsoft/FluidFramework/issues/8470.\n * - A new data store may have \"root\" DDSs already created and we don't detect them today.\n */\n const gcDataSuperSet = concatGarbageCollectionData(this.gcDataFromLastRun, currentGCData);\n this.referencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {\n if (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {\n gcDataSuperSet.gcNodes[sourceNodeId] = outboundRoutes;\n } else {\n gcDataSuperSet.gcNodes[sourceNodeId].push(...outboundRoutes);\n }\n });\n\n /**\n * Run GC on the above reference graph to find all nodes that are referenced. For each one, if they are\n * unreferenced, stop tracking them and remove from unreferenced list.\n * Some of these nodes may be unreferenced now and if so, the current run will add unreferenced state for them.\n */\n const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, [\"/\"], this.mc.logger);\n for (const nodeId of gcResult.referencedNodeIds) {\n const nodeStateTracker = this.unreferencedNodesState.get(nodeId);\n if (nodeStateTracker !== undefined) {\n // Stop tracking so as to clear out any running timers.\n nodeStateTracker.stopTracking();\n // Delete the node as we don't need to track it any more.\n this.unreferencedNodesState.delete(nodeId);\n }\n }\n }\n\n /**\n * Validates that all new references are correctly identified and processed. The basic principle for validation is\n * that we should not have new references in the reference graph (GC data) that have not been notified to the\n * garbage collector via `referenceAdded`.\n * We validate that the references in the current reference graph should be a subset of the references in the last\n * run's reference graph + references since the last run.\n * @param currentGCData - The GC data (reference graph) from the current GC run.\n */\n private validateReferenceCorrectness(currentGCData: IGarbageCollectionData) {\n assert(\n this.gcDataFromLastRun !== undefined,\n 0x2b7, /* \"Can't validate correctness without GC data from last run\" */\n );\n\n // Get a list of all the outbound routes (or references) in the current GC data.\n const currentReferences: string[] = [];\n for (const [nodeId, outboundRoutes] of Object.entries(currentGCData.gcNodes)) {\n /**\n * Remove routes from a child node to its parent which is added implicitly by the runtime. For instance,\n * each adds its data store as an outbound route to mark it as referenced if the DDS is referenced.\n * We won't get any explicit notification for these references so they must be removed before validation.\n */\n const explicitRoutes = outboundRoutes.filter((route) => !nodeId.startsWith(route));\n currentReferences.push(...explicitRoutes);\n }\n\n // Get a list of outbound routes (or references) from the last run's GC data plus references added since the\n // last run that were notified via `referenceAdded`.\n const explicitReferences: string[] = [];\n for (const [, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {\n explicitReferences.push(...outboundRoutes);\n }\n this.referencesSinceLastRun.forEach((outboundRoutes: string[]) => {\n explicitReferences.push(...outboundRoutes);\n });\n\n // Validate that the current reference graph doesn't have references that we are not already aware of. If this\n // happens, it might indicate data corruption since we may delete objects prematurely.\n currentReferences.forEach((route: string) => {\n // Validate references for data stores only. Currently, layers below data stores don't have GC implemented\n // so there is no guarantee their references will be notified.\n if (this.runtime.getNodeType(route) === GCNodeType.DataStore && !explicitReferences.includes(route)) {\n /**\n * The following log will be enabled once this issue is resolved:\n * https://github.com/microsoft/FluidFramework/issues/8878.\n */\n // We should ideally throw a data corruption error here. However, send an error for now until we have\n // implemented sweep and have reasonable confidence in the sweep process.\n // this.mc.logger.sendErrorEvent({\n // eventName: \"gcUnknownOutboundRoute\",\n // route,\n // });\n }\n });\n }\n\n /**\n * Generates the stats of a garbage collection run from the given results of the run. Also, logs any pending events\n * in the pendingEventsQueue. This should be called before updating the current state because it generates stats\n * based on previous state of the system.\n * @param gcResult - The result of a GC run.\n * @returns the GC stats of the GC run.\n */\n private generateStatsAndLogEvents(gcResult: IGCResult): IGCStats {\n // Log pending events for unreferenced nodes after GC has run. We should have the package data available for\n // them now since the GC run should have loaded these nodes.\n let event = this.pendingEventsQueue.shift();\n while (event !== undefined) {\n const pkg = this.getNodePackagePath(event.id);\n this.mc.logger.sendErrorEvent({\n ...event,\n pkg: pkg ? { value: `/${pkg.join(\"/\")}`, tag: TelemetryDataTag.PackageData } : undefined,\n });\n event = this.pendingEventsQueue.shift();\n }\n\n const gcStats: IGCStats = {\n nodeCount: 0,\n dataStoreCount: 0,\n attachmentBlobCount: 0,\n unrefNodeCount: 0,\n unrefDataStoreCount: 0,\n unrefAttachmentBlobCount: 0,\n updatedNodeCount: 0,\n updatedDataStoreCount: 0,\n updatedAttachmentBlobCount: 0,\n };\n\n const updateNodeStats = (nodeId: string, referenced: boolean) => {\n gcStats.nodeCount++;\n /**\n * `this.unreferencedNodesState` has the previous unreferenced state of all nodes. `referenced` flag passed\n * here is current state of the give node. Check if the reference state of the changed.\n */\n const stateUpdated = this.unreferencedNodesState.has(nodeId) ? referenced : !referenced;\n if (stateUpdated) {\n gcStats.updatedNodeCount++;\n }\n if (!referenced) {\n gcStats.unrefNodeCount++;\n }\n\n if (this.runtime.getNodeType(nodeId) === GCNodeType.DataStore) {\n gcStats.dataStoreCount++;\n if (stateUpdated) {\n gcStats.updatedDataStoreCount++;\n }\n if (!referenced) {\n gcStats.unrefDataStoreCount++;\n }\n }\n if (this.runtime.getNodeType(nodeId) === GCNodeType.Blob) {\n gcStats.attachmentBlobCount++;\n if (stateUpdated) {\n gcStats.updatedAttachmentBlobCount++;\n }\n if (!referenced) {\n gcStats.unrefAttachmentBlobCount++;\n }\n }\n };\n\n for (const nodeId of gcResult.referencedNodeIds) {\n updateNodeStats(nodeId, true /* referenced */);\n }\n\n for (const nodeId of gcResult.deletedNodeIds) {\n updateNodeStats(nodeId, false /* referenced */);\n }\n\n return gcStats;\n }\n\n /**\n * Logs an event if a node is inactive and is used.\n */\n private logIfInactive(\n eventSuffix: \"Changed\" | \"Loaded\" | \"Revived\",\n nodeId: string,\n currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(),\n packagePath?: readonly string[],\n requestHeaders?: IRequestHeader,\n ) {\n // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip\n // logging as nothing interesting would have happened worth logging.\n if (currentReferenceTimestampMs === undefined) {\n return;\n }\n\n const eventName = `inactiveObject_${eventSuffix}`;\n // We log a particular event for a given node only once so that it is not too noisy.\n const uniqueEventId = `${nodeId}-${eventName}`;\n const nodeState = this.unreferencedNodesState.get(nodeId);\n if (nodeState?.inactive && !this.loggedUnreferencedEvents.has(uniqueEventId)) {\n this.loggedUnreferencedEvents.add(uniqueEventId);\n const event: IUnreferencedEvent = {\n eventName,\n id: nodeId,\n age: currentReferenceTimestampMs - nodeState.unreferencedTimestampMs,\n timeout: this.deleteTimeoutMs,\n lastSummaryTime: this.getLastSummaryTimestampMs(),\n externalRequest: requestHeaders?.[RuntimeHeaders.externalRequest],\n viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],\n };\n\n // If the package data for the node exists, log immediately. Otherwise, queue it and it will be logged the\n // next time GC runs as the package data should be available then.\n const pkg = packagePath ?? this.getNodePackagePath(nodeId);\n if (pkg !== undefined) {\n this.mc.logger.sendErrorEvent({\n ...event,\n pkg: { value: `/${pkg.join(\"/\")}`, tag: TelemetryDataTag.PackageData },\n });\n } else {\n this.pendingEventsQueue.push(event);\n }\n }\n }\n}\n\n/**\n * Gets the garbage collection state from the given snapshot tree. The GC state may be written into multiple blobs.\n * Merge the GC state from all such blobs and return the merged GC state.\n */\nasync function getGCStateFromSnapshot(\n gcSnapshotTree: ISnapshotTree,\n readAndParseBlob: ReadAndParseBlob,\n): Promise<IGarbageCollectionState> {\n let rootGCState: IGarbageCollectionState = { gcNodes: {} };\n for (const key of Object.keys(gcSnapshotTree.blobs)) {\n // Skip blobs that do not start with the GC prefix.\n if (!key.startsWith(gcBlobPrefix)) {\n continue;\n }\n\n const blobId = gcSnapshotTree.blobs[key];\n if (blobId === undefined) {\n continue;\n }\n const gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n assert(gcState !== undefined, 0x2ad /* \"GC blob missing from snapshot\" */);\n // Merge the GC state of this blob into the root GC state.\n rootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n }\n return rootGCState;\n}\n\n/**\n * setLongTimeout is used for timeouts longer than setTimeout's ~24.8 day max\n * @param timeoutMs - the total time the timeout needs to last in ms\n * @param timeoutFn - the function to execute when the timer ends\n * @param setTimerFn - the function used to update your timer variable\n */\nfunction setLongTimeout(\n timeoutMs: number,\n timeoutFn: () => void,\n setTimerFn: (timer: ReturnType<typeof setTimeout>) => void,\n) {\n // The setTimeout max is 24.8 days before looping occurs.\n const maxTimeout = 2147483647;\n let timer: ReturnType<typeof setTimeout>;\n if (timeoutMs > maxTimeout) {\n const newTimeoutMs = timeoutMs - maxTimeout;\n timer = setTimeout(() => setLongTimeout(newTimeoutMs, timeoutFn, setTimerFn), maxTimeout);\n } else {\n timer = setTimeout(() => timeoutFn(), timeoutMs);\n }\n setTimerFn(timer);\n}\n"]}
@@ -84,25 +84,15 @@ export interface IOrderedClientElectionEvents extends IEvent {
84
84
  export interface ISerializedElection {
85
85
  /** Sequence number at the time of the latest election. */
86
86
  readonly electionSequenceNumber: number;
87
- /** Most recently elected client id. This is either:
88
- * 1. the interactive elected parent client, in which case electedClientId === electedParentId,
89
- * and the SummaryManager on the elected client will spawn a summarizer client, or
90
- * 2. the non-interactive summarizer client itself. */
87
+ /** Most recently elected client id. */
91
88
  readonly electedClientId: string | undefined;
92
- /** Most recently elected parent client id. This is always an interactive client. */
93
- readonly electedParentId: string | undefined;
94
89
  }
95
90
  /** Contract for maintaining a deterministic client election based on eligibility. */
96
91
  export interface IOrderedClientElection extends IEventProvider<IOrderedClientElectionEvents> {
97
92
  /** Count of eligible clients in the collection. */
98
93
  readonly eligibleCount: number;
99
- /** Currently elected client. This is either:
100
- * 1. the interactive elected parent client, in which case electedClientId === electedParentId,
101
- * and the SummaryManager on the elected client will spawn a summarizer client, or
102
- * 2. the non-interactive summarizer client itself. */
94
+ /** Currently elected client. */
103
95
  readonly electedClient: ITrackedClient | undefined;
104
- /** Currently elected parent client. This is always an interactive client. */
105
- readonly electedParent: ITrackedClient | undefined;
106
96
  /** Sequence number of most recent election. */
107
97
  readonly electionSequenceNumber: number;
108
98
  /** Marks the currently elected client as invalid, and elects the next eligible client. */
@@ -127,57 +117,22 @@ export declare class OrderedClientElection extends TypedEventEmitter<IOrderedCli
127
117
  private readonly isEligibleFn;
128
118
  private _eligibleCount;
129
119
  private _electedClient;
130
- private _electedParent;
131
120
  private _electionSequenceNumber;
132
121
  get eligibleCount(): number;
133
- get electionSequenceNumber(): number;
134
- /**
135
- * OrderedClientCollection tracks electedClient and electedParent separately. This allows us to handle the case
136
- * where a new interactive parent client has been elected, but the summarizer is still doing work, so
137
- * a new summarizer should not yet be spawned. In this case, changing electedParent will cause SummaryManager
138
- * to stop the current summarizer, but a new summarizer will not be spawned until the old summarizer client has
139
- * left the quorum.
140
- *
141
- * Details:
142
- *
143
- * electedParent is the interactive client that has been elected to spawn a summarizer. It is typically the oldest
144
- * eligible interactive client in the quorum. Only the electedParent is permitted to spawn a summarizer.
145
- * Once elected, this client will remain the electedParent until it leaves the quorum or the summarizer that
146
- * it spawned stops producing summaries, at which point a new electedParent will be chosen.
147
- *
148
- * electedClient is the non-interactive summarizer client if one exists. If not, then electedClient is equal to
149
- * electedParent. If electedParent === electedClient, this is the signal for electedParent to spawn a new
150
- * electedClient. Once a summarizer client becomes electedClient, a new summarizer will not be spawned until
151
- * electedClient leaves the quorum.
152
- *
153
- * A typical sequence looks like this:
154
- * i. Begin by electing A. electedParent === A, electedClient === A.
155
- * ii. SummaryManager running on A spawns a summarizer client, A'. electedParent === A, electedClient === A'
156
- * iii. A' stops producing summaries. A new parent client, B, is elected. electedParent === B, electedClient === A'
157
- * iv. SummaryManager running on A detects the change to electedParent and tells the summarizer to stop, but A'
158
- * is in mid-summarization. No new summarizer is spawned, as electedParent !== electedClient.
159
- * v. A' completes its summary, and the summarizer and backing client are torn down.
160
- * vi. A' leaves the quorum, and B takes its place as electedClient. electedParent === B, electedClient === B
161
- * vii. SummaryManager running on B spawns a summarizer client, B'. electedParent === B, electedClient === B'
162
- */
163
122
  get electedClient(): ILinkedClient | undefined;
164
- get electedParent(): ILinkedClient | undefined;
123
+ get electionSequenceNumber(): number;
165
124
  constructor(logger: ITelemetryLogger, orderedClientCollection: IOrderedClientCollection,
166
125
  /** Serialized state from summary or current sequence number at time of load if new. */
167
126
  initialState: ISerializedElection | number, isEligibleFn: (c: ITrackedClient) => boolean);
168
- /** Tries changing the elected client, raising an event if it is different.
169
- * Note that this function does no eligibility or suitability checks. If we get here, then
170
- * we will set _electedClient, and we will set _electedParent if this is an interactive client.
171
- */
127
+ /** Tries changing the elected client, raising an event if it is different. */
172
128
  private tryElectingClient;
173
- private tryElectingParent;
174
129
  /**
175
- * Helper function to find the first eligible parent client starting with the passed in client,
130
+ * Helper function to find the first eligible client starting with the passed in client,
176
131
  * or undefined if none are eligible.
177
132
  * @param client - client to start checking
178
133
  * @returns oldest eligible client starting with passed in client or undefined if none.
179
134
  */
180
- private findFirstEligibleParent;
135
+ private findFirstEligibleClient;
181
136
  /**
182
137
  * Updates tracking for when a new client is added to the collection.
183
138
  * Will automatically elect that new client if none is elected currently.
@@ -193,13 +148,7 @@ export declare class OrderedClientElection extends TypedEventEmitter<IOrderedCli
193
148
  */
194
149
  private removeClient;
195
150
  getAllEligibleClients(): ITrackedClient[];
196
- /** Advance election to the next-oldest client. This is called if the current parent is leaving the quorum,
197
- * or if the current summarizer is not responsive and we want to stop it and spawn a new one.
198
- */
199
151
  incrementElectedClient(sequenceNumber: number): void;
200
- /** (Re-)start election with the oldest client in the quorum. This is called if we need to summarize
201
- * and no client has been elected.
202
- */
203
152
  resetElectedClient(sequenceNumber: number): void;
204
153
  peekNextElectedClient(): ITrackedClient | undefined;
205
154
  serialize(): ISerializedElection;
@@ -1 +1 @@
1
- {"version":3,"file":"orderedClientElection.d.ts","sourceRoot":"","sources":["../src/orderedClientElection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orderedClientElection.d.ts","sourceRoot":"","sources":["../src/orderedClientElection.ts"],"names":[],"mappings":"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"}