@fluidframework/container-runtime 2.0.0-dev.4.2.0.153917 → 2.0.0-dev.4.3.0.158678

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 (221) hide show
  1. package/dist/containerRuntime.d.ts +33 -3
  2. package/dist/containerRuntime.d.ts.map +1 -1
  3. package/dist/containerRuntime.js +187 -58
  4. package/dist/containerRuntime.js.map +1 -1
  5. package/dist/dataStoreContext.d.ts +2 -1
  6. package/dist/dataStoreContext.d.ts.map +1 -1
  7. package/dist/dataStoreContext.js +3 -0
  8. package/dist/dataStoreContext.js.map +1 -1
  9. package/dist/dataStores.d.ts +5 -5
  10. package/dist/dataStores.d.ts.map +1 -1
  11. package/dist/dataStores.js +3 -6
  12. package/dist/dataStores.js.map +1 -1
  13. package/dist/gc/garbageCollection.d.ts.map +1 -1
  14. package/dist/gc/garbageCollection.js +5 -5
  15. package/dist/gc/garbageCollection.js.map +1 -1
  16. package/dist/gc/gcConfigs.d.ts.map +1 -1
  17. package/dist/gc/gcConfigs.js +1 -3
  18. package/dist/gc/gcConfigs.js.map +1 -1
  19. package/dist/gc/gcDefinitions.js +1 -1
  20. package/dist/gc/gcDefinitions.js.map +1 -1
  21. package/dist/id-compressor/appendOnlySortedMap.d.ts +146 -0
  22. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
  23. package/dist/id-compressor/appendOnlySortedMap.js +360 -0
  24. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -0
  25. package/dist/id-compressor/idCompressor.d.ts +279 -0
  26. package/dist/id-compressor/idCompressor.d.ts.map +1 -0
  27. package/dist/id-compressor/idCompressor.js +1258 -0
  28. package/dist/id-compressor/idCompressor.js.map +1 -0
  29. package/dist/id-compressor/idRange.d.ts +11 -0
  30. package/dist/id-compressor/idRange.d.ts.map +1 -0
  31. package/dist/id-compressor/idRange.js +29 -0
  32. package/dist/id-compressor/idRange.js.map +1 -0
  33. package/dist/id-compressor/index.d.ts +14 -0
  34. package/dist/id-compressor/index.d.ts.map +1 -0
  35. package/dist/id-compressor/index.js +38 -0
  36. package/dist/id-compressor/index.js.map +1 -0
  37. package/dist/id-compressor/numericUuid.d.ts +59 -0
  38. package/dist/id-compressor/numericUuid.d.ts.map +1 -0
  39. package/dist/id-compressor/numericUuid.js +325 -0
  40. package/dist/id-compressor/numericUuid.js.map +1 -0
  41. package/dist/id-compressor/sessionIdNormalizer.d.ts +138 -0
  42. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
  43. package/dist/id-compressor/sessionIdNormalizer.js +488 -0
  44. package/dist/id-compressor/sessionIdNormalizer.js.map +1 -0
  45. package/dist/id-compressor/utils.d.ts +57 -0
  46. package/dist/id-compressor/utils.d.ts.map +1 -0
  47. package/dist/id-compressor/utils.js +90 -0
  48. package/dist/id-compressor/utils.js.map +1 -0
  49. package/dist/id-compressor/uuidUtilities.d.ts +30 -0
  50. package/dist/id-compressor/uuidUtilities.d.ts.map +1 -0
  51. package/dist/id-compressor/uuidUtilities.js +106 -0
  52. package/dist/id-compressor/uuidUtilities.js.map +1 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +5 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/opLifecycle/batchManager.d.ts +9 -2
  58. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  59. package/dist/opLifecycle/batchManager.js +21 -2
  60. package/dist/opLifecycle/batchManager.js.map +1 -1
  61. package/dist/opLifecycle/index.d.ts +1 -1
  62. package/dist/opLifecycle/index.d.ts.map +1 -1
  63. package/dist/opLifecycle/index.js.map +1 -1
  64. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  65. package/dist/opLifecycle/opGroupingManager.js +5 -0
  66. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  67. package/dist/opLifecycle/outbox.d.ts +2 -2
  68. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  69. package/dist/opLifecycle/outbox.js +34 -22
  70. package/dist/opLifecycle/outbox.js.map +1 -1
  71. package/dist/packageVersion.d.ts +1 -1
  72. package/dist/packageVersion.js +1 -1
  73. package/dist/packageVersion.js.map +1 -1
  74. package/dist/pendingStateManager.d.ts +1 -1
  75. package/dist/pendingStateManager.d.ts.map +1 -1
  76. package/dist/pendingStateManager.js +11 -3
  77. package/dist/pendingStateManager.js.map +1 -1
  78. package/dist/summary/index.d.ts +1 -1
  79. package/dist/summary/index.d.ts.map +1 -1
  80. package/dist/summary/index.js +2 -1
  81. package/dist/summary/index.js.map +1 -1
  82. package/dist/summary/orderedClientElection.d.ts +1 -0
  83. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  84. package/dist/summary/orderedClientElection.js +17 -1
  85. package/dist/summary/orderedClientElection.js.map +1 -1
  86. package/dist/summary/runningSummarizer.d.ts +0 -1
  87. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  88. package/dist/summary/runningSummarizer.js +1 -17
  89. package/dist/summary/runningSummarizer.js.map +1 -1
  90. package/dist/summary/summaryFormat.d.ts +3 -0
  91. package/dist/summary/summaryFormat.d.ts.map +1 -1
  92. package/dist/summary/summaryFormat.js +3 -1
  93. package/dist/summary/summaryFormat.js.map +1 -1
  94. package/dist/summary/summaryManager.d.ts.map +1 -1
  95. package/dist/summary/summaryManager.js +2 -0
  96. package/dist/summary/summaryManager.js.map +1 -1
  97. package/lib/containerRuntime.d.ts +33 -3
  98. package/lib/containerRuntime.d.ts.map +1 -1
  99. package/lib/containerRuntime.js +170 -60
  100. package/lib/containerRuntime.js.map +1 -1
  101. package/lib/dataStoreContext.d.ts +2 -1
  102. package/lib/dataStoreContext.d.ts.map +1 -1
  103. package/lib/dataStoreContext.js +3 -0
  104. package/lib/dataStoreContext.js.map +1 -1
  105. package/lib/dataStores.d.ts +5 -5
  106. package/lib/dataStores.d.ts.map +1 -1
  107. package/lib/dataStores.js +3 -6
  108. package/lib/dataStores.js.map +1 -1
  109. package/lib/gc/garbageCollection.d.ts.map +1 -1
  110. package/lib/gc/garbageCollection.js +5 -5
  111. package/lib/gc/garbageCollection.js.map +1 -1
  112. package/lib/gc/gcConfigs.d.ts.map +1 -1
  113. package/lib/gc/gcConfigs.js +1 -3
  114. package/lib/gc/gcConfigs.js.map +1 -1
  115. package/lib/gc/gcDefinitions.js +1 -1
  116. package/lib/gc/gcDefinitions.js.map +1 -1
  117. package/lib/id-compressor/appendOnlySortedMap.d.ts +146 -0
  118. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
  119. package/lib/id-compressor/appendOnlySortedMap.js +355 -0
  120. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -0
  121. package/lib/id-compressor/idCompressor.d.ts +279 -0
  122. package/lib/id-compressor/idCompressor.d.ts.map +1 -0
  123. package/lib/id-compressor/idCompressor.js +1248 -0
  124. package/lib/id-compressor/idCompressor.js.map +1 -0
  125. package/lib/id-compressor/idRange.d.ts +11 -0
  126. package/lib/id-compressor/idRange.d.ts.map +1 -0
  127. package/lib/id-compressor/idRange.js +25 -0
  128. package/lib/id-compressor/idRange.js.map +1 -0
  129. package/lib/id-compressor/index.d.ts +14 -0
  130. package/lib/id-compressor/index.d.ts.map +1 -0
  131. package/lib/id-compressor/index.js +14 -0
  132. package/lib/id-compressor/index.js.map +1 -0
  133. package/lib/id-compressor/numericUuid.d.ts +59 -0
  134. package/lib/id-compressor/numericUuid.d.ts.map +1 -0
  135. package/lib/id-compressor/numericUuid.js +315 -0
  136. package/lib/id-compressor/numericUuid.js.map +1 -0
  137. package/lib/id-compressor/sessionIdNormalizer.d.ts +138 -0
  138. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
  139. package/lib/id-compressor/sessionIdNormalizer.js +484 -0
  140. package/lib/id-compressor/sessionIdNormalizer.js.map +1 -0
  141. package/lib/id-compressor/utils.d.ts +57 -0
  142. package/lib/id-compressor/utils.d.ts.map +1 -0
  143. package/lib/id-compressor/utils.js +79 -0
  144. package/lib/id-compressor/utils.js.map +1 -0
  145. package/lib/id-compressor/uuidUtilities.d.ts +30 -0
  146. package/lib/id-compressor/uuidUtilities.d.ts.map +1 -0
  147. package/lib/id-compressor/uuidUtilities.js +98 -0
  148. package/lib/id-compressor/uuidUtilities.js.map +1 -0
  149. package/lib/index.d.ts +1 -0
  150. package/lib/index.d.ts.map +1 -1
  151. package/lib/index.js +1 -0
  152. package/lib/index.js.map +1 -1
  153. package/lib/opLifecycle/batchManager.d.ts +9 -2
  154. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  155. package/lib/opLifecycle/batchManager.js +19 -1
  156. package/lib/opLifecycle/batchManager.js.map +1 -1
  157. package/lib/opLifecycle/index.d.ts +1 -1
  158. package/lib/opLifecycle/index.d.ts.map +1 -1
  159. package/lib/opLifecycle/index.js.map +1 -1
  160. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  161. package/lib/opLifecycle/opGroupingManager.js +5 -0
  162. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  163. package/lib/opLifecycle/outbox.d.ts +2 -2
  164. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  165. package/lib/opLifecycle/outbox.js +35 -23
  166. package/lib/opLifecycle/outbox.js.map +1 -1
  167. package/lib/packageVersion.d.ts +1 -1
  168. package/lib/packageVersion.js +1 -1
  169. package/lib/packageVersion.js.map +1 -1
  170. package/lib/pendingStateManager.d.ts +1 -1
  171. package/lib/pendingStateManager.d.ts.map +1 -1
  172. package/lib/pendingStateManager.js +11 -3
  173. package/lib/pendingStateManager.js.map +1 -1
  174. package/lib/summary/index.d.ts +1 -1
  175. package/lib/summary/index.d.ts.map +1 -1
  176. package/lib/summary/index.js +1 -1
  177. package/lib/summary/index.js.map +1 -1
  178. package/lib/summary/orderedClientElection.d.ts +1 -0
  179. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  180. package/lib/summary/orderedClientElection.js +17 -1
  181. package/lib/summary/orderedClientElection.js.map +1 -1
  182. package/lib/summary/runningSummarizer.d.ts +0 -1
  183. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  184. package/lib/summary/runningSummarizer.js +1 -17
  185. package/lib/summary/runningSummarizer.js.map +1 -1
  186. package/lib/summary/summaryFormat.d.ts +3 -0
  187. package/lib/summary/summaryFormat.d.ts.map +1 -1
  188. package/lib/summary/summaryFormat.js +2 -0
  189. package/lib/summary/summaryFormat.js.map +1 -1
  190. package/lib/summary/summaryManager.d.ts.map +1 -1
  191. package/lib/summary/summaryManager.js +2 -0
  192. package/lib/summary/summaryManager.js.map +1 -1
  193. package/package.json +27 -18
  194. package/src/containerRuntime.ts +256 -88
  195. package/src/dataStoreContext.ts +6 -0
  196. package/src/dataStores.ts +4 -7
  197. package/src/gc/garbageCollection.ts +7 -6
  198. package/src/gc/gcConfigs.ts +1 -3
  199. package/src/gc/gcDefinitions.ts +1 -1
  200. package/src/id-compressor/README.md +3 -0
  201. package/src/id-compressor/appendOnlySortedMap.ts +427 -0
  202. package/src/id-compressor/idCompressor.ts +1854 -0
  203. package/src/id-compressor/idRange.ts +35 -0
  204. package/src/id-compressor/index.ts +35 -0
  205. package/src/id-compressor/numericUuid.ts +383 -0
  206. package/src/id-compressor/sessionIdNormalizer.ts +609 -0
  207. package/src/id-compressor/utils.ts +114 -0
  208. package/src/id-compressor/uuidUtilities.ts +123 -0
  209. package/src/index.ts +1 -0
  210. package/src/opLifecycle/README.md +13 -0
  211. package/src/opLifecycle/batchManager.ts +35 -2
  212. package/src/opLifecycle/index.ts +1 -1
  213. package/src/opLifecycle/opGroupingManager.ts +5 -1
  214. package/src/opLifecycle/outbox.ts +57 -23
  215. package/src/packageVersion.ts +1 -1
  216. package/src/pendingStateManager.ts +21 -7
  217. package/src/summary/index.ts +1 -0
  218. package/src/summary/orderedClientElection.ts +15 -2
  219. package/src/summary/runningSummarizer.ts +3 -24
  220. package/src/summary/summaryFormat.ts +4 -0
  221. package/src/summary/summaryManager.ts +2 -0
