@fluidframework/container-runtime 0.59.4001 → 1.1.0-75972

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 (157) hide show
  1. package/.eslintrc.js +1 -1
  2. package/dist/blobManager.d.ts +2 -2
  3. package/dist/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager.js +12 -11
  5. package/dist/blobManager.js.map +1 -1
  6. package/dist/connectionTelemetry.d.ts +19 -0
  7. package/dist/connectionTelemetry.d.ts.map +1 -1
  8. package/dist/connectionTelemetry.js +23 -23
  9. package/dist/connectionTelemetry.js.map +1 -1
  10. package/dist/containerRuntime.d.ts +137 -29
  11. package/dist/containerRuntime.d.ts.map +1 -1
  12. package/dist/containerRuntime.js +338 -118
  13. package/dist/containerRuntime.js.map +1 -1
  14. package/dist/dataStore.d.ts.map +1 -1
  15. package/dist/dataStore.js +14 -3
  16. package/dist/dataStore.js.map +1 -1
  17. package/dist/dataStoreContext.d.ts +4 -2
  18. package/dist/dataStoreContext.d.ts.map +1 -1
  19. package/dist/dataStoreContext.js +16 -5
  20. package/dist/dataStoreContext.js.map +1 -1
  21. package/dist/dataStoreRegistry.d.ts +0 -4
  22. package/dist/dataStoreRegistry.d.ts.map +1 -1
  23. package/dist/dataStoreRegistry.js +12 -1
  24. package/dist/dataStoreRegistry.js.map +1 -1
  25. package/dist/dataStores.d.ts +4 -3
  26. package/dist/dataStores.d.ts.map +1 -1
  27. package/dist/dataStores.js +13 -7
  28. package/dist/dataStores.js.map +1 -1
  29. package/dist/garbageCollection.d.ts +23 -27
  30. package/dist/garbageCollection.d.ts.map +1 -1
  31. package/dist/garbageCollection.js +44 -119
  32. package/dist/garbageCollection.js.map +1 -1
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/orderedClientElection.js +0 -4
  38. package/dist/orderedClientElection.js.map +1 -1
  39. package/dist/packageVersion.d.ts +1 -1
  40. package/dist/packageVersion.d.ts.map +1 -1
  41. package/dist/packageVersion.js +1 -1
  42. package/dist/packageVersion.js.map +1 -1
  43. package/dist/pendingStateManager.d.ts +30 -29
  44. package/dist/pendingStateManager.d.ts.map +1 -1
  45. package/dist/pendingStateManager.js +72 -109
  46. package/dist/pendingStateManager.js.map +1 -1
  47. package/dist/runningSummarizer.d.ts +4 -3
  48. package/dist/runningSummarizer.d.ts.map +1 -1
  49. package/dist/runningSummarizer.js +11 -6
  50. package/dist/runningSummarizer.js.map +1 -1
  51. package/dist/serializedSnapshotStorage.d.ts +58 -0
  52. package/dist/serializedSnapshotStorage.d.ts.map +1 -0
  53. package/dist/serializedSnapshotStorage.js +108 -0
  54. package/dist/serializedSnapshotStorage.js.map +1 -0
  55. package/dist/summarizer.d.ts +11 -4
  56. package/dist/summarizer.d.ts.map +1 -1
  57. package/dist/summarizer.js +18 -9
  58. package/dist/summarizer.js.map +1 -1
  59. package/dist/summarizerHeuristics.d.ts +5 -3
  60. package/dist/summarizerHeuristics.d.ts.map +1 -1
  61. package/dist/summarizerHeuristics.js +10 -3
  62. package/dist/summarizerHeuristics.js.map +1 -1
  63. package/dist/summarizerTypes.d.ts +4 -2
  64. package/dist/summarizerTypes.d.ts.map +1 -1
  65. package/dist/summarizerTypes.js.map +1 -1
  66. package/dist/summaryManager.d.ts +3 -3
  67. package/dist/summaryManager.d.ts.map +1 -1
  68. package/dist/summaryManager.js +7 -7
  69. package/dist/summaryManager.js.map +1 -1
  70. package/garbageCollection.md +9 -1
  71. package/lib/blobManager.d.ts +2 -2
  72. package/lib/blobManager.d.ts.map +1 -1
  73. package/lib/blobManager.js +12 -11
  74. package/lib/blobManager.js.map +1 -1
  75. package/lib/connectionTelemetry.d.ts +19 -0
  76. package/lib/connectionTelemetry.d.ts.map +1 -1
  77. package/lib/connectionTelemetry.js +23 -23
  78. package/lib/connectionTelemetry.js.map +1 -1
  79. package/lib/containerRuntime.d.ts +137 -29
  80. package/lib/containerRuntime.d.ts.map +1 -1
  81. package/lib/containerRuntime.js +341 -121
  82. package/lib/containerRuntime.js.map +1 -1
  83. package/lib/dataStore.d.ts.map +1 -1
  84. package/lib/dataStore.js +15 -4
  85. package/lib/dataStore.js.map +1 -1
  86. package/lib/dataStoreContext.d.ts +4 -2
  87. package/lib/dataStoreContext.d.ts.map +1 -1
  88. package/lib/dataStoreContext.js +16 -5
  89. package/lib/dataStoreContext.js.map +1 -1
  90. package/lib/dataStoreRegistry.d.ts +0 -4
  91. package/lib/dataStoreRegistry.d.ts.map +1 -1
  92. package/lib/dataStoreRegistry.js +12 -1
  93. package/lib/dataStoreRegistry.js.map +1 -1
  94. package/lib/dataStores.d.ts +4 -3
  95. package/lib/dataStores.d.ts.map +1 -1
  96. package/lib/dataStores.js +14 -8
  97. package/lib/dataStores.js.map +1 -1
  98. package/lib/garbageCollection.d.ts +23 -27
  99. package/lib/garbageCollection.d.ts.map +1 -1
  100. package/lib/garbageCollection.js +43 -117
  101. package/lib/garbageCollection.js.map +1 -1
  102. package/lib/index.d.ts +2 -2
  103. package/lib/index.d.ts.map +1 -1
  104. package/lib/index.js +1 -1
  105. package/lib/index.js.map +1 -1
  106. package/lib/orderedClientElection.js +0 -4
  107. package/lib/orderedClientElection.js.map +1 -1
  108. package/lib/packageVersion.d.ts +1 -1
  109. package/lib/packageVersion.d.ts.map +1 -1
  110. package/lib/packageVersion.js +1 -1
  111. package/lib/packageVersion.js.map +1 -1
  112. package/lib/pendingStateManager.d.ts +30 -29
  113. package/lib/pendingStateManager.d.ts.map +1 -1
  114. package/lib/pendingStateManager.js +72 -109
  115. package/lib/pendingStateManager.js.map +1 -1
  116. package/lib/runningSummarizer.d.ts +4 -3
  117. package/lib/runningSummarizer.d.ts.map +1 -1
  118. package/lib/runningSummarizer.js +11 -6
  119. package/lib/runningSummarizer.js.map +1 -1
  120. package/lib/serializedSnapshotStorage.d.ts +58 -0
  121. package/lib/serializedSnapshotStorage.d.ts.map +1 -0
  122. package/lib/serializedSnapshotStorage.js +104 -0
  123. package/lib/serializedSnapshotStorage.js.map +1 -0
  124. package/lib/summarizer.d.ts +11 -4
  125. package/lib/summarizer.d.ts.map +1 -1
  126. package/lib/summarizer.js +18 -9
  127. package/lib/summarizer.js.map +1 -1
  128. package/lib/summarizerHeuristics.d.ts +5 -3
  129. package/lib/summarizerHeuristics.d.ts.map +1 -1
  130. package/lib/summarizerHeuristics.js +10 -3
  131. package/lib/summarizerHeuristics.js.map +1 -1
  132. package/lib/summarizerTypes.d.ts +4 -2
  133. package/lib/summarizerTypes.d.ts.map +1 -1
  134. package/lib/summarizerTypes.js.map +1 -1
  135. package/lib/summaryManager.d.ts +3 -3
  136. package/lib/summaryManager.d.ts.map +1 -1
  137. package/lib/summaryManager.js +7 -7
  138. package/lib/summaryManager.js.map +1 -1
  139. package/package.json +19 -32
  140. package/src/blobManager.ts +29 -15
  141. package/src/connectionTelemetry.ts +60 -39
  142. package/src/containerRuntime.ts +502 -156
  143. package/src/dataStore.ts +21 -4
  144. package/src/dataStoreContext.ts +27 -5
  145. package/src/dataStoreRegistry.ts +8 -1
  146. package/src/dataStores.ts +21 -8
  147. package/src/garbageCollection.ts +81 -166
  148. package/src/index.ts +7 -1
  149. package/src/orderedClientElection.ts +1 -1
  150. package/src/packageVersion.ts +1 -1
  151. package/src/pendingStateManager.ts +104 -123
  152. package/src/runningSummarizer.ts +20 -10
  153. package/src/serializedSnapshotStorage.ts +146 -0
  154. package/src/summarizer.ts +20 -16
  155. package/src/summarizerHeuristics.ts +21 -5
  156. package/src/summarizerTypes.ts +4 -2
  157. package/src/summaryManager.ts +5 -6
