@fluidframework/container-runtime 2.0.0-dev.7.4.0.217212 → 2.0.0-dev.7.4.0.221926

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 (233) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/api-extractor.json +0 -3
  3. package/api-report/container-runtime.api.md +77 -73
  4. package/dist/blobManager.d.ts +4 -4
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/container-runtime-alpha.d.ts +1361 -132
  8. package/dist/container-runtime-beta.d.ts +40 -2
  9. package/dist/container-runtime-public.d.ts +40 -2
  10. package/dist/container-runtime-untrimmed.d.ts +106 -93
  11. package/dist/containerRuntime.d.ts +19 -17
  12. package/dist/containerRuntime.d.ts.map +1 -1
  13. package/dist/containerRuntime.js +44 -24
  14. package/dist/containerRuntime.js.map +1 -1
  15. package/dist/dataStores.d.ts +10 -15
  16. package/dist/dataStores.d.ts.map +1 -1
  17. package/dist/dataStores.js +63 -36
  18. package/dist/dataStores.js.map +1 -1
  19. package/dist/gc/garbageCollection.d.ts +29 -10
  20. package/dist/gc/garbageCollection.d.ts.map +1 -1
  21. package/dist/gc/garbageCollection.js +149 -67
  22. package/dist/gc/garbageCollection.js.map +1 -1
  23. package/dist/gc/gcConfigs.d.ts.map +1 -1
  24. package/dist/gc/gcConfigs.js +34 -37
  25. package/dist/gc/gcConfigs.js.map +1 -1
  26. package/dist/gc/gcDefinitions.d.ts +97 -44
  27. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  28. package/dist/gc/gcDefinitions.js +26 -16
  29. package/dist/gc/gcDefinitions.js.map +1 -1
  30. package/dist/gc/gcHelpers.d.ts +18 -25
  31. package/dist/gc/gcHelpers.d.ts.map +1 -1
  32. package/dist/gc/gcHelpers.js +29 -45
  33. package/dist/gc/gcHelpers.js.map +1 -1
  34. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  35. package/dist/gc/gcTelemetry.js +14 -3
  36. package/dist/gc/gcTelemetry.js.map +1 -1
  37. package/dist/gc/gcUnreferencedStateTracker.d.ts +11 -5
  38. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  39. package/dist/gc/gcUnreferencedStateTracker.js +43 -19
  40. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  41. package/dist/gc/index.d.ts +1 -1
  42. package/dist/gc/index.d.ts.map +1 -1
  43. package/dist/gc/index.js +4 -4
  44. package/dist/gc/index.js.map +1 -1
  45. package/dist/index.d.ts +13 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +16 -5
  48. package/dist/index.js.map +1 -1
  49. package/dist/messageTypes.d.ts +13 -5
  50. package/dist/messageTypes.d.ts.map +1 -1
  51. package/dist/messageTypes.js +5 -0
  52. package/dist/messageTypes.js.map +1 -1
  53. package/dist/packageVersion.d.ts +1 -1
  54. package/dist/packageVersion.js +1 -1
  55. package/dist/packageVersion.js.map +1 -1
  56. package/dist/pendingStateManager.d.ts +1 -0
  57. package/dist/pendingStateManager.d.ts.map +1 -1
  58. package/dist/pendingStateManager.js +1 -0
  59. package/dist/pendingStateManager.js.map +1 -1
  60. package/dist/summary/orderedClientElection.d.ts +1 -1
  61. package/dist/summary/orderedClientElection.js.map +1 -1
  62. package/dist/summary/summarizerTypes.d.ts +28 -28
  63. package/dist/summary/summarizerTypes.js.map +1 -1
  64. package/dist/summary/summaryCollection.d.ts +3 -3
  65. package/dist/summary/summaryCollection.js.map +1 -1
  66. package/dist/summary/summaryFormat.d.ts +3 -3
  67. package/dist/summary/summaryFormat.js.map +1 -1
  68. package/lib/blobManager.d.ts +4 -4
  69. package/lib/blobManager.d.ts.map +1 -1
  70. package/lib/blobManager.js.map +1 -1
  71. package/lib/container-runtime-alpha.d.ts +1361 -132
  72. package/lib/container-runtime-beta.d.ts +40 -2
  73. package/lib/container-runtime-public.d.ts +40 -2
  74. package/lib/container-runtime-untrimmed.d.ts +106 -93
  75. package/lib/containerRuntime.d.ts +19 -17
  76. package/lib/containerRuntime.d.ts.map +1 -1
  77. package/lib/containerRuntime.js +46 -26
  78. package/lib/containerRuntime.js.map +1 -1
  79. package/lib/dataStores.d.ts +10 -15
  80. package/lib/dataStores.d.ts.map +1 -1
  81. package/lib/dataStores.js +65 -38
  82. package/lib/dataStores.js.map +1 -1
  83. package/lib/gc/garbageCollection.d.ts +29 -10
  84. package/lib/gc/garbageCollection.d.ts.map +1 -1
  85. package/lib/gc/garbageCollection.js +151 -69
  86. package/lib/gc/garbageCollection.js.map +1 -1
  87. package/lib/gc/gcConfigs.d.ts.map +1 -1
  88. package/lib/gc/gcConfigs.js +37 -40
  89. package/lib/gc/gcConfigs.js.map +1 -1
  90. package/lib/gc/gcDefinitions.d.ts +97 -44
  91. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  92. package/lib/gc/gcDefinitions.js +25 -15
  93. package/lib/gc/gcDefinitions.js.map +1 -1
  94. package/lib/gc/gcHelpers.d.ts +18 -25
  95. package/lib/gc/gcHelpers.d.ts.map +1 -1
  96. package/lib/gc/gcHelpers.js +27 -43
  97. package/lib/gc/gcHelpers.js.map +1 -1
  98. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  99. package/lib/gc/gcTelemetry.js +14 -3
  100. package/lib/gc/gcTelemetry.js.map +1 -1
  101. package/lib/gc/gcUnreferencedStateTracker.d.ts +11 -5
  102. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  103. package/lib/gc/gcUnreferencedStateTracker.js +43 -19
  104. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  105. package/lib/gc/index.d.ts +1 -1
  106. package/lib/gc/index.d.ts.map +1 -1
  107. package/lib/gc/index.js +1 -1
  108. package/lib/gc/index.js.map +1 -1
  109. package/lib/index.d.ts +13 -1
  110. package/lib/index.d.ts.map +1 -1
  111. package/lib/index.js +15 -1
  112. package/lib/index.js.map +1 -1
  113. package/lib/messageTypes.d.ts +13 -5
  114. package/lib/messageTypes.d.ts.map +1 -1
  115. package/lib/messageTypes.js +5 -0
  116. package/lib/messageTypes.js.map +1 -1
  117. package/lib/packageVersion.d.ts +1 -1
  118. package/lib/packageVersion.js +1 -1
  119. package/lib/packageVersion.js.map +1 -1
  120. package/lib/pendingStateManager.d.ts +1 -0
  121. package/lib/pendingStateManager.d.ts.map +1 -1
  122. package/lib/pendingStateManager.js +1 -0
  123. package/lib/pendingStateManager.js.map +1 -1
  124. package/lib/summary/orderedClientElection.d.ts +1 -1
  125. package/lib/summary/orderedClientElection.js.map +1 -1
  126. package/lib/summary/summarizerTypes.d.ts +28 -28
  127. package/lib/summary/summarizerTypes.js.map +1 -1
  128. package/lib/summary/summaryCollection.d.ts +3 -3
  129. package/lib/summary/summaryCollection.js.map +1 -1
  130. package/lib/summary/summaryFormat.d.ts +3 -3
  131. package/lib/summary/summaryFormat.js.map +1 -1
  132. package/package.json +18 -15
  133. package/src/blobManager.ts +5 -5
  134. package/src/containerRuntime.ts +66 -40
  135. package/src/dataStores.ts +118 -59
  136. package/src/gc/garbageCollection.md +14 -15
  137. package/src/gc/garbageCollection.ts +182 -75
  138. package/src/gc/gcConfigs.ts +50 -52
  139. package/src/gc/gcDefinitions.ts +112 -50
  140. package/src/gc/gcHelpers.ts +31 -52
  141. package/src/gc/gcTelemetry.ts +16 -4
  142. package/src/gc/gcUnreferencedStateTracker.ts +61 -22
  143. package/src/gc/index.ts +4 -3
  144. package/src/index.ts +17 -1
  145. package/src/messageTypes.ts +16 -2
  146. package/src/packageVersion.ts +1 -1
  147. package/src/pendingStateManager.ts +1 -0
  148. package/src/summary/orderedClientElection.ts +1 -1
  149. package/src/summary/summarizerTypes.ts +28 -28
  150. package/src/summary/summaryCollection.ts +3 -3
  151. package/src/summary/summaryFormat.ts +3 -3
  152. package/dist/id-compressor/appendOnlySortedMap.d.ts +0 -124
  153. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +0 -1
  154. package/dist/id-compressor/appendOnlySortedMap.js +0 -318
  155. package/dist/id-compressor/appendOnlySortedMap.js.map +0 -1
  156. package/dist/id-compressor/finalSpace.d.ts +0 -29
  157. package/dist/id-compressor/finalSpace.d.ts.map +0 -1
  158. package/dist/id-compressor/finalSpace.js +0 -62
  159. package/dist/id-compressor/finalSpace.js.map +0 -1
  160. package/dist/id-compressor/idCompressor.d.ts +0 -54
  161. package/dist/id-compressor/idCompressor.d.ts.map +0 -1
  162. package/dist/id-compressor/idCompressor.js +0 -495
  163. package/dist/id-compressor/idCompressor.js.map +0 -1
  164. package/dist/id-compressor/identifiers.d.ts +0 -32
  165. package/dist/id-compressor/identifiers.d.ts.map +0 -1
  166. package/dist/id-compressor/identifiers.js +0 -15
  167. package/dist/id-compressor/identifiers.js.map +0 -1
  168. package/dist/id-compressor/index.d.ts +0 -13
  169. package/dist/id-compressor/index.d.ts.map +0 -1
  170. package/dist/id-compressor/index.js +0 -32
  171. package/dist/id-compressor/index.js.map +0 -1
  172. package/dist/id-compressor/persistanceUtilities.d.ts +0 -22
  173. package/dist/id-compressor/persistanceUtilities.d.ts.map +0 -1
  174. package/dist/id-compressor/persistanceUtilities.js +0 -43
  175. package/dist/id-compressor/persistanceUtilities.js.map +0 -1
  176. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +0 -46
  177. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +0 -1
  178. package/dist/id-compressor/sessionSpaceNormalizer.js +0 -80
  179. package/dist/id-compressor/sessionSpaceNormalizer.js.map +0 -1
  180. package/dist/id-compressor/sessions.d.ts +0 -115
  181. package/dist/id-compressor/sessions.d.ts.map +0 -1
  182. package/dist/id-compressor/sessions.js +0 -305
  183. package/dist/id-compressor/sessions.js.map +0 -1
  184. package/dist/id-compressor/utilities.d.ts +0 -52
  185. package/dist/id-compressor/utilities.d.ts.map +0 -1
  186. package/dist/id-compressor/utilities.js +0 -169
  187. package/dist/id-compressor/utilities.js.map +0 -1
  188. package/lib/id-compressor/appendOnlySortedMap.d.ts +0 -124
  189. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +0 -1
  190. package/lib/id-compressor/appendOnlySortedMap.js +0 -314
  191. package/lib/id-compressor/appendOnlySortedMap.js.map +0 -1
  192. package/lib/id-compressor/finalSpace.d.ts +0 -29
  193. package/lib/id-compressor/finalSpace.d.ts.map +0 -1
  194. package/lib/id-compressor/finalSpace.js +0 -58
  195. package/lib/id-compressor/finalSpace.js.map +0 -1
  196. package/lib/id-compressor/idCompressor.d.ts +0 -54
  197. package/lib/id-compressor/idCompressor.d.ts.map +0 -1
  198. package/lib/id-compressor/idCompressor.js +0 -491
  199. package/lib/id-compressor/idCompressor.js.map +0 -1
  200. package/lib/id-compressor/identifiers.d.ts +0 -32
  201. package/lib/id-compressor/identifiers.d.ts.map +0 -1
  202. package/lib/id-compressor/identifiers.js +0 -11
  203. package/lib/id-compressor/identifiers.js.map +0 -1
  204. package/lib/id-compressor/index.d.ts +0 -13
  205. package/lib/id-compressor/index.d.ts.map +0 -1
  206. package/lib/id-compressor/index.js +0 -13
  207. package/lib/id-compressor/index.js.map +0 -1
  208. package/lib/id-compressor/persistanceUtilities.d.ts +0 -22
  209. package/lib/id-compressor/persistanceUtilities.d.ts.map +0 -1
  210. package/lib/id-compressor/persistanceUtilities.js +0 -34
  211. package/lib/id-compressor/persistanceUtilities.js.map +0 -1
  212. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +0 -46
  213. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +0 -1
  214. package/lib/id-compressor/sessionSpaceNormalizer.js +0 -76
  215. package/lib/id-compressor/sessionSpaceNormalizer.js.map +0 -1
  216. package/lib/id-compressor/sessions.d.ts +0 -115
  217. package/lib/id-compressor/sessions.d.ts.map +0 -1
  218. package/lib/id-compressor/sessions.js +0 -290
  219. package/lib/id-compressor/sessions.js.map +0 -1
  220. package/lib/id-compressor/utilities.d.ts +0 -52
  221. package/lib/id-compressor/utilities.d.ts.map +0 -1
  222. package/lib/id-compressor/utilities.js +0 -151
  223. package/lib/id-compressor/utilities.js.map +0 -1
  224. package/src/id-compressor/README.md +0 -69
  225. package/src/id-compressor/appendOnlySortedMap.ts +0 -366
  226. package/src/id-compressor/finalSpace.ts +0 -67
  227. package/src/id-compressor/idCompressor.ts +0 -630
  228. package/src/id-compressor/identifiers.ts +0 -42
  229. package/src/id-compressor/index.ts +0 -26
  230. package/src/id-compressor/persistanceUtilities.ts +0 -58
  231. package/src/id-compressor/sessionSpaceNormalizer.ts +0 -83
  232. package/src/id-compressor/sessions.ts +0 -405
  233. package/src/id-compressor/utilities.ts +0 -190
