@fluidframework/container-runtime 2.0.0-internal.6.4.0 → 2.0.0-internal.7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/dist/blobManager.d.ts +3 -6
  3. package/dist/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager.js +23 -48
  5. package/dist/blobManager.js.map +1 -1
  6. package/dist/containerHandleContext.js +3 -3
  7. package/dist/containerHandleContext.js.map +1 -1
  8. package/dist/containerRuntime.d.ts +13 -14
  9. package/dist/containerRuntime.d.ts.map +1 -1
  10. package/dist/containerRuntime.js +253 -237
  11. package/dist/containerRuntime.js.map +1 -1
  12. package/dist/dataStore.js +9 -9
  13. package/dist/dataStore.js.map +1 -1
  14. package/dist/dataStoreContext.d.ts +2 -3
  15. package/dist/dataStoreContext.d.ts.map +1 -1
  16. package/dist/dataStoreContext.js +88 -87
  17. package/dist/dataStoreContext.js.map +1 -1
  18. package/dist/dataStoreRegistry.js +3 -3
  19. package/dist/dataStoreRegistry.js.map +1 -1
  20. package/dist/dataStores.d.ts +0 -16
  21. package/dist/dataStores.d.ts.map +1 -1
  22. package/dist/dataStores.js +0 -48
  23. package/dist/dataStores.js.map +1 -1
  24. package/dist/deltaManagerProxyBase.js +4 -4
  25. package/dist/deltaManagerProxyBase.js.map +1 -1
  26. package/dist/deltaManagerSummarizerProxy.js +6 -6
  27. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  28. package/dist/deltaScheduler.js.map +1 -1
  29. package/dist/gc/garbageCollection.d.ts +12 -3
  30. package/dist/gc/garbageCollection.d.ts.map +1 -1
  31. package/dist/gc/garbageCollection.js +54 -31
  32. package/dist/gc/garbageCollection.js.map +1 -1
  33. package/dist/gc/gcConfigs.d.ts +1 -0
  34. package/dist/gc/gcConfigs.d.ts.map +1 -1
  35. package/dist/gc/gcConfigs.js +12 -2
  36. package/dist/gc/gcConfigs.js.map +1 -1
  37. package/dist/gc/gcDefinitions.d.ts +25 -22
  38. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  39. package/dist/gc/gcDefinitions.js.map +1 -1
  40. package/dist/gc/gcTelemetry.d.ts +13 -7
  41. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  42. package/dist/gc/gcTelemetry.js +74 -42
  43. package/dist/gc/gcTelemetry.js.map +1 -1
  44. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  45. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  46. package/dist/gc/index.d.ts +2 -2
  47. package/dist/gc/index.d.ts.map +1 -1
  48. package/dist/gc/index.js +1 -5
  49. package/dist/gc/index.js.map +1 -1
  50. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  51. package/dist/id-compressor/idCompressor.js.map +1 -1
  52. package/dist/id-compressor/identifiers.d.ts +3 -3
  53. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  54. package/dist/messageTypes.d.ts +17 -17
  55. package/dist/messageTypes.d.ts.map +1 -1
  56. package/dist/messageTypes.js +1 -1
  57. package/dist/messageTypes.js.map +1 -1
  58. package/dist/opLifecycle/batchManager.js +6 -6
  59. package/dist/opLifecycle/batchManager.js.map +1 -1
  60. package/dist/opLifecycle/definitions.d.ts +2 -2
  61. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  62. package/dist/packageVersion.d.ts +1 -1
  63. package/dist/packageVersion.js +1 -1
  64. package/dist/packageVersion.js.map +1 -1
  65. package/dist/pendingStateManager.d.ts +3 -19
  66. package/dist/pendingStateManager.d.ts.map +1 -1
  67. package/dist/pendingStateManager.js +20 -39
  68. package/dist/pendingStateManager.js.map +1 -1
  69. package/dist/summary/orderedClientElection.d.ts +3 -3
  70. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  71. package/dist/summary/orderedClientElection.js +54 -54
  72. package/dist/summary/orderedClientElection.js.map +1 -1
  73. package/dist/summary/runWhileConnectedCoordinator.js +6 -6
  74. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  75. package/dist/summary/runningSummarizer.js +37 -37
  76. package/dist/summary/runningSummarizer.js.map +1 -1
  77. package/dist/summary/summarizer.d.ts.map +1 -1
  78. package/dist/summary/summarizer.js +8 -6
  79. package/dist/summary/summarizer.js.map +1 -1
  80. package/dist/summary/summarizerClientElection.js +6 -6
  81. package/dist/summary/summarizerClientElection.js.map +1 -1
  82. package/dist/summary/summarizerHeuristics.js +9 -9
  83. package/dist/summary/summarizerHeuristics.js.map +1 -1
  84. package/dist/summary/summarizerNode/summarizerNode.js +7 -7
  85. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  86. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  87. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  88. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  89. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  90. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  91. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  92. package/dist/summary/summarizerTypes.d.ts +12 -12
  93. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  94. package/dist/summary/summaryCollection.d.ts +2 -2
  95. package/dist/summary/summaryCollection.d.ts.map +1 -1
  96. package/dist/summary/summaryCollection.js +21 -21
  97. package/dist/summary/summaryCollection.js.map +1 -1
  98. package/dist/summary/summaryFormat.d.ts +5 -5
  99. package/dist/summary/summaryFormat.d.ts.map +1 -1
  100. package/dist/summary/summaryGenerator.d.ts +3 -3
  101. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  102. package/dist/summary/summaryManager.js +7 -7
  103. package/dist/summary/summaryManager.js.map +1 -1
  104. package/dist/throttler.js +16 -16
  105. package/dist/throttler.js.map +1 -1
  106. package/dist/tsdoc-metadata.json +1 -1
  107. package/lib/blobManager.d.ts +3 -6
  108. package/lib/blobManager.d.ts.map +1 -1
  109. package/lib/blobManager.js +24 -49
  110. package/lib/blobManager.js.map +1 -1
  111. package/lib/containerHandleContext.js +3 -3
  112. package/lib/containerHandleContext.js.map +1 -1
  113. package/lib/containerRuntime.d.ts +13 -14
  114. package/lib/containerRuntime.d.ts.map +1 -1
  115. package/lib/containerRuntime.js +249 -235
  116. package/lib/containerRuntime.js.map +1 -1
  117. package/lib/dataStore.js +9 -9
  118. package/lib/dataStore.js.map +1 -1
  119. package/lib/dataStoreContext.d.ts +2 -3
  120. package/lib/dataStoreContext.d.ts.map +1 -1
  121. package/lib/dataStoreContext.js +89 -88
  122. package/lib/dataStoreContext.js.map +1 -1
  123. package/lib/dataStoreRegistry.js +3 -3
  124. package/lib/dataStoreRegistry.js.map +1 -1
  125. package/lib/dataStores.d.ts +0 -16
  126. package/lib/dataStores.d.ts.map +1 -1
  127. package/lib/dataStores.js +2 -50
  128. package/lib/dataStores.js.map +1 -1
  129. package/lib/deltaManagerProxyBase.js +4 -4
  130. package/lib/deltaManagerProxyBase.js.map +1 -1
  131. package/lib/deltaManagerSummarizerProxy.js +6 -6
  132. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  133. package/lib/deltaScheduler.js.map +1 -1
  134. package/lib/gc/garbageCollection.d.ts +12 -3
  135. package/lib/gc/garbageCollection.d.ts.map +1 -1
  136. package/lib/gc/garbageCollection.js +55 -32
  137. package/lib/gc/garbageCollection.js.map +1 -1
  138. package/lib/gc/gcConfigs.d.ts +1 -0
  139. package/lib/gc/gcConfigs.d.ts.map +1 -1
  140. package/lib/gc/gcConfigs.js +14 -4
  141. package/lib/gc/gcConfigs.js.map +1 -1
  142. package/lib/gc/gcDefinitions.d.ts +25 -22
  143. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  144. package/lib/gc/gcDefinitions.js.map +1 -1
  145. package/lib/gc/gcTelemetry.d.ts +13 -7
  146. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  147. package/lib/gc/gcTelemetry.js +74 -42
  148. package/lib/gc/gcTelemetry.js.map +1 -1
  149. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  150. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  151. package/lib/gc/index.d.ts +2 -2
  152. package/lib/gc/index.d.ts.map +1 -1
  153. package/lib/gc/index.js +2 -2
  154. package/lib/gc/index.js.map +1 -1
  155. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  156. package/lib/id-compressor/idCompressor.js.map +1 -1
  157. package/lib/id-compressor/identifiers.d.ts +3 -3
  158. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  159. package/lib/messageTypes.d.ts +17 -17
  160. package/lib/messageTypes.d.ts.map +1 -1
  161. package/lib/opLifecycle/batchManager.js +6 -6
  162. package/lib/opLifecycle/batchManager.js.map +1 -1
  163. package/lib/opLifecycle/definitions.d.ts +2 -2
  164. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  165. package/lib/packageVersion.d.ts +1 -1
  166. package/lib/packageVersion.js +1 -1
  167. package/lib/packageVersion.js.map +1 -1
  168. package/lib/pendingStateManager.d.ts +3 -19
  169. package/lib/pendingStateManager.d.ts.map +1 -1
  170. package/lib/pendingStateManager.js +20 -39
  171. package/lib/pendingStateManager.js.map +1 -1
  172. package/lib/summary/orderedClientElection.d.ts +3 -3
  173. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  174. package/lib/summary/orderedClientElection.js +54 -54
  175. package/lib/summary/orderedClientElection.js.map +1 -1
  176. package/lib/summary/runWhileConnectedCoordinator.js +6 -6
  177. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  178. package/lib/summary/runningSummarizer.js +37 -37
  179. package/lib/summary/runningSummarizer.js.map +1 -1
  180. package/lib/summary/summarizer.d.ts.map +1 -1
  181. package/lib/summary/summarizer.js +8 -6
  182. package/lib/summary/summarizer.js.map +1 -1
  183. package/lib/summary/summarizerClientElection.js +6 -6
  184. package/lib/summary/summarizerClientElection.js.map +1 -1
  185. package/lib/summary/summarizerHeuristics.js +9 -9
  186. package/lib/summary/summarizerHeuristics.js.map +1 -1
  187. package/lib/summary/summarizerNode/summarizerNode.js +7 -7
  188. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  189. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  190. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  191. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  192. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  193. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  194. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  195. package/lib/summary/summarizerTypes.d.ts +12 -12
  196. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  197. package/lib/summary/summaryCollection.d.ts +2 -2
  198. package/lib/summary/summaryCollection.d.ts.map +1 -1
  199. package/lib/summary/summaryCollection.js +21 -21
  200. package/lib/summary/summaryCollection.js.map +1 -1
  201. package/lib/summary/summaryFormat.d.ts +5 -5
  202. package/lib/summary/summaryFormat.d.ts.map +1 -1
  203. package/lib/summary/summaryGenerator.d.ts +3 -3
  204. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  205. package/lib/summary/summaryManager.js +6 -6
  206. package/lib/summary/summaryManager.js.map +1 -1
  207. package/lib/throttler.js +16 -16
  208. package/lib/throttler.js.map +1 -1
  209. package/package.json +53 -21
  210. package/src/blobManager.ts +18 -58
  211. package/src/containerRuntime.ts +68 -49
  212. package/src/dataStore.ts +1 -1
  213. package/src/dataStoreContext.ts +18 -14
  214. package/src/dataStores.ts +2 -80
  215. package/src/gc/garbageCollection.ts +53 -24
  216. package/src/gc/gcConfigs.ts +22 -4
  217. package/src/gc/gcDefinitions.ts +23 -20
  218. package/src/gc/gcEarlyAdoption.md +1 -1
  219. package/src/gc/gcTelemetry.ts +103 -56
  220. package/src/gc/index.ts +0 -4
  221. package/src/packageVersion.ts +1 -1
  222. package/src/pendingStateManager.ts +7 -46
  223. package/src/summary/summarizer.ts +3 -1