@@ -1,5 +1,5 @@
1
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
- import { assert, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
2
+ import { assert, delay, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
3
3
  import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
4
4
  import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
5
5
  import { readAndParse } from "@fluidframework/driver-utils";
@@ -15,7 +15,7 @@ import { PendingStateManager } from "./pendingStateManager";
15
15
  import { pkgVersion } from "./packageVersion";
16
16
  import { BlobManager } from "./blobManager";
17
17
  import { DataStores, getSummaryForDatastores } from "./dataStores";
18
- import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
18
+ import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, idCompressorBlobName, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
19
19
  import { formExponentialFn, Throttler } from "./throttler";
20
20
  import { GarbageCollector, GCNodeType, gcTombstoneGenerationOptionName, shouldAllowGcTombstoneEnforcement, trimLeadingAndTrailingSlashes, } from "./gc";
21
21
  import { channelToDataStore, isDataStoreAliasMessage } from "./dataStore";
@@ -37,6 +37,12 @@ export var ContainerMessageType;
37
37
  ContainerMessageType["Rejoin"] = "rejoin";
38
38
  // Sets the alias of a root data store
39
39
  ContainerMessageType["Alias"] = "alias";
40
+ /**
41
+ * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
42
+ * the last allocation op was sent.
43
+ * See the [IdCompressor README](./id-compressor/README.md) for more details.
44
+ */
45
+ ContainerMessageType["IdAllocation"] = "idAllocation";
40
46
  })(ContainerMessageType || (ContainerMessageType = {}));