@@ -20,9 +20,10 @@ import {
20
20
  IRefreshSummaryResult,
21
21
  } from "../summary";
22
22
  import { RuntimeHeaderData } from "../containerRuntime";
23
+ import { ContainerRuntimeGCMessage } from "../messageTypes";
23
24
 
24
25
  /**
25
- * @internal
26
+ * @alpha
26
27
  */
27
28
  export type GCVersion = number;
28
29
 
@@ -32,27 +33,25 @@ export const stableGCVersion: GCVersion = 3;
32
33
  export const nextGCVersion: GCVersion = 4;
33
34
 
34
35
  /**
35
- * This undocumented GC Option (on ContainerRuntime Options) allows an app to disable enforcing GC on old documents by incrementing this value
36
+ * This undocumented GC Option (on ContainerRuntime Options) allows an app to disable throwing an error when tombstone
37
+ * object is loaded (requested), merely logging a message instead.
36
38
  *
37
- * If unset, GC Tombstone phase will operate as otherwise configured
38
- * Otherwise, only enforce GC Tombstone if the passed in value matches the persisted value
39
- */
40
- export const gcTombstoneGenerationOptionName = "gcTombstoneGeneration";
41
-
42
- /**
43
- * This undocumented GC Option (on ContainerRuntime Options) allows an app to enable throwing an error when tombstone
44
- * object is loaded (requested).
39
+ * By default, attempting to load a Tombstoned object will result in an error.
45
40
  */
