@fluidframework/container-runtime 2.0.0-internal.1.0.0.84253 → 2.0.0-internal.1.1.0

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 (91) hide show
  1. package/.mocharc.js +12 -0
  2. package/dist/blobManager.d.ts +7 -1
  3. package/dist/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager.js +18 -1
  5. package/dist/blobManager.js.map +1 -1
  6. package/dist/containerRuntime.d.ts +2 -66
  7. package/dist/containerRuntime.d.ts.map +1 -1
  8. package/dist/containerRuntime.js +37 -295
  9. package/dist/containerRuntime.js.map +1 -1
  10. package/dist/dataStoreContext.d.ts +3 -5
  11. package/dist/dataStoreContext.d.ts.map +1 -1
  12. package/dist/dataStoreContext.js +13 -23
  13. package/dist/dataStoreContext.js.map +1 -1
  14. package/dist/dataStores.d.ts.map +1 -1
  15. package/dist/dataStores.js +1 -6
  16. package/dist/dataStores.js.map +1 -1
  17. package/dist/garbageCollection.d.ts +37 -6
  18. package/dist/garbageCollection.d.ts.map +1 -1
  19. package/dist/garbageCollection.js +61 -65
  20. package/dist/garbageCollection.js.map +1 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/packageVersion.d.ts +1 -1
  26. package/dist/packageVersion.d.ts.map +1 -1
  27. package/dist/packageVersion.js +1 -1
  28. package/dist/packageVersion.js.map +1 -1
  29. package/dist/pendingStateManager.d.ts.map +1 -1
  30. package/dist/pendingStateManager.js +15 -2
  31. package/dist/pendingStateManager.js.map +1 -1
  32. package/dist/scheduleManager.d.ts +28 -0
  33. package/dist/scheduleManager.d.ts.map +1 -0
  34. package/dist/scheduleManager.js +235 -0
  35. package/dist/scheduleManager.js.map +1 -0
  36. package/dist/summaryCollection.js +1 -1
  37. package/dist/summaryCollection.js.map +1 -1
  38. package/dist/summaryManager.d.ts.map +1 -1
  39. package/dist/summaryManager.js +20 -5
  40. package/dist/summaryManager.js.map +1 -1
  41. package/lib/blobManager.d.ts +7 -1
  42. package/lib/blobManager.d.ts.map +1 -1
  43. package/lib/blobManager.js +19 -2
  44. package/lib/blobManager.js.map +1 -1
  45. package/lib/containerRuntime.d.ts +2 -66
  46. package/lib/containerRuntime.d.ts.map +1 -1
  47. package/lib/containerRuntime.js +38 -295
  48. package/lib/containerRuntime.js.map +1 -1
  49. package/lib/dataStoreContext.d.ts +3 -5
  50. package/lib/dataStoreContext.d.ts.map +1 -1
  51. package/lib/dataStoreContext.js +13 -23
  52. package/lib/dataStoreContext.js.map +1 -1
  53. package/lib/dataStores.d.ts.map +1 -1
  54. package/lib/dataStores.js +1 -6
  55. package/lib/dataStores.js.map +1 -1
  56. package/lib/garbageCollection.d.ts +37 -6
  57. package/lib/garbageCollection.d.ts.map +1 -1
  58. package/lib/garbageCollection.js +47 -52
  59. package/lib/garbageCollection.js.map +1 -1
  60. package/lib/index.d.ts +2 -1
  61. package/lib/index.d.ts.map +1 -1
  62. package/lib/index.js +2 -1
  63. package/lib/index.js.map +1 -1
  64. package/lib/packageVersion.d.ts +1 -1
  65. package/lib/packageVersion.d.ts.map +1 -1
  66. package/lib/packageVersion.js +1 -1
  67. package/lib/packageVersion.js.map +1 -1
  68. package/lib/pendingStateManager.d.ts.map +1 -1
  69. package/lib/pendingStateManager.js +15 -2
  70. package/lib/pendingStateManager.js.map +1 -1
  71. package/lib/scheduleManager.d.ts +28 -0
  72. package/lib/scheduleManager.d.ts.map +1 -0
  73. package/lib/scheduleManager.js +231 -0
  74. package/lib/scheduleManager.js.map +1 -0
  75. package/lib/summaryCollection.js +1 -1
  76. package/lib/summaryCollection.js.map +1 -1
  77. package/lib/summaryManager.d.ts.map +1 -1
  78. package/lib/summaryManager.js +20 -5
  79. package/lib/summaryManager.js.map +1 -1
  80. package/package.json +19 -15
  81. package/src/blobManager.ts +23 -1
  82. package/src/containerRuntime.ts +42 -392
  83. package/src/dataStoreContext.ts +10 -25
  84. package/src/dataStores.ts +0 -6
  85. package/src/garbageCollection.ts +64 -69
  86. package/src/index.ts +1 -2
  87. package/src/packageVersion.ts +1 -1
  88. package/src/pendingStateManager.ts +18 -2
  89. package/src/scheduleManager.ts +294 -0
  90. package/src/summaryCollection.ts +1 -1
  91. 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