package/src/dataStores.ts CHANGED
@@ -50,12 +50,7 @@ import { buildSnapshotTree } from "@fluidframework/driver-utils";
50
50
  import { assert, Lazy } from "@fluidframework/core-utils";
51
51
  import { v4 as uuid } from "uuid";
52
52
  import { DataStoreContexts } from "./dataStoreContexts";
53
- import {
54
- ContainerRuntime,
55
- defaultRuntimeHeaderData,
56
- RuntimeHeaderData,
57
- TombstoneResponseHeaderKey,
58
- } from "./containerRuntime";
53
+ import { ContainerRuntime, defaultRuntimeHeaderData, RuntimeHeaderData } from "./containerRuntime";
59
54
  import {
60
55
  FluidDataStoreContext,
61
56
  RemoteFluidDataStoreContext,
@@ -65,12 +60,7 @@ import {
65
60
  } from "./dataStoreContext";
66
61
  import { StorageServiceWithAttachBlobs } from "./storageServiceWithAttachBlobs";
67
62
  import { IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
68
- import {
69
- GCNodeType,
70
- disableDatastoreSweepKey,
71
- throwOnTombstoneLoadKey,
72
- sendGCUnexpectedUsageEvent,
73
- } from "./gc";
63
+ import { GCNodeType, disableDatastoreSweepKey, sendGCUnexpectedUsageEvent } from "./gc";
74
64
  import {
75
65
  summarizerClientType,
76
66
  IContainerRuntimeMetadata,
@@ -104,8 +94,6 @@ export class DataStores implements IDisposable {
104
94
  // Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
105
95
  // root data stores that are added.
106
96
  private dataStoresSinceLastGC: string[] = [];
107
- /** If true, throw an error when a tombstone data store is retrieved. */
108
- private readonly throwOnTombstoneLoad: boolean;
109
97
  // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
110
98
  // the container runtime to other nodes.
111
99
  private readonly containerRuntimeHandle: IFluidHandle;
@@ -140,12 +128,6 @@ export class DataStores implements IDisposable {
140
128
  this.runtime.IFluidHandleContext,
141
129
  );
142
130
 
143
- // Tombstone should only throw when the feature flag is enabled and the client isn't a summarizer
144
- this.throwOnTombstoneLoad =
145
- this.mc.config.getBoolean(throwOnTombstoneLoadKey) === true &&
146
- this.runtime.gcTombstoneEnforcementAllowed &&
147
- this.runtime.clientDetails.type !== summarizerClientType;
148
-
149
131
  // Extract stores stored inside the snapshot
150
132
  const fluidDataStores = new Map<string, ISnapshotTree>();
151
133
  if (baseSnapshot) {
@@ -455,9 +437,6 @@ export class DataStores implements IDisposable {
455
437
  const request: IRequest = { url: id };
456
438
  throw responseToException(create404Response(request), request);
457
439
  }
458
-
459
- this.validateNotTombstoned(context, requestHeaderData);
460
-
461
440
  return context;
462
441
  }
463
442
 
@@ -477,8 +456,6 @@ export class DataStores implements IDisposable {
477
456
  if (context === undefined) {
478
457
  return undefined;
479
458
  }
480
- // Check if the data store is tombstoned. If so, we want to log a telemetry event.
481
- this.checkIfTombstoned(context, requestHeaderData);
482
459
  return context;
483
460
  }
484
461
 
@@ -529,61 +506,6 @@ export class DataStores implements IDisposable {
529
506
  }
530
507
  }
531
508
 
532
- /**
533
- * Checks if the data store has not been marked as tombstone by GC or not.
534
- * @param context - the data store context in question
535
- * @param requestHeaderData - the request header information to log if the validation detects the data store has been tombstoned
536
- * @returns true if the data store is tombstoned. Otherwise, returns false.
537
- */
538
- private checkIfTombstoned(
539
- context: FluidDataStoreContext,
540
- requestHeaderData: RuntimeHeaderData,
541
- ) {
542
- if (!context.tombstoned) {
543
- return false;
544
- }
545
- const logErrorEvent = this.throwOnTombstoneLoad && !requestHeaderData.allowTombstone;
546
- sendGCUnexpectedUsageEvent(
547
- this.mc,
548
- {
549
- eventName: "GC_Tombstone_DataStore_Requested",
550
- category: logErrorEvent ? "error" : "generic",
551
- isSummarizerClient: this.runtime.clientDetails.type === summarizerClientType,
552
- id: context.id,
553
- headers: JSON.stringify(requestHeaderData),
554
- gcTombstoneEnforcementAllowed: this.runtime.gcTombstoneEnforcementAllowed,
555
- },
556
- context.isLoaded ? context.packagePath : undefined,
557
- );
558
- return true;
559
- }
560
-
561
- /**
562
- * Validates that the data store context requested has not been marked as tombstone by GC.
563
- * @param context - the data store context in question
564
- * @param request - the request information to log if the validation detects the data store has been tombstoned
565
- * @param requestHeaderData - the request header information to log if the validation detects the data store has been tombstoned
566
- */
567
- private validateNotTombstoned(
568
- context: FluidDataStoreContext,
569
- requestHeaderData: RuntimeHeaderData,
570
- ) {
571
- if (this.checkIfTombstoned(context, requestHeaderData)) {
572
- // The requested data store is removed by gc. Create a 404 gc response exception.
573
- const request: IRequest = { url: context.id };
574
- const error = responseToException(
575
- createResponseError(404, "DataStore was deleted", request, {
576
- [TombstoneResponseHeaderKey]: true,
577
- }),
578
- request,
579
- );
580
- // Throw an error if configured via options and via request headers.
581
- if (this.throwOnTombstoneLoad && !requestHeaderData.allowTombstone) {
582
- throw error;
583
- }
584
- }
585
- }
586
-
587
509
  public processSignal(fluidDataStoreId: string, message: IInboundSignalMessage, local: boolean) {
588
510
  this.validateNotDeleted(fluidDataStoreId);
589
511
  const context = this.contexts.get(fluidDataStoreId);
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { LazyPromise, Timer } from "@fluidframework/core-utils";
7
- import { IRequest, IRequestHeader } from "@fluidframework/core-interfaces";
7
+ import { IRequest } from "@fluidframework/core-interfaces";
8
8
  import {
9
9
  gcTreeKey,
10
10
  IGarbageCollectionData,
@@ -23,9 +23,9 @@ import {
23
23
  } from "@fluidframework/telemetry-utils";
24
24
 
25
25
  import {
26
- AllowInactiveRequestHeaderKey,
27
26
  InactiveResponseHeaderKey,
28
- RuntimeHeaders,
27
+ RuntimeHeaderData,
28
+ TombstoneResponseHeaderKey,
29
29
  } from "../containerRuntime";
30
30
  import { ClientSessionExpiredError } from "../error";
31
31
  import { IRefreshSummaryResult } from "../summary";
@@ -113,6 +113,19 @@ export class GarbageCollector implements IGarbageCollector {
113
113
  private readonly summaryStateTracker: GCSummaryStateTracker;
114
114
  private readonly telemetryTracker: GCTelemetryTracker;
115
115
 
116
+ /** If false, loading or using a Tombstoned object should merely log, not fail */
117
+ public get tombstoneEnforcementAllowed(): boolean {
118
+ return this.configs.tombstoneEnforcementAllowed;
119
+ }
120
+ /** If true, throw an error when a tombstone data store is retrieved */
121
+ public get throwOnTombstoneLoad(): boolean {
122
+ return this.configs.throwOnTombstoneLoad;
123
+ }
124
+ /** If true, throw an error when a tombstone data store is used */
125
+ public get throwOnTombstoneUsage(): boolean {
126
+ return this.configs.throwOnTombstoneUsage;
127
+ }
128
+
116
129
  /** For a given node path, returns the node's package path. */
117
130
  private readonly getNodePackagePath: (
118
131
  nodePath: string,
@@ -176,7 +189,6 @@ export class GarbageCollector implements IGarbageCollector {
176
189
  this.mc,
177
190
  this.configs,
178
191
  this.isSummarizerClient,
179
- this.runtime.gcTombstoneEnforcementAllowed,
180
192
  createParams.createContainerMetadata,
181
193
  (nodeId: string) => this.runtime.getNodeType(nodeId),
182
194
  (nodeId: string) => this.unreferencedNodesState.get(nodeId),
@@ -850,11 +862,13 @@ export class GarbageCollector implements IGarbageCollector {
850
862
  }
851
863
 
852
864
  /**
853
- * Called when a node with the given id is updated. If the node is inactive, log an error.
865
+ * Called when a node with the given id is updated. If the node is inactive or tombstoned, this will log an error
866
+ * or throw an error if failing on incorrect usage is configured.
854
867
  * @param nodePath - The path of the node that changed.
855
868
  * @param reason - Whether the node was loaded or changed.
856
869
  * @param timestampMs - The timestamp when the node changed.
857
870
  * @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.
871
+ * @param request - The original request for loads to preserve it in telemetry.
858
872
  * @param requestHeaders - If the node was loaded via request path, the headers in the request.
859
873
  */
860
874
  public nodeUpdated(
@@ -862,12 +876,15 @@ export class GarbageCollector implements IGarbageCollector {
862
876
  reason: "Loaded" | "Changed",
863
877
  timestampMs?: number,
864
878
  packagePath?: readonly string[],
865
- requestHeaders?: IRequestHeader,
879
+ request?: IRequest,
880
+ headerData?: RuntimeHeaderData,
866
881
  ) {
867
882
  if (!this.configs.shouldRunGC) {
868
883
  return;
869
884
  }
870
885
 
886
+ const isTombstoned = this.tombstones.includes(nodePath);
887
+
871
888
  // This will log if appropriate
872
889
  this.telemetryTracker.nodeUsed({
873
890
  id: nodePath,
@@ -876,32 +893,44 @@ export class GarbageCollector implements IGarbageCollector {
876
893
  timestampMs ?? this.runtime.getCurrentReferenceTimestampMs(),
877
894
  packagePath,
878
895
  completedGCRuns: this.completedRuns,
879
- isTombstoned: this.tombstones.includes(nodePath),
896
+ isTombstoned,
880
897
  lastSummaryTime: this.getLastSummaryTimestampMs(),
881
- viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],
898
+ headers: headerData,
882
899
  });
883
900
 
884
- // Unless this is a Loaded event, we're done after telemetry tracking
885
- if (reason !== "Loaded") {
901
+ const nodeType = this.runtime.getNodeType(nodePath);
902
+
903
+ // Unless this is a Loaded event for a Blob or DataStore, we're done after telemetry tracking
904
+ if (reason !== "Loaded" || ![GCNodeType.Blob, GCNodeType.DataStore].includes(nodeType)) {
886
905
  return;
887
906
  }
888
907
 
889
- // We may throw when loading an Inactive object, depending on these preconditions
890
- const shouldThrowOnInactiveLoad =
891
- !this.isSummarizerClient &&
892
- this.configs.throwOnInactiveLoad === true &&
893
- requestHeaders?.[AllowInactiveRequestHeaderKey] !== true;
894
- const state = this.unreferencedNodesState.get(nodePath)?.state;
895
-
896
- if (shouldThrowOnInactiveLoad && state === "Inactive") {
897
- const request: IRequest = { url: nodePath };
898
- const error = responseToException(
899
- createResponseError(404, "Object is inactive", request, {
900
- [InactiveResponseHeaderKey]: true,
908
+ const errorRequest: IRequest = request ?? { url: nodePath };
909
+ // If the object is tombstoned and tombstone enforcement is configured, throw an error.
910
+ if (isTombstoned && this.throwOnTombstoneLoad && headerData?.allowTombstone !== true) {
911
+ // The requested data store is removed by gc. Create a 404 gc response exception.
912
+ throw responseToException(
913
+ createResponseError(404, `${nodeType} was tombstoned`, errorRequest, {
914
+ [TombstoneResponseHeaderKey]: true,
901
915
  }),
902
- request,
916
+ errorRequest,
903
917
  );
904
- throw error;
918
+ }
919
+
920
+ // If the object is inactive and inactive enforcement is configured, throw an error.
921
+ if (this.unreferencedNodesState.get(nodePath)?.state === "Inactive") {
922
+ const shouldThrowOnInactiveLoad =
923
+ !this.isSummarizerClient &&
924
+ this.configs.throwOnInactiveLoad === true &&
925
+ headerData?.allowInactive !== true;
926
+ if (shouldThrowOnInactiveLoad) {
927
+ throw responseToException(
928
+ createResponseError(404, `${nodeType} is inactive`, errorRequest, {
929
+ [InactiveResponseHeaderKey]: true,
930
+ }),
931
+ errorRequest,
932
+ );
933
+ }
905
934
  }
906
935
  }
907
936
 
@@ -24,8 +24,10 @@ import {
24
24
  runSessionExpiryKey,
25
25
  runSweepKey,
26
26
  stableGCVersion,
27
+ throwOnTombstoneLoadKey,
28
+ throwOnTombstoneUsageKey,
27
29
  } from "./gcDefinitions";
28
- import { getGCVersion, shouldAllowGcSweep } from "./gcHelpers";
30
+ import { getGCVersion, shouldAllowGcSweep, shouldAllowGcTombstoneEnforcement } from "./gcHelpers";
29
31
 
30
32
  /**
31
33
  * Generates configurations for the Garbage Collector that it uses to determine what to run and how.
@@ -42,6 +44,7 @@ export function generateGCConfigs(
42
44
  gcOptions: IGCRuntimeOptions;
43
45
  metadata: IContainerRuntimeMetadata | undefined;
44
46
  existing: boolean;
47
+ isSummarizerClient: boolean;
45
48
  },
46
49
  ): IGarbageCollectorConfigs {
47
50
  let gcEnabled: boolean;
@@ -152,8 +155,6 @@ export function generateGCConfigs(
152
155
  throw new UsageError("inactive timeout should not be greater than the sweep timeout");
153
156
  }
154
157
 
155
- const throwOnInactiveLoad: boolean | undefined = createParams.gcOptions.throwOnInactiveLoad;
156
-
157
158
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
158
159
  const testMode =
159
160
  mc.config.getBoolean(gcTestModeKey) ?? createParams.gcOptions.runGCInTestMode === true;
@@ -162,6 +163,20 @@ export function generateGCConfigs(
162
163
  const tombstoneMode = !shouldRunSweep && mc.config.getBoolean(disableTombstoneKey) !== true;
163
164
  const runFullGC = createParams.gcOptions.runFullGC;
164
165
 
166
+ const throwOnInactiveLoad: boolean | undefined = createParams.gcOptions.throwOnInactiveLoad;
167
+ const tombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
168
+ createParams.metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
169
+ createParams.gcOptions[gcTombstoneGenerationOptionName] /* current */,
170
+ );
171
+ const throwOnTombstoneLoad =
172
+ mc.config.getBoolean(throwOnTombstoneLoadKey) === true &&
173
+ tombstoneEnforcementAllowed &&
174
+ !createParams.isSummarizerClient;
175
+ const throwOnTombstoneUsage =
176
+ mc.config.getBoolean(throwOnTombstoneUsageKey) === true &&
177
+ tombstoneEnforcementAllowed &&
178
+ !createParams.isSummarizerClient;
179
+
165
180
  return {
166
181
  gcEnabled,
167
182
  sweepEnabled,
@@ -173,10 +188,13 @@ export function generateGCConfigs(
173
188
  sessionExpiryTimeoutMs,
174
189
  sweepTimeoutMs,
175
190
  inactiveTimeoutMs,
176
- throwOnInactiveLoad,
177
191
  persistedGcFeatureMatrix,
178
192
  gcVersionInBaseSnapshot,
179
193
  gcVersionInEffect,
194
+ throwOnInactiveLoad,
195
+ tombstoneEnforcementAllowed,
196
+ throwOnTombstoneLoad,
197
+ throwOnTombstoneUsage,
180
198
  };
181
199
  }
182
200
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { ICriticalContainerError } from "@fluidframework/container-definitions";
7
- import { IRequestHeader } from "@fluidframework/core-interfaces";
7
+ import { IRequest } from "@fluidframework/core-interfaces";
8
8
  import { ISnapshotTree } from "@fluidframework/protocol-definitions";
9
9
  import {
10
10
  IGarbageCollectionData,
@@ -19,6 +19,7 @@ import {
19
19
  ICreateContainerMetadata,
20
20
  IRefreshSummaryResult,
21
21
  } from "../summary";
22
+ import { RuntimeHeaderData } from "../containerRuntime";
22
23
 
23
24
  export type GCVersion = number;
24
25
 
@@ -193,8 +194,6 @@ export interface IGarbageCollectionRuntime {
193
194
  getNodeType(nodePath: string): GCNodeType;
194
195
  /** Called when the runtime should close because of an error. */
195
196
  closeFn: (error?: ICriticalContainerError) => void;
196
- /** If false, loading or using a Tombstoned object should merely log, not fail */
197
- gcTombstoneEnforcementAllowed: boolean;
198
197
  }
199
198
 
200
199
  /** Defines the contract for the garbage collector. */
@@ -205,6 +204,12 @@ export interface IGarbageCollector {
205
204
  readonly summaryStateNeedsReset: boolean;
206
205
  /** The count of data stores whose GC state updated since the last summary. */
207
206
  readonly updatedDSCountSinceLastSummary: number;
207
+ /** Tells whether tombstone feature is enabled and enforced. */
208
+ readonly tombstoneEnforcementAllowed: boolean;
209
+ /** Tells whether loading a tombstone object should fail or merely log. */
210
+ readonly throwOnTombstoneLoad: boolean;
211
+ /** Tells whether using a tombstone object should fail or merely log. */
212
+ readonly throwOnTombstoneUsage: boolean;
208
213
  /** Initialize the state from the base snapshot after its creation. */
209
214
  initializeBaseState(): Promise<void>;
210
215
  /** Run garbage collection and update the reference / used state of the system. */
@@ -228,13 +233,17 @@ export interface IGarbageCollector {
228
233
  getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase>;
229
234
  /** Called when the latest summary of the system has been refreshed. */
230
235
  refreshLatestSummary(result: IRefreshSummaryResult): Promise<void>;
231
- /** Called when a node is updated. Used to detect and log when an inactive node is changed or loaded. */
236
+ /**
237
+ * Called when a node with the given path is updated. If the node is inactive or tombstoned, this will log an error
238
+ * or throw an error if failing on incorrect usage is configured.
239
+ */
232
240
  nodeUpdated(
233
241
  nodePath: string,
234
242
  reason: "Loaded" | "Changed",
235
243
  timestampMs?: number,
236
244
  packagePath?: readonly string[],
237
- requestHeaders?: IRequestHeader,
245
+ request?: IRequest,
246
+ headerData?: RuntimeHeaderData,
238
247
  ): void;
239
248
  /** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */
240
249
  addedOutboundReference(fromNodePath: string, toNodePath: string): void;
@@ -267,24 +276,12 @@ export interface IGCRuntimeOptions {
267
276
  * GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
268
277
  * and marked as such in the summary. This option enables the mark phase.
269
278
  * In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
270
- * Sweep phase can be enabled via the "sweepAllowed" option.
279
+ * Sweep phase can be enabled using the "gcSweepGeneration" option.
271
280
  *
272
281
  * Note: This setting is persisted in the container's summary and cannot be changed.
273
282
  */
274
283
  gcAllowed?: boolean;
275
284
 
276
- /**
277
- * @deprecated - @see gcSweepGenerationOptionName and @see GCFeatureMatrix.sweepGeneration
278
- *
279
- * Flag that if true, enables GC's sweep phase for a new container.
280
- *
281
- * This will allow GC to eventually delete unreferenced objects from the container.
282
- * This flag should only be set to true if "gcAllowed" is true.
283
- *
284
- * Note: This setting is persisted in the container's summary and cannot be changed.
285
- */
286
- sweepAllowed?: boolean;
287
-
288
285
  /**
289
286
  * Flag that if true, will disable garbage collection for the session.
290
287
  * Can be used to disable running GC on containers where it is allowed via the gcAllowed option.
@@ -344,8 +341,6 @@ export interface IGarbageCollectorConfigs {
344
341
  readonly sweepTimeoutMs: number | undefined;
345
342
  /** The time after which an unreferenced node is inactive. */
346
343
  readonly inactiveTimeoutMs: number;
347
- /** It is easier for users to diagnose InactiveObject usage if we throw on load, which this option enables */
348
- readonly throwOnInactiveLoad: boolean | undefined;
349
344
  /** Tracks whether GC should run in test mode. In this mode, unreferenced objects are deleted immediately. */
350
345
  readonly testMode: boolean;
351
346
  /**
@@ -361,6 +356,14 @@ export interface IGarbageCollectorConfigs {
361
356
  readonly gcVersionInBaseSnapshot: GCVersion | undefined;
362
357
  /** The current version of GC data in the running code */
363
358
  readonly gcVersionInEffect: GCVersion;
359
+ /** It is easier for users to diagnose InactiveObject usage if we throw on load, which this option enables */
360
+ readonly throwOnInactiveLoad: boolean | undefined;
361
+ /** If false, loading or using a Tombstoned object should merely log, not fail */
362
+ readonly tombstoneEnforcementAllowed: boolean;
363
+ /** If true, throw an error when a tombstone data store is retrieved */
364
+ readonly throwOnTombstoneLoad: boolean;
365
+ /** If true, throw an error when a tombstone data store is used. */
366
+ readonly throwOnTombstoneUsage: boolean;
364
367
  }
365
368
 
366
369
  /** The state of node that is unreferenced. */
@@ -78,7 +78,7 @@ For this to work, you must disable the `Fluid.GarbageCollection.ThrowOnTombstone
78
78
 
79
79
  When a Tombstoned object (via `handle.get()`) fails to load, the 404 response error object has an `underlyingResponseHeaders` with the
80
80
  `isTombstoned` flag set to true: i.e. `error.underlyingResponseHeaders?.isTombstoned === true`. In this case,
81
- you may turn around and use `IContainerRuntime.resolveHandle` with `allowTombstone: true` in `IRequest.headers` to request
81
+ you may turn around and use `IContainerRuntimeWithResolveHandle_Deprecated.resolveHandle` with `allowTombstone: true` in `IRequest.headers` to request
82
82
  the object again - this time it will succeed.
83
83
 
84
84
  To be very clear once again - This path uses deprecated APIs (`resolveHandle`) and comes with no guarantees of support.