@fluidframework/container-runtime 2.0.0-internal.1.0.0.83139 → 2.0.0-internal.1.1.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 (124) hide show
  1. package/.mocharc.js +12 -0
  2. package/dist/batchTracker.js +1 -1
  3. package/dist/batchTracker.js.map +1 -1
  4. package/dist/blobManager.d.ts +7 -1
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +34 -17
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/containerRuntime.d.ts +3 -104
  9. package/dist/containerRuntime.d.ts.map +1 -1
  10. package/dist/containerRuntime.js +83 -395
  11. package/dist/containerRuntime.js.map +1 -1
  12. package/dist/dataStore.d.ts +1 -1
  13. package/dist/dataStore.d.ts.map +1 -1
  14. package/dist/dataStore.js +2 -3
  15. package/dist/dataStore.js.map +1 -1
  16. package/dist/dataStoreContext.d.ts +3 -5
  17. package/dist/dataStoreContext.d.ts.map +1 -1
  18. package/dist/dataStoreContext.js +13 -23
  19. package/dist/dataStoreContext.js.map +1 -1
  20. package/dist/dataStores.d.ts +1 -1
  21. package/dist/dataStores.d.ts.map +1 -1
  22. package/dist/dataStores.js +3 -8
  23. package/dist/dataStores.js.map +1 -1
  24. package/dist/garbageCollection.d.ts +37 -6
  25. package/dist/garbageCollection.d.ts.map +1 -1
  26. package/dist/garbageCollection.js +61 -65
  27. package/dist/garbageCollection.js.map +1 -1
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +3 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.d.ts.map +1 -1
  34. package/dist/packageVersion.js +1 -1
  35. package/dist/packageVersion.js.map +1 -1
  36. package/dist/pendingStateManager.d.ts.map +1 -1
  37. package/dist/pendingStateManager.js +15 -2
  38. package/dist/pendingStateManager.js.map +1 -1
  39. package/dist/runningSummarizer.js +1 -1
  40. package/dist/runningSummarizer.js.map +1 -1
  41. package/dist/scheduleManager.d.ts +28 -0
  42. package/dist/scheduleManager.d.ts.map +1 -0
  43. package/dist/scheduleManager.js +235 -0
  44. package/dist/scheduleManager.js.map +1 -0
  45. package/dist/summarizer.d.ts.map +1 -1
  46. package/dist/summarizer.js +20 -1
  47. package/dist/summarizer.js.map +1 -1
  48. package/dist/summaryCollection.js +1 -1
  49. package/dist/summaryCollection.js.map +1 -1
  50. package/dist/summaryGenerator.js +1 -1
  51. package/dist/summaryGenerator.js.map +1 -1
  52. package/dist/summaryManager.d.ts.map +1 -1
  53. package/dist/summaryManager.js +20 -5
  54. package/dist/summaryManager.js.map +1 -1
  55. package/lib/batchTracker.js +1 -1
  56. package/lib/batchTracker.js.map +1 -1
  57. package/lib/blobManager.d.ts +7 -1
  58. package/lib/blobManager.d.ts.map +1 -1
  59. package/lib/blobManager.js +35 -18
  60. package/lib/blobManager.js.map +1 -1
  61. package/lib/containerRuntime.d.ts +3 -104
  62. package/lib/containerRuntime.d.ts.map +1 -1
  63. package/lib/containerRuntime.js +84 -395
  64. package/lib/containerRuntime.js.map +1 -1
  65. package/lib/dataStore.d.ts +1 -1
  66. package/lib/dataStore.d.ts.map +1 -1
  67. package/lib/dataStore.js +2 -3
  68. package/lib/dataStore.js.map +1 -1
  69. package/lib/dataStoreContext.d.ts +3 -5
  70. package/lib/dataStoreContext.d.ts.map +1 -1
  71. package/lib/dataStoreContext.js +13 -23
  72. package/lib/dataStoreContext.js.map +1 -1
  73. package/lib/dataStores.d.ts +1 -1
  74. package/lib/dataStores.d.ts.map +1 -1
  75. package/lib/dataStores.js +3 -8
  76. package/lib/dataStores.js.map +1 -1
  77. package/lib/garbageCollection.d.ts +37 -6
  78. package/lib/garbageCollection.d.ts.map +1 -1
  79. package/lib/garbageCollection.js +47 -52
  80. package/lib/garbageCollection.js.map +1 -1
  81. package/lib/index.d.ts +2 -1
  82. package/lib/index.d.ts.map +1 -1
  83. package/lib/index.js +2 -1
  84. package/lib/index.js.map +1 -1
  85. package/lib/packageVersion.d.ts +1 -1
  86. package/lib/packageVersion.d.ts.map +1 -1
  87. package/lib/packageVersion.js +1 -1
  88. package/lib/packageVersion.js.map +1 -1
  89. package/lib/pendingStateManager.d.ts.map +1 -1
  90. package/lib/pendingStateManager.js +15 -2
  91. package/lib/pendingStateManager.js.map +1 -1
  92. package/lib/runningSummarizer.js +1 -1
  93. package/lib/runningSummarizer.js.map +1 -1
  94. package/lib/scheduleManager.d.ts +28 -0
  95. package/lib/scheduleManager.d.ts.map +1 -0
  96. package/lib/scheduleManager.js +231 -0
  97. package/lib/scheduleManager.js.map +1 -0
  98. package/lib/summarizer.d.ts.map +1 -1
  99. package/lib/summarizer.js +22 -3
  100. package/lib/summarizer.js.map +1 -1
  101. package/lib/summaryCollection.js +1 -1
  102. package/lib/summaryCollection.js.map +1 -1
  103. package/lib/summaryGenerator.js +1 -1
  104. package/lib/summaryGenerator.js.map +1 -1
  105. package/lib/summaryManager.d.ts.map +1 -1
  106. package/lib/summaryManager.js +20 -5
  107. package/lib/summaryManager.js.map +1 -1
  108. package/package.json +32 -19
  109. package/src/batchTracker.ts +1 -1
  110. package/src/blobManager.ts +43 -17
  111. package/src/containerRuntime.ts +113 -547
  112. package/src/dataStore.ts +1 -4
  113. package/src/dataStoreContext.ts +10 -25
  114. package/src/dataStores.ts +13 -19
  115. package/src/garbageCollection.ts +64 -69
  116. package/src/index.ts +1 -2
  117. package/src/packageVersion.ts +1 -1
  118. package/src/pendingStateManager.ts +18 -2
  119. package/src/runningSummarizer.ts +1 -1
  120. package/src/scheduleManager.ts +294 -0
  121. package/src/summarizer.ts +28 -3
  122. package/src/summaryCollection.ts +1 -1
  123. package/src/summaryGenerator.ts +1 -1
  124. package/src/summaryManager.ts +20 -5
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.ScheduleManager = exports.unpackRuntimeMessage = exports.isRuntimeMessage = exports.RuntimeMessage = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
3
+ exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.unpackRuntimeMessage = exports.isRuntimeMessage = exports.RuntimeMessage = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
4
4
  const container_definitions_1 = require("@fluidframework/container-definitions");