41
47
  export const DefaultSummaryConfiguration = {
42
48
  state: "enabled",
@@ -92,6 +98,12 @@ const defaultCompressionConfig = {
92
98
  compressionAlgorithm: CompressionAlgorithms.lz4,
93
99
  };
94
100
  const defaultChunkSizeInBytes = 204800;
101
+ /**
102
+ * Instead of refreshing from latest because we do not have 100% confidence in the state
103
+ * of the current system, we should close the summarizer and let it recover.
104
+ * This delay's goal is to prevent tight restart loops
105
+ */
106
+ const defaultCloseSummarizerDelayMs = 10000; // 10 seconds
95
107
  /**
96
108
  * @deprecated - use ContainerRuntimeMessage instead
97
109
  */
@@ -138,8 +150,8 @@ export class ContainerRuntime extends TypedEventEmitter {
138
150
  /**
139
151
  * @internal
140
152
  */
141
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
142
- var _a, _b, _c, _d, _e, _f, _g, _h;
153
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration, initializeEntryPoint) {
154
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
143
155
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
144
156
  super();
145
157
  this.context = context;
@@ -201,6 +213,7 @@ export class ContainerRuntime extends TypedEventEmitter {
201
213
  };
202
214
  this.innerDeltaManager = context.deltaManager;
203
215
  this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
216
+ this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
204
217
  let loadSummaryNumber;
205
218
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
206
219
  // get the values from the metadata blob.
@@ -212,6 +225,9 @@ export class ContainerRuntime extends TypedEventEmitter {
212
225
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
213
226
  // the count is reset to 0.
214
227
  loadSummaryNumber = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _b !== void 0 ? _b : 0;
228
+ // Enabling the IdCompressor is a one-way operation and we only want to
229
+ // allow new containers to turn it on
230
+ this.idCompressorEnabled = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _c !== void 0 ? _c : false;
215
231
  }
216
232
  else {
217
233
  this.createContainerMetadata = {
@@ -219,12 +235,13 @@ export class ContainerRuntime extends TypedEventEmitter {
219
235
  createContainerTimestamp: Date.now(),
220
236
  };
221
237
  loadSummaryNumber = 0;
238
+ this.idCompressorEnabled =
239
+ (_d = this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) !== null && _d !== void 0 ? _d : idCompressor !== undefined;
222
240
  }
223
241
  this.nextSummaryNumber = loadSummaryNumber + 1;
224
242
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
225
243
  this._connected = this.context.connected;
226
- this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
227
- this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
244
+ this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_e = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _e === void 0 ? void 0 : _e.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
228
245
  this.mc.logger.sendTelemetryEvent({
229
246
  eventName: "GCFeatureMatrix",
230
247
  metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
@@ -232,7 +249,7 @@ export class ContainerRuntime extends TypedEventEmitter {
232
249
  gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
233
250
  }),
234
251
  });
235
- this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : uuid();
252
+ this.telemetryDocumentId = (_f = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _f !== void 0 ? _f : uuid();
236
253
  this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
237
254
  const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
238
255
  const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
@@ -251,10 +268,13 @@ export class ContainerRuntime extends TypedEventEmitter {
251
268
  this.heuristicsDisabled = this.isHeuristicsDisabled();
252
269
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
253
270
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
271
+ if (this.idCompressorEnabled) {
272
+ this.idCompressor = idCompressor;
273
+ }
254
274
  this.maxConsecutiveReconnects =
255
- (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
275
+ (_g = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _g !== void 0 ? _g : this.defaultMaxConsecutiveReconnects;
256
276
  if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
257
- ((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
277
+ ((_h = context.supportedFeatures) === null || _h === void 0 ? void 0 : _h.get("referenceSequenceNumbers")) !== true) {
258
278
  // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
259
279
  this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
260
280
  this._flushMode = FlushMode.TurnBased;
@@ -263,7 +283,7 @@ export class ContainerRuntime extends TypedEventEmitter {
263
283
  this._flushMode = runtimeOptions.flushMode;
264
284
  }
265
285
  const pendingRuntimeState = context.pendingLocalState;
266
- const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
286
+ const maxSnapshotCacheDurationMs = (_k = (_j = this._storage) === null || _j === void 0 ? void 0 : _j.policies) === null || _k === void 0 ? void 0 : _k.maximumCacheDurationMs;
267
287
  if (maxSnapshotCacheDurationMs !== undefined &&
268
288
  maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
269
289
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
@@ -315,15 +335,9 @@ export class ContainerRuntime extends TypedEventEmitter {
315
335
  this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
316
336
  this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
317
337
  if (!this.disposed) {
318
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
319
- Promise.resolve().then(() => {
320
- // Blob attaches need to be in their own batch (grouped batching would hide metadata)
321
- this.flush();
322
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
323
- localId,
324
- blobId,
325
- });
326
- this.flush();
338
+ this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
339
+ localId,
340
+ blobId,
327
341
  });
328
342
  }
329
343
  }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, (error) => this.closeFn(error));
@@ -358,10 +372,17 @@ export class ContainerRuntime extends TypedEventEmitter {
358
372
  },
359
373
  logger: this.mc.logger,
360
374
  groupingManager: opGroupingManager,
375
+ getCurrentSequenceNumbers: () => ({
376
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
377
+ clientSequenceNumber: this._processedClientSequenceNumber,
378
+ }),
361
379
  });
362
380
  this.context.quorum.on("removeMember", (clientId) => {
363
381
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
364
382
  });
383
+ this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethod");
384
+ const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
385
+ this.closeSummarizerDelayMs = closeSummarizerDelayOverride !== null && closeSummarizerDelayOverride !== void 0 ? closeSummarizerDelayOverride : defaultCloseSummarizerDelayMs;
365
386
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
366
387
  this.dirtyContainer =
367
388
  this.context.attachState !== AttachState.Attached ||
@@ -439,6 +460,9 @@ export class ContainerRuntime extends TypedEventEmitter {
439
460
  disableChunking,
440
461
  disableAttachReorder: this.disableAttachReorder,
441
462
  disablePartialFlush,
463
+ idCompressorEnabled: this.idCompressorEnabled,
464
+ summaryStateUpdateMethod: this.summaryStateUpdateMethod,
465
+ closeSummarizerDelayOverride,
442
466
  }), telemetryDocumentId: this.telemetryDocumentId, groupedBatchingEnabled: this.groupedBatchingEnabled }));