@@ -78,10 +78,6 @@ var RuntimeHeaders;
78
78
  RuntimeHeaders["viaHandle"] = "viaHandle";
79
79
  })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
80
80
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
81
- // Feature gate for the max op size. If the value is negative, chunking is enabled
82
- // and all ops over 16k would be chunked. If the value is positive, all ops with
83
- // a size strictly larger will be rejected and the container closed with an error.
84
- const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
85
81
  // By default, we should reject any op larger than 768KB,
86
82
  // in order to account for some extra overhead from serialization
87
83
  // to not reach the 1MB limits in socket.io and Kafka.
@@ -127,230 +123,6 @@ function unpackRuntimeMessage(message) {
127
123
  return message;
128
124
  }
129
125
  exports.unpackRuntimeMessage = unpackRuntimeMessage;
130
- /**
131
- * This class controls pausing and resuming of inbound queue to ensure that we never
132
- * start processing ops in a batch IF we do not have all ops in the batch.
133
- */
134
- class ScheduleManagerCore {
135
- constructor(deltaManager, logger) {
136
- this.deltaManager = deltaManager;
137
- this.logger = logger;
138
- this.localPaused = false;
139
- this.timePaused = 0;
140
- this.batchCount = 0;
141
- // Listen for delta manager sends and add batch metadata to messages
142
- this.deltaManager.on("prepareSend", (messages) => {
143
- if (messages.length === 0) {
144
- return;
145
- }
146
- // First message will have the batch flag set to true if doing a batched send
147
- const firstMessageMetadata = messages[0].metadata;
148
- if (!(firstMessageMetadata === null || firstMessageMetadata === void 0 ? void 0 : firstMessageMetadata.batch)) {
149
- return;
150
- }
151
- // If the batch contains only a single op, clear the batch flag.
152
- if (messages.length === 1) {
153
- delete firstMessageMetadata.batch;
154
- return;
155
- }
156
- // Set the batch flag to false on the last message to indicate the end of the send batch
157
- const lastMessage = messages[messages.length - 1];
158
- lastMessage.metadata = Object.assign(Object.assign({}, lastMessage.metadata), { batch: false });
159
- });
160
- // Listen for updates and peek at the inbound
161
- this.deltaManager.inbound.on("push", (message) => {
162
- this.trackPending(message);
163
- });
164
- // Start with baseline - empty inbound queue.
165
- (0, common_utils_1.assert)(!this.localPaused, 0x293 /* "initial state" */);
166
- const allPending = this.deltaManager.inbound.toArray();
167
- for (const pending of allPending) {
168
- this.trackPending(pending);
169
- }
170
- // We are intentionally directly listening to the "op" to inspect system ops as well.
171
- // If we do not observe system ops, we are likely to hit 0x296 assert when system ops
172
- // precedes start of incomplete batch.
173
- this.deltaManager.on("op", (message) => this.afterOpProcessing(message.sequenceNumber));
174
- }
175
- /**
176
- * The only public function in this class - called when we processed an op,
177
- * to make decision if op processing should be paused or not afer that.
178
- */
179
- afterOpProcessing(sequenceNumber) {
180
- (0, common_utils_1.assert)(!this.localPaused, 0x294 /* "can't have op processing paused if we are processing an op" */);
181
- // If the inbound queue is ever empty, nothing to do!
182
- if (this.deltaManager.inbound.length === 0) {
183
- (0, common_utils_1.assert)(this.pauseSequenceNumber === undefined, 0x295 /* "there should be no pending batch if we have no ops" */);
184
- return;
185
- }
186
- // The queue is
187
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
188
- // - here (processing ops until reaching start of incomplete batch)
189
- // - in trackPending(), when queue was empty and start of batch showed up.
190
- // 2. resumed when batch end comes in (in trackPending())
191
- // do we have incomplete batch to worry about?
192
- if (this.pauseSequenceNumber !== undefined) {
193
- (0, common_utils_1.assert)(sequenceNumber < this.pauseSequenceNumber, 0x296 /* "we should never start processing incomplete batch!" */);
194
- // If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!
195
- if (sequenceNumber + 1 === this.pauseSequenceNumber) {
196
- this.pauseQueue();
197
- }
198
- }
199
- }
200
- pauseQueue() {
201
- (0, common_utils_1.assert)(!this.localPaused, 0x297 /* "always called from resumed state" */);
202
- this.localPaused = true;
203
- this.timePaused = common_utils_1.performance.now();
204
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
205
- this.deltaManager.inbound.pause();
206
- }
207
- resumeQueue(startBatch, messageEndBatch) {
208
- const endBatch = messageEndBatch.sequenceNumber;
209
- const duration = this.localPaused ? (common_utils_1.performance.now() - this.timePaused) : undefined;
210
- this.batchCount++;
211
- if (this.batchCount % 1000 === 1) {
212
- this.logger.sendTelemetryEvent({
213
- eventName: "BatchStats",
214
- sequenceNumber: endBatch,
215
- length: endBatch - startBatch + 1,
216
- msnDistance: endBatch - messageEndBatch.minimumSequenceNumber,
217
- duration,
218
- batchCount: this.batchCount,
219
- interrupted: this.localPaused,
220
- });
221
- }
222
- // Return early if no change in value
223
- if (!this.localPaused) {
224
- return;
225
- }
226
- this.localPaused = false;
227
- // Random round number - we want to know when batch waiting paused op processing.
228
- if (duration !== undefined && duration > connectionTelemetry_1.latencyThreshold) {
229
- this.logger.sendErrorEvent({
230
- eventName: "MaxBatchWaitTimeExceeded",
231
- duration,
232
- sequenceNumber: endBatch,
233
- length: endBatch - startBatch,
234
- });
235
- }
236
- this.deltaManager.inbound.resume();
237
- }
238
- /**
239
- * Called for each incoming op (i.e. inbound "push" notification)
240
- */
241
- trackPending(message) {
242
- (0, common_utils_1.assert)(this.deltaManager.inbound.length !== 0, 0x298 /* "we have something in the queue that generates this event" */);
243
- (0, common_utils_1.assert)((this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined), 0x299 /* "non-synchronized state" */);
244
- const metadata = message.metadata;
245
- const batchMetadata = metadata === null || metadata === void 0 ? void 0 : metadata.batch;
246
- // Protocol messages are never part of a runtime batch of messages
247
- if (!(0, driver_utils_1.isUnpackedRuntimeMessage)(message)) {
248
- // Protocol messages should never show up in the middle of the batch!
249
- (0, common_utils_1.assert)(this.currentBatchClientId === undefined, 0x29a /* "System message in the middle of batch!" */);
250
- (0, common_utils_1.assert)(batchMetadata === undefined, 0x29b /* "system op in a batch?" */);
251
- (0, common_utils_1.assert)(!this.localPaused, 0x29c /* "we should be processing ops when there is no active batch" */);
252
- return;
253
- }
254
- if (this.currentBatchClientId === undefined && batchMetadata === undefined) {
255
- (0, common_utils_1.assert)(!this.localPaused, 0x29d /* "we should be processing ops when there is no active batch" */);
256
- return;
257
- }
258
- // If the client ID changes then we can move the pause point. If it stayed the same then we need to check.
259
- // If batchMetadata is not undefined then if it's true we've begun a new batch - if false we've ended
260
- // the previous one
261
- if (this.currentBatchClientId !== undefined || batchMetadata === false) {
262
- if (this.currentBatchClientId !== message.clientId) {
263
- // "Batch not closed, yet message from another client!"
264
- throw new container_utils_1.DataCorruptionError("OpBatchIncomplete", Object.assign({ runtimeVersion: packageVersion_1.pkgVersion, batchClientId: this.currentBatchClientId }, (0, container_utils_1.extractSafePropertiesFromMessage)(message)));
265
- }
266
- }
267
- // The queue is
268
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
269
- // - in afterOpProcessing() - processing ops until reaching start of incomplete batch
270
- // - here (batchMetadata == false below), when queue was empty and start of batch showed up.
271
- // 2. resumed when batch end comes in (batchMetadata === true case below)
272
- if (batchMetadata) {
273
- (0, common_utils_1.assert)(this.currentBatchClientId === undefined, 0x29e /* "there can't be active batch" */);
274
- (0, common_utils_1.assert)(!this.localPaused, 0x29f /* "we should be processing ops when there is no active batch" */);
275
- this.pauseSequenceNumber = message.sequenceNumber;
276
- this.currentBatchClientId = message.clientId;
277
- // Start of the batch
278
- // Only pause processing if queue has no other ops!
279
- // If there are any other ops in the queue, processing will be stopped when they are processed!
280
- if (this.deltaManager.inbound.length === 1) {
281
- this.pauseQueue();
282
- }
283
- }
284
- else if (batchMetadata === false) {
285
- (0, common_utils_1.assert)(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
286
- // Batch is complete, we can process it!
287
- this.resumeQueue(this.pauseSequenceNumber, message);
288
- this.pauseSequenceNumber = undefined;
289
- this.currentBatchClientId = undefined;
290
- }
291
- else {
292
- // Continuation of current batch. Do nothing
293
- (0, common_utils_1.assert)(this.currentBatchClientId !== undefined, 0x2a1 /* "logic error" */);
294
- }
295
- }
296
- }
297
- /**
298
- * This class has the following responsibilities:
299
- * 1. It tracks batches as we process ops and raises "batchBegin" and "batchEnd" events.
300
- * As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)
301
- * 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch
302
- * unless all ops of the batch are in.
303
- */
304
- class ScheduleManager {
305
- constructor(deltaManager, emitter, logger) {
306
- this.deltaManager = deltaManager;
307
- this.emitter = emitter;
308
- this.logger = logger;
309
- this.hitError = false;
310
- this.deltaScheduler = new deltaScheduler_1.DeltaScheduler(this.deltaManager, telemetry_utils_1.ChildLogger.create(this.logger, "DeltaScheduler"));
311
- void new ScheduleManagerCore(deltaManager, logger);
312
- }
313
- beforeOpProcessing(message) {
314
- var _a;
315
- if (this.batchClientId !== message.clientId) {
316
- (0, common_utils_1.assert)(this.batchClientId === undefined, 0x2a2 /* "Batch is interrupted by other client op. Should be caught by trackPending()" */);
317
- // This could be the beginning of a new batch or an individual message.
318
- this.emitter.emit("batchBegin", message);
319
- this.deltaScheduler.batchBegin(message);
320
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
321
- if (batch) {
322
- this.batchClientId = message.clientId;
323
- }
324
- else {
325
- this.batchClientId = undefined;
326
- }
327
- }
328
- }
329
- afterOpProcessing(error, message) {
330
- var _a;
331
- // If this is no longer true, we need to revisit what we do where we set this.hitError.
332
- (0, common_utils_1.assert)(!this.hitError, 0x2a3 /* "container should be closed on any error" */);
333
- if (error) {
334
- // We assume here that loader will close container and stop processing all future ops.
335
- // This is implicit dependency. If this flow changes, this code might no longer be correct.
336
- this.hitError = true;
337
- this.batchClientId = undefined;
338
- this.emitter.emit("batchEnd", error, message);
339
- this.deltaScheduler.batchEnd(message);
340
- return;
341
- }
342
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
343
- // If no batchClientId has been set then we're in an individual batch. Else, if we get
344
- // batch end metadata, this is end of the current batch.
345
- if (this.batchClientId === undefined || batch === false) {
346
- this.batchClientId = undefined;
347
- this.emitter.emit("batchEnd", undefined, message);
348
- this.deltaScheduler.batchEnd(message);
349
- return;
350
- }
351
- }
352
- }
353
- exports.ScheduleManager = ScheduleManager;
354
126
  /**
355
127
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
356
128
  * special-case for document dirty state. Ultimately we should have no special-cases from the
@@ -378,7 +150,7 @@ exports.getDeviceSpec = getDeviceSpec;
378
150
  */
379
151
  class ContainerRuntime extends common_utils_1.TypedEventEmitter {
380
152
  constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
381
- var _a, _b, _c, _d, _e, _f;
153
+ var _a, _b, _c, _d;
382
154
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, exports.DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
383
155
  super();
384
156
  this.context = context;
@@ -389,7 +161,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
389
161
  this._storage = _storage;
390
162
  this.requestHandler = requestHandler;
391
163
  this.summaryConfiguration = summaryConfiguration;
392
- this.defaultMaxConsecutiveReconnects = 15;
164
+ this.defaultMaxConsecutiveReconnects = 7;
393
165
  this._orderSequentiallyCalls = 0;
394
166
  this.needsFlush = false;
395
167
  this.flushTrigger = false;
@@ -433,8 +205,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
433
205
  }
434
206
  };