5
5
  const common_utils_1 = require("@fluidframework/common-utils");
6
6
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
@@ -16,7 +16,6 @@ const containerHandleContext_1 = require("./containerHandleContext");
16
16
  const dataStoreRegistry_1 = require("./dataStoreRegistry");
17
17
  const summarizer_1 = require("./summarizer");
18
18
  const summaryManager_1 = require("./summaryManager");
19
- const deltaScheduler_1 = require("./deltaScheduler");
20
19
  const connectionTelemetry_1 = require("./connectionTelemetry");
21
20
  const pendingStateManager_1 = require("./pendingStateManager");
22
21
  const packageVersion_1 = require("./packageVersion");
@@ -32,6 +31,7 @@ const garbageCollection_1 = require("./garbageCollection");
32
31
  const dataStore_1 = require("./dataStore");
33
32
  const batchTracker_1 = require("./batchTracker");
34
33
  const serializedSnapshotStorage_1 = require("./serializedSnapshotStorage");
34
+ const scheduleManager_1 = require("./scheduleManager");
35
35
  var ContainerMessageType;
36
36
  (function (ContainerMessageType) {
37
37
  // An op to be delivered to store
@@ -77,12 +77,7 @@ var RuntimeHeaders;
77
77
  /** True if the request is coming from an IFluidHandle. */
78
78
  RuntimeHeaders["viaHandle"] = "viaHandle";
79
79
  })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
80
- const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
81
80
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
82
- // Feature gate for the max op size. If the value is negative, chunking is enabled
83
- // and all ops over 16k would be chunked. If the value is positive, all ops with
84
- // a size strictly larger will be rejected and the container closed with an error.
85
- const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
86
81
  // By default, we should reject any op larger than 768KB,
87
82
  // in order to account for some extra overhead from serialization
88
83
  // to not reach the 1MB limits in socket.io and Kafka.
@@ -128,230 +123,6 @@ function unpackRuntimeMessage(message) {
128
123
  return message;
129
124
  }
130
125
  exports.unpackRuntimeMessage = unpackRuntimeMessage;