443
467
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
444
468
  BindBatchTracker(this, this.logger);
@@ -498,7 +522,7 @@ export class ContainerRuntime extends TypedEventEmitter {
498
522
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
499
523
  */
500
524
  static async loadRuntime(params) {
501
- var _a, _b, _c, _d;
525
+ var _a, _b, _c, _d, _e, _f;
502
526
  const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
503
527
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
504
528
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
@@ -509,7 +533,7 @@ export class ContainerRuntime extends TypedEventEmitter {
509
533
  runtimeVersion: pkgVersion,
510
534
  },
511
535
  });
512
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
536
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
513
537
  const registry = new FluidDataStoreRegistry(registryEntries);
514
538
  const tryFetchBlob = async (blobName) => {
515
539
  var _a;
@@ -521,11 +545,12 @@ export class ContainerRuntime extends TypedEventEmitter {
521
545
  return readAndParse(context.storage, blobId);
522
546
  }
523
547
  };
524
- const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
548
+ const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
525
549
  tryFetchBlob(chunksBlobName),
526
550
  tryFetchBlob(metadataBlobName),
527
551
  tryFetchBlob(electedSummarizerBlobName),
528
552
  tryFetchBlob(aliasBlobName),
553
+ tryFetchBlob(idCompressorBlobName),
529
554
  ]);