46
- export const gcThrowOnTombstoneLoadOptionName = "gcThrowOnTombstoneLoad";
41
+ export const gcDisableThrowOnTombstoneLoadOptionName = "gcDisableThrowOnTombstoneLoad";
47
42
 
48
43
  /**
49
- * This GC Option (on ContainerRuntime Options) allows an app to disable GC Sweep on old documents by incrementing this value.
44
+ * This undocumented GC Option (on ContainerRuntime Options) allows configuring which documents can have Sweep enabled.
45
+ * This provides a way to disable both Tombstone Enforcement and Sweep.
46
+ *
47
+ * If unset, Tombstone Enforcement + Sweep will operate as otherwise configured.
48
+ * Otherwise, the Sweep Phase will be disabled for documents where persisted value doesn't match what is passed into this session.
49
+ * This provides a way to disallow Sweep for old documents that may be too difficult for an app to repair,
50
+ * in case a bug is found that violates GC's assumptions.
50
51
  *
51
- * If unset altogether, Sweep will be disabled.
52
- * If 0 is passed in, Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.
53
- * If any other number is passed in, Sweep will be enabled only for documents with the same value persisted.
52
+ * @see GCFeatureMatrix (gcGeneration)
54
53
  */
55
- export const gcSweepGenerationOptionName = "gcSweepGeneration";
54
+ export const gcGenerationOptionName = "gcGeneration";
56
55
 
57
56
  /** Config key to turn GC on / off. */
58
57
  export const runGCKey = "Fluid.GarbageCollection.RunGC";
@@ -89,28 +88,33 @@ export const maxSnapshotCacheExpiryMs = 5 * oneDayMs;
89
88
 
90
89
  export const defaultInactiveTimeoutMs = 7 * oneDayMs; // 7 days