131
- /**
132
- * This class controls pausing and resuming of inbound queue to ensure that we never
133
- * start processing ops in a batch IF we do not have all ops in the batch.
134
- */
135
- class ScheduleManagerCore {
136
- constructor(deltaManager, logger) {
137
- this.deltaManager = deltaManager;
138
- this.logger = logger;
139
- this.localPaused = false;
140
- this.timePaused = 0;
141
- this.batchCount = 0;
142
- // Listen for delta manager sends and add batch metadata to messages
143
- this.deltaManager.on("prepareSend", (messages) => {
144
- if (messages.length === 0) {
145
- return;
146
- }
147
- // First message will have the batch flag set to true if doing a batched send
148
- const firstMessageMetadata = messages[0].metadata;
149
- if (!(firstMessageMetadata === null || firstMessageMetadata === void 0 ? void 0 : firstMessageMetadata.batch)) {
150
- return;
151
- }
152
- // If the batch contains only a single op, clear the batch flag.
153
- if (messages.length === 1) {
154
- delete firstMessageMetadata.batch;
155
- return;
156
- }
157
- // Set the batch flag to false on the last message to indicate the end of the send batch
158
- const lastMessage = messages[messages.length - 1];
159
- lastMessage.metadata = Object.assign(Object.assign({}, lastMessage.metadata), { batch: false });
160
- });
161
- // Listen for updates and peek at the inbound
162
- this.deltaManager.inbound.on("push", (message) => {
163
- this.trackPending(message);
164
- });
165
- // Start with baseline - empty inbound queue.
166
- (0, common_utils_1.assert)(!this.localPaused, 0x293 /* "initial state" */);
167
- const allPending = this.deltaManager.inbound.toArray();
168
- for (const pending of allPending) {
169
- this.trackPending(pending);
170
- }
171
- // We are intentionally directly listening to the "op" to inspect system ops as well.
172
- // If we do not observe system ops, we are likely to hit 0x296 assert when system ops
173
- // precedes start of incomplete batch.
174
- this.deltaManager.on("op", (message) => this.afterOpProcessing(message.sequenceNumber));
175
- }
176
- /**
177
- * The only public function in this class - called when we processed an op,
178
- * to make decision if op processing should be paused or not afer that.
179
- */
180
- afterOpProcessing(sequenceNumber) {
181
- (0, common_utils_1.assert)(!this.localPaused, 0x294 /* "can't have op processing paused if we are processing an op" */);
182
- // If the inbound queue is ever empty, nothing to do!
183
- if (this.deltaManager.inbound.length === 0) {
184
- (0, common_utils_1.assert)(this.pauseSequenceNumber === undefined, 0x295 /* "there should be no pending batch if we have no ops" */);
185
- return;
186
- }
187
- // The queue is
188
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
189
- // - here (processing ops until reaching start of incomplete batch)
190
- // - in trackPending(), when queue was empty and start of batch showed up.
191
- // 2. resumed when batch end comes in (in trackPending())
192
- // do we have incomplete batch to worry about?
193
- if (this.pauseSequenceNumber !== undefined) {
194
- (0, common_utils_1.assert)(sequenceNumber < this.pauseSequenceNumber, 0x296 /* "we should never start processing incomplete batch!" */);
195
- // If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!
196
- if (sequenceNumber + 1 === this.pauseSequenceNumber) {
197
- this.pauseQueue();
198
- }
199
- }
200
- }
201
- pauseQueue() {
202
- (0, common_utils_1.assert)(!this.localPaused, 0x297 /* "always called from resumed state" */);
203
- this.localPaused = true;
204
- this.timePaused = common_utils_1.performance.now();
205
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
206
- this.deltaManager.inbound.pause();
207
- }
208
- resumeQueue(startBatch, messageEndBatch) {
209
- const endBatch = messageEndBatch.sequenceNumber;
210
- const duration = this.localPaused ? (common_utils_1.performance.now() - this.timePaused) : undefined;
211
- this.batchCount++;
212
- if (this.batchCount % 1000 === 1) {
213
- this.logger.sendTelemetryEvent({
214
- eventName: "BatchStats",
215
- sequenceNumber: endBatch,
216
- length: endBatch - startBatch + 1,
217
- msnDistance: endBatch - messageEndBatch.minimumSequenceNumber,
218
- duration,
219
- batchCount: this.batchCount,
220
- interrupted: this.localPaused,
221
- });
222
- }
223
- // Return early if no change in value
224
- if (!this.localPaused) {
225
- return;
226
- }
227
- this.localPaused = false;
228
- // Random round number - we want to know when batch waiting paused op processing.
229
- if (duration !== undefined && duration > connectionTelemetry_1.latencyThreshold) {
230
- this.logger.sendErrorEvent({
231
- eventName: "MaxBatchWaitTimeExceeded",
232
- duration,
233
- sequenceNumber: endBatch,
234
- length: endBatch - startBatch,
235
- });
236
- }
237
- this.deltaManager.inbound.resume();
238
- }
239
- /**
240
- * Called for each incoming op (i.e. inbound "push" notification)
241
- */
242
- trackPending(message) {
243
- (0, common_utils_1.assert)(this.deltaManager.inbound.length !== 0, 0x298 /* "we have something in the queue that generates this event" */);
244
- (0, common_utils_1.assert)((this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined), 0x299 /* "non-synchronized state" */);
245
- const metadata = message.metadata;
246
- const batchMetadata = metadata === null || metadata === void 0 ? void 0 : metadata.batch;
247
- // Protocol messages are never part of a runtime batch of messages
248
- if (!(0, driver_utils_1.isUnpackedRuntimeMessage)(message)) {
249
- // Protocol messages should never show up in the middle of the batch!
250
- (0, common_utils_1.assert)(this.currentBatchClientId === undefined, 0x29a /* "System message in the middle of batch!" */);
251
- (0, common_utils_1.assert)(batchMetadata === undefined, 0x29b /* "system op in a batch?" */);
252
- (0, common_utils_1.assert)(!this.localPaused, 0x29c /* "we should be processing ops when there is no active batch" */);
253
- return;
254
- }
255
- if (this.currentBatchClientId === undefined && batchMetadata === undefined) {
256
- (0, common_utils_1.assert)(!this.localPaused, 0x29d /* "we should be processing ops when there is no active batch" */);
257
- return;
258
- }
259
- // If the client ID changes then we can move the pause point. If it stayed the same then we need to check.
260
- // If batchMetadata is not undefined then if it's true we've begun a new batch - if false we've ended
261
- // the previous one
262
- if (this.currentBatchClientId !== undefined || batchMetadata === false) {
263
- if (this.currentBatchClientId !== message.clientId) {
264
- // "Batch not closed, yet message from another client!"
265
- throw new container_utils_1.DataCorruptionError("OpBatchIncomplete", Object.assign({ runtimeVersion: packageVersion_1.pkgVersion, batchClientId: this.currentBatchClientId }, (0, container_utils_1.extractSafePropertiesFromMessage)(message)));
266
- }
267
- }
268
- // The queue is
269
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
270
- // - in afterOpProcessing() - processing ops until reaching start of incomplete batch
271
- // - here (batchMetadata == false below), when queue was empty and start of batch showed up.
272
- // 2. resumed when batch end comes in (batchMetadata === true case below)
273
- if (batchMetadata) {
274
- (0, common_utils_1.assert)(this.currentBatchClientId === undefined, 0x29e /* "there can't be active batch" */);
275
- (0, common_utils_1.assert)(!this.localPaused, 0x29f /* "we should be processing ops when there is no active batch" */);
276
- this.pauseSequenceNumber = message.sequenceNumber;
277
- this.currentBatchClientId = message.clientId;
278
- // Start of the batch
279
- // Only pause processing if queue has no other ops!
280
- // If there are any other ops in the queue, processing will be stopped when they are processed!
281
- if (this.deltaManager.inbound.length === 1) {
282
- this.pauseQueue();
283
- }
284
- }
285
- else if (batchMetadata === false) {
286
- (0, common_utils_1.assert)(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
287
- // Batch is complete, we can process it!
288
- this.resumeQueue(this.pauseSequenceNumber, message);
289
- this.pauseSequenceNumber = undefined;
290
- this.currentBatchClientId = undefined;
291
- }
292
- else {
293
- // Continuation of current batch. Do nothing
294
- (0, common_utils_1.assert)(this.currentBatchClientId !== undefined, 0x2a1 /* "logic error" */);
295
- }
296
- }
297
- }
298
- /**
299
- * This class has the following responsibilities:
300
- * 1. It tracks batches as we process ops and raises "batchBegin" and "batchEnd" events.
301
- * As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)
302
- * 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch
303
- * unless all ops of the batch are in.
304
- */
305
- class ScheduleManager {
306
- constructor(deltaManager, emitter, logger) {
307
- this.deltaManager = deltaManager;
308
- this.emitter = emitter;
309
- this.logger = logger;
310
- this.hitError = false;
311
- this.deltaScheduler = new deltaScheduler_1.DeltaScheduler(this.deltaManager, telemetry_utils_1.ChildLogger.create(this.logger, "DeltaScheduler"));
312
- void new ScheduleManagerCore(deltaManager, logger);
313
- }
314
- beforeOpProcessing(message) {
315
- var _a;
316
- if (this.batchClientId !== message.clientId) {
317
- (0, common_utils_1.assert)(this.batchClientId === undefined, 0x2a2 /* "Batch is interrupted by other client op. Should be caught by trackPending()" */);
318
- // This could be the beginning of a new batch or an individual message.
319
- this.emitter.emit("batchBegin", message);
320
- this.deltaScheduler.batchBegin(message);
321
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
322
- if (batch) {
323
- this.batchClientId = message.clientId;
324
- }
325
- else {
326
- this.batchClientId = undefined;
327
- }
328
- }
329
- }
330
- afterOpProcessing(error, message) {
331
- var _a;
332
- // If this is no longer true, we need to revisit what we do where we set this.hitError.
333
- (0, common_utils_1.assert)(!this.hitError, 0x2a3 /* "container should be closed on any error" */);
334
- if (error) {
335
- // We assume here that loader will close container and stop processing all future ops.
336
- // This is implicit dependency. If this flow changes, this code might no longer be correct.
337
- this.hitError = true;
338
- this.batchClientId = undefined;
339
- this.emitter.emit("batchEnd", error, message);
340
- this.deltaScheduler.batchEnd(message);
341
- return;
342
- }
343
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
344
- // If no batchClientId has been set then we're in an individual batch. Else, if we get
345
- // batch end metadata, this is end of the current batch.
346
- if (this.batchClientId === undefined || batch === false) {
347
- this.batchClientId = undefined;
348
- this.emitter.emit("batchEnd", undefined, message);
349
- this.deltaScheduler.batchEnd(message);
350
- return;
351
- }
352
- }
353
- }
354
- exports.ScheduleManager = ScheduleManager;
355
126
  /**
356
127
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
357
128
  * special-case for document dirty state. Ultimately we should have no special-cases from the
@@ -379,7 +150,7 @@ exports.getDeviceSpec = getDeviceSpec;
379
150
  */
380
151
  class ContainerRuntime extends common_utils_1.TypedEventEmitter {
381
152
  constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
382
- var _a, _b, _c, _d, _e, _f, _g, _h;
153
+ var _a, _b, _c, _d;
383
154
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, exports.DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
384
155
  super();
385
156
  this.context = context;
@@ -390,7 +161,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
390
161
  this._storage = _storage;
391
162
  this.requestHandler = requestHandler;
392
163
  this.summaryConfiguration = summaryConfiguration;
393
- this.defaultMaxConsecutiveReconnects = 15;
164
+ this.defaultMaxConsecutiveReconnects = 7;
394
165
  this._orderSequentiallyCalls = 0;
395
166
  this.needsFlush = false;
396
167
  this.flushTrigger = false;
@@ -434,8 +205,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
434
205
  }
435
206
  };