530
555
  const loadExisting = existing === true || context.existing === true;
531
556
  // read snapshot blobs needed for BlobManager to load
@@ -557,6 +582,15 @@ export class ContainerRuntime extends TypedEventEmitter {
557
582
  }
558
583
  }
559
584
  }
585
+ const idCompressorEnabled = (_f = (_e = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _e !== void 0 ? _e : runtimeOptions.enableRuntimeIdCompressor) !== null && _f !== void 0 ? _f : false;
586
+ let idCompressor;
587
+ if (idCompressorEnabled) {
588
+ const { IdCompressor, createSessionId } = await import("./id-compressor");
589
+ idCompressor =
590
+ serializedIdCompressor !== undefined
591
+ ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
592
+ : new IdCompressor(createSessionId(), logger);
593
+ }
560
594
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
561
595
  summaryOptions,
562
596
  gcOptions,
@@ -565,9 +599,10 @@ export class ContainerRuntime extends TypedEventEmitter {
565
599
  compressionOptions,
566
600
  maxBatchSizeInBytes,
567
601
  chunkSizeInBytes,
602
+ enableRuntimeIdCompressor,
568
603
  enableOpReentryCheck,
569
604
  enableGroupedBatching,
570
- }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
605
+ }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
571
606
  initializeEntryPoint);
