@fluidframework/container-runtime 2.0.0-rc.4.0.0 → 2.0.0-rc.4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,10 @@ import { BatchMessage, IBatch, IBatchCheckpoint } from "./definitions.js";
7
7
  export interface IBatchManagerOptions {
8
8
  readonly hardLimit: number;
9
9
  readonly compressionOptions?: ICompressionRuntimeOptions;
10
+ /**
11
+ * If true, the outbox is allowed to rebase the batch during flushing.
12
+ */
13
+ readonly canRebase: boolean;
10
14
  }
11
15
  export interface BatchSequenceNumbers {
12
16
  referenceSequenceNumber?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;CACzD;AAED,MAAM,WAAW,oBAAoB;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAQD;;GAEG;AACH,qBAAa,YAAY;aA2BI,OAAO,EAAE,oBAAoB;IA1BzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAEhC,IAAW,MAAM,WAEhB;IACD,IAAW,kBAAkB,WAE5B;IAED,IAAW,eAAe,IAAI,oBAAoB,CAKjD;IAED,OAAO,KAAK,uBAAuB,GAIlC;IAED,OAAO,CAAC,oBAAoB,CAAqB;gBAErB,OAAO,EAAE,oBAAoB;IAElD,IAAI,CACV,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,OAAO,EAClB,2BAA2B,CAAC,EAAE,MAAM,GAClC,OAAO;IAyBV,IAAW,KAAK,YAEf;IAEM,QAAQ,IAAI,MAAM;IAgBzB;;OAEG;IACI,UAAU,IAAI,gBAAgB;CAerC;AAiBD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAElD,CAAC;AAEF,eAAO,MAAM,oBAAoB,YACvB,oBAAoB,gBACf,oBAAoB,KAChC,OASF,CAAC"}
1
+ {"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAQD;;GAEG;AACH,qBAAa,YAAY;aA2BI,OAAO,EAAE,oBAAoB;IA1BzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAEhC,IAAW,MAAM,WAEhB;IACD,IAAW,kBAAkB,WAE5B;IAED,IAAW,eAAe,IAAI,oBAAoB,CAKjD;IAED,OAAO,KAAK,uBAAuB,GAIlC;IAED,OAAO,CAAC,oBAAoB,CAAqB;gBAErB,OAAO,EAAE,oBAAoB;IAElD,IAAI,CACV,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,OAAO,EAClB,2BAA2B,CAAC,EAAE,MAAM,GAClC,OAAO;IAyBV,IAAW,KAAK,YAEf;IAEM,QAAQ,IAAI,MAAM;IAgBzB;;OAEG;IACI,UAAU,IAAI,gBAAgB;CAerC;AAiBD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAElD,CAAC;AAEF,eAAO,MAAM,oBAAoB,YACvB,oBAAoB,gBACf,oBAAoB,KAChC,OASF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\n\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n}\n\nexport interface BatchSequenceNumbers {\n\treferenceSequenceNumber?: number;\n\tclientSequenceNumber?: number;\n}\n\n/**\n * Estimated size of the stringification overhead for an op accumulated\n * from runtime to loader to the service.\n */\nconst opOverhead = 200;\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: BatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\tprivate hasReentrantOps = false;\n\n\tpublic get length() {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes() {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get sequenceNumbers(): BatchSequenceNumbers {\n\t\treturn {\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tclientSequenceNumber: this.clientSequenceNumber,\n\t\t};\n\t}\n\n\tprivate get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: this.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\tprivate clientSequenceNumber: number | undefined;\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(\n\t\tmessage: BatchMessage,\n\t\treentrant: boolean,\n\t\tcurrentClientSequenceNumber?: number,\n\t): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.contents?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\t\tthis.hasReentrantOps = this.hasReentrantOps || reentrant;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + opOverhead * opCount;\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.pendingBatch.length === 0) {\n\t\t\tthis.clientSequenceNumber = currentClientSequenceNumber;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty() {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\tpublic popBatch(): IBatch {\n\t\tconst batch: IBatch = {\n\t\t\tcontent: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\thasReentrantOps: this.hasReentrantOps,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\t\tthis.clientSequenceNumber = undefined;\n\t\tthis.hasReentrantOps = false;\n\n\t\treturn addBatchMetadata(batch);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: BatchMessage) => void) => {\n\t\t\t\tfor (let i = this.pendingBatch.length; i > startPoint; ) {\n\t\t\t\t\ti--;\n\t\t\t\t\tconst message = this.pendingBatch[i];\n\t\t\t\t\tthis.batchContentSize -= message.contents?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\n\t\t\t\tthis.pendingBatch.length = startPoint;\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: IBatch): IBatch => {\n\tif (batch.content.length > 1) {\n\t\tbatch.content[0].metadata = {\n\t\t\t...batch.content[0].metadata,\n\t\t\tbatch: true,\n\t\t};\n\t\tbatch.content[batch.content.length - 1].metadata = {\n\t\t\t...batch.content[batch.content.length - 1].metadata,\n\t\t\tbatch: false,\n\t\t};\n\t}\n\n\treturn batch;\n};\n\n/**\n * Estimates the real size in bytes on the socket for a given batch. It assumes that\n * the envelope size (and the size of an empty op) is 200 bytes, taking into account\n * extra overhead from stringification.\n *\n * @param batch - the batch to inspect\n * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire\n */\nexport const estimateSocketSize = (batch: IBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.content.length;\n};\n\nexport const sequenceNumbersMatch = (\n\tseqNums: BatchSequenceNumbers,\n\totherSeqNums: BatchSequenceNumbers,\n): boolean => {\n\treturn (\n\t\t(seqNums.referenceSequenceNumber === undefined ||\n\t\t\totherSeqNums.referenceSequenceNumber === undefined ||\n\t\t\tseqNums.referenceSequenceNumber === otherSeqNums.referenceSequenceNumber) &&\n\t\t(seqNums.clientSequenceNumber === undefined ||\n\t\t\totherSeqNums.clientSequenceNumber === undefined ||\n\t\t\tseqNums.clientSequenceNumber === otherSeqNums.clientSequenceNumber)\n\t);\n};\n"]}
1
+ {"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\n\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n\n\t/**\n\t * If true, the outbox is allowed to rebase the batch during flushing.\n\t */\n\treadonly canRebase: boolean;\n}\n\nexport interface BatchSequenceNumbers {\n\treferenceSequenceNumber?: number;\n\tclientSequenceNumber?: number;\n}\n\n/**\n * Estimated size of the stringification overhead for an op accumulated\n * from runtime to loader to the service.\n */\nconst opOverhead = 200;\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: BatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\tprivate hasReentrantOps = false;\n\n\tpublic get length() {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes() {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get sequenceNumbers(): BatchSequenceNumbers {\n\t\treturn {\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tclientSequenceNumber: this.clientSequenceNumber,\n\t\t};\n\t}\n\n\tprivate get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: this.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\tprivate clientSequenceNumber: number | undefined;\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(\n\t\tmessage: BatchMessage,\n\t\treentrant: boolean,\n\t\tcurrentClientSequenceNumber?: number,\n\t): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.contents?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\t\tthis.hasReentrantOps = this.hasReentrantOps || reentrant;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + opOverhead * opCount;\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.pendingBatch.length === 0) {\n\t\t\tthis.clientSequenceNumber = currentClientSequenceNumber;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty() {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\tpublic popBatch(): IBatch {\n\t\tconst batch: IBatch = {\n\t\t\tcontent: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\thasReentrantOps: this.hasReentrantOps,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\t\tthis.clientSequenceNumber = undefined;\n\t\tthis.hasReentrantOps = false;\n\n\t\treturn addBatchMetadata(batch);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: BatchMessage) => void) => {\n\t\t\t\tfor (let i = this.pendingBatch.length; i > startPoint; ) {\n\t\t\t\t\ti--;\n\t\t\t\t\tconst message = this.pendingBatch[i];\n\t\t\t\t\tthis.batchContentSize -= message.contents?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\n\t\t\t\tthis.pendingBatch.length = startPoint;\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: IBatch): IBatch => {\n\tif (batch.content.length > 1) {\n\t\tbatch.content[0].metadata = {\n\t\t\t...batch.content[0].metadata,\n\t\t\tbatch: true,\n\t\t};\n\t\tbatch.content[batch.content.length - 1].metadata = {\n\t\t\t...batch.content[batch.content.length - 1].metadata,\n\t\t\tbatch: false,\n\t\t};\n\t}\n\n\treturn batch;\n};\n\n/**\n * Estimates the real size in bytes on the socket for a given batch. It assumes that\n * the envelope size (and the size of an empty op) is 200 bytes, taking into account\n * extra overhead from stringification.\n *\n * @param batch - the batch to inspect\n * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire\n */\nexport const estimateSocketSize = (batch: IBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.content.length;\n};\n\nexport const sequenceNumbersMatch = (\n\tseqNums: BatchSequenceNumbers,\n\totherSeqNums: BatchSequenceNumbers,\n): boolean => {\n\treturn (\n\t\t(seqNums.referenceSequenceNumber === undefined ||\n\t\t\totherSeqNums.referenceSequenceNumber === undefined ||\n\t\t\tseqNums.referenceSequenceNumber === otherSeqNums.referenceSequenceNumber) &&\n\t\t(seqNums.clientSequenceNumber === undefined ||\n\t\t\totherSeqNums.clientSequenceNumber === undefined ||\n\t\t\tseqNums.clientSequenceNumber === otherSeqNums.clientSequenceNumber)\n\t);\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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"}
@@ -54,9 +54,9 @@ export class Outbox {
54
54
  Number.POSITIVE_INFINITY;
55
55
  // We need to allow infinite size batches if we enable compression
56
56
  const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
57
- this.mainBatch = new BatchManager({ hardLimit });
58
- this.blobAttachBatch = new BatchManager({ hardLimit });
59
- this.idAllocationBatch = new BatchManager({ hardLimit });
57
+ this.mainBatch = new BatchManager({ hardLimit, canRebase: true });
58
+ this.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });
59
+ this.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });
60
60
  }