@@ -11,7 +11,6 @@ import { mergeStats, SummaryTreeBuilder, } from "@fluidframework/runtime-utils";
11
11
  import { ChildLogger, loggerToMonitoringContext, PerformanceEvent, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
12
12
  import { RuntimeHeaders } from "./containerRuntime";
13
13
  import { getSummaryForDatastores } from "./dataStores";
14
- import { pkgVersion } from "./packageVersion";
15
14
  import { getGCVersion, metadataBlobName, dataStoreAttributesBlobName, } from "./summaryFormat";
16
15
  /** This is the current version of garbage collection. */
17
16
  const GCVersion = 1;
@@ -31,12 +30,8 @@ const writeAtRootKey = "Fluid.GarbageCollection.WriteDataAtRoot";
31
30
  export const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
32
31
  // Feature gate key to disable expiring session after a set period of time, even if expiry value is present
33
32
  export const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
34
- // Feature gate key to log error messages if GC reference validation fails.
35
- export const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
36
33
  // Feature gate key to write the gc blob as a handle if the data is the same.
37
34
  export const trackGCStateKey = "Fluid.GarbageCollection.TrackGCState";
38
- // Feature gate key to limit which versions can write the gc blob as a handle if the data is the same.
39
- export const trackGCStateMinimumVersionKey = "Fluid.GarbageCollection.TrackGCState.MinVersion";
40
35
  const defaultInactiveTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
41
36
  export const defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days
42
37
  /** The types of GC nodes in the GC reference graph. */
@@ -114,21 +109,12 @@ class UnreferencedStateTracker {
114
109
  * NodeId = "dds1" NodeId = "dds2"
115
110
  */
116
111
  export class GarbageCollector {
117
- constructor(runtime, gcOptions,
118
- /** For a given node path, returns the node's package path. */
119
- getNodePackagePath,
120
- /** Returns the timestamp of the last summary generated for this container. */
121
- getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient = true) {
112
+ constructor(createParams) {
122
113
  var _a, _b, _c, _d, _e, _f, _g;
123
- this.runtime = runtime;
124
- this.gcOptions = gcOptions;
125
- this.getNodePackagePath = getNodePackagePath;
126
- this.getLastSummaryTimestampMs = getLastSummaryTimestampMs;
127
- this.isSummarizerClient = isSummarizerClient;
128
114
  /**
129
115
  * Tells whether the GC data should be written to the root of the summary tree.
130
116
  */
131
- this._writeDataAtRoot = false;
117
+ this._writeDataAtRoot = true;
132
118
  /**
133
119
  * Tells whether the initial GC state needs to be reset. This can happen under 2 conditions:
134
120
  * 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after
@@ -154,7 +140,15 @@ export class GarbageCollector {
154
140
  this.pendingEventsQueue = [];
155
141
  // The number of times GC has successfully completed on this instance of GarbageCollector.
156
142
  this.completedRuns = 0;
157
- this.mc = loggerToMonitoringContext(ChildLogger.create(baseLogger, "GarbageCollector", { all: { completedGCRuns: () => this.completedRuns } }));
143
+ this.runtime = createParams.runtime;
144
+ this.isSummarizerClient = createParams.isSummarizerClient;
145
+ this.gcOptions = createParams.gcOptions;
146
+ this.getNodePackagePath = createParams.getNodePackagePath;
147
+ this.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;
148
+ const baseSnapshot = createParams.baseSnapshot;
149
+ const metadata = createParams.metadata;
150
+ const readAndParseBlob = createParams.readAndParseBlob;
151
+ this.mc = loggerToMonitoringContext(ChildLogger.create(createParams.baseLogger, "GarbageCollector", { all: { completedGCRuns: () => this.completedRuns } }));
158
152
  let prevSummaryGCVersion;
159
153
  /**
160
154
  * The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
@@ -163,7 +157,7 @@ export class GarbageCollector {
163
157
  * 3. Whether GC session expiry is enabled or not.
164
158
  * For existing containers, we get this information from the metadata blob of its summary.
165
159
  */
166
- if (existing) {
160
+ if (createParams.existing) {
167
161
  prevSummaryGCVersion = getGCVersion(metadata);
168
162
  // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
169
163
  // other existing documents, GC is enabled.
@@ -174,12 +168,14 @@ export class GarbageCollector {
174
168
  else {
175
169
  // Sweep should not be enabled without enabling GC mark phase. We could silently disable sweep in this
176
170
  // scenario but explicitly failing makes it clearer and promotes correct usage.
177
- if (gcOptions.sweepAllowed && !gcOptions.gcAllowed) {
171
+ if (this.gcOptions.sweepAllowed && this.gcOptions.gcAllowed === false) {
178
172
  throw new UsageError("GC sweep phase cannot be enabled without enabling GC mark phase");
179
173
  }
180
- // For new documents, GC has to be explicitly enabled via the flags in GC options.
181
- this.gcEnabled = gcOptions.gcAllowed === true;
182
- this.sweepEnabled = gcOptions.sweepAllowed === true;
174
+ // For new documents, GC is enabled by default. It can be explicitly disabled by setting the gcAllowed
175
+ // flag in GC options to false.
176
+ this.gcEnabled = this.gcOptions.gcAllowed !== false;
177
+ // The sweep phase has to be explicitly enabled by setting the sweepAllowed flag in GC options to true.
178
+ this.sweepEnabled = this.gcOptions.sweepAllowed === true;
183
179
  // Set the Session Expiry only if the flag is enabled or the test option is set.
184
180
  if (this.mc.config.getBoolean(runSessionExpiryKey) && this.gcEnabled) {
185
181
  this.sessionExpiryTimeoutMs = defaultSessionExpiryDurationMs;
@@ -213,10 +209,8 @@ export class GarbageCollector {
213
209
  // GC must be enabled for the document.
214
210
  this.gcEnabled
215
211
  // GC must not be disabled via GC options.
216
- && !gcOptions.disableGC);
217
- const minimumVersion = this.mc.config.getString(trackGCStateMinimumVersionKey);
218
- const shouldTrackStateForVersion = meetsMinimumVersionRequirement(pkgVersion, minimumVersion);
219
- this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true && shouldTrackStateForVersion;
212
+ && !this.gcOptions.disableGC);
213
+ this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true;
220
214
  /**
221
215
  * Whether sweep should run or not. The following conditions have to be met to run sweep:
222
216
  * 1. Overall GC or mark phase must be enabled (this.shouldRunGC).
@@ -228,19 +222,15 @@ export class GarbageCollector {
228
222
  this.inactiveTimeoutMs =
229
223
  (_e = (_d = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _d !== void 0 ? _d : this.gcOptions.inactiveTimeoutMs) !== null && _e !== void 0 ? _e : defaultInactiveTimeoutMs;
230
224
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
231
- this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : gcOptions.runGCInTestMode === true;
232
- /**
233
- * Enable resetting initial state once the following issue is resolved:
234
- * https://github.com/microsoft/FluidFramework/issues/8878.
235
- * Currently, the GC tree is not written at root, so we don't know if the base snapshot contains GC tree or not.
236
- */
237
- // The GC state needs to be reset if the base snapshot contains GC tree and GC is disabled or it doesn't contain
238
- // GC tree and GC is enabled.
239
- // const gcTreePresent = baseSnapshot?.trees[gcTreeKey] !== undefined;
240
- // this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;
241
- // If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that
242
- // the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.
243
- this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : this.gcOptions.writeDataAtRoot === true;
225
+ this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : this.gcOptions.runGCInTestMode === true;
226
+ // GC state is written into root of the summary tree by default. Can be overridden via feature flag for now.
227
+ this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : true;
228
+ if (this._writeDataAtRoot) {
229
+ // The GC state needs to be reset if the base snapshot contains GC tree and GC is disabled or it doesn't
230
+ // contain GC tree and GC is enabled.
231
+ const gcTreePresent = (baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[gcTreeKey]) !== undefined;
232
+ this.initialStateNeedsReset = gcTreePresent !== this.shouldRunGC;
233
+ }
244
234
  // Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do
245
235
  // this once since it involves fetching blobs from storage which is expensive.
246
236
  const baseSummaryStateP = new LazyPromise(async () => {
@@ -329,7 +319,7 @@ export class GarbageCollector {
329
319
  // Run GC on the nodes in the base summary to get the routes used in each node in the container.
330
320
  // This is an optimization for space (vs performance) wherein we don't need to store the used routes of
331
321
  // each node in the summary.
332
- const usedRoutes = runGarbageCollection(gcNodes, ["/"], this.mc.logger).referencedNodeIds;
322
+ const usedRoutes = runGarbageCollection(gcNodes, ["/"]).referencedNodeIds;
333
323
  const baseGCDetailsMap = unpackChildNodesGCDetails({ gcData: { gcNodes }, usedRoutes });
334
324
  // Currently, the nodes may write the GC data. So, we need to update it's base GC details with the
335
325
  // unreferenced timestamp. Once we start writing the GC data here, we won't need to do this anymore.
@@ -345,7 +335,7 @@ export class GarbageCollector {
345
335
  });
346
336
  // Log all the GC options and the state determined by the garbage collector. This is interesting only for the
347
337
  // summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.
348
- const gcConfigProps = JSON.stringify(Object.assign({ gcEnabled: this.gcEnabled, sweepEnabled: this.sweepEnabled, runGC: this.shouldRunGC, runSweep: this.shouldRunSweep, writeAtRoot: this._writeDataAtRoot, testMode: this.testMode, sessionExpiry: this.sessionExpiryTimeoutMs, inactiveTimeout: this.inactiveTimeoutMs, existing }, this.gcOptions));
338
+ const gcConfigProps = JSON.stringify(Object.assign({ gcEnabled: this.gcEnabled, sweepEnabled: this.sweepEnabled, runGC: this.shouldRunGC, runSweep: this.shouldRunSweep, writeAtRoot: this._writeDataAtRoot, testMode: this.testMode, sessionExpiry: this.sessionExpiryTimeoutMs, inactiveTimeout: this.inactiveTimeoutMs, existing: createParams.existing }, this.gcOptions));
349
339
  if (this.isSummarizerClient) {
350
340
  this.mc.logger.sendTelemetryEvent({
351
341
  eventName: "GarbageCollectorLoaded",
@@ -361,8 +351,8 @@ export class GarbageCollector {
361
351
  });
362
352
  }
363
353
  }
364
- static create(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient) {
365
- return new GarbageCollector(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient);
354
+ static create(createParams) {
355
+ return new GarbageCollector(createParams);
366
356
  }
367
357
  /**
368
358
  * Tells whether the GC state needs to be reset in the next summary. We need to do this if:
@@ -394,7 +384,7 @@ export class GarbageCollector {
394
384
  await this.runtime.updateStateBeforeGC();
395
385
  // Get the runtime's GC data and run GC on the reference graph in it.
396
386
  const gcData = await this.runtime.getGCData(fullGC);
397
- const gcResult = runGarbageCollection(gcData.gcNodes, ["/"], logger);
387
+ const gcResult = runGarbageCollection(gcData.gcNodes, ["/"]);
398
388
  const gcStats = this.generateStatsAndLogEvents(gcResult, logger);
399
389
  // Update the state since the last GC run. There can be nodes that were referenced between the last and
400
390
  // the current run. We need to identify than and update their unreferenced state if needed.
@@ -421,7 +411,7 @@ export class GarbageCollector {
421
411
  * We current write the entire GC state in a single blob. This can be modified later to write multiple
422
412
  * blobs. All the blob keys should start with `gcBlobPrefix`.
423
413
  */
424
- summarize(fullTree, trackState) {
414
+ summarize(fullTree, trackState, telemetryContext) {
425
415
  var _a;
426
416
  if (!this.shouldRunGC || this.previousGCDataFromLastRun === undefined) {
427
417
  return;
@@ -483,9 +473,6 @@ export class GarbageCollector {
483
473
  * latest summary tracked.
484
474
  */
485
475
  async latestSummaryStateRefreshed(result, readAndParseBlob) {
486
- // After a summary is successfully submitted and ack'd by this client, the GC state should have been reset in
487
- // the summary and doesn't need to be reset anymore.
488
- this.initialStateNeedsReset = false;
489
476
  if (!this.shouldRunGC || !result.latestSummaryUpdated) {
490
477
  return;
491
478
  }
@@ -493,6 +480,7 @@ export class GarbageCollector {
493
480
  // Basically, it was written in the current GC version.
494
481
  if (result.wasSummaryTracked) {
495
482
  this.latestSummaryGCVersion = this.currentGCVersion;
483
+ this.initialStateNeedsReset = false;
496
484
  if (this.trackGCState) {
497
485
  this.latestSerializedSummaryState = this.pendingSerializedSummaryState;
498
486
  this.pendingSerializedSummaryState = undefined;
@@ -615,10 +603,7 @@ export class GarbageCollector {
615
603
  }
616
604
  // Find any references that haven't been identified correctly.
617
605
  const missingExplicitReferences = this.findMissingExplicitReferences(currentGCData, this.previousGCDataFromLastRun, this.newReferencesSinceLastRun);
618
- // The following log will be enabled once this issue is resolved:
619
- // https://github.com/microsoft/FluidFramework/issues/8878.
620
- if (this.mc.config.getBoolean(logUnknownOutboundReferencesKey) === true
621
- && missingExplicitReferences.length > 0) {
606
+ if (this.writeDataAtRoot && missingExplicitReferences.length > 0) {
622
607
  missingExplicitReferences.forEach((missingExplicitReference) => {
623
608
  const event = {
624
609
  eventName: "gcUnknownOutboundReferences",
@@ -662,7 +647,7 @@ export class GarbageCollector {
662
647
  * unreferenced, stop tracking them and remove from unreferenced list.
663
648
  * Some of these nodes may be unreferenced now and if so, the current run will add unreferenced state for them.
664
649
  */
665
- const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, ["/"], logger);
650
+ const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, ["/"]);
666
651
  for (const nodeId of gcResult.referencedNodeIds) {
667
652
  const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
668
653
  if (nodeStateTracker !== undefined) {
@@ -742,11 +727,10 @@ export class GarbageCollector {
742
727
  };
743
728
  const updateNodeStats = (nodeId, referenced) => {
744
729
  gcStats.nodeCount++;
745
- /**
746
- * `this.unreferencedNodesState` has the previous unreferenced state of all nodes. `referenced` flag passed
747
- * here is current state of the give node. Check if the reference state of the changed.
748
- */
749
- const stateUpdated = this.unreferencedNodesState.has(nodeId) ? referenced : !referenced;
730
+ // If there is no previous GC data, every node's state is generated and is considered as updated.
731
+ // Otherwise, find out if any node went from referenced to unreferenced or vice-versa.
732
+ const stateUpdated = this.previousGCDataFromLastRun === undefined ||
733
+ this.unreferencedNodesState.has(nodeId) === referenced;
750
734
  if (stateUpdated) {
751
735
  gcStats.updatedNodeCount++;
752
736
  }
@@ -822,7 +806,7 @@ export class GarbageCollector {
822
806
  // next time GC runs as the package data should be available then.
823
807
  const pkg = packagePath !== null && packagePath !== void 0 ? packagePath : this.getNodePackagePath(nodeId);
824
808
  if (pkg !== undefined) {
825
- this.mc.logger.sendErrorEvent(Object.assign(Object.assign({}, event), { pkg: { value: `/${pkg.join("/")}`, tag: TelemetryDataTag.PackageData } }));
809
+ this.mc.logger.sendErrorEvent(Object.assign(Object.assign({}, event), { pkg: { value: pkg.join("/"), tag: TelemetryDataTag.PackageData } }));
826
810
  }
827
811
  else {
828
812
  this.pendingEventsQueue.push(event);
@@ -881,62 +865,4 @@ function setLongTimeout(timeoutMs, timeoutFn, setTimerFn) {
881
865
  }
882
866
  setTimerFn(timer);
883
867
  }
884
- /**
885
- * meetsMinimumVersionRequirement is used determining if a feature version should be run. This is similar to feature
886
- * flags. The advantage of this is that if we ship a bug in version 0.1.1 and fix it in version 0.2.1. We can keep this
887
- * feature disabled for version 0.1.1 and enabled for 0.2.1. Older versions will run without the feature and new
888
- * versions will run with the feature.
889
- * @param currentVersion - the total time the timeout needs to last in ms
890
- * @param minimumVersion - the function to execute when the timer ends
891
- */
892
- function meetsMinimumVersionRequirement(currentVersion, minimumVersion) {
893
- return minimumVersion === undefined || semverCompare(currentVersion, minimumVersion) >= 0;
894
- }
895
- /**
896
- * Compare semver versions.
897
- * @param currentVersion - assumed to be any valid semver version
898
- * @param minimumVersion - must be [major].[minor].[patch], where major, minor, and patch are all numbers
899
- * as it complicates the algorithm if we allow comparisons against minimum pre-release versions.
900
- * @returns
901
- * 0 if the currentVersion equals the minimumVersion
902
- * 1 if the currentVersion is greater than the minimumVersion
903
- * -1 if the minimumVersion is greater than the currentVersion
904
- */
905
- export function semverCompare(currentVersion, minimumVersion) {
906
- const minimumValues = minimumVersion.split(".").map((value) => {
907
- assert(isNaN(+value) === false, 0x2fa /* Expected real numbers in minimum version! */);
908
- return Number.parseInt(value, 10);
909
- });
910
- assert(minimumValues.length === 3, 0x2fb /* Expected minimumVersion to be [major].[minor].[patch] */);
911
- const [minMajor, minMinor, minPatch] = minimumValues;
912
- const currentValuesString = currentVersion.split(/\W/);
913
- assert(currentValuesString.length >= 3, 0x2fc /* Expected version to match semver rules! */);
914
- const currentValues = currentValuesString.slice(0, 3).map((value) => {
915
- assert(isNaN(+value) === false, 0x2fd /* Expected real numbers in minimum version! */);
916
- return Number.parseInt(value, 10);
917
- });
918
- const [cMajor, cMinor, cPatch] = currentValues;
919
- if (cMajor > minMajor) {
920
- return 1;
921
- }
922
- else if (minMajor > cMajor) {
923
- return -1;
924
- }
925
- if (cMinor > minMinor) {
926
- return 1;
927
- }
928
- else if (minMinor > cMinor) {
929
- return -1;
930
- }
931
- if (cPatch > minPatch) {
932
- return 1;
933
- }
934
- else if (minPatch > cPatch) {
935
- return -1;
936
- }
937
- if (currentValuesString.length === 3) {
938
- return 0;
939
- }
940
- return -1;
941
- }
942
868
  //# sourceMappingURL=garbageCollection.js.map