572
607
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
573
608
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
@@ -803,12 +838,17 @@ export class ContainerRuntime extends TypedEventEmitter {
803
838
  summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
804
839
  // The last message processed at the time of summary. If there are no new messages, use the message from the
805
840
  // last summary.
806
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
841
+ message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId, idCompressorEnabled: this.idCompressorEnabled ? true : undefined });
807
842
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
808
843
  }
809
844
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
810
845
  var _a;
811
846
  this.addMetadataToSummary(summaryTree);
847
+ if (this.idCompressorEnabled) {
848
+ assert(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
849
+ const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
850
+ addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
851
+ }
812
852
  if (this.remoteMessageProcessor.partialMessages.size > 0) {
813
853
  const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
814
854
  addBlobToSummary(summaryTree, chunksBlobName, content);
@@ -890,12 +930,28 @@ export class ContainerRuntime extends TypedEventEmitter {
890
930
  // Officially transition from the old state to the new state.
891
931
  this.updateDocumentDirtyState(newState);
892
932
  }
893
- async applyStashedOp(type, op) {
933
+ /**
934
+ * Updates the runtime's IdCompressor with the stashed state present in the given op. This is a bit of a
935
+ * hack and is unnecessarily expensive. As it stands, every locally stashed op (all ops that get stored in
936
+ * the PendingStateManager) will store their serialized representation locally until ack'd. Upon receiving
937
+ * this stashed state, the IdCompressor blindly deserializes to the stashed state and assumes the session.
938
+ * Technically only the last stashed state is needed to do this correctly, but we would have to write some
939
+ * more hacky code to modify the batch before it gets sent out.
940
+ * @param content - An IdAllocationOp with "stashedState", which is a representation of un-ack'd local state.
941
+ */
942
+ async applyStashedIdAllocationOp(op) {
943
+ const { IdCompressor } = await import("./id-compressor");
944
+ this.idCompressor = IdCompressor.deserialize(op.stashedState);
945
+ }
946
+ async applyStashedOp(type, contents) {
894
947
  switch (type) {
895
948
  case ContainerMessageType.FluidDataStoreOp:
896
- return this.dataStores.applyStashedOp(op);
949
+ return this.dataStores.applyStashedOp(contents);
897
950
  case ContainerMessageType.Attach:
898
- return this.dataStores.applyStashedAttachOp(op);
951
+ return this.dataStores.applyStashedAttachOp(contents);
952
+ case ContainerMessageType.IdAllocation:
953
+ assert(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
954
+ return this.applyStashedIdAllocationOp(contents);
899
955
  case ContainerMessageType.Alias:
900
956
  case ContainerMessageType.BlobAttach:
901
957
  return;
@@ -991,6 +1047,7 @@ export class ContainerRuntime extends TypedEventEmitter {
991
1047
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
992
1048
  // messages once a batch has been fully processed.
993
1049
  this.scheduleManager.beforeOpProcessing(message);
1050
+ this._processedClientSequenceNumber = message.clientSequenceNumber;
994
1051
  try {
995
1052
  let localOpMetadata;
996
1053
  if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
@@ -1015,6 +1072,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1015
1072
  case ContainerMessageType.BlobAttach:
1016
1073
  this.blobManager.processBlobAttachOp(message, local);
1017
1074
  break;
1075
+ case ContainerMessageType.IdAllocation:
1076
+ assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1077
+ this.idCompressor.finalizeCreationRange(message.contents);
1078
+ break;
1018
1079
  case ContainerMessageType.ChunkedOp:
1019
1080
  case ContainerMessageType.Rejoin:
1020
1081
  break;
@@ -1324,17 +1385,21 @@ export class ContainerRuntime extends TypedEventEmitter {
1324
1385
  fullGC,
1325
1386
  runSweep,
1326
1387
  });
1327
- let gcStats;
1328
- if (runGC) {
1329
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1388
+ try {
1389
+ let gcStats;
1390
+ if (runGC) {
1391
+ gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1392
+ }
1393
+ const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1394
+ assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1395
+ return { stats, summary, gcStats };
1396
+ }
1397
+ finally {
1398
+ this.logger.sendTelemetryEvent({
1399
+ eventName: "SummarizeTelemetry",
1400
+ details: telemetryContext.serialize(),
1401
+ });
1330
1402
  }
1331
- const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1332
- this.logger.sendTelemetryEvent({
1333
- eventName: "SummarizeTelemetry",
1334
- details: telemetryContext.serialize(),
1335
- });
1336
- assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1337
- return { stats, summary, gcStats };
1338
1403
  }
1339
1404
  /**
1340
1405
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
@@ -1721,6 +1786,35 @@ export class ContainerRuntime extends TypedEventEmitter {
1721
1786
  this.verifyNotClosed();
1722
1787
  return this.blobManager.createBlob(blob);
1723
1788
  }
1789
+ maybeSubmitIdAllocationOp(type) {
1790
+ var _a, _b;
1791
+ if (type !== ContainerMessageType.IdAllocation) {
1792
+ let idAllocationBatchMessage;
1793
+ let idRange;
1794
+ if (this.idCompressorEnabled) {
1795
+ assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
1796
+ idRange = this.idCompressor.takeNextCreationRange();
1797
+ // Don't include the idRange if there weren't any Ids allocated
1798
+ idRange = ((_a = idRange === null || idRange === void 0 ? void 0 : idRange.ids) === null || _a === void 0 ? void 0 : _a.first) !== undefined ? idRange : undefined;
1799
+ }
1800
+ if (idRange !== undefined) {
1801
+ const idAllocationMessage = {
1802
+ type: ContainerMessageType.IdAllocation,
1803
+ contents: idRange,
1804
+ };
1805
+ idAllocationBatchMessage = {
1806
+ contents: JSON.stringify(idAllocationMessage),
1807
+ deserializedContent: idAllocationMessage,
1808
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1809
+ metadata: undefined,
1810
+ localOpMetadata: (_b = this.idCompressor) === null || _b === void 0 ? void 0 : _b.serialize(true),
1811
+ };
1812
+ }
1813
+ if (idAllocationBatchMessage !== undefined) {
1814
+ this.outbox.submit(idAllocationBatchMessage);
1815
+ }
1816
+ }
1817
+ }
1724
1818
  submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
1725
1819
  this.verifyNotClosed();
1726
1820
  this.verifyCanSubmitOps();
@@ -1743,6 +1837,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1743
1837
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1744
1838
  };
1745
1839
  try {
1840
+ // Submit an IdAllocation op if any Ids have been generated since
1841
+ // the last op was submitted. Don't submit another if it's an IdAllocation
1842
+ // op as that means we're in resubmission flow and we don't want to send
1843
+ // IdRanges out of order.
1844
+ this.maybeSubmitIdAllocationOp(type);
1746
1845
  // If this is attach message for new data store, and we are in a batch, send this op out of order
1747
1846
  // Is it safe:
1748
1847
  // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
@@ -1879,6 +1978,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1879
1978
  break;
1880
1979
  case ContainerMessageType.Attach:
1881
1980
  case ContainerMessageType.Alias:
1981
+ case ContainerMessageType.IdAllocation:
1882
1982
  this.submit(type, content, localOpMetadata);
1883
1983
  break;
1884
1984
  case ContainerMessageType.ChunkedOp:
@@ -1928,6 +2028,19 @@ export class ContainerRuntime extends TypedEventEmitter {
1928
2028
  ackHandle,
1929
2029
  targetSequenceNumber: summaryRefSeq,
1930
2030
  }, readAndParseBlob);
2031
+ /**
2032
+ * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
2033
+ * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
2034
+ * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
2035
+ * change that started fetching latest snapshot always.
2036
+ */
2037
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2038
+ fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2039
+ eventName: "RefreshLatestSummaryAckFetchBackCompat",
2040
+ ackHandle,
2041
+ targetSequenceNumber: summaryRefSeq,
2042
+ }, readAndParseBlob, ackHandle);
2043
+ }
1931
2044
  /**
1932
2045
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
1933
2046
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -1939,21 +2052,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1939
2052
  * state.
1940
2053
  */
1941
2054
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1942
- /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
1943
- fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
1944
- eventName: "RefreshLatestSummaryAckFetch",
2055
+ const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1945
2056
  ackHandle,
1946
- targetSequenceNumber: summaryRefSeq,
1947
- }, readAndParseBlob, ackHandle);
1948
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1949
- const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1950
- ackHandle,
1951
- summaryRefSeq,
1952
- fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1953
- });
1954
- this.closeFn(error);
1955
- throw error;
1956
- }
2057
+ summaryRefSeq,
2058
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2059
+ });
2060
+ this.closeFn(error);
2061
+ throw error;
1957
2062
  }
