@fluidframework/container-runtime 2.0.0-dev.4.4.0.162253 → 2.0.0-dev.4.4.0.162574

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.
@@ -22,15 +22,14 @@ export class GCSummaryStateTracker {
22
22
  wasGCRunInBaseSnapshot) {
23
23
  var _a;
24
24
  this.configs = configs;
25
- // The current version of GC running.
26
- this.currentGCVersion = this.configs.gcVersionInEffect;
27
25
  // Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced
28
26
  // to unreferenced or vice-versa.
29
27
  this.updatedDSCountSinceLastSummary = 0;
30
28
  this.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;
31
29
  // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the
32
30
  // latest tracked GC version. For new documents, we will be writing the first summary with the current version.
33
- this.latestSummaryGCVersion = (_a = this.configs.gcVersionInBaseSnapshot) !== null && _a !== void 0 ? _a : this.currentGCVersion;
31
+ this.latestSummaryGCVersion =
32
+ (_a = this.configs.gcVersionInBaseSnapshot) !== null && _a !== void 0 ? _a : this.configs.gcVersionInEffect;
34
33
  }
35
34
  /**
36
35
  * Tells whether the GC state needs to be reset. This can happen under 3 conditions:
@@ -66,7 +65,8 @@ export class GCSummaryStateTracker {
66
65
  */
67
66
  get doesSummaryStateNeedReset() {
68
67
  return (this.doesGCStateNeedReset ||
69
- (this.configs.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion));
68
+ (this.configs.shouldRunGC &&
69
+ this.latestSummaryGCVersion !== this.configs.gcVersionInEffect));
70
70
  }