436
207
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
437
- // Default to false (enabled).
438
- this.disableIsolatedChannels = (_b = this.runtimeOptions.summaryOptions.disableIsolatedChannels) !== null && _b !== void 0 ? _b : false;
439
208
  this._connected = this.context.connected;
440
209
  this.chunkMap = new Map(chunks);
441
210
  this.handleContext = new containerHandleContext_1.ContainerFluidHandleContext("", this);
@@ -448,15 +217,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
448
217
  this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
449
218
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
450
219
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
451
- this._aliasingEnabled =
452
- ((_c = this.mc.config.getBoolean(useDataStoreAliasingKey)) !== null && _c !== void 0 ? _c : false) ||
453
- ((_d = runtimeOptions.useDataStoreAliasing) !== null && _d !== void 0 ? _d : false);
454
- this._maxOpSizeInBytes = ((_e = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _e !== void 0 ? _e : defaultMaxOpSizeInBytes);
455
220
  this.maxConsecutiveReconnects =
456
- (_f = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _f !== void 0 ? _f : this.defaultMaxConsecutiveReconnects;
221
+ (_b = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _b !== void 0 ? _b : this.defaultMaxConsecutiveReconnects;
457
222
  this._flushMode = runtimeOptions.flushMode;
458
223
  const pendingRuntimeState = context.pendingLocalState;
459
- const baseSnapshot = (_g = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _g !== void 0 ? _g : context.baseSnapshot;
224
+ const baseSnapshot = (_c = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _c !== void 0 ? _c : context.baseSnapshot;
460
225
  this.garbageCollector = garbageCollection_1.GarbageCollector.create({
461
226
  runtime: this,
462
227
  gcOptions: this.runtimeOptions.gcOptions,
@@ -490,8 +255,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
490
255
  this.summarizerNode.loadBaseSummaryWithoutDifferential(baseSnapshot);
491
256
  }
492
257
  this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
493
- this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this);
494
- this.scheduleManager = new ScheduleManager(context.deltaManager, this, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
258
+ this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => {
259
+ if (!this.disposed) {
260
+ this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId });
261
+ }
262
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
263
+ this.scheduleManager = new scheduleManager_1.ScheduleManager(context.deltaManager, this, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
495
264
  this.deltaSender = this.deltaManager;
496
265
  this.pendingStateManager = new pendingStateManager_1.PendingStateManager({
497
266
  applyStashedOp: this.applyStashedOp.bind(this),
@@ -583,7 +352,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
583
352
  };
584
353
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
585
354
  // the count is reset to 0.
586
- loadSummaryNumber = (_h = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _h !== void 0 ? _h : 0;
355
+ loadSummaryNumber = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _d !== void 0 ? _d : 0;
587
356
  }
588
357
  else {
589
358
  this.createContainerMetadata = {
@@ -618,7 +387,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
618
387
  runtimeVersion: packageVersion_1.pkgVersion,
619
388
  },
620
389
  });
621
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, flushMode = defaultFlushMode, enableOfflineLoad = false, } = runtimeOptions;
390
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, } = runtimeOptions;
622
391
  const pendingRuntimeState = context.pendingLocalState;
623
392
  const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
624
393
  const storage = !pendingRuntimeState ?
@@ -671,7 +440,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
671
440
  summaryOptions,
672
441
  gcOptions,
673
442
  loadSequenceNumberVerification,
674
- useDataStoreAliasing,
675
443
  flushMode,
676
444
  enableOfflineLoad,
677
445
  }, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
@@ -930,7 +698,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
930
698
  var _a;
931
699
  const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
932
700
  // Increment the summary number for the next summary that will be generated.
933
- summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined }), this.garbageCollector.getMetadata()), {
701
+ summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
934
702
  // The last message processed at the time of summary. If there are no new messages, use the message from the
935
703
  // last summary.
936
704
  message: (_a = (0, summaryFormat_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
@@ -1053,8 +821,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1053
821
  // ensure we don't submit ops referencing a blob that has not been uploaded
1054
822
  const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
1055
823
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
1056
- (0, common_utils_1.assert)(!this.delayConnectClientId, "Connect event delay must be canceled before subsequent connect event");
1057
- (0, common_utils_1.assert)(!!clientId, "Must have clientId when connecting");
824
+ (0, common_utils_1.assert)(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
825
+ (0, common_utils_1.assert)(!!clientId, 0x393 /* Must have clientId when connecting */);
1058
826
  this.delayConnectClientId = clientId;
1059
827
  this.blobManager.onConnected().then(() => {
1060
828
  // make sure we didn't reconnect before the promise resolved
@@ -1068,17 +836,18 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1068
836
  this.setConnectionStateCore(connected, clientId);
1069
837
  }
1070
838
  setConnectionStateCore(connected, clientId) {
1071
- (0, common_utils_1.assert)(!this.delayConnectClientId, "connect event delay must be cleared before propagating connect event");
839
+ (0, common_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1072
840
  this.verifyNotClosed();
1073
841
  // There might be no change of state due to Container calling this API after loading runtime.
1074
842
  const changeOfState = this._connected !== connected;
1075
- const reconnection = changeOfState && connected;
843
+ const reconnection = changeOfState && !connected;
1076
844
  this._connected = connected;
1077
845
  if (!connected) {
1078
846
  this._perfSignalData.signalsLost = 0;
1079
847
  this._perfSignalData.signalTimestamp = 0;
1080
848
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1081
849
  }
850
+ // Fail while disconnected
1082
851
  if (reconnection) {
1083
852
  this.consecutiveReconnects++;
1084
853
  if (!this.shouldContinueReconnecting()) {
@@ -1310,59 +1079,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1310
1079
  }
1311
1080
  async createDataStore(pkg) {
1312
1081
  const internalId = (0, uuid_1.v4)();
1313
- return (0, dataStore_1.channelToDataStore)(await this._createDataStore(pkg, false /* isRoot */, internalId), internalId, this, this.dataStores, this.mc.logger);
1314
- }
1315
- /**
1316
- * Creates a root datastore directly with a user generated id and attaches it to storage.
1317
- * It is vulnerable to name collisions and should not be used.
1318
- *
1319
- * This method will be removed. See #6465.
1320
- */
1321
- async createRootDataStoreLegacy(pkg, rootDataStoreId) {
1322
- const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
1323
- fluidDataStore.makeVisibleAndAttachGraph();
1324
- return fluidDataStore;
1325
- }
1326
- /**
1327
- * @deprecated - will be removed in an upcoming release. See #9660.
1328
- */
1329
- async createRootDataStore(pkg, rootDataStoreId) {
1330
- if (rootDataStoreId.includes("/")) {
1331
- throw new container_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1332
- }
1333
- return this._aliasingEnabled === true ?
1334
- this.createAndAliasDataStore(pkg, rootDataStoreId) :
1335
- this.createRootDataStoreLegacy(pkg, rootDataStoreId);
1336
- }
1337
- /**
1338
- * Creates a data store then attempts to alias it.
1339
- * If aliasing fails, it will raise an exception.
1340
- *
1341
- * This method will be removed. See #6465.
1342
- *
1343
- * @param pkg - Package name of the data store
1344
- * @param alias - Alias to be assigned to the data store
1345
- * @param props - Properties for the data store
1346
- * @returns - An aliased data store which can can be found / loaded by alias.
1347
- */
1348
- async createAndAliasDataStore(pkg, alias, props) {
1349
- const internalId = (0, uuid_1.v4)();
1350
- try {
1351
- // A similar call may have been initiated by the same client, so we should try to get
1352
- // a possible existing aliased datastore first.
1353
- const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
1354
- return (0, dataStore_1.channelToDataStore)(existingDataStore, internalId, this, this.dataStores, this.mc.logger, true);
1355
- }
1356
- catch (err) {
1357
- const newChannel = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
1358
- const newDataStore = (0, dataStore_1.channelToDataStore)(newChannel, internalId, this, this.dataStores, this.mc.logger);
1359
- const aliasResult = await newDataStore.trySetAlias(alias);
1360
- if (aliasResult === "Success") {
1361
- return newDataStore;
1362
- }
1363
- const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
1364
- return (0, dataStore_1.channelToDataStore)(existingDataStore, internalId, this, this.dataStores, this.mc.logger, true);
1365
- }
1082
+ return (0, dataStore_1.channelToDataStore)(await this._createDataStore(pkg, internalId), internalId, this, this.dataStores, this.mc.logger);
1366
1083
  }
1367
1084
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1368
1085
  if (rootDataStoreId.includes("/")) {
@@ -1373,31 +1090,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1373
1090
  createDetachedDataStore(pkg) {
1374
1091
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1375
1092
  }
1376
- /**
1377
- * Creates a possibly root datastore directly with a possibly user generated id and attaches it to storage.
1378
- * It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
1379
- *
1380
- * This method will be removed. See #6465.
1381
- */
1382
- async _createDataStoreWithPropsLegacy(pkg, props, id = (0, uuid_1.v4)(), isRoot = false) {
1383
- const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1384
- if (isRoot) {
1385
- fluidDataStore.makeVisibleAndAttachGraph();
1386
- this.logger.sendTelemetryEvent({
1387
- eventName: "Root datastore with props",
1388
- hasProps: props !== undefined,
1389
- });
1390
- }
1093
+ async _createDataStoreWithProps(pkg, props, id = (0, uuid_1.v4)()) {
1094
+ const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props).realize();
1391
1095
  return (0, dataStore_1.channelToDataStore)(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1392
1096
  }
1393
- async _createDataStoreWithProps(pkg, props, id = (0, uuid_1.v4)(), isRoot = false) {
1394
- return this._aliasingEnabled === true && isRoot ?
1395
- this.createAndAliasDataStore(pkg, id, props) :
1396
- this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
1397
- }
1398
- async _createDataStore(pkg, isRoot, id = (0, uuid_1.v4)(), props) {
1097
+ async _createDataStore(pkg, id = (0, uuid_1.v4)(), props) {
1399
1098
  return this.dataStores
1400
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props)
1099
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1401
1100
  .realize();
1402
1101
  }
1403
1102
  canSendOps() {
@@ -1489,10 +1188,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1489
1188
  this.blobManager.setRedirectTable(blobRedirectTable);
1490
1189
  }
1491
1190
  const summarizeResult = this.dataStores.createSummary(telemetryContext);
1492
- if (!this.disableIsolatedChannels) {
1493
- // Wrap data store summaries in .channels subtree.
1494
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1495
- }
1191
+ // Wrap data store summaries in .channels subtree.
1192
+ (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1496
1193
  this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1497
1194
  return summarizeResult.summary;
1498
1195
  }
@@ -1507,12 +1204,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1507
1204
  }
1508
1205
  async summarizeInternal(fullTree, trackState, telemetryContext) {
1509
1206
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1510
- let pathPartsForChildren;
1511
- if (!this.disableIsolatedChannels) {
1512
- // Wrap data store summaries in .channels subtree.
1513
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1514
- pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1515
- }
1207
+ // Wrap data store summaries in .channels subtree.
1208
+ (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1209
+ const pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1516
1210
  this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1517
1211
  return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
1518
1212
  }
@@ -1671,16 +1365,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1671
1365
  const summaryNumberLogger = telemetry_utils_1.ChildLogger.create(summaryLogger, undefined, {
1672
1366
  all: { summaryNumber },
1673
1367
  });
1368
+ let latestSnapshotVersionId;
1674
1369
  if (refreshLatestAck) {
1675
- const latestSummaryRefSeq = await this.refreshLatestSummaryAckFromServer(telemetry_utils_1.ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1676
- if (latestSummaryRefSeq > this.deltaManager.lastSequenceNumber) {
1370
+ const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(telemetry_utils_1.ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1371
+ const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1372
+ latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1373
+ if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
1677
1374
  // We need to catch up to the latest summary's reference sequence number before pausing.
1678
1375
  await telemetry_utils_1.PerformanceEvent.timedExecAsync(summaryNumberLogger, {
1679
1376
  eventName: "WaitingForSeq",
1680
1377
  lastSequenceNumber: this.deltaManager.lastSequenceNumber,
1681
- targetSequenceNumber: latestSummaryRefSeq,
1378
+ targetSequenceNumber: latestSnapshotRefSeq,
1682
1379
  lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
1683
- }, async () => waitForSeq(this.deltaManager, latestSummaryRefSeq), { start: true, end: true, cancel: "error" });
1380
+ }, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
1684
1381
  }
1685
1382
  }
1686
1383
  try {
@@ -1716,7 +1413,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1716
1413
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1717
1414
  };
1718
1415
  }
1719
- (0, common_utils_1.assert)(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), "it's one and the same thing");
1416
+ (0, common_utils_1.assert)(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), 0x395 /* it's one and the same thing */);
1720
1417
  if (lastAck !== this.summaryCollection.latestAck) {
1721
1418
  return {
1722
1419
  continue: false,
@@ -1762,7 +1459,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1762
1459
  // Counting dataStores and handles
1763
1460
  // Because handles are unchanged dataStores in the current logic,
1764
1461
  // summarized dataStore count is total dataStore count minus handle count
1765
- const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[runtime_definitions_1.channelsTreeName];
1462
+ const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1766
1463
  (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1767
1464
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1768
1465
  const gcSummaryTreeStats = summaryTree.tree[garbageCollection_1.gcTreeKey]
@@ -1781,17 +1478,34 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1781
1478
  if (!continueResult.continue) {
1782
1479
  return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1783
1480
  }
1784
- const summaryContext = lastAck === undefined
1785
- ? {
1481
+ // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
1482
+ // summary. So if the previous summarizer closes just after submitting the summary and before
1483
+ // submitting the summaryOp then we can't rely on summaryAck. So in case we have
1484
+ // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1485
+ // the one fetched from storage as parent as that is the latest.
1486
+ let summaryContext;
1487
+ if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
1488
+ && latestSnapshotVersionId !== undefined) {
1489
+ summaryContext = {
1490
+ proposalHandle: undefined,
1491
+ ackHandle: latestSnapshotVersionId,
1492
+ referenceSequenceNumber: summaryRefSeqNum,
1493
+ };
1494
+ }
1495
+ else if (lastAck === undefined) {
1496
+ summaryContext = {
1786
1497
  proposalHandle: undefined,
1787
1498
  ackHandle: (_b = this.context.getLoadedFromVersion()) === null || _b === void 0 ? void 0 : _b.id,
1788
1499
  referenceSequenceNumber: summaryRefSeqNum,
1789
- }
1790
- : {
1500
+ };
1501
+ }
1502
+ else {
1503
+ summaryContext = {
1791
1504
  proposalHandle: lastAck.summaryOp.contents.handle,
1792
1505
  ackHandle: lastAck.summaryAck.contents.handle,
1793
1506
  referenceSequenceNumber: summaryRefSeqNum,
1794
1507
  };
1508
+ }
1795
1509
  let handle;
1796
1510
  try {
1797
1511
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
@@ -1898,7 +1612,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1898
1612
  let opMetadataInternal = opMetadata;
1899
1613
  if (this.canSendOps()) {
1900
1614
  const serializedContent = JSON.stringify(content);
1901
- const maxOpSize = this.context.deltaManager.maxMessageSize;
1902
1615
  // If in TurnBased flush mode we will trigger a flush at the next turn break
1903
1616
  if (this.flushMode === runtime_definitions_1.FlushMode.TurnBased && !this.needsFlush) {
1904
1617
  opMetadataInternal = Object.assign(Object.assign({}, opMetadata), { batch: true });
@@ -1912,7 +1625,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1912
1625
  });
1913
1626
  }
1914
1627
  }
1915
- clientSequenceNumber = this.submitMaybeChunkedMessages(type, content, serializedContent, maxOpSize, this._flushMode === runtime_definitions_1.FlushMode.TurnBased, opMetadataInternal);
1628
+ if (!serializedContent || serializedContent.length <= defaultMaxOpSizeInBytes) {
1629
+ clientSequenceNumber = this.submitRuntimeMessage(type, content, this._flushMode === runtime_definitions_1.FlushMode.TurnBased /* batch */, opMetadataInternal);
1630
+ }
1631
+ else {
1632
+ // If the content length is larger than the client configured message size
1633
+ // instead of splitting the content, we will fail by explicitly closing the container
1634
+ this.closeFn(new container_utils_1.GenericError("OpTooLarge",
1635
+ /* error */ undefined, {
1636
+ length: serializedContent.length,
1637
+ limit: defaultMaxOpSizeInBytes,
1638
+ }));
1639
+ clientSequenceNumber = -1;
1640
+ }
1916
1641
  }
1917
1642
  // Let the PendingStateManager know that a message was submitted.
1918
1643
  this.pendingStateManager.onSubmitMessage(type, clientSequenceNumber, this.deltaManager.lastSequenceNumber, content, localOpMetadata, opMetadataInternal);
@@ -1920,46 +1645,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1920
1645
  this.updateDocumentDirtyState(true);
1921
1646
  }
1922
1647
  }
1923
- submitMaybeChunkedMessages(type, content, serializedContent, serverMaxOpSize, batch, opMetadataInternal = undefined) {
1924
- if (this._maxOpSizeInBytes >= 0) {
1925
- // Chunking disabled
1926
- if (!serializedContent || serializedContent.length <= this._maxOpSizeInBytes) {
1927
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1928
- }
1929
- // When chunking is disabled, we ignore the server max message size
1930
- // and if the content length is larger than the client configured message size
1931
- // instead of splitting the content, we will fail by explicitly close the container
1932
- this.closeFn(new container_utils_1.GenericError("OpTooLarge",
1933
- /* error */ undefined, {
1934
- length: serializedContent.length,
1935
- limit: this._maxOpSizeInBytes,
1936
- }));
1937
- return -1;
1938
- }
1939
- // Chunking enabled, fallback on the server's max message size
1940
- // and split the content accordingly
1941
- if (!serializedContent || serializedContent.length <= serverMaxOpSize) {
1942
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1943
- }
1944
- return this.submitChunkedMessage(type, serializedContent, serverMaxOpSize);
1945
- }
1946
- submitChunkedMessage(type, content, maxOpSize) {
1947
- const contentLength = content.length;
1948
- const chunkN = Math.floor((contentLength - 1) / maxOpSize) + 1;
1949
- let offset = 0;
1950
- let clientSequenceNumber = 0;
1951
- for (let i = 1; i <= chunkN; i = i + 1) {
1952
- const chunkedOp = {
1953
- chunkId: i,
1954
- contents: content.substr(offset, maxOpSize),
1955
- originalType: type,
1956
- totalChunks: chunkN,
1957
- };
1958
- offset += maxOpSize;
1959
- clientSequenceNumber = this.submitRuntimeMessage(ContainerMessageType.ChunkedOp, chunkedOp, false);
1960
- }
1961
- return clientSequenceNumber;
1962
- }
1963
1648
  submitSystemMessage(type, contents) {
1964
1649
  this.verifyNotClosed();
1965
1650
  (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
@@ -2030,12 +1715,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2030
1715
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2031
1716
  async refreshLatestSummaryAck(proposalHandle, ackHandle, summaryRefSeq, summaryLogger) {
2032
1717
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2033
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, async () => this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
1718
+ const { snapshotTree } = await this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
2034
1719
  eventName: "RefreshLatestSummaryGetSnapshot",
2035
1720
  ackHandle,
2036
1721
  summaryRefSeq,
2037
1722
  fetchLatest: false,
2038
- }), readAndParseBlob, summaryLogger);
1723
+ });
1724
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
2039
1725
  // Notify the garbage collector so it can update its latest summary state.
2040
1726
  await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
2041
1727
  }
@@ -2046,16 +1732,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2046
1732
  * @returns downloaded snapshot's reference sequence number
2047
1733
  */
2048
1734
  async refreshLatestSummaryAckFromServer(summaryLogger) {
2049
- const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1735
+ const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
2050
1736
  eventName: "RefreshLatestSummaryGetSnapshot",
2051
1737
  fetchLatest: true,
2052
1738
  }, driver_definitions_1.FetchSource.noCache);
2053
1739
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2054
- const snapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(snapshot, readAndParseBlob);
2055
- const result = await this.summarizerNode.refreshLatestSummary(undefined, snapshotRefSeq, async () => snapshot, readAndParseBlob, summaryLogger);
1740
+ const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(snapshotTree, readAndParseBlob);
1741
+ const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
2056
1742
  // Notify the garbage collector so it can update its latest summary state.
2057
1743
  await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
2058
- return snapshotRefSeq;
1744
+ return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2059
1745
  }
2060
1746
  async fetchSnapshotFromStorage(versionId, logger, event, fetchSource) {
2061
1747
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
@@ -2068,7 +1754,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2068
1754
  (0, common_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2069
1755
  stats.getSnapshotDuration = trace.trace().duration;
2070
1756
  perfEvent.end(stats);
2071
- return maybeSnapshot;
1757
+ return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
2072
1758
  });
2073
1759
  }
2074
1760
  notifyAttaching(snapshot) {
@@ -2095,6 +1781,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2095
1781
  if (previousPendingState) {
2096
1782
  return {
2097
1783
  pending: this.pendingStateManager.getLocalState(),
1784
+ pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2098
1785
  snapshotBlobs: previousPendingState.snapshotBlobs,
2099
1786
  baseSnapshot: previousPendingState.baseSnapshot,
2100
1787
  savedOps: this.savedOps,
@@ -2104,6 +1791,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2104
1791
  (0, common_utils_1.assert)(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
2105
1792
  return {
2106
1793
  pending: this.pendingStateManager.getLocalState(),
1794
+ pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2107
1795
  snapshotBlobs: this.baseSnapshotBlobs,
2108
1796
  baseSnapshot: this.context.baseSnapshot,
2109
1797
  savedOps: this.savedOps,