91
90
  export const defaultSessionExpiryDurationMs = 30 * oneDayMs; // 30 days
91
+ export const defaultSweepGracePeriodMs = 1 * oneDayMs; // 1 day
92
92
 
93
93
  /**
94
- * @see IGCMetadata.gcFeatureMatrix
95
- * @internal
94
+ * @see IGCMetadata.gcFeatureMatrix and @see gcGenerationOptionName
95
+ * @alpha
96
96
  */
97
- export interface GCFeatureMatrix {
98
- /**
99
- * The Tombstone Generation value in effect when this file was created.
100
- * Gives a way for an app to disqualify old files from GC Tombstone enforcement.
101
- * Provided via Container Runtime Options.
102
- */
103
- tombstoneGeneration?: number;
104
- /**
105
- * The Sweep Generation value in effect when this file was created.
106
- * Gives a way for an app to disqualify old files from GC Sweep.
107
- * Provided via Container Runtime Options.
108
- */
109
- sweepGeneration?: number;
110
- }
97
+ export type GCFeatureMatrix =
98
+ | {
99
+ /**
100
+ * The GC Generation value in effect when this file was created.
101
+ * Gives a way for an app to disqualify old files from GC Sweep.
102
+ * Provided via Container Runtime Options.
103
+ */
104
+ gcGeneration?: number;
105
+ /** Deprecated property from legacy type. Will not be set concurrently with gcGeneration */
106
+ tombstoneGeneration?: undefined;
107
+ }
108
+ | {
109
+ /**
110
+ * The Tombstone Generation value in effect when this file was created.
111
+ * Legacy - new containers would get gcGeneration instead (if anything)
112
+ */
113
+ tombstoneGeneration: number;
114
+ };
111
115
 
112
116
  /**
113
- * @internal
117
+ * @alpha
114
118
  */