435
207
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
436
- // Default to false (enabled).
437
- this.disableIsolatedChannels = (_b = this.runtimeOptions.summaryOptions.disableIsolatedChannels) !== null && _b !== void 0 ? _b : false;
438
208
  this._connected = this.context.connected;
439
209
  this.chunkMap = new Map(chunks);
440
210
  this.handleContext = new containerHandleContext_1.ContainerFluidHandleContext("", this);
@@ -447,12 +217,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
447
217
  this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
448
218
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
449
219
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
450
- this._maxOpSizeInBytes = ((_c = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _c !== void 0 ? _c : defaultMaxOpSizeInBytes);
451
220
  this.maxConsecutiveReconnects =
452
- (_d = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _d !== void 0 ? _d : this.defaultMaxConsecutiveReconnects;
221
+ (_b = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _b !== void 0 ? _b : this.defaultMaxConsecutiveReconnects;
453
222
  this._flushMode = runtimeOptions.flushMode;
454
223
  const pendingRuntimeState = context.pendingLocalState;
455
- const baseSnapshot = (_e = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _e !== void 0 ? _e : context.baseSnapshot;
224
+ const baseSnapshot = (_c = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _c !== void 0 ? _c : context.baseSnapshot;
456
225
  this.garbageCollector = garbageCollection_1.GarbageCollector.create({
457
226
  runtime: this,
458
227
  gcOptions: this.runtimeOptions.gcOptions,
@@ -486,8 +255,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
486
255
  this.summarizerNode.loadBaseSummaryWithoutDifferential(baseSnapshot);
487
256
  }
488
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);
489
- 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);
490
- 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"));
491
264
  this.deltaSender = this.deltaManager;
492
265
  this.pendingStateManager = new pendingStateManager_1.PendingStateManager({
493
266
  applyStashedOp: this.applyStashedOp.bind(this),
@@ -579,7 +352,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
579
352
  };
580
353
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
581
354
  // the count is reset to 0.
582
- loadSummaryNumber = (_f = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _f !== void 0 ? _f : 0;
355
+ loadSummaryNumber = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _d !== void 0 ? _d : 0;
583
356
  }
584
357
  else {
585
358
  this.createContainerMetadata = {
@@ -925,7 +698,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
925
698
  var _a;
926
699
  const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
927
700
  // Increment the summary number for the next summary that will be generated.
928
- summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined }), this.garbageCollector.getMetadata()), {
701
+ summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
929
702
  // The last message processed at the time of summary. If there are no new messages, use the message from the
930
703
  // last summary.
931
704
  message: (_a = (0, summaryFormat_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
@@ -1067,13 +840,14 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1067
840
  this.verifyNotClosed();
1068
841
  // There might be no change of state due to Container calling this API after loading runtime.
1069
842
  const changeOfState = this._connected !== connected;
1070
- const reconnection = changeOfState && connected;
843
+ const reconnection = changeOfState && !connected;
1071
844
  this._connected = connected;
1072
845
  if (!connected) {
1073
846
  this._perfSignalData.signalsLost = 0;
1074
847
  this._perfSignalData.signalTimestamp = 0;
1075
848
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1076
849
  }
850
+ // Fail while disconnected
1077
851
  if (reconnection) {
1078
852
  this.consecutiveReconnects++;
1079
853
  if (!this.shouldContinueReconnecting()) {
@@ -1414,10 +1188,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1414
1188
  this.blobManager.setRedirectTable(blobRedirectTable);
1415
1189
  }
1416
1190
  const summarizeResult = this.dataStores.createSummary(telemetryContext);
1417
- if (!this.disableIsolatedChannels) {
1418
- // Wrap data store summaries in .channels subtree.
1419
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1420
- }
1191
+ // Wrap data store summaries in .channels subtree.
1192
+ (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1421
1193
  this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1422
1194
  return summarizeResult.summary;
1423
1195
  }
@@ -1432,12 +1204,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1432
1204
  }
1433
1205
  async summarizeInternal(fullTree, trackState, telemetryContext) {
1434
1206
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1435
- let pathPartsForChildren;
1436
- if (!this.disableIsolatedChannels) {
1437
- // Wrap data store summaries in .channels subtree.
1438
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1439
- pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1440
- }
1207
+ // Wrap data store summaries in .channels subtree.
1208
+ (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1209
+ const pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1441
1210
  this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1442
1211
  return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
1443
1212
  }
@@ -1690,7 +1459,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1690
1459
  // Counting dataStores and handles
1691
1460
  // Because handles are unchanged dataStores in the current logic,
1692
1461
  // summarized dataStore count is total dataStore count minus handle count
1693
- const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[runtime_definitions_1.channelsTreeName];
1462
+ const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1694
1463
  (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1695
1464
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1696
1465
  const gcSummaryTreeStats = summaryTree.tree[garbageCollection_1.gcTreeKey]
@@ -1843,7 +1612,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1843
1612
  let opMetadataInternal = opMetadata;
1844
1613
  if (this.canSendOps()) {
1845
1614
  const serializedContent = JSON.stringify(content);
1846
- const maxOpSize = this.context.deltaManager.maxMessageSize;
1847
1615
  // If in TurnBased flush mode we will trigger a flush at the next turn break
1848
1616
  if (this.flushMode === runtime_definitions_1.FlushMode.TurnBased && !this.needsFlush) {
1849
1617
  opMetadataInternal = Object.assign(Object.assign({}, opMetadata), { batch: true });
@@ -1857,7 +1625,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1857
1625
  });
1858
1626
  }
1859
1627
  }
1860
- 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
+ }
1861
1641
  }
1862
1642
  // Let the PendingStateManager know that a message was submitted.
1863
1643
  this.pendingStateManager.onSubmitMessage(type, clientSequenceNumber, this.deltaManager.lastSequenceNumber, content, localOpMetadata, opMetadataInternal);
@@ -1865,46 +1645,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1865
1645
  this.updateDocumentDirtyState(true);
1866
1646
  }
1867
1647
  }
1868
- submitMaybeChunkedMessages(type, content, serializedContent, serverMaxOpSize, batch, opMetadataInternal = undefined) {
1869
- if (this._maxOpSizeInBytes >= 0) {
1870
- // Chunking disabled
1871
- if (!serializedContent || serializedContent.length <= this._maxOpSizeInBytes) {
1872
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1873
- }
1874
- // When chunking is disabled, we ignore the server max message size
1875
- // and if the content length is larger than the client configured message size
1876
- // instead of splitting the content, we will fail by explicitly close the container
1877
- this.closeFn(new container_utils_1.GenericError("OpTooLarge",
1878
- /* error */ undefined, {
1879
- length: serializedContent.length,
1880
- limit: this._maxOpSizeInBytes,
1881
- }));
1882
- return -1;
1883
- }
1884
- // Chunking enabled, fallback on the server's max message size
1885
- // and split the content accordingly
1886
- if (!serializedContent || serializedContent.length <= serverMaxOpSize) {
1887
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1888
- }
1889
- return this.submitChunkedMessage(type, serializedContent, serverMaxOpSize);
1890
- }
1891
- submitChunkedMessage(type, content, maxOpSize) {
1892
- const contentLength = content.length;
1893
- const chunkN = Math.floor((contentLength - 1) / maxOpSize) + 1;
1894
- let offset = 0;
1895
- let clientSequenceNumber = 0;
1896
- for (let i = 1; i <= chunkN; i = i + 1) {
1897
- const chunkedOp = {
1898
- chunkId: i,
1899
- contents: content.substr(offset, maxOpSize),
1900
- originalType: type,
1901
- totalChunks: chunkN,
1902
- };
1903
- offset += maxOpSize;
1904
- clientSequenceNumber = this.submitRuntimeMessage(ContainerMessageType.ChunkedOp, chunkedOp, false);
1905
- }
1906
- return clientSequenceNumber;
1907
- }
1908
1648
  submitSystemMessage(type, contents) {
1909
1649
  this.verifyNotClosed();
1910
1650
  (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
@@ -2041,6 +1781,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2041
1781
  if (previousPendingState) {
2042
1782
  return {
2043
1783
  pending: this.pendingStateManager.getLocalState(),
1784
+ pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2044
1785
  snapshotBlobs: previousPendingState.snapshotBlobs,
2045
1786
  baseSnapshot: previousPendingState.baseSnapshot,
2046
1787
  savedOps: this.savedOps,
@@ -2050,6 +1791,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2050
1791
  (0, common_utils_1.assert)(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
2051
1792
  return {
2052
1793
  pending: this.pendingStateManager.getLocalState(),
1794
+ pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2053
1795
  snapshotBlobs: this.baseSnapshotBlobs,
2054
1796
  baseSnapshot: this.context.baseSnapshot,
2055
1797
  savedOps: this.savedOps,