61
61
  get messageCount() {
62
62
  return this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;
@@ -165,7 +165,7 @@ export class Outbox {
165
165
  }
166
166
  const rawBatch = batchManager.popBatch();
167
167
  const shouldGroup = !disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);
168
- if (rawBatch.hasReentrantOps === true && shouldGroup) {
168
+ if (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {
169
169
  assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
170
170
  // If a batch contains reentrant ops (ops created as a result from processing another op)
171
171
  // it needs to be rebased so that we can ensure consistent reference sequence numbers
@@ -190,6 +190,7 @@ export class Outbox {
190
190
  */
191
191
  rebase(rawBatch, batchManager) {
192
192
  assert(!this.rebasing, 0x6fb /* Reentrancy */);
193
+ assert(batchManager.options.canRebase, "BatchManager does not support rebase");
193
194
  this.rebasing = true;
194
195
  for (const message of rawBatch.content) {
195
196
  this.params.reSubmit({
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tGenericError,\n\tMonitoringContext,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { IPendingBatchMessage, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n} from \"./batchManager.js\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: IBatch) => void;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryBaseLogger;\n\treadonly groupingManager: OpGroupingManager;\n\treadonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;\n\treadonly reSubmit: (message: IPendingBatchMessage) => void;\n\treadonly opReentrancy: () => boolean;\n\treadonly closeContainer: (error?: ICriticalContainerError) => void;\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\nexport class Outbox {\n\tprivate readonly mc: MonitoringContext;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly blobAttachBatch: BatchManager;\n\tprivate readonly idAllocationBatch: BatchManager;\n\tprivate batchRebasesToReport = 5;\n\tprivate rebasing = false;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.mc = createChildMonitoringContext({ logger: params.logger, namespace: \"Outbox\" });\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit });\n\t\tthis.idAllocationBatch = new BatchManager({ hardLimit });\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * If we detect that the reference sequence number of the incoming message does not match\n\t * what was already in the batch managers, this means that batching has been interrupted so\n\t * we will flush the accumulated messages to account for that and create a new batch with the new\n\t * message as the first message.\n\t */\n\tprivate maybeFlushPartialBatch() {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\t(sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\tcategory: this.params.config.disablePartialFlush ? \"error\" : \"generic\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t},\n\t\t\t\tgetLongStack(() => new UsageError(\"Submission of an out of order message\")),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flushAll();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// blobAttach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.blobAttachBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.blobAttachBatch);\n\t\t}\n\t}\n\n\tpublic submitIdAllocation(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tif (\n\t\t\t!this.idAllocationBatch.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.idAllocationBatch);\n\n\t\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.idAllocationBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.idAllocationBatch);\n\t\t}\n\t}\n\n\tprivate addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tif (this.isContextReentrant()) {\n\t\t\tconst error = new UsageError(\"Flushing is not supported inside DDS event handlers\");\n\t\t\tthis.params.closeContainer(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tthis.flushAll();\n\t}\n\n\tprivate flushAll() {\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\tthis.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);\n\t\tthis.flushInternal(this.mainBatch);\n\t}\n\n\tprivate flushInternal(batchManager: BatchManager, disableGroupedBatching: boolean = false) {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch();\n\t\tconst shouldGroup =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);\n\t\tif (rawBatch.hasReentrantOps === true && shouldGroup) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\t// Did we disconnect?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\t// Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.\n\t\tif (this.params.shouldSend()) {\n\t\t\tconst processedBatch = this.compressBatch(\n\t\t\t\tshouldGroup ? this.params.groupingManager.groupBatch(rawBatch) : rawBatch,\n\t\t\t);\n\t\t\tthis.sendBatch(processedBatch);\n\t\t}\n\n\t\tthis.persistBatch(rawBatch.content);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: IBatch, batchManager: BatchManager) {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.content) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tcontent: message.contents!,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.content.length,\n\t\t\t\t\treferenceSequenceNumber: rawBatch.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"BatchRebase\"),\n\t\t\t);\n\t\t\tthis.batchRebasesToReport--;\n\t\t}\n\n\t\tthis.flushInternal(batchManager);\n\t\tthis.rebasing = false;\n\t}\n\n\tprivate isContextReentrant(): boolean {\n\t\treturn this.params.opReentrancy() && !this.rebasing;\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitFirstBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.content.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\n\t\tconst length = batch.content.length;\n\t\tif (length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.content.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\n\t\t}\n\n\t\tif (this.params.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tassert(\n\t\t\t\tbatch.content[0].compression === undefined,\n\t\t\t\t0x5a6 /* Compression should not have happened if the loader does not support it */,\n\t\t\t);\n\n\t\t\tthis.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t\t0x58e /* Batch must not be empty */,\n\t\t\t);\n\t\t\tthis.params.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate persistBatch(batch: BatchMessage[]) {\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tmessage.contents!,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\t// This variable is declared with a specific type so that we have a standard import of the IBatchCheckpoint type.\n\t\t// When the type is inferred, the generated .d.ts uses a dynamic import which doesn't resolve.\n\t\tconst mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();\n\t\treturn {\n\t\t\tmainBatch,\n\t\t\tblobAttachBatch: this.blobAttachBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tGenericError,\n\tMonitoringContext,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { IPendingBatchMessage, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n} from \"./batchManager.js\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: IBatch) => void;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryBaseLogger;\n\treadonly groupingManager: OpGroupingManager;\n\treadonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;\n\treadonly reSubmit: (message: IPendingBatchMessage) => void;\n\treadonly opReentrancy: () => boolean;\n\treadonly closeContainer: (error?: ICriticalContainerError) => void;\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\nexport class Outbox {\n\tprivate readonly mc: MonitoringContext;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly blobAttachBatch: BatchManager;\n\tprivate readonly idAllocationBatch: BatchManager;\n\tprivate batchRebasesToReport = 5;\n\tprivate rebasing = false;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.mc = createChildMonitoringContext({ logger: params.logger, namespace: \"Outbox\" });\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * If we detect that the reference sequence number of the incoming message does not match\n\t * what was already in the batch managers, this means that batching has been interrupted so\n\t * we will flush the accumulated messages to account for that and create a new batch with the new\n\t * message as the first message.\n\t */\n\tprivate maybeFlushPartialBatch() {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\t(sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\tcategory: this.params.config.disablePartialFlush ? \"error\" : \"generic\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t},\n\t\t\t\tgetLongStack(() => new UsageError(\"Submission of an out of order message\")),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flushAll();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// blobAttach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.blobAttachBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.blobAttachBatch);\n\t\t}\n\t}\n\n\tpublic submitIdAllocation(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tif (\n\t\t\t!this.idAllocationBatch.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.idAllocationBatch);\n\n\t\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.idAllocationBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.idAllocationBatch);\n\t\t}\n\t}\n\n\tprivate addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tif (this.isContextReentrant()) {\n\t\t\tconst error = new UsageError(\"Flushing is not supported inside DDS event handlers\");\n\t\t\tthis.params.closeContainer(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tthis.flushAll();\n\t}\n\n\tprivate flushAll() {\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\tthis.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);\n\t\tthis.flushInternal(this.mainBatch);\n\t}\n\n\tprivate flushInternal(batchManager: BatchManager, disableGroupedBatching: boolean = false) {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch();\n\t\tconst shouldGroup =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);\n\t\tif (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\t// Did we disconnect?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\t// Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.\n\t\tif (this.params.shouldSend()) {\n\t\t\tconst processedBatch = this.compressBatch(\n\t\t\t\tshouldGroup ? this.params.groupingManager.groupBatch(rawBatch) : rawBatch,\n\t\t\t);\n\t\t\tthis.sendBatch(processedBatch);\n\t\t}\n\n\t\tthis.persistBatch(rawBatch.content);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: IBatch, batchManager: BatchManager) {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, \"BatchManager does not support rebase\");\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.content) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tcontent: message.contents!,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.content.length,\n\t\t\t\t\treferenceSequenceNumber: rawBatch.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"BatchRebase\"),\n\t\t\t);\n\t\t\tthis.batchRebasesToReport--;\n\t\t}\n\n\t\tthis.flushInternal(batchManager);\n\t\tthis.rebasing = false;\n\t}\n\n\tprivate isContextReentrant(): boolean {\n\t\treturn this.params.opReentrancy() && !this.rebasing;\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitFirstBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.content.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\n\t\tconst length = batch.content.length;\n\t\tif (length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.content.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\n\t\t}\n\n\t\tif (this.params.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tassert(\n\t\t\t\tbatch.content[0].compression === undefined,\n\t\t\t\t0x5a6 /* Compression should not have happened if the loader does not support it */,\n\t\t\t);\n\n\t\t\tthis.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t\t0x58e /* Batch must not be empty */,\n\t\t\t);\n\t\t\tthis.params.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate persistBatch(batch: BatchMessage[]) {\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tmessage.contents!,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\t// This variable is declared with a specific type so that we have a standard import of the IBatchCheckpoint type.\n\t\t// When the type is inferred, the generated .d.ts uses a dynamic import which doesn't resolve.\n\t\tconst mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();\n\t\treturn {\n\t\t\tmainBatch,\n\t\t\tblobAttachBatch: this.blobAttachBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "2.0.0-rc.4.0.0";
8
+ export declare const pkgVersion = "2.0.0-rc.4.0.1";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-runtime";
8
- export const pkgVersion = "2.0.0-rc.4.0.0";
8
+ export const pkgVersion = "2.0.0-rc.4.0.1";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-rc.4.0.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-rc.4.0.1\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-rc.4.0.0",
3
+ "version": "2.0.0-rc.4.0.1",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -127,19 +127,19 @@
127
127
  "temp-directory": "nyc/.nyc_output"
128
128
  },
129
129
  "dependencies": {
130
- "@fluid-internal/client-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
131
- "@fluidframework/container-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
132
- "@fluidframework/container-runtime-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
133
- "@fluidframework/core-interfaces": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
134
- "@fluidframework/core-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
135
- "@fluidframework/datastore": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
136
- "@fluidframework/driver-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
137
- "@fluidframework/driver-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
138
- "@fluidframework/id-compressor": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
130
+ "@fluid-internal/client-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
131
+ "@fluidframework/container-definitions": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
132
+ "@fluidframework/container-runtime-definitions": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
133
+ "@fluidframework/core-interfaces": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
134
+ "@fluidframework/core-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
135
+ "@fluidframework/datastore": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
136
+ "@fluidframework/driver-definitions": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
137
+ "@fluidframework/driver-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
138
+ "@fluidframework/id-compressor": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
139
139
  "@fluidframework/protocol-definitions": "^3.2.0",
140
- "@fluidframework/runtime-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
141
- "@fluidframework/runtime-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
142
- "@fluidframework/telemetry-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
140
+ "@fluidframework/runtime-definitions": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
141
+ "@fluidframework/runtime-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
142
+ "@fluidframework/telemetry-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
143
143
  "@tylerbu/sorted-btree-es6": "^1.8.0",
144
144
  "double-ended-queue": "^2.1.0-0",
145
145
  "lz4js": "^0.2.0",
@@ -148,16 +148,16 @@
148
148
  "devDependencies": {
149
149
  "@arethetypeswrong/cli": "^0.15.2",
150
150
  "@biomejs/biome": "^1.6.2",
151
- "@fluid-internal/mocha-test-setup": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
152
- "@fluid-private/stochastic-test-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
153
- "@fluid-private/test-pairwise-generator": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
151
+ "@fluid-internal/mocha-test-setup": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
152
+ "@fluid-private/stochastic-test-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
153
+ "@fluid-private/test-pairwise-generator": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
154
154
  "@fluid-tools/benchmark": "^0.48.0",
155
155
  "@fluid-tools/build-cli": "^0.38.0",
156
156
  "@fluidframework/build-common": "^2.0.3",
157
157
  "@fluidframework/build-tools": "^0.38.0",
158
158
  "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-rc.3.0.0",
159
159
  "@fluidframework/eslint-config-fluid": "^5.1.0",
160
- "@fluidframework/test-runtime-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
160
+ "@fluidframework/test-runtime-utils": ">=2.0.0-rc.4.0.1 <2.0.0-rc.4.1.0",
161
161
  "@microsoft/api-extractor": "^7.43.1",
162
162
  "@types/double-ended-queue": "^2.1.0",
163
163
  "@types/mocha": "^9.1.1",
@@ -2342,6 +2342,7 @@ export class ContainerRuntime
2342
2342
  let newState: boolean;
2343
2343
 
2344
2344
  try {
2345
+ this.submitIdAllocationOpIfNeeded(true);
2345
2346
  // replay the ops
2346
2347
  this.pendingStateManager.replayPendingStates();
2347
2348
  } finally {
@@ -3918,9 +3919,11 @@ export class ContainerRuntime
3918
3919
  return this.blobManager.createBlob(blob, signal);
3919
3920
  }
3920
3921
 
3921
- private submitIdAllocationOpIfNeeded(): void {
3922
+ private submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false): void {
3922
3923
  if (this._idCompressor) {
3923
- const idRange = this._idCompressor.takeNextCreationRange();
3924
+ const idRange = resubmitOutstandingRanges
3925
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
3926
+ : this._idCompressor.takeNextCreationRange();
3924
3927
  // Don't include the idRange if there weren't any Ids allocated
3925
3928
  if (idRange?.ids !== undefined) {
3926
3929
  const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
@@ -4136,7 +4139,13 @@ export class ContainerRuntime
4136
4139
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
4137
4140
  break;
4138
4141
  case ContainerMessageType.IdAllocation: {
4139
- this.submit(message, localOpMetadata);
4142
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
4143
+ // avoid being submitted out of order. For example, if the pending state manager contained
4144
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
4145
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
4146
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
4147
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
4148
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
4140
4149
  break;
4141
4150
  }
4142
4151
  case ContainerMessageType.BlobAttach:
@@ -10,6 +10,11 @@ import { BatchMessage, IBatch, IBatchCheckpoint } from "./definitions.js";
10
10
  export interface IBatchManagerOptions {
11
11
  readonly hardLimit: number;
12
12
  readonly compressionOptions?: ICompressionRuntimeOptions;
13
+
14
+ /**
15
+ * If true, the outbox is allowed to rebase the batch during flushing.
16
+ */
17
+ readonly canRebase: boolean;
13
18
  }
14
19
 
15
20
  export interface BatchSequenceNumbers {
@@ -112,9 +112,9 @@ export class Outbox {
112
112
  // We need to allow infinite size batches if we enable compression
113
113
  const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
114
114
 
115
- this.mainBatch = new BatchManager({ hardLimit });
116
- this.blobAttachBatch = new BatchManager({ hardLimit });
117
- this.idAllocationBatch = new BatchManager({ hardLimit });
115
+ this.mainBatch = new BatchManager({ hardLimit, canRebase: true });
116
+ this.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });
117
+ this.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });
118
118
  }
119
119
 
120
120
  public get messageCount(): number {
@@ -270,7 +270,7 @@ export class Outbox {
270
270
  const rawBatch = batchManager.popBatch();
271
271
  const shouldGroup =
272
272
  !disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);
273
- if (rawBatch.hasReentrantOps === true && shouldGroup) {
273
+ if (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {
274
274
  assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
275
275
  // If a batch contains reentrant ops (ops created as a result from processing another op)
276
276
  // it needs to be rebased so that we can ensure consistent reference sequence numbers
@@ -300,6 +300,7 @@ export class Outbox {
300
300
  */
301
301
  private rebase(rawBatch: IBatch, batchManager: BatchManager) {
302
302
  assert(!this.rebasing, 0x6fb /* Reentrancy */);
303
+ assert(batchManager.options.canRebase, "BatchManager does not support rebase");
303
304
 
304
305
  this.rebasing = true;
305
306
  for (const message of rawBatch.content) {
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-rc.4.0.0";
9
+ export const pkgVersion = "2.0.0-rc.4.0.1";