115
119
  export interface IGCMetadata {
116
120
  /**
@@ -139,7 +143,7 @@ export interface IGCMetadata {
139
143
  * - True means sweep phase is enabled.
140
144
  * - False means sweep phase is disabled. If GC is disabled as per gcFeature, sweep is also disabled.
141
145
  *
142
- * @deprecated use GCFeatureMatrix.sweepGeneration instead. @see GCFeatureMatrix.sweepGeneration
146
+ * @deprecated use GCFeatureMatrix.gcGeneration instead. @see GCFeatureMatrix.gcGeneration
143
147
  */
144
148
  readonly sweepEnabled?: boolean;
145
149
  /** If this is present, the session for this container will expire after this time and the container will close */
@@ -150,7 +154,7 @@ export interface IGCMetadata {
150
154
 
151
155
  /**
152
156
  * The statistics of the system state after a garbage collection mark phase run.
153
- * @internal
157
+ * @alpha
154
158
  */
155
159
  export interface IMarkPhaseStats {
156
160
  /** The number of nodes in the container. */
@@ -175,7 +179,7 @@ export interface IMarkPhaseStats {
175
179
 
176
180
  /**
177
181
  * The statistics of the system state after a garbage collection sweep phase run.
178
- * @internal
182
+ * @alpha
179
183
  */
180
184
  export interface ISweepPhaseStats {
181
185
  /** The number of nodes in the lifetime of the container. */
@@ -194,13 +198,13 @@ export interface ISweepPhaseStats {
194
198
 
195
199
  /**
196
200
  * The statistics of the system state after a garbage collection run.
197
- * @internal
201
+ * @alpha
198
202
  */
199
203
  export interface IGCStats extends IMarkPhaseStats, ISweepPhaseStats {}
200
204
 
201
205
  /**
202
206
  * The types of GC nodes in the GC reference graph.
203
- * @internal
207
+ * @alpha
204
208
  */
205
209
  export const GCNodeType = {
206
210
  // Nodes that are for data stores.
@@ -214,10 +218,41 @@ export const GCNodeType = {
214
218
  };
215
219
 
216
220
  /**
217
- * @internal
221
+ * @alpha
218
222
  */
219
223
  export type GCNodeType = (typeof GCNodeType)[keyof typeof GCNodeType];
220
224
 
225
+ /**
226
+ * The type of a garbage collection message.
227
+ * @internal
228
+ */
229
+ export const GarbageCollectionMessageType = {
230
+ /** Message sent directing GC to delete the given nodes */
231
+ Sweep: "Sweep",
232
+ } as const;
233
+
234
+ /**
235
+ * @internal
236
+ */
237
+ export type GarbageCollectionMessageType =
238
+ (typeof GarbageCollectionMessageType)[keyof typeof GarbageCollectionMessageType];
239
+
240
+ /**
241
+ * The garbage collection sweep message.
242
+ * @internal
243
+ */
244
+ export interface ISweepMessage {
245
+ type: "Sweep";
246
+ // The ids of nodes that are deleted.
247
+ deletedNodeIds: string[];
248
+ }
249
+
250
+ /**
251
+ * Type for a message to be used for sending / received garbage collection messages.
252
+ * @internal
253
+ */
254
+ export type GarbageCollectionMessage = ISweepMessage;
255
+
221
256
  /**
222
257
  * Defines the APIs for the runtime object to be passed to the garbage collector.
223
258
  */
@@ -227,17 +262,17 @@ export interface IGarbageCollectionRuntime {
227
262
  /** Returns the garbage collection data of the runtime. */
228
263
  getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
229
264
  /** After GC has run, called to notify the runtime of routes that are used in it. */
230
- updateUsedRoutes(usedRoutes: string[]): void;
265
+ updateUsedRoutes(usedRoutes: readonly string[]): void;
231
266
  /** After GC has run, called to notify the runtime of routes that are unused in it. */
232
- updateUnusedRoutes(unusedRoutes: string[]): void;
267
+ updateUnusedRoutes(unusedRoutes: readonly string[]): void;
233
268
  /**
234
269
  * After GC has run and identified nodes that are sweep ready, called to delete the sweep ready nodes. The runtime
235
270
  * should return the routes of nodes that were deleted.
236
271
  * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
237
272
  */
238
- deleteSweepReadyNodes(sweepReadyRoutes: string[]): string[];
273
+ deleteSweepReadyNodes(sweepReadyRoutes: readonly string[]): readonly string[];
239
274
  /** Called to notify the runtime of routes that are tombstones. */
240
- updateTombstonedRoutes(tombstoneRoutes: string[]): void;
275
+ updateTombstonedRoutes(tombstoneRoutes: readonly string[]): void;
241
276
  /** Returns a referenced timestamp to be used to track unreferenced nodes. */
242
277
  getCurrentReferenceTimestampMs(): number | undefined;
243
278
  /** Returns the type of the GC node. */
@@ -297,6 +332,8 @@ export interface IGarbageCollector {
297
332
  ): void;
298
333
  /** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */
299
334
  addedOutboundReference(fromNodePath: string, toNodePath: string): void;
335
+ /** Called to process a garbage collection message. */
336
+ processMessage(message: ContainerRuntimeGCMessage, local: boolean): void;
300
337
  /** Returns true if this node has been deleted by GC during sweep phase. */
301
338
  isNodeDeleted(nodePath: string): boolean;
302
339
  setConnectionState(connected: boolean, clientId?: string): void;
@@ -317,10 +354,11 @@ export interface IGarbageCollectorCreateParams {
317
354
  readonly getLastSummaryTimestampMs: () => number | undefined;
318
355
  readonly readAndParseBlob: ReadAndParseBlob;
319
356
  readonly activeConnection: () => boolean;
357
+ readonly submitMessage: (message: ContainerRuntimeGCMessage) => void;
320
358
  }
321
359
 
322
360
  /**
323
- * @internal
361
+ * @alpha
324
362
  */
325
363
  export interface IGCRuntimeOptions {
326
364
  /**
@@ -329,7 +367,7 @@ export interface IGCRuntimeOptions {
329
367
  * GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
330
368
  * and marked as such in the summary. This option enables the mark phase.
331
369
  * In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
332
- * Sweep phase can be enabled using the "gcSweepGeneration" option.
370
+ * Sweep phase can be enabled using the "enableGCSweep" option.
333
371
  *
334
372
  * Note: This setting is persisted in the container's summary and cannot be changed.
335
373
  */
@@ -341,6 +379,17 @@ export interface IGCRuntimeOptions {
341
379
  */
342
380
  disableGC?: boolean;
343
381
 
382
+ /**
383
+ * Flag that if true, will enable the full Sweep Phase of garbage collection for this session,
384
+ * where Tombstoned objects are permanently deleted from the container.
385
+ *
386
+ * IMPORTANT: This only applies if this document is allowed to run Sweep Phase.
387
+ *
388
+ * Current default behavior is for Sweep Phase not to delete Tombstoned objects,
389
+ * but merely to prevent them from being loaded.
390
+ */
391
+ enableGCSweep?: true;
392
+
344
393
  /**
345
394
  * Flag that will bypass optimizations and generate GC data for all nodes irrespective of whether a node
346
395
  * changed or not.
@@ -354,6 +403,13 @@ export interface IGCRuntimeOptions {
354
403
  */
355
404
  sessionExpiryTimeoutMs?: number;
356
405
 
406
+ /**
407
+ * Delay between when Tombstone should run and when the object should be deleted.
408
+ * This grace period gives a chance to intervene to recover if needed, before Sweep deletes the object.
409
+ * If not present, a default (non-zero) value will be used.
410
+ */
411
+ sweepGracePeriodMs?: number;
412
+
357
413
  /**
358
414
  * Allows additional GC options to be passed.
359
415
  */
@@ -392,15 +448,21 @@ export interface IGarbageCollectorConfigs {
392
448
  readonly sessionExpiryTimeoutMs: number | undefined;
393
449
  /** The time after which an unreferenced node is ready to be swept. */
394
450
  readonly sweepTimeoutMs: number | undefined;
451
+ /**
452
+ * The delay between tombstone and sweep. Not persisted, so concurrent sessions may use different values.
453
+ * Sweep is implemented in an eventually-consistent way so this is acceptable.
454
+ */
455
+ readonly sweepGracePeriodMs: number;
395
456
  /** The time after which an unreferenced node is inactive. */
396
457
  readonly inactiveTimeoutMs: number;
397
458
  /** Tracks whether GC should run in test mode. In this mode, unreferenced objects are deleted immediately. */
398
459
  readonly testMode: boolean;
399
460
  /**
400
- * Tracks whether GC should run in tombstone mode. In this mode, sweep ready objects are marked as tombstones.
461
+ * Tracks whether GC should run in tombstone mode. In this mode, objects are marked as tombstones as a step along the
462
+ * way before they are fully deleted.
401
463
  * In interactive (non-summarizer) clients, tombstone objects behave as if they are deleted, i.e., access to them
402
- * is not allowed. However, these objects can be accessed after referencing them first. It is used as a staging
403
- * step for sweep where accidental sweep ready objects can be recovered.
464
+ * is not allowed. However, these objects can be accessed after referencing them first. It is used as a "warning"
465
+ * step before sweep, where objects wrongly marked as unreferenced can be recovered.
404
466
  */
405
467
  readonly tombstoneMode: boolean;
406
468
  /** @see GCFeatureMatrix. */
@@ -411,8 +473,6 @@ export interface IGarbageCollectorConfigs {
411
473
  readonly gcVersionInEffect: GCVersion;
412
474
  /** It is easier for users to diagnose InactiveObject usage if we throw on load, which this option enables */
413
475
  readonly throwOnInactiveLoad: boolean | undefined;
414
- /** If false, loading or using a Tombstoned object should merely log, not fail */
415
- readonly tombstoneEnforcementAllowed: boolean;
416
476
  /** If true, throw an error when a tombstone data store is retrieved */
417
477
  readonly throwOnTombstoneLoad: boolean;
418
478
  /** If true, throw an error when a tombstone data store is used. */
@@ -425,6 +485,8 @@ export const UnreferencedState = {
425
485
  Active: "Active",
426
486
  /** The node is inactive, i.e., it should not become referenced. */
427
487
  Inactive: "Inactive",
488
+ /** The node is ready to be tombstoned */
489
+ TombstoneReady: "TombstoneReady",
428
490
  /** The node is ready to be deleted by the sweep phase. */
429
491
  SweepReady: "SweepReady",
430
492
  } as const;
@@ -28,64 +28,34 @@ export function getGCVersion(metadata?: IGCMetadata): GCVersion {
28
28
  }
29
29
 
30
30
  /**
31
- * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted
32
- * TombstoneGeneration values
33
- *
34
- * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants
35
- * such that enforcing GC Tombstone (Failing on Tombstone load/usage) would cause legitimate data loss,
36
- * the container author may increment the generation value for Tombstone such that containers created
37
- * with a different value will not be subjected to GC enforcement.
38
- *
39
- * If no generation is provided at runtime, this defaults to return true to maintain expected default behavior
40
- *
41
- * @param persistedGeneration - The persisted tombstoneGeneration value
42
- * @param currentGeneration - The current app-provided tombstoneGeneration value
43
- * @returns true if GC Tombstone enforcement (Fail on Tombstone load/usage) should be allowed for this document
44
- */
45
- export function shouldAllowGcTombstoneEnforcement(
46
- persistedGeneration: number | undefined,
47
- currentGeneration: number | undefined,
48
- ): boolean {
49
- // If no Generation value is provided for this session, then we should default to letting Tombstone feature behave as intended.
50
- if (currentGeneration === undefined) {
51
- return true;
52
- }
53
- return persistedGeneration === currentGeneration;
54
- }
55
-
56
- /**
57
- * Indicates whether Sweep is allowed for this document based on the GC Feature Matrix and current SweepGeneration
31
+ * Indicates whether Sweep is allowed for this document based on the persisted GC Feature Matrix and current gcGeneration.
32
+ * This applies to the entire Sweep Phase the same - both Tombstone Enforcement (i.e. should loading a Tombstone fail?) and Deletion.
58
33
  *
59
34
  * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants
60
35
  * such that enforcing GC Sweep would cause legitimate data loss, the container author may increment the generation value for Sweep
61
36
  * such that containers created with a different value will not be subjected to GC Sweep.
62
37
  *
63
- * If no generation is provided, Sweep will be disabled.
64
- * Passing 0 is a special case: Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.
38
+ * If no generation is provided, Sweep will be enabled for all documents.
39
+ *
40
+ * For backwards compatibility, the current generation value is also compared against the persisted gcTombstoneGeneration if present.
65
41
  *
66
- * @param persistedGenerations - The persisted sweep/tombstone generations from the GC Feature Matrix
67
- * @param currentGeneration - The current app-provided sweepGeneration value
42
+ * @param featureMatrix - The GC Feature Matrix, containing the persisted generation value
43
+ * @param currentGeneration - The current app-provided gcGeneration value
68
44
  * @returns true if GC Sweep should be allowed for this document
69
45
  */
70
46
  export function shouldAllowGcSweep(
71
- persistedGenerations: Pick<GCFeatureMatrix, "sweepGeneration" | "tombstoneGeneration">,
47
+ featureMatrix: GCFeatureMatrix,
72
48
  currentGeneration: number | undefined,
73
49
  ): boolean {
74
- // If no Generation value is provided for this session, default to false
50
+ // If no Generation value is provided for this session, default to true
75
51
  if (currentGeneration === undefined) {
76
- return false;
52
+ return true;
77
53
  }
78
54
 
79
- // 0 is a special case: It matches both SweepGeneration and TombstoneGeneration
80
- // This is an optimistic measure to maximize coverage of GC Sweep if no bumps to TombstoneGeneration are needed before enabling Sweep.
81
- if (currentGeneration === 0) {
82
- return (
83
- persistedGenerations.sweepGeneration === 0 ||
84
- persistedGenerations.tombstoneGeneration === 0
85
- );
86
- }
55
+ // tombstoneGeneration is the predecessor and needs to be supported for back-compat reasons
56
+ const targetGeneration = featureMatrix.tombstoneGeneration ?? featureMatrix.gcGeneration;
87
57
 
88
- return persistedGenerations.sweepGeneration === currentGeneration;
58
+ return currentGeneration === targetGeneration;
89
59
  }
90
60
 
91
61
  /**
@@ -151,19 +121,12 @@ export function concatGarbageCollectionStates(
151
121
  /**
152
122
  * Helper function that clones the GC data.
153
123
  * @param gcData - The GC data to clone.
154
- * @param filter - Optional function to filter out node ids not to be included in the cloned GC data. Returns
155
- * true to filter out nodes.
156
124
  * @returns a clone of the given GC data.
157
125
  */
158
- export function cloneGCData(
159
- gcData: IGarbageCollectionData,
160
- filter?: (id: string) => boolean,
161
- ): IGarbageCollectionData {
126
+ export function cloneGCData(gcData: IGarbageCollectionData): IGarbageCollectionData {
162
127
  const clonedGCNodes: { [id: string]: string[] } = {};
163
128
  for (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {
164
- if (filter?.(id) !== true) {
165
- clonedGCNodes[id] = Array.from(outboundRoutes);
166
- }
129
+ clonedGCNodes[id] = Array.from(outboundRoutes);
167
130
  }
168
131
  return {
169
132
  gcNodes: clonedGCNodes,
@@ -303,3 +266,19 @@ export function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBa
303
266
  export function trimLeadingAndTrailingSlashes(str: string) {
304
267
  return str.replace(/^\/+|\/+$/g, "");
305
268
  }
269
+
270
+ /**
271
+ * Utility to implement compat behaviors given an unknown message type
272
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
273
+ *
274
+ * @param _unknownGCMessageType - Typed as never to ensure all known types have been
275
+ * handled before calling this function (e.g. in a switch statement).
276
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
277
+ */
278
+ export function compatBehaviorAllowsGCMessageType(
279
+ _unknownGCMessageType: never,
280
+ compatBehavior: "Ignore" | "FailToProcess" | undefined,
281
+ ): boolean {
282
+ // undefined defaults to same behavior as "FailToProcess"
283
+ return compatBehavior === "Ignore";
284
+ }
@@ -142,6 +142,21 @@ export class GCTelemetryTracker {
142
142
 
143
143
  const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
144
144
  const nodeType = this.getNodeType(nodeUsageProps.id);
145
+ const timeout = (() => {
146
+ switch (nodeStateTracker?.state) {
147
+ case UnreferencedState.Inactive:
148
+ return this.configs.inactiveTimeoutMs;
149
+ case UnreferencedState.TombstoneReady:
150
+ return this.configs.sweepTimeoutMs;
151
+ case UnreferencedState.SweepReady:
152
+ return (
153
+ this.configs.sweepTimeoutMs &&
154
+ this.configs.sweepTimeoutMs + this.configs.sweepGracePeriodMs
155
+ );
156
+ default:
157
+ return undefined;
158
+ }
159
+ })();
145
160
  const {
146
161
  usageType,
147
162
  currentReferenceTimestampMs,
@@ -159,10 +174,7 @@ export class GCTelemetryTracker {
159
174
  ? nodeUsageProps.currentReferenceTimestampMs -
160
175
  nodeStateTracker.unreferencedTimestampMs
161
176
  : -1,
162
- timeout:
163
- nodeStateTracker?.state === UnreferencedState.Inactive
164
- ? this.configs.inactiveTimeoutMs
165
- : this.configs.sweepTimeoutMs,
177
+ timeout,
166
178
  ...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
167
179
  ...propsToLog,
168
180
  ...this.createContainerMetadata,
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { assert, Timer } from "@fluidframework/core-utils";
7
+ import { validatePrecondition } from "@fluidframework/telemetry-utils";
7
8
  import { UnreferencedState } from "./gcDefinitions";
8
9
 
9
10
  /** A wrapper around common-utils Timer that requires the timeout when calling start/restart */
@@ -26,7 +27,7 @@ class TimerWithNoDefaultTimeout extends Timer {
26
27
 
27
28
  /**
28
29
  * Helper class that tracks the state of an unreferenced node such as the time it was unreferenced and if it can
29
- * be deleted by the sweep phase.
30
+ * be tombstoned or deleted by the sweep phase.
30
31
  */
31
32
  export class UnreferencedStateTracker {
32
33
  private _state: UnreferencedState = UnreferencedState.Active;
@@ -36,6 +37,8 @@ export class UnreferencedStateTracker {
36
37
 
37
38
  /** Timer to indicate when an unreferenced object is considered Inactive */
38
39
  private readonly inactiveTimer: TimerWithNoDefaultTimeout;
40
+ /** Timer to indicate when an unreferenced object is Tombstone-Ready */
41
+ private readonly tombstoneTimer: TimerWithNoDefaultTimeout;
39
42
  /** Timer to indicate when an unreferenced object is Sweep-Ready */
40
43
  private readonly sweepTimer: TimerWithNoDefaultTimeout;
41
44
 
@@ -45,32 +48,49 @@ export class UnreferencedStateTracker {
45
48
  private readonly inactiveTimeoutMs: number,
46
49
  /** The current reference timestamp used to track how long this node has been unreferenced for. */
47
50
  currentReferenceTimestampMs: number,
48
- /** The time after which node transitions to SweepReady state; undefined if session expiry is disabled. */
49
- private readonly sweepTimeoutMs: number | undefined,
51
+ /** The time after which node transitions to TombstoneReady state; undefined if session expiry is disabled. */
52
+ private readonly tombstoneTimeoutMs: number | undefined,
53
+ /** The delay from TombstoneReady to SweepReady (only applies if tombstoneTimeoutMs is defined) */
54
+ private readonly sweepGracePeriodMs: number,
50
55
  ) {
51
- if (this.sweepTimeoutMs !== undefined) {
52
- assert(
53
- this.inactiveTimeoutMs <= this.sweepTimeoutMs,
54
- 0x3b0 /* inactive timeout must not be greater than the sweep timeout */,
55
- );
56
- }
56
+ validatePrecondition(
57
+ this.tombstoneTimeoutMs === undefined ||
58
+ this.tombstoneTimeoutMs >= this.inactiveTimeoutMs,
59
+ "inactiveTimeoutMs must not be greater than the tombstoneTimeoutMs",
60
+ );
57
61
 
58
62
  this.sweepTimer = new TimerWithNoDefaultTimeout(() => {
59
63
  this._state = UnreferencedState.SweepReady;
60
64
  assert(
61
- !this.inactiveTimer.hasTimer,
62
- 0x3b1 /* inactiveTimer still running after sweepTimer fired! */,
65
+ !this.inactiveTimer.hasTimer && !this.tombstoneTimer.hasTimer,
66
+ 0x863 /* inactiveTimer or tombstoneTimer still running after sweepTimer fired! */,
63
67
  );
64
68
  });
65
69
 
70
+ this.tombstoneTimer = new TimerWithNoDefaultTimeout(() => {
71
+ this._state = UnreferencedState.TombstoneReady;
72
+ assert(
73
+ !this.inactiveTimer.hasTimer,
74
+ 0x864 /* inactiveTimer still running after tombstoneTimer fired! */,
75
+ ); // aka 0x3b1
76
+
77
+ if (this.sweepGracePeriodMs > 0) {
78
+ // After the node becomes tombstone ready, start the sweep timer after which the node will be ready for sweep.
79
+ this.sweepTimer.restart(this.sweepGracePeriodMs);
80
+ } else {
81
+ this._state = UnreferencedState.SweepReady;
82
+ }
83
+ });
84
+
66
85
  this.inactiveTimer = new TimerWithNoDefaultTimeout(() => {
67
86
  this._state = UnreferencedState.Inactive;
68
87
 
69
- // After the node becomes inactive, start the sweep timer after which the node will be ready for sweep.
70
- if (this.sweepTimeoutMs !== undefined) {
71
- this.sweepTimer.restart(this.sweepTimeoutMs - this.inactiveTimeoutMs);
88
+ // After the node becomes inactive, start the tombstone timer after which the node will be ready for tombstone.
89
+ if (this.tombstoneTimeoutMs !== undefined) {
90
+ this.tombstoneTimer.restart(this.tombstoneTimeoutMs - this.inactiveTimeoutMs);
72
91
  }
73
92
  });
93
+
74
94
  this.updateTracking(currentReferenceTimestampMs);
75
95
  }
76
96
 
@@ -78,21 +98,39 @@ export class UnreferencedStateTracker {
78
98
  public updateTracking(currentReferenceTimestampMs: number) {
79
99
  const unreferencedDurationMs = currentReferenceTimestampMs - this.unreferencedTimestampMs;
80
100
 
81
- // If the node has been unreferenced for sweep timeout amount of time, update the state to SweepReady.
82
- if (this.sweepTimeoutMs !== undefined && unreferencedDurationMs >= this.sweepTimeoutMs) {
101
+ // Below we will set the appropriate timer (or none). Any running timers are superceded by the new currentReferenceTimestampMs
102
+ this.clearTimers();
103
+
104
+ // If the node has been unreferenced long enough, update the state to SweepReady.
105
+ if (
106
+ this.tombstoneTimeoutMs !== undefined &&
107
+ unreferencedDurationMs >= this.tombstoneTimeoutMs + this.sweepGracePeriodMs
108
+ ) {
83
109
  this._state = UnreferencedState.SweepReady;
84
- this.clearTimers();
85
110
  return;
86
111
  }
87
112
 
88
- // If the node has been unreferenced for inactive timeoutMs amount of time, update the state to inactive.
89
- // Also, start a timer for the sweep timeout.
113
+ // If the node has been unreferenced long enough, update the state to TombstoneReady.
114
+ // Also, start a timer for the remainder of the sweep delay.
115
+ if (
116
+ this.tombstoneTimeoutMs !== undefined &&
117
+ unreferencedDurationMs >= this.tombstoneTimeoutMs
118
+ ) {
119
+ this._state = UnreferencedState.TombstoneReady;
120
+
121
+ this.sweepTimer.restart(
122
+ this.tombstoneTimeoutMs + this.sweepGracePeriodMs - unreferencedDurationMs,
123
+ );
124
+ return;
125
+ }
126
+
127
+ // If the node has been unreferenced for long enough, update the state to inactive.
128
+ // Also, start a timer for the remainder of the tombstone timeout.
90
129
  if (unreferencedDurationMs >= this.inactiveTimeoutMs) {
91
130
  this._state = UnreferencedState.Inactive;
92
- this.inactiveTimer.clear();
93
131
 
94
- if (this.sweepTimeoutMs !== undefined) {
95
- this.sweepTimer.restart(this.sweepTimeoutMs - unreferencedDurationMs);
132
+ if (this.tombstoneTimeoutMs !== undefined) {
133
+ this.tombstoneTimer.restart(this.tombstoneTimeoutMs - unreferencedDurationMs);
96
134
  }
97
135
  return;
98
136
  }
@@ -103,6 +141,7 @@ export class UnreferencedStateTracker {
103
141
 
104
142
  private clearTimers() {
105
143
  this.inactiveTimer.clear();
144
+ this.tombstoneTimer.clear();
106
145
  this.sweepTimer.clear();
107
146
  }
108
147
 
package/src/gc/index.ts CHANGED
@@ -7,12 +7,12 @@ export { GarbageCollector } from "./garbageCollection";
7
7
  export {
8
8
  nextGCVersion,
9
9
  defaultInactiveTimeoutMs,
10
+ defaultSweepGracePeriodMs,
10
11
  defaultSessionExpiryDurationMs,
11
12
  GCNodeType,
12
13
  gcTestModeKey,
13
- gcTombstoneGenerationOptionName,
14
- gcThrowOnTombstoneLoadOptionName,
15
- gcSweepGenerationOptionName,
14
+ gcDisableThrowOnTombstoneLoadOptionName,
15
+ gcGenerationOptionName,
16
16
  GCFeatureMatrix,
17
17
  GCVersion,
18
18
  gcVersionUpgradeToV4Key,
@@ -35,6 +35,7 @@ export {
35
35
  disableDatastoreSweepKey,
36
36
  UnreferencedState,
37
37
  throwOnTombstoneLoadOverrideKey,
38
+ GarbageCollectionMessage,
38
39
  } from "./gcDefinitions";
39
40
  export {
40
41
  cloneGCData,
package/src/index.ts CHANGED
@@ -93,5 +93,21 @@ export {
93
93
  IRetriableFailureResult,
94
94
  ISummarizeEventProps,
95
95
  } from "./summary";
96
- export { isStableId, generateStableId, assertIsStableId } from "./id-compressor";
97
96
  export { IChunkedOp, unpackRuntimeMessage } from "./opLifecycle";
97
+
98
+ // Re-exports for backwards compatibility.
99
+ // Will be removed in the future.
100
+ export {
101
+ /**
102
+ * @deprecated Import from `@fluidframework/id-compressor` instead.
103
+ */
104
+ assertIsStableId,
105
+ /**
106
+ * @deprecated Import from `@fluidframework/id-compressor` instead.
107
+ */
108
+ generateStableId,
109
+ /**
110
+ * @deprecated Import from `@fluidframework/id-compressor` instead.
111
+ */
112
+ isStableId,
113
+ } from "@fluidframework/id-compressor";