71
71
  /**
72
72
  * Called during GC initialization. Initialize the latest summary data from the base snapshot data.
@@ -197,7 +197,7 @@ export class GCSummaryStateTracker {
197
197
  // If the summary was tracked by this client, it was the one that generated the summary in the first place.
198
198
  // Update latest state from pending.
199
199
  if (result.wasSummaryTracked) {
200
- this.latestSummaryGCVersion = this.currentGCVersion;
200
+ this.latestSummaryGCVersion = this.configs.gcVersionInEffect;
201
201
  this.latestSummaryData = this.pendingSummaryData;
202
202
  this.pendingSummaryData = undefined;
203
203
  this.updatedDSCountSinceLastSummary = 0;
@@ -221,7 +221,7 @@ export class GCSummaryStateTracker {
221
221
  // in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes
222
222
  // because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The
223
223
  // deletedNodes info is needed to identify when these nodes are used.
224
- if (getGCVersion(metadata) !== this.currentGCVersion) {
224
+ if (getGCVersion(metadata) !== this.configs.gcVersionInEffect) {
225
225
  snapshotData = {
226
226
  gcState: undefined,
227
227
  tombstones: undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"gcSummaryStateTracker.js","sourceRoot":"","sources":["../../src/gc/gcSummaryStateTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport { mergeStats, ReadAndParseBlob, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName, RefreshSummaryResult } from \"../summary\";\nimport { GCVersion, IGCStats } from \"./gcDefinitions\";\nimport { getGCDataFromSnapshot, generateSortedGCState, getGCVersion } from \"./gcHelpers\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { IGarbageCollectorConfigs } from \".\";\n\nexport const gcStateBlobKey = `${gcBlobPrefix}_root`;\n\n/**\n * The GC data that is tracked for a summary.\n */\nexport interface IGCSummaryTrackingData {\n\tserializedGCState: string | undefined;\n\tserializedTombstones: string | undefined;\n\tserializedDeletedNodes: string | undefined;\n}\n\n/**\n * Encapsulates the garbage collection state that is tracked across summaries.\n * It maintains the GC state as per the latest summary in by the server. It updates state when a summary tracked by this\n * client is acked by the server or from a snapshot is downloaded from the server.\n * On summarize, it decides whether to write new state or re-use previous summary's state.\n */\nexport class GCSummaryStateTracker {\n\t// The current version of GC running.\n\tpublic readonly currentGCVersion: GCVersion = this.configs.gcVersionInEffect;\n\t// This is the version of GC data in the latest summary being tracked.\n\tprivate latestSummaryGCVersion: GCVersion;\n\n\t// Keeps track of the GC data from the latest summary successfully acked by the server.\n\tprivate latestSummaryData: IGCSummaryTrackingData | undefined;\n\t// Keeps track of the GC data from the last summary submitted to the server but not yet acked.\n\tprivate pendingSummaryData: IGCSummaryTrackingData | undefined;\n\n\t// Tracks whether there was GC was run in latest summary being tracked.\n\tprivate wasGCRunInLatestSummary: boolean;\n\n\t// Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced\n\t// to unreferenced or vice-versa.\n\tpublic updatedDSCountSinceLastSummary: number = 0;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly configs: Pick<\n\t\t\tIGarbageCollectorConfigs,\n\t\t\t\"shouldRunGC\" | \"tombstoneMode\" | \"gcVersionInBaseSnapshot\" | \"gcVersionInEffect\"\n\t\t>,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\n\t\t// For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n\t\t// latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n\t\tthis.latestSummaryGCVersion = this.configs.gcVersionInBaseSnapshot ?? this.currentGCVersion;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset. This can happen under 3 conditions:\n\t *\n\t * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n\t * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n\t *\n\t * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n\t * a document and the first time GC is enabled after is was disabled before.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * Note that the state will be reset only once for the first summary generated after this returns true. After that,\n\t * this will return false.\n\t */\n\tpublic get doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.configs.shouldRunGC;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n\t *\n\t * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n\t *\n\t * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * 4. The GC version in the latest summary is different from the current GC version. This can happen if:\n\t *\n\t * 4.1. The summary this client loaded with has data from a different GC version.\n\t *\n\t * 4.2. This client's latest summary was updated from a snapshot that has a different GC version.\n\t */\n\tpublic get doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset ||\n\t\t\t(this.configs.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion)\n\t\t);\n\t}\n\n\t/**\n\t * Called during GC initialization. Initialize the latest summary data from the base snapshot data.\n\t */\n\tpublic initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData) {\n\t\t// If tracking state across summaries, update latest summary data from the snapshot's GC data.\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: baseSnapshotData.gcState\n\t\t\t\t? JSON.stringify(generateSortedGCState(baseSnapshotData.gcState))\n\t\t\t\t: undefined,\n\t\t\tserializedTombstones: JSON.stringify(baseSnapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(baseSnapshotData.deletedNodes),\n\t\t};\n\t}\n\n\t/**\n\t * Summarizes three component of the GC data - GC state, tombstones and deleted nodes.\n\t * It does incremental summary, i.e., it writes summary tree / summary blob only for the component that changed.\n\t * For components that did not change, a summary handle is returned that points to the previous successful summary.\n\t * If none of the components changed, it returns a summary handle for the entire GC data.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\tgcState: IGarbageCollectionState,\n\t\tdeletedNodes: Set<string>,\n\t\ttombstones: string[],\n\t): ISummarizeResult | undefined {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst serializedGCState = JSON.stringify(generateSortedGCState(gcState));\n\t\t// Serialize and write deleted nodes, if any. This is done irrespective of whether sweep is enabled or not so\n\t\t// to identify deleted nodes' usage.\n\t\tconst serializedDeletedNodes =\n\t\t\tdeletedNodes.size > 0 ? JSON.stringify(Array.from(deletedNodes).sort()) : undefined;\n\t\t// If running in tombstone mode, serialize and write tombstones, if any.\n\t\tconst serializedTombstones = this.configs.tombstoneMode\n\t\t\t? tombstones.length > 0\n\t\t\t\t? JSON.stringify(tombstones.sort())\n\t\t\t\t: undefined\n\t\t\t: undefined;\n\n\t\t/**\n\t\t * Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,\n\t\t * write summary handle instead of summary tree for GC.\n\t\t * Otherwise, write the GC summary tree. In the tree, for each of these that changed, write a summary blob and\n\t\t * for each of these that did not change, write a summary handle.\n\t\t */\n\t\tthis.pendingSummaryData = {\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t};\n\n\t\tif (trackState && !fullTree && this.latestSummaryData !== undefined) {\n\t\t\t// If nothing changed since last summary, send a summary handle for the entire GC data.\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData.serializedGCState === serializedGCState &&\n\t\t\t\tthis.latestSummaryData.serializedTombstones === serializedTombstones &&\n\t\t\t\tthis.latestSummaryData.serializedDeletedNodes === serializedDeletedNodes\n\t\t\t) {\n\t\t\t\tconst stats = mergeStats();\n\t\t\t\tstats.handleNodeCount++;\n\t\t\t\treturn {\n\t\t\t\t\tsummary: {\n\t\t\t\t\t\ttype: SummaryType.Handle,\n\t\t\t\t\t\thandle: `/${gcTreeKey}`,\n\t\t\t\t\t\thandleType: SummaryType.Tree,\n\t\t\t\t\t},\n\t\t\t\t\tstats,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// If some state changed, build a GC summary tree.\n\t\t\treturn this.buildGCSummaryTree(\n\t\t\t\tserializedGCState,\n\t\t\t\tserializedTombstones,\n\t\t\t\tserializedDeletedNodes,\n\t\t\t\ttrue /* trackState */,\n\t\t\t);\n\t\t}\n\t\t// If not tracking GC state, build a GC summary tree without any summary handles.\n\t\treturn this.buildGCSummaryTree(\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t\tfalse /* trackState */,\n\t\t);\n\t}\n\n\t/**\n\t * Builds the GC summary tree which contains GC state, deleted nodes and tombstones.\n\t * If trackState is false, all of GC state, deleted nodes and tombstones are written as summary blobs.\n\t * If trackState is true, only states that changed are written. Rest are written as handles.\n\t * @param serializedGCState - The GC state serialized as string.\n\t * @param serializedTombstones - The tombstone state serialized as string.\n\t * @param serializedDeletedNodes - Deleted nodes serialized as string.\n\t * @param trackState - Whether we are tracking GC state across summaries.\n\t * @returns the GC summary tree.\n\t */\n\tprivate buildGCSummaryTree(\n\t\tserializedGCState: string,\n\t\tserializedTombstones: string | undefined,\n\t\tserializedDeletedNodes: string | undefined,\n\t\ttrackState: boolean,\n\t): ISummaryTreeWithStats {\n\t\tconst builder = new SummaryTreeBuilder();\n\n\t\t// If the GC state hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {\n\t\t\tbuilder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcStateBlobKey, serializedGCState);\n\t\t}\n\n\t\t// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a\n\t\t// summary blob.\n\t\tif (serializedTombstones !== undefined) {\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData?.serializedTombstones === serializedTombstones &&\n\t\t\t\ttrackState\n\t\t\t) {\n\t\t\t\tbuilder.addHandle(\n\t\t\t\t\tgcTombstoneBlobKey,\n\t\t\t\t\tSummaryType.Blob,\n\t\t\t\t\t`/${gcTreeKey}/${gcTombstoneBlobKey}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tbuilder.addBlob(gcTombstoneBlobKey, serializedTombstones);\n\t\t\t}\n\t\t}\n\n\t\t// If there are no deleted nodes, return the summary tree.\n\t\tif (serializedDeletedNodes === undefined) {\n\t\t\treturn builder.getSummaryTree();\n\t\t}\n\n\t\t// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (\n\t\t\tthis.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&\n\t\t\ttrackState\n\t\t) {\n\t\t\tbuilder.addHandle(\n\t\t\t\tgcDeletedBlobKey,\n\t\t\t\tSummaryType.Blob,\n\t\t\t\t`/${gcTreeKey}/${gcDeletedBlobKey}`,\n\t\t\t);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcDeletedBlobKey, serializedDeletedNodes);\n\t\t}\n\t\treturn builder.getSummaryTree();\n\t}\n\n\t/**\n\t * Called to refresh the latest summary state. This happens when either a pending summary is acked or a snapshot\n\t * is downloaded and should be used to update the state.\n\t */\n\tpublic async refreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tresult: RefreshSummaryResult,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<IGarbageCollectionSnapshotData | undefined> {\n\t\t// If the latest summary was updated and the summary was tracked, this client is the one that generated this\n\t\t// summary. So, update wasGCRunInLatestSummary.\n\t\t// Note that this has to be updated if GC did not run too. Otherwise, `gcStateNeedsReset` will always return\n\t\t// true in scenarios where GC is disabled but enabled in the snapshot we loaded from.\n\t\tif (result.latestSummaryUpdated && result.wasSummaryTracked) {\n\t\t\tthis.wasGCRunInLatestSummary = this.configs.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.configs.shouldRunGC) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was tracked by this client, it was the one that generated the summary in the first place.\n\t\t// Update latest state from pending.\n\t\tif (result.wasSummaryTracked) {\n\t\t\tthis.latestSummaryGCVersion = this.currentGCVersion;\n\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\tthis.pendingSummaryData = undefined;\n\t\t\tthis.updatedDSCountSinceLastSummary = 0;\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was not tracked by this client, the state should be updated from the downloaded snapshot.\n\t\tconst snapshotTree = result.snapshotTree;\n\t\tconst metadataBlobId = snapshotTree.blobs[metadataBlobName];\n\t\tconst metadata = metadataBlobId\n\t\t\t? await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId)\n\t\t\t: undefined;\n\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\n\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\t// If GC ran in the container that generated this snapshot, it will have a GC tree.\n\t\tthis.wasGCRunInLatestSummary = gcSnapshotTree !== undefined;\n\n\t\tif (gcSnapshotTree === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet snapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t// If the GC version in the snapshot does not match the GC version currently in effect, the GC data\n\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes\n\t\t// because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The\n\t\t// deletedNodes info is needed to identify when these nodes are used.\n\t\tif (getGCVersion(metadata) !== this.currentGCVersion) {\n\t\t\tsnapshotData = {\n\t\t\t\tgcState: undefined,\n\t\t\t\ttombstones: undefined,\n\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t};\n\t\t}\n\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: JSON.stringify(snapshotData.gcState),\n\t\t\tserializedTombstones: JSON.stringify(snapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(snapshotData.deletedNodes),\n\t\t};\n\t\treturn snapshotData;\n\t}\n\n\t/**\n\t * Called to update the state from a GC run's stats. Used to update the count of data stores whose state updated.\n\t */\n\tpublic updateStateFromGCRunStats(stats: IGCStats) {\n\t\tthis.updatedDSCountSinceLastSummary += stats.updatedDataStoreCount;\n\t}\n}\n"]}
1
+ {"version":3,"file":"gcSummaryStateTracker.js","sourceRoot":"","sources":["../../src/gc/gcSummaryStateTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tgcTreeKey,\n\tISummarizeResult,\n\tISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport { mergeStats, ReadAndParseBlob, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { IContainerRuntimeMetadata, metadataBlobName, RefreshSummaryResult } from \"../summary\";\nimport { GCVersion, IGCStats } from \"./gcDefinitions\";\nimport { getGCDataFromSnapshot, generateSortedGCState, getGCVersion } from \"./gcHelpers\";\nimport { IGarbageCollectionSnapshotData, IGarbageCollectionState } from \"./gcSummaryDefinitions\";\nimport { IGarbageCollectorConfigs } from \".\";\n\nexport const gcStateBlobKey = `${gcBlobPrefix}_root`;\n\n/**\n * The GC data that is tracked for a summary.\n */\nexport interface IGCSummaryTrackingData {\n\tserializedGCState: string | undefined;\n\tserializedTombstones: string | undefined;\n\tserializedDeletedNodes: string | undefined;\n}\n\n/**\n * Encapsulates the garbage collection state that is tracked across summaries.\n * It maintains the GC state as per the latest summary in by the server. It updates state when a summary tracked by this\n * client is acked by the server or from a snapshot is downloaded from the server.\n * On summarize, it decides whether to write new state or re-use previous summary's state.\n */\nexport class GCSummaryStateTracker {\n\t// This is the version of GC data in the latest summary being tracked.\n\tprivate latestSummaryGCVersion: GCVersion;\n\n\t// Keeps track of the GC data from the latest summary successfully acked by the server.\n\tprivate latestSummaryData: IGCSummaryTrackingData | undefined;\n\t// Keeps track of the GC data from the last summary submitted to the server but not yet acked.\n\tprivate pendingSummaryData: IGCSummaryTrackingData | undefined;\n\n\t// Tracks whether there was GC was run in latest summary being tracked.\n\tprivate wasGCRunInLatestSummary: boolean;\n\n\t// Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced\n\t// to unreferenced or vice-versa.\n\tpublic updatedDSCountSinceLastSummary: number = 0;\n\n\tconstructor(\n\t\t// Tells whether GC should run or not.\n\t\tprivate readonly configs: Pick<\n\t\t\tIGarbageCollectorConfigs,\n\t\t\t\"shouldRunGC\" | \"tombstoneMode\" | \"gcVersionInBaseSnapshot\" | \"gcVersionInEffect\"\n\t\t>,\n\t\t// Tells whether GC was run in the base snapshot this container loaded from.\n\t\twasGCRunInBaseSnapshot: boolean,\n\t) {\n\t\tthis.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;\n\t\t// For existing document, the latest summary is the one that we loaded from. So, use its GC version as the\n\t\t// latest tracked GC version. For new documents, we will be writing the first summary with the current version.\n\t\tthis.latestSummaryGCVersion =\n\t\t\tthis.configs.gcVersionInBaseSnapshot ?? this.configs.gcVersionInEffect;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset. This can happen under 3 conditions:\n\t *\n\t * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after\n\t * it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.\n\t *\n\t * 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on\n\t * a document and the first time GC is enabled after is was disabled before.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * Note that the state will be reset only once for the first summary generated after this returns true. After that,\n\t * this will return false.\n\t */\n\tpublic get doesGCStateNeedReset(): boolean {\n\t\treturn this.wasGCRunInLatestSummary !== this.configs.shouldRunGC;\n\t}\n\n\t/**\n\t * Tells whether the GC state needs to be reset in the next summary. We need to do this if:\n\t *\n\t * 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.\n\t *\n\t * 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.\n\t *\n\t * 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.\n\t *\n\t * 4. The GC version in the latest summary is different from the current GC version. This can happen if:\n\t *\n\t * 4.1. The summary this client loaded with has data from a different GC version.\n\t *\n\t * 4.2. This client's latest summary was updated from a snapshot that has a different GC version.\n\t */\n\tpublic get doesSummaryStateNeedReset(): boolean {\n\t\treturn (\n\t\t\tthis.doesGCStateNeedReset ||\n\t\t\t(this.configs.shouldRunGC &&\n\t\t\t\tthis.latestSummaryGCVersion !== this.configs.gcVersionInEffect)\n\t\t);\n\t}\n\n\t/**\n\t * Called during GC initialization. Initialize the latest summary data from the base snapshot data.\n\t */\n\tpublic initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData) {\n\t\t// If tracking state across summaries, update latest summary data from the snapshot's GC data.\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: baseSnapshotData.gcState\n\t\t\t\t? JSON.stringify(generateSortedGCState(baseSnapshotData.gcState))\n\t\t\t\t: undefined,\n\t\t\tserializedTombstones: JSON.stringify(baseSnapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(baseSnapshotData.deletedNodes),\n\t\t};\n\t}\n\n\t/**\n\t * Summarizes three component of the GC data - GC state, tombstones and deleted nodes.\n\t * It does incremental summary, i.e., it writes summary tree / summary blob only for the component that changed.\n\t * For components that did not change, a summary handle is returned that points to the previous successful summary.\n\t * If none of the components changed, it returns a summary handle for the entire GC data.\n\t */\n\tpublic summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean,\n\t\tgcState: IGarbageCollectionState,\n\t\tdeletedNodes: Set<string>,\n\t\ttombstones: string[],\n\t): ISummarizeResult | undefined {\n\t\tif (!this.configs.shouldRunGC) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst serializedGCState = JSON.stringify(generateSortedGCState(gcState));\n\t\t// Serialize and write deleted nodes, if any. This is done irrespective of whether sweep is enabled or not so\n\t\t// to identify deleted nodes' usage.\n\t\tconst serializedDeletedNodes =\n\t\t\tdeletedNodes.size > 0 ? JSON.stringify(Array.from(deletedNodes).sort()) : undefined;\n\t\t// If running in tombstone mode, serialize and write tombstones, if any.\n\t\tconst serializedTombstones = this.configs.tombstoneMode\n\t\t\t? tombstones.length > 0\n\t\t\t\t? JSON.stringify(tombstones.sort())\n\t\t\t\t: undefined\n\t\t\t: undefined;\n\n\t\t/**\n\t\t * Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,\n\t\t * write summary handle instead of summary tree for GC.\n\t\t * Otherwise, write the GC summary tree. In the tree, for each of these that changed, write a summary blob and\n\t\t * for each of these that did not change, write a summary handle.\n\t\t */\n\t\tthis.pendingSummaryData = {\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t};\n\n\t\tif (trackState && !fullTree && this.latestSummaryData !== undefined) {\n\t\t\t// If nothing changed since last summary, send a summary handle for the entire GC data.\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData.serializedGCState === serializedGCState &&\n\t\t\t\tthis.latestSummaryData.serializedTombstones === serializedTombstones &&\n\t\t\t\tthis.latestSummaryData.serializedDeletedNodes === serializedDeletedNodes\n\t\t\t) {\n\t\t\t\tconst stats = mergeStats();\n\t\t\t\tstats.handleNodeCount++;\n\t\t\t\treturn {\n\t\t\t\t\tsummary: {\n\t\t\t\t\t\ttype: SummaryType.Handle,\n\t\t\t\t\t\thandle: `/${gcTreeKey}`,\n\t\t\t\t\t\thandleType: SummaryType.Tree,\n\t\t\t\t\t},\n\t\t\t\t\tstats,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// If some state changed, build a GC summary tree.\n\t\t\treturn this.buildGCSummaryTree(\n\t\t\t\tserializedGCState,\n\t\t\t\tserializedTombstones,\n\t\t\t\tserializedDeletedNodes,\n\t\t\t\ttrue /* trackState */,\n\t\t\t);\n\t\t}\n\t\t// If not tracking GC state, build a GC summary tree without any summary handles.\n\t\treturn this.buildGCSummaryTree(\n\t\t\tserializedGCState,\n\t\t\tserializedTombstones,\n\t\t\tserializedDeletedNodes,\n\t\t\tfalse /* trackState */,\n\t\t);\n\t}\n\n\t/**\n\t * Builds the GC summary tree which contains GC state, deleted nodes and tombstones.\n\t * If trackState is false, all of GC state, deleted nodes and tombstones are written as summary blobs.\n\t * If trackState is true, only states that changed are written. Rest are written as handles.\n\t * @param serializedGCState - The GC state serialized as string.\n\t * @param serializedTombstones - The tombstone state serialized as string.\n\t * @param serializedDeletedNodes - Deleted nodes serialized as string.\n\t * @param trackState - Whether we are tracking GC state across summaries.\n\t * @returns the GC summary tree.\n\t */\n\tprivate buildGCSummaryTree(\n\t\tserializedGCState: string,\n\t\tserializedTombstones: string | undefined,\n\t\tserializedDeletedNodes: string | undefined,\n\t\ttrackState: boolean,\n\t): ISummaryTreeWithStats {\n\t\tconst builder = new SummaryTreeBuilder();\n\n\t\t// If the GC state hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {\n\t\t\tbuilder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcStateBlobKey, serializedGCState);\n\t\t}\n\n\t\t// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a\n\t\t// summary blob.\n\t\tif (serializedTombstones !== undefined) {\n\t\t\tif (\n\t\t\t\tthis.latestSummaryData?.serializedTombstones === serializedTombstones &&\n\t\t\t\ttrackState\n\t\t\t) {\n\t\t\t\tbuilder.addHandle(\n\t\t\t\t\tgcTombstoneBlobKey,\n\t\t\t\t\tSummaryType.Blob,\n\t\t\t\t\t`/${gcTreeKey}/${gcTombstoneBlobKey}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tbuilder.addBlob(gcTombstoneBlobKey, serializedTombstones);\n\t\t\t}\n\t\t}\n\n\t\t// If there are no deleted nodes, return the summary tree.\n\t\tif (serializedDeletedNodes === undefined) {\n\t\t\treturn builder.getSummaryTree();\n\t\t}\n\n\t\t// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.\n\t\tif (\n\t\t\tthis.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&\n\t\t\ttrackState\n\t\t) {\n\t\t\tbuilder.addHandle(\n\t\t\t\tgcDeletedBlobKey,\n\t\t\t\tSummaryType.Blob,\n\t\t\t\t`/${gcTreeKey}/${gcDeletedBlobKey}`,\n\t\t\t);\n\t\t} else {\n\t\t\tbuilder.addBlob(gcDeletedBlobKey, serializedDeletedNodes);\n\t\t}\n\t\treturn builder.getSummaryTree();\n\t}\n\n\t/**\n\t * Called to refresh the latest summary state. This happens when either a pending summary is acked or a snapshot\n\t * is downloaded and should be used to update the state.\n\t */\n\tpublic async refreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tresult: RefreshSummaryResult,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<IGarbageCollectionSnapshotData | undefined> {\n\t\t// If the latest summary was updated and the summary was tracked, this client is the one that generated this\n\t\t// summary. So, update wasGCRunInLatestSummary.\n\t\t// Note that this has to be updated if GC did not run too. Otherwise, `gcStateNeedsReset` will always return\n\t\t// true in scenarios where GC is disabled but enabled in the snapshot we loaded from.\n\t\tif (result.latestSummaryUpdated && result.wasSummaryTracked) {\n\t\t\tthis.wasGCRunInLatestSummary = this.configs.shouldRunGC;\n\t\t}\n\n\t\tif (!result.latestSummaryUpdated || !this.configs.shouldRunGC) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was tracked by this client, it was the one that generated the summary in the first place.\n\t\t// Update latest state from pending.\n\t\tif (result.wasSummaryTracked) {\n\t\t\tthis.latestSummaryGCVersion = this.configs.gcVersionInEffect;\n\t\t\tthis.latestSummaryData = this.pendingSummaryData;\n\t\t\tthis.pendingSummaryData = undefined;\n\t\t\tthis.updatedDSCountSinceLastSummary = 0;\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// If the summary was not tracked by this client, the state should be updated from the downloaded snapshot.\n\t\tconst snapshotTree = result.snapshotTree;\n\t\tconst metadataBlobId = snapshotTree.blobs[metadataBlobName];\n\t\tconst metadata = metadataBlobId\n\t\t\t? await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId)\n\t\t\t: undefined;\n\t\tthis.latestSummaryGCVersion = getGCVersion(metadata);\n\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\t// If GC ran in the container that generated this snapshot, it will have a GC tree.\n\t\tthis.wasGCRunInLatestSummary = gcSnapshotTree !== undefined;\n\n\t\tif (gcSnapshotTree === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet snapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t// If the GC version in the snapshot does not match the GC version currently in effect, the GC data\n\t\t// in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes\n\t\t// because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The\n\t\t// deletedNodes info is needed to identify when these nodes are used.\n\t\tif (getGCVersion(metadata) !== this.configs.gcVersionInEffect) {\n\t\t\tsnapshotData = {\n\t\t\t\tgcState: undefined,\n\t\t\t\ttombstones: undefined,\n\t\t\t\tdeletedNodes: snapshotData.deletedNodes,\n\t\t\t};\n\t\t}\n\n\t\tthis.latestSummaryData = {\n\t\t\tserializedGCState: JSON.stringify(snapshotData.gcState),\n\t\t\tserializedTombstones: JSON.stringify(snapshotData.tombstones),\n\t\t\tserializedDeletedNodes: JSON.stringify(snapshotData.deletedNodes),\n\t\t};\n\t\treturn snapshotData;\n\t}\n\n\t/**\n\t * Called to update the state from a GC run's stats. Used to update the count of data stores whose state updated.\n\t */\n\tpublic updateStateFromGCRunStats(stats: IGCStats) {\n\t\tthis.updatedDSCountSinceLastSummary += stats.updatedDataStoreCount;\n\t}\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "2.0.0-dev.4.4.0.162253";
8
+ export declare const pkgVersion = "2.0.0-dev.4.4.0.162574";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-runtime";
8
- export const pkgVersion = "2.0.0-dev.4.4.0.162253";
8
+ export const pkgVersion = "2.0.0-dev.4.4.0.162574";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.4.4.0.162253\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.4.4.0.162574\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-dev.4.4.0.162253",
3
+ "version": "2.0.0-dev.4.4.0.162574",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -37,19 +37,19 @@
37
37
  "dependencies": {
38
38
  "@fluidframework/common-definitions": "^0.20.1",
39
39
  "@fluidframework/common-utils": "^1.1.1",
40
- "@fluidframework/container-definitions": "2.0.0-dev.4.4.0.162253",
41
- "@fluidframework/container-runtime-definitions": "2.0.0-dev.4.4.0.162253",
42
- "@fluidframework/container-utils": "2.0.0-dev.4.4.0.162253",
43
- "@fluidframework/core-interfaces": "2.0.0-dev.4.4.0.162253",
44
- "@fluidframework/datastore": "2.0.0-dev.4.4.0.162253",
45
- "@fluidframework/driver-definitions": "2.0.0-dev.4.4.0.162253",
46
- "@fluidframework/driver-utils": "2.0.0-dev.4.4.0.162253",
47
- "@fluidframework/garbage-collector": "2.0.0-dev.4.4.0.162253",
40
+ "@fluidframework/container-definitions": "2.0.0-dev.4.4.0.162574",
41
+ "@fluidframework/container-runtime-definitions": "2.0.0-dev.4.4.0.162574",
42
+ "@fluidframework/container-utils": "2.0.0-dev.4.4.0.162574",
43
+ "@fluidframework/core-interfaces": "2.0.0-dev.4.4.0.162574",
44
+ "@fluidframework/datastore": "2.0.0-dev.4.4.0.162574",
45
+ "@fluidframework/driver-definitions": "2.0.0-dev.4.4.0.162574",
46
+ "@fluidframework/driver-utils": "2.0.0-dev.4.4.0.162574",
47
+ "@fluidframework/garbage-collector": "2.0.0-dev.4.4.0.162574",
48
48
  "@fluidframework/protocol-base": "^0.1039.1000",
49
49
  "@fluidframework/protocol-definitions": "^1.1.0",
50
- "@fluidframework/runtime-definitions": "2.0.0-dev.4.4.0.162253",
51
- "@fluidframework/runtime-utils": "2.0.0-dev.4.4.0.162253",
52
- "@fluidframework/telemetry-utils": "2.0.0-dev.4.4.0.162253",
50
+ "@fluidframework/runtime-definitions": "2.0.0-dev.4.4.0.162574",
51
+ "@fluidframework/runtime-utils": "2.0.0-dev.4.4.0.162574",
52
+ "@fluidframework/telemetry-utils": "2.0.0-dev.4.4.0.162574",
53
53
  "double-ended-queue": "^2.1.0-0",
54
54
  "events": "^3.1.0",
55
55
  "lz4js": "^0.2.0",
@@ -57,15 +57,15 @@
57
57
  "uuid": "^8.3.1"
58
58
  },
59
59
  "devDependencies": {
60
- "@fluid-internal/stochastic-test-utils": "2.0.0-dev.4.4.0.162253",
60
+ "@fluid-internal/stochastic-test-utils": "2.0.0-dev.4.4.0.162574",
61
61
  "@fluid-tools/benchmark": "^0.46.0",
62
62
  "@fluid-tools/build-cli": "^0.17.0",
63
63
  "@fluidframework/build-common": "^1.1.0",
64
64
  "@fluidframework/build-tools": "^0.17.0",
65
65
  "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.4.1.0",
66
66
  "@fluidframework/eslint-config-fluid": "^2.0.0",
67
- "@fluidframework/mocha-test-setup": "2.0.0-dev.4.4.0.162253",
68
- "@fluidframework/test-runtime-utils": "2.0.0-dev.4.4.0.162253",
67
+ "@fluidframework/mocha-test-setup": "2.0.0-dev.4.4.0.162574",
68
+ "@fluidframework/test-runtime-utils": "2.0.0-dev.4.4.0.162574",
69
69
  "@microsoft/api-extractor": "^7.34.4",
70
70
  "@types/double-ended-queue": "^2.1.0",
71
71
  "@types/events": "^3.0.0",
@@ -202,10 +202,7 @@ export class GarbageCollector implements IGarbageCollector {
202
202
  // in the snapshot cannot be interpreted correctly. Set everything to undefined except for
203
203
  // deletedNodes because irrespective of GC versions, these nodes have been deleted and cannot be
204
204
  // brought back. The deletedNodes info is needed to identify when these nodes are used.
205
- if (
206
- this.configs.gcVersionInBaseSnapshot !==
207
- this.summaryStateTracker.currentGCVersion
208
- ) {
205
+ if (this.configs.gcVersionInEffect !== this.configs.gcVersionInBaseSnapshot) {
209
206
  return {
210
207
  gcState: undefined,
211
208
  tombstones: undefined,
@@ -823,10 +820,10 @@ export class GarbageCollector implements IGarbageCollector {
823
820
  public getMetadata(): IGCMetadata {
824
821
  return {
825
822
  /**
826
- * If GC is enabled, the GC data is written using the current GC version and that is the gcFeature that goes
823
+ * If GC is enabled, the GC data is written using the GC version in effect and that is the gcFeature that goes
827
824
  * into the metadata blob. If GC is disabled, the gcFeature is 0.
828
825
  */
829
- gcFeature: this.configs.gcEnabled ? this.summaryStateTracker.currentGCVersion : 0,
826
+ gcFeature: this.configs.gcEnabled ? this.configs.gcVersionInEffect : 0,
830
827
  gcFeatureMatrix: this.configs.persistedGcFeatureMatrix,
831
828
  sessionExpiryTimeoutMs: this.configs.sessionExpiryTimeoutMs,
832
829
  sweepEnabled: false, // DEPRECATED - to be removed
@@ -106,21 +106,26 @@ export function generateGCConfigs(
106
106
  createParams.gcOptions[gcSweepGenerationOptionName] /* currentGeneration */,
107
107
  );
108
108
 
109
+ // If version upgrade is not enabled, fall back to the stable GC version.
110
+ const gcVersionInEffect =
111
+ mc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;
112
+
113
+ // The GC version is up-to-date if the GC version in effect is at least equal to the GC version in base snapshot.
114
+ // If it is not up-to-date, there is a newer version of GC out there which is more reliable than this. So, GC
115
+ // should not run as it may produce incorrect / unreliable state.
116
+ const isGCVersionUpToDate =
117
+ gcVersionInBaseSnapshot === undefined || gcVersionInEffect >= gcVersionInBaseSnapshot;
118
+
109
119
  /**
110
120
  * Whether GC should run or not. The following conditions have to be met to run sweep:
111
- *
112
121
  * 1. GC should be enabled for this container.
113
- *
114
122
  * 2. GC should not be disabled via disableGC GC option.
115
- *
123
+ * 3. The current GC version should be greater of equal to the GC version in the base snapshot.
116
124
  * These conditions can be overridden via runGCKey feature flag.
117
125
  */
118
126
  const shouldRunGC =
119
127
  mc.config.getBoolean(runGCKey) ??
120
- // GC must be enabled for the document.
121
- (gcEnabled &&
122
- // GC must not be disabled via GC options.
123
- !createParams.gcOptions.disableGC);
128
+ (gcEnabled && !createParams.gcOptions.disableGC && isGCVersionUpToDate);
124
129
 
125
130
  /**
126
131
  * Whether sweep should run or not. The following conditions have to be met to run sweep:
@@ -156,10 +161,6 @@ export function generateGCConfigs(
156
161
  const tombstoneMode = !shouldRunSweep && mc.config.getBoolean(disableTombstoneKey) !== true;
157
162
  const runFullGC = createParams.gcOptions.runFullGC;
158
163
 
159
- // If version upgrade is not enabled, fall back to the stable GC version.
160
- const gcVersionInEffect =
161
- mc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;
162
-
163
164
  return {
164
165
  gcEnabled,
165
166
  sweepEnabled,
@@ -37,8 +37,6 @@ export interface IGCSummaryTrackingData {
37
37
  * On summarize, it decides whether to write new state or re-use previous summary's state.
38
38
  */
39
39
  export class GCSummaryStateTracker {
40
- // The current version of GC running.
41
- public readonly currentGCVersion: GCVersion = this.configs.gcVersionInEffect;
42
40
  // This is the version of GC data in the latest summary being tracked.
43
41
  private latestSummaryGCVersion: GCVersion;
44
42
 
@@ -66,7 +64,8 @@ export class GCSummaryStateTracker {
66
64
  this.wasGCRunInLatestSummary = wasGCRunInBaseSnapshot;
67
65
  // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the
68
66
  // latest tracked GC version. For new documents, we will be writing the first summary with the current version.
69
- this.latestSummaryGCVersion = this.configs.gcVersionInBaseSnapshot ?? this.currentGCVersion;
67
+ this.latestSummaryGCVersion =
68
+ this.configs.gcVersionInBaseSnapshot ?? this.configs.gcVersionInEffect;
70
69
  }
71
70
 
72
71
  /**
@@ -105,7 +104,8 @@ export class GCSummaryStateTracker {
105
104
  public get doesSummaryStateNeedReset(): boolean {
106
105
  return (
107
106
  this.doesGCStateNeedReset ||
108
- (this.configs.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion)
107
+ (this.configs.shouldRunGC &&
108
+ this.latestSummaryGCVersion !== this.configs.gcVersionInEffect)
109
109
  );
110
110
  }
111
111
 
@@ -287,7 +287,7 @@ export class GCSummaryStateTracker {
287
287
  // If the summary was tracked by this client, it was the one that generated the summary in the first place.
288
288
  // Update latest state from pending.
289
289
  if (result.wasSummaryTracked) {
290
- this.latestSummaryGCVersion = this.currentGCVersion;
290
+ this.latestSummaryGCVersion = this.configs.gcVersionInEffect;
291
291
  this.latestSummaryData = this.pendingSummaryData;
292
292
  this.pendingSummaryData = undefined;
293
293
  this.updatedDSCountSinceLastSummary = 0;
@@ -316,7 +316,7 @@ export class GCSummaryStateTracker {
316
316
  // in the snapshot cannot be interpreted correctly. Set everything to undefined except for deletedNodes
317
317
  // because irrespective of GC versions, these nodes have been deleted and cannot be brought back. The
318
318
  // deletedNodes info is needed to identify when these nodes are used.
319
- if (getGCVersion(metadata) !== this.currentGCVersion) {
319
+ if (getGCVersion(metadata) !== this.configs.gcVersionInEffect) {
320
320
  snapshotData = {
321
321
  gcState: undefined,
322
322
  tombstones: undefined,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-dev.4.4.0.162253";
9
+ export const pkgVersion = "2.0.0-dev.4.4.0.162574";