1958
2063
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
1959
2064
  // wait for the delta manager to catch up before refreshing the latest Summary.
@@ -1992,15 +2097,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1992
2097
  }
1993
2098
  async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
1994
2099
  var _a;
1995
- const recoveryMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummarizationRecoveryMethod");
1996
- if (recoveryMethod === "restart") {
1997
- const error = new GenericError("Restarting summarizer instead of refreshing");
1998
- this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined }), error);
1999
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
2000
- this.closeFn();
2001
- throw error;
2002
- }
2003
- return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2100
+ const snapshotResults = await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2004
2101
  const stats = {};
2005
2102
  const trace = Trace.start();
2006
2103
  const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
@@ -2019,6 +2116,19 @@ export class ContainerRuntime extends TypedEventEmitter {
2019
2116
  latestSnapshotRefSeq,
2020
2117
  };
2021
2118
  });
2119
+ // We choose to close the summarizer after the snapshot cache is updated to avoid
2120
+ // situations which the main client (which is likely to be re-elected as the leader again)
2121
+ // loads the summarizer from cache.
2122
+ if (this.summaryStateUpdateMethod === "restart") {
2123
+ const error = new GenericError("Restarting summarizer instead of refreshing");
2124
+ this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined, closeSummarizerDelayMs: this.closeSummarizerDelayMs }), error);
2125
+ // Delay 10 seconds before restarting summarizer to prevent the summarizer from restarting too frequently.
2126
+ await delay(this.closeSummarizerDelayMs);
2127
+ (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
2128
+ this.closeFn();
2129
+ throw error;
2130
+ }
2131
+ return snapshotResults;
2022
2132
  }
2023
2133
  notifyAttaching() { } // do nothing (deprecated method)
2024
2134
  getPendingLocalState() {