@fluidframework/container-runtime 2.70.0-361092 → 2.70.0-361788
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.
- package/container-runtime.test-files.tar +0 -0
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +0 -1
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +15 -5
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +42 -9
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/messageTypes.d.ts +1 -1
- package/dist/messageTypes.js +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.d.ts +2 -2
- package/dist/opLifecycle/duplicateBatchDetector.js +2 -2
- package/dist/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +2 -2
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +5 -3
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSerialization.d.ts +2 -2
- package/dist/opLifecycle/opSerialization.js +2 -2
- package/dist/opLifecycle/opSerialization.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +1 -1
- package/dist/opLifecycle/opSplitter.js +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +2 -2
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +9 -2
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +1 -1
- package/dist/pendingStateManager.js +1 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runtimeLayerCompatState.d.ts +4 -3
- package/dist/runtimeLayerCompatState.d.ts.map +1 -1
- package/dist/runtimeLayerCompatState.js +4 -35
- package/dist/runtimeLayerCompatState.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.d.ts +0 -36
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/dist/storageServiceWithAttachBlobs.js +0 -55
- package/dist/storageServiceWithAttachBlobs.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +1 -1
- package/dist/summary/documentSchema.js +1 -1
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +6 -6
- package/dist/summary/summaryFormat.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +0 -1
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +15 -5
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +42 -9
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/messageTypes.d.ts +1 -1
- package/lib/messageTypes.js +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.d.ts +2 -2
- package/lib/opLifecycle/duplicateBatchDetector.js +2 -2
- package/lib/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +2 -2
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +5 -3
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSerialization.d.ts +2 -2
- package/lib/opLifecycle/opSerialization.js +2 -2
- package/lib/opLifecycle/opSerialization.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +2 -2
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +9 -2
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +1 -1
- package/lib/pendingStateManager.js +1 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runtimeLayerCompatState.d.ts +4 -3
- package/lib/runtimeLayerCompatState.d.ts.map +1 -1
- package/lib/runtimeLayerCompatState.js +5 -36
- package/lib/runtimeLayerCompatState.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts +0 -36
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/lib/storageServiceWithAttachBlobs.js +0 -55
- package/lib/storageServiceWithAttachBlobs.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +1 -1
- package/lib/summary/documentSchema.js +1 -1
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +6 -6
- package/lib/summary/summaryFormat.js.map +1 -1
- package/package.json +20 -17
- package/src/blobManager/blobManager.ts +0 -1
- package/src/containerRuntime.ts +52 -13
- package/src/dataStoreContext.ts +1 -0
- package/src/messageTypes.ts +1 -1
- package/src/opLifecycle/duplicateBatchDetector.ts +2 -2
- package/src/opLifecycle/opGroupingManager.ts +7 -4
- package/src/opLifecycle/opSerialization.ts +2 -2
- package/src/opLifecycle/opSplitter.ts +1 -1
- package/src/opLifecycle/outbox.ts +12 -2
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +1 -1
- package/src/runtimeLayerCompatState.ts +23 -39
- package/src/storageServiceWithAttachBlobs.ts +0 -92
- package/src/summary/documentSchema.ts +1 -1
- package/src/summary/summaryFormat.ts +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicateBatchDetector.js","sourceRoot":"","sources":["../../src/opLifecycle/duplicateBatchDetector.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,kEAA6D;AAG7D,uDAAwD;AAGxD;;GAEG;AACH,MAAa,sBAAsB;IAWlC;;OAEG;IACH,YAAY,oBAAoD;QAbhE;;WAEG;QACc,gBAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QAEjD;;WAEG;QACc,qBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;QAM7D,IAAI,oBAAoB,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;YACtD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC;gBACtD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,mBAAmB,CACzB,UAA0B;QAE1B,MAAM,EAAE,cAAc,EAAE,qBAAqB,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC;QAExE,+GAA+G;QAC/G,6IAA6I;QAC7I,IAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;QAE7C,6EAA6E;QAC7E,oGAAoG;QACpG,4EAA4E;QAC5E,4GAA4G;QAC5G,MAAM,OAAO,GAAG,IAAA,qCAAmB,EAAC,UAAU,CAAC,CAAC;QAEhD,2EAA2E;QAC3E,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,KAAK,MAAM,CAAC,mBAAmB,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;gBACnF,IAAI,YAAY,KAAK,OAAO,EAAE,CAAC;oBAC9B,OAAO;wBACN,SAAS,EAAE,IAAI;wBACf,mBAAmB;qBACnB,CAAC;gBACH,CAAC;YACF,CAAC;YACD,IAAA,iBAAM,EAAC,KAAK,EAAE,KAAK,CAAC,0DAA0D,CAAC,CAAC;QACjF,CAAC;QAED,kFAAkF;QAClF,IAAA,iBAAM,EACL,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,EAC1C,KAAK,CAAC,wDAAwD,CAC9D,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE9B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACK,gBAAgB,CAAC,GAAW;QACnC,KAAK,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC/D,IAAI,cAAc,GAAG,GAAG,EAAE,CAAC;gBAC1B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC7C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,4BAA4B,CAClC,gBAAoC;QAEpC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,gBAAgB,EAAE,GAAG,CACpB,+BAA+B,EAC/B,kBAAkB,EAClB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAC1B,CAAC;QAEF,OAAO,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;CACD;AAtGD,wDAsGC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryContext } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { getEffectiveBatchId } from \"./batchManager.js\";\nimport type { BatchStartInfo } from \"./remoteMessageProcessor.js\";\n\n/**\n * This class tracks recent batchIds we've seen, and checks incoming batches for duplicates.\n */\nexport class DuplicateBatchDetector {\n\t/**\n\t * All batchIds we've seen recently enough (based on MSN) that we need to watch for duplicates\n\t */\n\tprivate readonly batchIdsAll = new Set<string>();\n\n\t/**\n\t * We map from sequenceNumber to batchId to find which ones we can stop tracking as MSN advances\n\t */\n\tprivate readonly batchIdsBySeqNum = new Map<number, string>();\n\n\t/**\n\t * Initialize from snapshot data if provided - otherwise initialize empty\n\t */\n\tconstructor(batchIdsFromSnapshot: [number, string][] | undefined) {\n\t\tif (batchIdsFromSnapshot) {\n\t\t\tthis.batchIdsBySeqNum = new Map(batchIdsFromSnapshot);\n\t\t\tfor (const batchId of this.batchIdsBySeqNum.values()) {\n\t\t\t\tthis.batchIdsAll.add(batchId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Records this batch's batchId, and checks if it's a duplicate of a batch we've already seen.\n\t * If it's a duplicate, also return the sequence number of the other batch for logging.\n\t *\n\t * @remarks
|
|
1
|
+
{"version":3,"file":"duplicateBatchDetector.js","sourceRoot":"","sources":["../../src/opLifecycle/duplicateBatchDetector.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,kEAA6D;AAG7D,uDAAwD;AAGxD;;GAEG;AACH,MAAa,sBAAsB;IAWlC;;OAEG;IACH,YAAY,oBAAoD;QAbhE;;WAEG;QACc,gBAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QAEjD;;WAEG;QACc,qBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;QAM7D,IAAI,oBAAoB,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;YACtD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC;gBACtD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,mBAAmB,CACzB,UAA0B;QAE1B,MAAM,EAAE,cAAc,EAAE,qBAAqB,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC;QAExE,+GAA+G;QAC/G,6IAA6I;QAC7I,IAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;QAE7C,6EAA6E;QAC7E,oGAAoG;QACpG,4EAA4E;QAC5E,4GAA4G;QAC5G,MAAM,OAAO,GAAG,IAAA,qCAAmB,EAAC,UAAU,CAAC,CAAC;QAEhD,2EAA2E;QAC3E,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,KAAK,MAAM,CAAC,mBAAmB,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;gBACnF,IAAI,YAAY,KAAK,OAAO,EAAE,CAAC;oBAC9B,OAAO;wBACN,SAAS,EAAE,IAAI;wBACf,mBAAmB;qBACnB,CAAC;gBACH,CAAC;YACF,CAAC;YACD,IAAA,iBAAM,EAAC,KAAK,EAAE,KAAK,CAAC,0DAA0D,CAAC,CAAC;QACjF,CAAC;QAED,kFAAkF;QAClF,IAAA,iBAAM,EACL,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,EAC1C,KAAK,CAAC,wDAAwD,CAC9D,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE9B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACK,gBAAgB,CAAC,GAAW;QACnC,KAAK,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC/D,IAAI,cAAc,GAAG,GAAG,EAAE,CAAC;gBAC1B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC7C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,4BAA4B,CAClC,gBAAoC;QAEpC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,gBAAgB,EAAE,GAAG,CACpB,+BAA+B,EAC/B,kBAAkB,EAClB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAC1B,CAAC;QAEF,OAAO,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;CACD;AAtGD,wDAsGC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ITelemetryContext } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { getEffectiveBatchId } from \"./batchManager.js\";\nimport type { BatchStartInfo } from \"./remoteMessageProcessor.js\";\n\n/**\n * This class tracks recent batchIds we've seen, and checks incoming batches for duplicates.\n */\nexport class DuplicateBatchDetector {\n\t/**\n\t * All batchIds we've seen recently enough (based on MSN) that we need to watch for duplicates\n\t */\n\tprivate readonly batchIdsAll = new Set<string>();\n\n\t/**\n\t * We map from sequenceNumber to batchId to find which ones we can stop tracking as MSN advances\n\t */\n\tprivate readonly batchIdsBySeqNum = new Map<number, string>();\n\n\t/**\n\t * Initialize from snapshot data if provided - otherwise initialize empty\n\t */\n\tconstructor(batchIdsFromSnapshot: [number, string][] | undefined) {\n\t\tif (batchIdsFromSnapshot) {\n\t\t\tthis.batchIdsBySeqNum = new Map(batchIdsFromSnapshot);\n\t\t\tfor (const batchId of this.batchIdsBySeqNum.values()) {\n\t\t\t\tthis.batchIdsAll.add(batchId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Records this batch's batchId, and checks if it's a duplicate of a batch we've already seen.\n\t * If it's a duplicate, also return the sequence number of the other batch for logging.\n\t *\n\t * @remarks We also use the minimumSequenceNumber to clear out old batchIds that are no longer at risk for duplicates.\n\t */\n\tpublic processInboundBatch(\n\t\tbatchStart: BatchStartInfo,\n\t): { duplicate: true; otherSequenceNumber: number } | { duplicate: false } {\n\t\tconst { sequenceNumber, minimumSequenceNumber } = batchStart.keyMessage;\n\n\t\t// Glance at this batch's MSN. Any batchIds we're tracking with a lower sequence number are now safe to forget.\n\t\t// Why? Because any other client holding the same batch locally would have seen the earlier batch and closed before submitting its duplicate.\n\t\tthis.clearOldBatchIds(minimumSequenceNumber);\n\n\t\t// getEffectiveBatchId is only needed in the SUPER rare/surprising case where\n\t\t// the original batch (not resubmitted, so no batchId) arrives in parallel with a resubmitted batch.\n\t\t// In the presence of typical network conditions, this would not be possible\n\t\t// (the original batch should roundtrip WAY before another container could rehydrate, connect, and resubmit)\n\t\tconst batchId = getEffectiveBatchId(batchStart);\n\n\t\t// Check this batch against the tracked batchIds to see if it's a duplicate\n\t\tif (this.batchIdsAll.has(batchId)) {\n\t\t\tfor (const [otherSequenceNumber, otherBatchId] of this.batchIdsBySeqNum.entries()) {\n\t\t\t\tif (otherBatchId === batchId) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tduplicate: true,\n\t\t\t\t\t\totherSequenceNumber,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tassert(false, 0xa34 /* Should have found the batchId in batchIdBySeqNum map */);\n\t\t}\n\n\t\t// Now we know it's not a duplicate, so add it to the tracked batchIds and return.\n\t\tassert(\n\t\t\t!this.batchIdsBySeqNum.has(sequenceNumber),\n\t\t\t0xa35 /* batchIdsAll and batchIdsBySeqNum should be in sync */,\n\t\t);\n\t\tthis.batchIdsBySeqNum.set(sequenceNumber, batchId);\n\t\tthis.batchIdsAll.add(batchId);\n\n\t\treturn { duplicate: false };\n\t}\n\n\t/**\n\t * Batches that started before the MSN are not at risk for a sequenced duplicate to arrive,\n\t * since the batch start has been processed by all clients, and local batches are deduped and the forked client would close.\n\t */\n\tprivate clearOldBatchIds(msn: number): void {\n\t\tfor (const [sequenceNumber, batchId] of this.batchIdsBySeqNum) {\n\t\t\tif (sequenceNumber < msn) {\n\t\t\t\tthis.batchIdsBySeqNum.delete(sequenceNumber);\n\t\t\t\tthis.batchIdsAll.delete(batchId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a snapshot of the state of the detector which can be included in a summary\n\t * and used to \"rehydrate\" this class when loading from a snapshot.\n\t *\n\t * @returns A serializable object representing the state of the detector, or undefined if there is nothing to save.\n\t */\n\tpublic getRecentBatchInfoForSummary(\n\t\ttelemetryContext?: ITelemetryContext,\n\t): [number, string][] | undefined {\n\t\tif (this.batchIdsBySeqNum.size === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\ttelemetryContext?.set(\n\t\t\t\"fluid_DuplicateBatchDetector_\",\n\t\t\t\"recentBatchCount\",\n\t\t\tthis.batchIdsBySeqNum.size,\n\t\t);\n\n\t\treturn [...this.batchIdsBySeqNum.entries()];\n\t}\n}\n"]}
|
|
@@ -28,7 +28,7 @@ export declare class OpGroupingManager {
|
|
|
28
28
|
* This is needed as a placeholder if a batch becomes empty on resubmit, but we are tracking batch IDs.
|
|
29
29
|
* @param resubmittingBatchId - batch ID of the resubmitting batch
|
|
30
30
|
* @param referenceSequenceNumber - reference sequence number
|
|
31
|
-
* @returns
|
|
31
|
+
* @returns The outbound batch as well as the interior placeholder message
|
|
32
32
|
*/
|
|
33
33
|
createEmptyGroupedBatch(resubmittingBatchId: string, referenceSequenceNumber: number): {
|
|
34
34
|
outboundBatch: OutboundSingletonBatch;
|
|
@@ -40,7 +40,7 @@ export declare class OpGroupingManager {
|
|
|
40
40
|
*
|
|
41
41
|
* If the batch already has only 1 message, it is returned as-is.
|
|
42
42
|
*
|
|
43
|
-
* @remarks
|
|
43
|
+
* @remarks Remember that a BatchMessage has its content JSON serialized, so the incoming batch message contents
|
|
44
44
|
* must be parsed first, and then the type and contents mentioned above are hidden in that JSON serialization.
|
|
45
45
|
*/
|
|
46
46
|
groupBatch(batch: OutboundBatch): OutboundSingletonBatch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opGroupingManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAM7F,OAAO,KAAK,EACX,0BAA0B,EAC1B,aAAa,EACb,sBAAsB,EACtB,MAAM,kBAAkB,CAAC;AAuB1B,wBAAgB,cAAc,CAAC,EAAE,EAAE,yBAAyB,GAAG,OAAO,CAErE;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,OAAO,iBAAiB,CAAC,cAAc,CAAC;IAC9C,QAAQ,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,qBAAa,iBAAiB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,MAAM,CAAC,QAAQ,CAAC,cAAc,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,MAAM,EAAE,uBAAuB,EAChD,MAAM,EAAE,oBAAoB;IAK7B;;;;;;OAMG;IACI,uBAAuB,CAC7B,mBAAmB,EAAE,MAAM,EAC3B,uBAAuB,EAAE,MAAM,GAC7B;QACF,aAAa,EAAE,sBAAsB,CAAC;QACtC,kBAAkB,EAAE,0BAA0B,CAAC;KAC/C;IA0BD;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,sBAAsB;
|
|
1
|
+
{"version":3,"file":"opGroupingManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAM7F,OAAO,KAAK,EACX,0BAA0B,EAC1B,aAAa,EACb,sBAAsB,EACtB,MAAM,kBAAkB,CAAC;AAuB1B,wBAAgB,cAAc,CAAC,EAAE,EAAE,yBAAyB,GAAG,OAAO,CAErE;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,OAAO,iBAAiB,CAAC,cAAc,CAAC;IAC9C,QAAQ,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,qBAAa,iBAAiB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,MAAM,CAAC,QAAQ,CAAC,cAAc,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,MAAM,EAAE,uBAAuB,EAChD,MAAM,EAAE,oBAAoB;IAK7B;;;;;;OAMG;IACI,uBAAuB,CAC7B,mBAAmB,EAAE,MAAM,EAC3B,uBAAuB,EAAE,MAAM,GAC7B;QACF,aAAa,EAAE,sBAAsB,CAAC;QACtC,kBAAkB,EAAE,0BAA0B,CAAC;KAC/C;IA0BD;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,sBAAsB;IAqDxD,SAAS,CAAC,EAAE,EAAE,yBAAyB,GAAG,yBAAyB,EAAE;IAcrE,sBAAsB,IAAI,OAAO;CAGxC"}
|
|
@@ -25,7 +25,7 @@ class OpGroupingManager {
|
|
|
25
25
|
* This is needed as a placeholder if a batch becomes empty on resubmit, but we are tracking batch IDs.
|
|
26
26
|
* @param resubmittingBatchId - batch ID of the resubmitting batch
|
|
27
27
|
* @param referenceSequenceNumber - reference sequence number
|
|
28
|
-
* @returns
|
|
28
|
+
* @returns The outbound batch as well as the interior placeholder message
|
|
29
29
|
*/
|
|
30
30
|
createEmptyGroupedBatch(resubmittingBatchId, referenceSequenceNumber) {
|
|
31
31
|
(0, internal_1.assert)(this.config.groupedBatchingEnabled, 0xa00 /* cannot create empty grouped batch when grouped batching is disabled */);
|
|
@@ -53,7 +53,7 @@ class OpGroupingManager {
|
|
|
53
53
|
*
|
|
54
54
|
* If the batch already has only 1 message, it is returned as-is.
|
|
55
55
|
*
|
|
56
|
-
* @remarks
|
|
56
|
+
* @remarks Remember that a BatchMessage has its content JSON serialized, so the incoming batch message contents
|
|
57
57
|
* must be parsed first, and then the type and contents mentioned above are hidden in that JSON serialization.
|
|
58
58
|
*/
|
|
59
59
|
groupBatch(batch) {
|
|
@@ -84,7 +84,9 @@ class OpGroupingManager {
|
|
|
84
84
|
const serializedContent = JSON.stringify({
|
|
85
85
|
type: OpGroupingManager.groupedBatchOp,
|
|
86
86
|
contents: batch.messages.map((message) => ({
|
|
87
|
-
contents: message.contents === undefined
|
|
87
|
+
contents: message.contents === undefined
|
|
88
|
+
? undefined
|
|
89
|
+
: JSON.parse(message.contents),
|
|
88
90
|
metadata: message.metadata,
|
|
89
91
|
compression: message.compression,
|
|
90
92
|
})),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opGroupingManager.js","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,kEAA6D;AAE7D,uEAGkD;AAsBlD,SAAS,eAAe,CAAC,UAAmB;IAC3C,OAAO,CACL,UAAoD,EAAE,IAAI;QAC3D,iBAAiB,CAAC,cAAc,CAChC,CAAC;AACH,CAAC;AAED,SAAgB,cAAc,CAAC,EAA6B;IAC3D,OAAO,eAAe,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAFD,wCAEC;AAgBD,MAAa,iBAAiB;IAI7B,YACkB,MAA+B,EAChD,MAA4B;QADX,WAAM,GAAN,MAAM,CAAyB;QAGhD,IAAI,CAAC,MAAM,GAAG,IAAA,4BAAiB,EAAC,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED;;;;;;OAMG;IACI,uBAAuB,CAC7B,mBAA2B,EAC3B,uBAA+B;QAK/B,IAAA,iBAAM,EACL,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAClC,KAAK,CAAC,yEAAyE,CAC/E,CAAC;QAEF,MAAM,iBAAiB,GAAsB;YAC5C,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,EAAE;SACZ,CAAC;QACF,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAEvD,MAAM,kBAAkB,GAA+B;YACtD,QAAQ,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE;YAC1C,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;YACrC,uBAAuB;YACvB,SAAS,EAAE,iBAAiB;SAC5B,CAAC;QACF,MAAM,aAAa,GAA2B;YAC7C,kBAAkB,EAAE,CAAC;YACrB,QAAQ,EAAE,CAAC,EAAE,GAAG,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACnF,uBAAuB;SACvB,CAAC;QACF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC;IAC9C,CAAC;IAED;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAoB;QACrC,IAAA,iBAAM,EAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACtE,IAAA,iBAAM,EAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAE1F,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,KAA+B,CAAC;QACxC,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBAC9B,SAAS,EAAE,iBAAiB;gBAC5B,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;gBAC7B,SAAS,EAAE,KAAK,CAAC,eAAe;gBAChC,uBAAuB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,uBAAuB;aAClE,CAAC,CAAC;QACJ,CAAC;QACD,kEAAkE;QAClE,IAAI,
|
|
1
|
+
{"version":3,"file":"opGroupingManager.js","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.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 type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type {\n\tLocalEmptyBatchPlaceholder,\n\tOutboundBatch,\n\tOutboundSingletonBatch,\n} from \"./definitions.js\";\n\n/**\n * Grouping makes assumptions about the shape of message contents. This interface codifies those assumptions, but does not validate them.\n */\ninterface IGroupedBatchMessageContents {\n\ttype: typeof OpGroupingManager.groupedBatchOp;\n\tcontents: IGroupedMessage[];\n}\n\ninterface IGroupedMessage {\n\tcontents?: unknown;\n\tmetadata?: Record<string, unknown>;\n\tcompression?: string;\n}\n\nfunction isGroupContents(opContents: unknown): opContents is IGroupedBatchMessageContents {\n\treturn (\n\t\t(opContents as Partial<IGroupedBatchMessageContents>)?.type ===\n\t\tOpGroupingManager.groupedBatchOp\n\t);\n}\n\nexport function isGroupedBatch(op: ISequencedDocumentMessage): boolean {\n\treturn isGroupContents(op.contents);\n}\n\nexport interface OpGroupingManagerConfig {\n\treadonly groupedBatchingEnabled: boolean;\n}\n\n/**\n * This is the type of an empty grouped batch we send over the wire\n * We also put this in the placeholder for an empty batch in the PendingStateManager.\n * But most places throughout the ContainerRuntime, this will not be used (just as Grouped Batches in general don't appear outside opLifecycle dir)\n */\nexport interface EmptyGroupedBatch {\n\ttype: typeof OpGroupingManager.groupedBatchOp;\n\tcontents: readonly [];\n}\n\nexport class OpGroupingManager {\n\tstatic readonly groupedBatchOp = \"groupedBatch\";\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly config: OpGroupingManagerConfig,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpGroupingManager\" });\n\t}\n\n\t/**\n\t * Creates a new batch with a single message of type \"groupedBatch\" and empty contents.\n\t * This is needed as a placeholder if a batch becomes empty on resubmit, but we are tracking batch IDs.\n\t * @param resubmittingBatchId - batch ID of the resubmitting batch\n\t * @param referenceSequenceNumber - reference sequence number\n\t * @returns The outbound batch as well as the interior placeholder message\n\t */\n\tpublic createEmptyGroupedBatch(\n\t\tresubmittingBatchId: string,\n\t\treferenceSequenceNumber: number,\n\t): {\n\t\toutboundBatch: OutboundSingletonBatch;\n\t\tplaceholderMessage: LocalEmptyBatchPlaceholder;\n\t} {\n\t\tassert(\n\t\t\tthis.config.groupedBatchingEnabled,\n\t\t\t0xa00 /* cannot create empty grouped batch when grouped batching is disabled */,\n\t\t);\n\n\t\tconst emptyGroupedBatch: EmptyGroupedBatch = {\n\t\t\ttype: \"groupedBatch\",\n\t\t\tcontents: [],\n\t\t};\n\t\tconst serializedOp = JSON.stringify(emptyGroupedBatch);\n\n\t\tconst placeholderMessage: LocalEmptyBatchPlaceholder = {\n\t\t\tmetadata: { batchId: resubmittingBatchId },\n\t\t\tlocalOpMetadata: { emptyBatch: true },\n\t\t\treferenceSequenceNumber,\n\t\t\truntimeOp: emptyGroupedBatch,\n\t\t};\n\t\tconst outboundBatch: OutboundSingletonBatch = {\n\t\t\tcontentSizeInBytes: 0,\n\t\t\tmessages: [{ ...placeholderMessage, runtimeOp: undefined, contents: serializedOp }],\n\t\t\treferenceSequenceNumber,\n\t\t};\n\t\treturn { outboundBatch, placeholderMessage };\n\t}\n\n\t/**\n\t * Converts the given batch into a \"grouped batch\" - a batch with a single message of type \"groupedBatch\",\n\t * with contents being an array of the original batch's messages.\n\t *\n\t * If the batch already has only 1 message, it is returned as-is.\n\t *\n\t * @remarks Remember that a BatchMessage has its content JSON serialized, so the incoming batch message contents\n\t * must be parsed first, and then the type and contents mentioned above are hidden in that JSON serialization.\n\t */\n\tpublic groupBatch(batch: OutboundBatch): OutboundSingletonBatch {\n\t\tassert(this.groupedBatchingEnabled(), 0xb79 /* grouping disabled! */);\n\t\tassert(batch.messages.length > 0, 0xb7a /* Unexpected attempt to group an empty batch */);\n\n\t\tif (batch.messages.length === 1) {\n\t\t\treturn batch as OutboundSingletonBatch;\n\t\t}\n\n\t\tif (batch.messages.length >= 1000) {\n\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"GroupLargeBatch\",\n\t\t\t\tlength: batch.messages.length,\n\t\t\t\treentrant: batch.hasReentrantOps,\n\t\t\t\treferenceSequenceNumber: batch.messages[0].referenceSequenceNumber,\n\t\t\t});\n\t\t}\n\t\t// We expect this will be on the first message, if present at all.\n\t\tlet groupedBatchId: unknown;\n\t\tfor (const message of batch.messages) {\n\t\t\tif (message.metadata !== undefined) {\n\t\t\t\tconst { batch: _batch, batchId, ...rest } = message.metadata;\n\t\t\t\tif (batchId !== undefined) {\n\t\t\t\t\tgroupedBatchId = batchId;\n\t\t\t\t}\n\t\t\t\tassert(Object.keys(rest).length === 0, 0x5dd /* cannot group ops with metadata */);\n\t\t\t}\n\t\t}\n\n\t\tconst serializedContent = JSON.stringify({\n\t\t\ttype: OpGroupingManager.groupedBatchOp,\n\t\t\tcontents: batch.messages.map<IGroupedMessage>((message) => ({\n\t\t\t\tcontents:\n\t\t\t\t\tmessage.contents === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: (JSON.parse(message.contents) as unknown),\n\t\t\t\tmetadata: message.metadata,\n\t\t\t\tcompression: message.compression,\n\t\t\t})),\n\t\t});\n\n\t\tconst groupedBatch: OutboundSingletonBatch = {\n\t\t\t...batch,\n\t\t\tmessages: [\n\t\t\t\t{\n\t\t\t\t\tmetadata: { batchId: groupedBatchId },\n\t\t\t\t\treferenceSequenceNumber: batch.messages[0].referenceSequenceNumber,\n\t\t\t\t\tcontents: serializedContent,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t\treturn groupedBatch;\n\t}\n\n\tpublic ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[] {\n\t\tassert(isGroupContents(op.contents), 0x947 /* can only ungroup a grouped batch */);\n\t\tconst contents: IGroupedBatchMessageContents = op.contents;\n\n\t\tlet fakeCsn = 1;\n\t\treturn contents.contents.map((subMessage) => ({\n\t\t\t...op,\n\t\t\tclientSequenceNumber: fakeCsn++,\n\t\t\tcontents: subMessage.contents,\n\t\t\tmetadata: subMessage.metadata,\n\t\t\tcompression: subMessage.compression,\n\t\t}));\n\t}\n\n\tpublic groupedBatchingEnabled(): boolean {\n\t\treturn this.config.groupedBatchingEnabled;\n\t}\n}\n"]}
|
|
@@ -9,13 +9,13 @@ import type { EmptyGroupedBatch } from "./opGroupingManager.js";
|
|
|
9
9
|
* Takes an incoming runtime message (outer type "op"), JSON.parses the message's contents in place,
|
|
10
10
|
* if needed (old Loader does this for us).
|
|
11
11
|
* Only to be used for runtime messages. The contents here would be the virtualized payload for a batch of ops.
|
|
12
|
-
* @remarks
|
|
12
|
+
* @remarks Serialization during submit happens via {@link serializeOp}
|
|
13
13
|
* @param mutableMessage - op message received
|
|
14
14
|
*/
|
|
15
15
|
export declare function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void;
|
|
16
16
|
/**
|
|
17
17
|
* Before submitting an op to the Outbox, its contents must be serialized using this function.
|
|
18
|
-
* @remarks
|
|
18
|
+
* @remarks The deserialization on process happens via the function {@link ensureContentsDeserialized}.
|
|
19
19
|
*
|
|
20
20
|
* @param toSerialize - op message to serialize. Also supports an array of ops.
|
|
21
21
|
*/
|
|
@@ -10,7 +10,7 @@ const internal_1 = require("@fluidframework/runtime-utils/internal");
|
|
|
10
10
|
* Takes an incoming runtime message (outer type "op"), JSON.parses the message's contents in place,
|
|
11
11
|
* if needed (old Loader does this for us).
|
|
12
12
|
* Only to be used for runtime messages. The contents here would be the virtualized payload for a batch of ops.
|
|
13
|
-
* @remarks
|
|
13
|
+
* @remarks Serialization during submit happens via {@link serializeOp}
|
|
14
14
|
* @param mutableMessage - op message received
|
|
15
15
|
*/
|
|
16
16
|
function ensureContentsDeserialized(mutableMessage) {
|
|
@@ -23,7 +23,7 @@ function ensureContentsDeserialized(mutableMessage) {
|
|
|
23
23
|
exports.ensureContentsDeserialized = ensureContentsDeserialized;
|
|
24
24
|
/**
|
|
25
25
|
* Before submitting an op to the Outbox, its contents must be serialized using this function.
|
|
26
|
-
* @remarks
|
|
26
|
+
* @remarks The deserialization on process happens via the function {@link ensureContentsDeserialized}.
|
|
27
27
|
*
|
|
28
28
|
* @param toSerialize - op message to serialize. Also supports an array of ops.
|
|
29
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opSerialization.js","sourceRoot":"","sources":["../../src/opLifecycle/opSerialization.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qEAIgD;AAMhD;;;;;;GAMG;AACH,SAAgB,0BAA0B,CAAC,cAAyC;IACnF,yEAAyE;IACzE,qFAAqF;IACrF,IAAI,OAAO,cAAc,CAAC,QAAQ,KAAK,QAAQ,IAAI,cAAc,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QACnF,cAAc,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC;AACF,CAAC;AAND,gEAMC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CAC1B,WAGiC;IAEjC,OAAO,IAAI,CAAC,SAAS,CACpB,WAAW;IACX,YAAY;IACZ,CAAC,GAAG,EAAE,KAAc,EAAE,EAAE;QACvB,yDAAyD;QACzD,IAAI,IAAA,wBAAa,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAA,uCAA4B,EAAC,IAAA,gCAAqB,EAAC,KAAK,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CACD,CAAC;AACH,CAAC;AAjBD,kCAiBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport type { LocalContainerRuntimeMessage } from \"../messageTypes.js\";\n\nimport type { EmptyGroupedBatch } from \"./opGroupingManager.js\";\n\n/**\n * Takes an incoming runtime message (outer type \"op\"), JSON.parses the message's contents in place,\n * if needed (old Loader does this for us).\n * Only to be used for runtime messages. The contents here would be the virtualized payload for a batch of ops.\n * @remarks
|
|
1
|
+
{"version":3,"file":"opSerialization.js","sourceRoot":"","sources":["../../src/opLifecycle/opSerialization.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qEAIgD;AAMhD;;;;;;GAMG;AACH,SAAgB,0BAA0B,CAAC,cAAyC;IACnF,yEAAyE;IACzE,qFAAqF;IACrF,IAAI,OAAO,cAAc,CAAC,QAAQ,KAAK,QAAQ,IAAI,cAAc,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QACnF,cAAc,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC;AACF,CAAC;AAND,gEAMC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CAC1B,WAGiC;IAEjC,OAAO,IAAI,CAAC,SAAS,CACpB,WAAW;IACX,YAAY;IACZ,CAAC,GAAG,EAAE,KAAc,EAAE,EAAE;QACvB,yDAAyD;QACzD,IAAI,IAAA,wBAAa,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAA,uCAA4B,EAAC,IAAA,gCAAqB,EAAC,KAAK,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CACD,CAAC;AACH,CAAC;AAjBD,kCAiBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport type { LocalContainerRuntimeMessage } from \"../messageTypes.js\";\n\nimport type { EmptyGroupedBatch } from \"./opGroupingManager.js\";\n\n/**\n * Takes an incoming runtime message (outer type \"op\"), JSON.parses the message's contents in place,\n * if needed (old Loader does this for us).\n * Only to be used for runtime messages. The contents here would be the virtualized payload for a batch of ops.\n * @remarks Serialization during submit happens via {@link serializeOp}\n * @param mutableMessage - op message received\n */\nexport function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void {\n\t// This should become unconditional once Loader LTS reaches 2.4 or later.\n\t// There will be a long time of needing both cases, until LTS advances to that point.\n\tif (typeof mutableMessage.contents === \"string\" && mutableMessage.contents !== \"\") {\n\t\tmutableMessage.contents = JSON.parse(mutableMessage.contents);\n\t}\n}\n\n/**\n * Before submitting an op to the Outbox, its contents must be serialized using this function.\n * @remarks The deserialization on process happens via the function {@link ensureContentsDeserialized}.\n *\n * @param toSerialize - op message to serialize. Also supports an array of ops.\n */\nexport function serializeOp(\n\ttoSerialize:\n\t\t| EmptyGroupedBatch\n\t\t| LocalContainerRuntimeMessage\n\t\t| LocalContainerRuntimeMessage[],\n): string {\n\treturn JSON.stringify(\n\t\ttoSerialize,\n\t\t// replacer:\n\t\t(key, value: unknown) => {\n\t\t\t// If 'value' is an IFluidHandle return its encoded form.\n\t\t\tif (isFluidHandle(value)) {\n\t\t\t\treturn encodeHandleForSerialization(toFluidHandleInternal(value));\n\t\t\t}\n\t\t\treturn value;\n\t\t},\n\t);\n}\n"]}
|
|
@@ -37,7 +37,7 @@ export declare class OpSplitter {
|
|
|
37
37
|
* To illustrate the current functionality, if the input is `[largeOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.
|
|
38
38
|
* `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4]` will be returned.
|
|
39
39
|
*
|
|
40
|
-
* @remarks
|
|
40
|
+
* @remarks A side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.
|
|
41
41
|
*
|
|
42
42
|
* @privateRemarks
|
|
43
43
|
* This maintains support for splitting a compressed batch with multiple messages (empty placeholders after the first),
|
|
@@ -73,7 +73,7 @@ class OpSplitter {
|
|
|
73
73
|
* To illustrate the current functionality, if the input is `[largeOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.
|
|
74
74
|
* `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4]` will be returned.
|
|
75
75
|
*
|
|
76
|
-
* @remarks
|
|
76
|
+
* @remarks A side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.
|
|
77
77
|
*
|
|
78
78
|
* @privateRemarks
|
|
79
79
|
* This maintains support for splitting a compressed batch with multiple messages (empty placeholders after the first),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opSplitter.js","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.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 type { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDataCorruptionError,\n\tcreateChildLogger,\n\textractSafePropertiesFromMessage,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype ContainerRuntimeChunkedOpMessage,\n} from \"../messageTypes.js\";\n\nimport type {\n\tIChunkedOp,\n\tOutboundBatchMessage,\n\tOutboundSingletonBatch,\n} from \"./definitions.js\";\nimport { estimateSocketSize } from \"./outbox.js\";\n\nexport function isChunkedMessage(message: ISequencedDocumentMessage): boolean {\n\treturn isChunkedContents(message.contents);\n}\n\ninterface IChunkedContents {\n\treadonly type: typeof ContainerMessageType.ChunkedOp;\n\treadonly contents: IChunkedOp;\n}\n\nfunction isChunkedContents(contents: unknown): contents is IChunkedContents {\n\treturn (contents as Partial<IChunkedContents>)?.type === ContainerMessageType.ChunkedOp;\n}\n\n/**\n * Responsible for creating and reconstructing chunked messages.\n */\nexport class OpSplitter {\n\t// Local copy of incomplete received chunks.\n\tprivate readonly chunkMap: Map<string, string[]>;\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tchunks: [string, string[]][],\n\t\tprivate readonly submitBatchFn:\n\t\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t\t| undefined,\n\t\tpublic readonly chunkSizeInBytes: number,\n\t\tprivate readonly maxBatchSizeInBytes: number,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.chunkMap = new Map<string, string[]>(chunks);\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpSplitter\" });\n\t}\n\n\tpublic get isBatchChunkingEnabled(): boolean {\n\t\treturn (\n\t\t\tthis.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined\n\t\t);\n\t}\n\n\tpublic get chunks(): ReadonlyMap<string, string[]> {\n\t\treturn this.chunkMap;\n\t}\n\n\tpublic clearPartialChunks(clientId: string): void {\n\t\tif (this.chunkMap.has(clientId)) {\n\t\t\tthis.chunkMap.delete(clientId);\n\t\t}\n\t}\n\n\tprivate addChunk(\n\t\tclientId: string,\n\t\tchunkedContent: IChunkedOp,\n\t\toriginalMessage: ISequencedDocumentMessage,\n\t): void {\n\t\tlet map = this.chunkMap.get(clientId);\n\t\tif (map === undefined) {\n\t\t\tmap = [];\n\t\t\tthis.chunkMap.set(clientId, map);\n\t\t}\n\n\t\tif (chunkedContent.chunkId !== map.length + 1) {\n\t\t\t// We are expecting the chunks to be processed sequentially, in the same order as they are sent.\n\t\t\t// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)\n\t\t\t// holding the existing chunks for that particular clientId.\n\t\t\tthrow new DataCorruptionError(\"Chunk Id mismatch\", {\n\t\t\t\t...extractSafePropertiesFromMessage(originalMessage),\n\t\t\t\tchunkMapLength: map.length,\n\t\t\t\tchunkId: chunkedContent.chunkId,\n\t\t\t\ttotalChunks: chunkedContent.totalChunks,\n\t\t\t});\n\t\t}\n\n\t\tmap.push(chunkedContent.contents);\n\t}\n\n\t/**\n\t * Takes a singleton batch, and splits the interior message into chunks, sending the chunks separately and\n\t * returning a new singleton batch containing the last chunk.\n\t *\n\t * A compressed batch is formed by one large op at the first position.\n\t *\n\t * If the op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire\n\t * and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.\n\t *\n\t * This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch.\n\t * This will ensure that the batch semantics of the original (non-compressed) batch are preserved, as the original chunked op\n\t * will be unrolled by the runtime when the first message in the batch is processed (as it is the last chunk).\n\t *\n\t * To illustrate the current functionality, if the input is `[largeOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.\n\t * `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4]` will be returned.\n\t *\n\t * @remarks - A side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @privateRemarks\n\t * This maintains support for splitting a compressed batch with multiple messages (empty placeholders after the first),\n\t * but this is only used for Unit Tests so the typing has been updated to preclude that.\n\t * That code should be moved out of this function into a test helper.\n\t *\n\t * @param batch - the compressed batch which needs to be split into chunks before being sent over the wire\n\t * @returns A batch with the last chunk in place of the original complete compressed content\n\t */\n\tpublic splitSingletonBatchMessage(batch: OutboundSingletonBatch): OutboundSingletonBatch {\n\t\tassert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.messages.length > 0,\n\t\t\t0x514 /* Batch needs to be non-empty */,\n\t\t);\n\t\tassert(\n\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t0x58a /* Batch must have a reference sequence number if non-empty */,\n\t\t);\n\t\tassert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);\n\t\tassert(\n\t\t\tthis.chunkSizeInBytes < this.maxBatchSizeInBytes,\n\t\t\t0x516 /* Chunk size needs to be smaller than the max batch size */,\n\t\t);\n\n\t\t// first message is the large compressed op to split, and we expect restOfMessages to be empty\n\t\t// (but we keep it here to support a legacy test case, wherein it contains empty placeholder messages)\n\t\tconst [firstMessage, ...restOfMessages] = batch.messages;\n\t\tassert(\n\t\t\t(firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,\n\t\t\t0x518 /* First message in the batch needs to be chunkable */,\n\t\t);\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tconst chunks = splitOp(\n\t\t\tfirstMessage,\n\t\t\tthis.chunkSizeInBytes,\n\t\t\t// If we estimate that the socket batch size will exceed the batch limit\n\t\t\t// we will inject an empty op to minimize the risk of the payload failing due to\n\t\t\t// the overhead from the trailing empty ops in the batch.\n\t\t\tsocketSize >= this.maxBatchSizeInBytes,\n\t\t);\n\n\t\tassert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);\n\t\t// Send the first N-1 chunks immediately\n\t\tfor (const chunk of chunks.slice(0, -1)) {\n\t\t\tthis.submitBatchFn(\n\t\t\t\t[chunkToBatchMessage(chunk, batch.referenceSequenceNumber)],\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// The last chunk will be part of the new batch and needs to\n\t\t// preserve the batch metadata of the original batch\n\t\tconst lastChunk = chunkToBatchMessage(\n\t\t\tchunks[chunks.length - 1],\n\t\t\tbatch.referenceSequenceNumber,\n\t\t\t{ batch: firstMessage.metadata?.batch },\n\t\t);\n\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\t// Used to be \"Chunked compressed batch\"\n\t\t\teventName: \"CompressedChunkedBatch\",\n\t\t\tlength: batch.messages.length,\n\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\tchunks: chunks.length,\n\t\t\tchunkSizeInBytes: this.chunkSizeInBytes,\n\t\t\tsocketSize,\n\t\t});\n\n\t\treturn {\n\t\t\tmessages: [lastChunk, ...restOfMessages],\n\t\t\tcontentSizeInBytes: lastChunk.contents?.length ?? 0,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\t}\n\n\tpublic processChunk(message: ISequencedDocumentMessage): ProcessChunkResult {\n\t\tassert(isChunkedContents(message.contents), 0x948 /* message not of type ChunkedOp */);\n\t\tconst contents: IChunkedContents = message.contents;\n\n\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\n\t\tconst clientId = message.clientId as string;\n\t\tconst chunkedContent = contents.contents;\n\t\tthis.addChunk(clientId, chunkedContent, message);\n\n\t\tif (chunkedContent.chunkId < chunkedContent.totalChunks) {\n\t\t\t// We are processing the op in chunks but haven't reached\n\t\t\t// the last chunk yet in order to reconstruct the original op\n\t\t\treturn {\n\t\t\t\tisFinalChunk: false,\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst serializedContent = this.chunkMap.get(clientId)!.join(\"\");\n\t\tthis.clearPartialChunks(clientId);\n\n\t\t// The final/complete message will contain the data from all the chunks.\n\t\t// It will have the sequenceNumber of the last chunk\n\t\tconst completeMessage = { ...message };\n\t\tcompleteMessage.contents =\n\t\t\tserializedContent === \"\" ? undefined : JSON.parse(serializedContent);\n\t\t// back-compat with 1.x builds\n\t\t// This is only required / present for non-compressed, chunked ops\n\t\t// For compressed ops, we have op grouping enabled, and type of each op is preserved within compressed content.\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\tcompleteMessage.type = (chunkedContent as any).originalType;\n\t\tcompleteMessage.metadata = chunkedContent.originalMetadata;\n\t\tcompleteMessage.compression = chunkedContent.originalCompression;\n\t\treturn {\n\t\t\tmessage: completeMessage,\n\t\t\tisFinalChunk: true,\n\t\t};\n\t}\n}\n\ntype ProcessChunkResult =\n\t| {\n\t\t\treadonly isFinalChunk: false;\n\t }\n\t| {\n\t\t\treadonly isFinalChunk: true;\n\t\t\treadonly message: ISequencedDocumentMessage;\n\t };\n\nconst chunkToBatchMessage = (\n\tchunk: IChunkedOp,\n\treferenceSequenceNumber: number,\n\tmetadata: Record<string, unknown> | undefined = undefined,\n): OutboundBatchMessage => {\n\tconst payload: ContainerRuntimeChunkedOpMessage = {\n\t\ttype: ContainerMessageType.ChunkedOp,\n\t\tcontents: chunk,\n\t};\n\treturn {\n\t\tcontents: JSON.stringify(payload),\n\t\tmetadata,\n\t\treferenceSequenceNumber,\n\t};\n};\n\n/**\n * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.\n *\n * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload\n * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.\n * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.\n *\n * @param op - the op to be split\n * @param chunkSizeInBytes - how large should the chunks be\n * @param extraOp - should an extra empty op be added to the result\n * @returns an array of chunked ops\n */\nexport const splitOp = (\n\top: OutboundBatchMessage,\n\tchunkSizeInBytes: number,\n\textraOp: boolean = false,\n): IChunkedOp[] => {\n\tconst chunks: IChunkedOp[] = [];\n\tassert(\n\t\top.contents !== undefined && op.contents !== null,\n\t\t0x51a /* We should have something to chunk */,\n\t);\n\n\tconst contentLength = op.contents.length;\n\tconst chunkCount =\n\t\tMath.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);\n\tlet offset = 0;\n\tfor (let chunkId = 1; chunkId <= chunkCount; chunkId++) {\n\t\tconst chunk: IChunkedOp = {\n\t\t\tchunkId,\n\t\t\tcontents: op.contents.slice(offset, offset + chunkSizeInBytes),\n\t\t\ttotalChunks: chunkCount,\n\t\t};\n\n\t\tif (chunkId === chunkCount) {\n\t\t\t// We don't need to port these to all the chunks,\n\t\t\t// as we rebuild the original op when we process the\n\t\t\t// last chunk, therefore it is the only one that needs it.\n\t\t\tchunk.originalMetadata = op.metadata;\n\t\t\tchunk.originalCompression = op.compression;\n\n\t\t\t// back-compat with 1.x builds\n\t\t\t// 2.x builds only do chunking for compressed ops.\n\t\t\t// originalType is no longer used in such cases, as each op preserves its type within compressed payload.\n\t\t\t// But, if 1.x builds see this op, and there is no type on the message, then it will ignore this message silently.\n\t\t\t// This is really bad, as we will crash on later ops and it's very hard to debug these cases.\n\t\t\t// If we put some known type here, then we will crash on it (as 1.x does not understand compression, and thus will not\n\t\t\t// find info on the op like address of the channel to deliver the op)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n\t\t\t(chunk as any).originalType = \"component\";\n\t\t}\n\n\t\tchunks.push(chunk);\n\t\toffset += chunkSizeInBytes;\n\t\tassert(\n\t\t\tchunkId >= chunkCount - 1 || offset <= contentLength,\n\t\t\t0x58b /* Content offset within bounds */,\n\t\t);\n\t}\n\n\tassert(\n\t\toffset >= contentLength,\n\t\t0x58c /* Content offset equal or larger than content length */,\n\t);\n\tassert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);\n\treturn chunks;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"opSplitter.js","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.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 type { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDataCorruptionError,\n\tcreateChildLogger,\n\textractSafePropertiesFromMessage,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype ContainerRuntimeChunkedOpMessage,\n} from \"../messageTypes.js\";\n\nimport type {\n\tIChunkedOp,\n\tOutboundBatchMessage,\n\tOutboundSingletonBatch,\n} from \"./definitions.js\";\nimport { estimateSocketSize } from \"./outbox.js\";\n\nexport function isChunkedMessage(message: ISequencedDocumentMessage): boolean {\n\treturn isChunkedContents(message.contents);\n}\n\ninterface IChunkedContents {\n\treadonly type: typeof ContainerMessageType.ChunkedOp;\n\treadonly contents: IChunkedOp;\n}\n\nfunction isChunkedContents(contents: unknown): contents is IChunkedContents {\n\treturn (contents as Partial<IChunkedContents>)?.type === ContainerMessageType.ChunkedOp;\n}\n\n/**\n * Responsible for creating and reconstructing chunked messages.\n */\nexport class OpSplitter {\n\t// Local copy of incomplete received chunks.\n\tprivate readonly chunkMap: Map<string, string[]>;\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tchunks: [string, string[]][],\n\t\tprivate readonly submitBatchFn:\n\t\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t\t| undefined,\n\t\tpublic readonly chunkSizeInBytes: number,\n\t\tprivate readonly maxBatchSizeInBytes: number,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.chunkMap = new Map<string, string[]>(chunks);\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpSplitter\" });\n\t}\n\n\tpublic get isBatchChunkingEnabled(): boolean {\n\t\treturn (\n\t\t\tthis.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined\n\t\t);\n\t}\n\n\tpublic get chunks(): ReadonlyMap<string, string[]> {\n\t\treturn this.chunkMap;\n\t}\n\n\tpublic clearPartialChunks(clientId: string): void {\n\t\tif (this.chunkMap.has(clientId)) {\n\t\t\tthis.chunkMap.delete(clientId);\n\t\t}\n\t}\n\n\tprivate addChunk(\n\t\tclientId: string,\n\t\tchunkedContent: IChunkedOp,\n\t\toriginalMessage: ISequencedDocumentMessage,\n\t): void {\n\t\tlet map = this.chunkMap.get(clientId);\n\t\tif (map === undefined) {\n\t\t\tmap = [];\n\t\t\tthis.chunkMap.set(clientId, map);\n\t\t}\n\n\t\tif (chunkedContent.chunkId !== map.length + 1) {\n\t\t\t// We are expecting the chunks to be processed sequentially, in the same order as they are sent.\n\t\t\t// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)\n\t\t\t// holding the existing chunks for that particular clientId.\n\t\t\tthrow new DataCorruptionError(\"Chunk Id mismatch\", {\n\t\t\t\t...extractSafePropertiesFromMessage(originalMessage),\n\t\t\t\tchunkMapLength: map.length,\n\t\t\t\tchunkId: chunkedContent.chunkId,\n\t\t\t\ttotalChunks: chunkedContent.totalChunks,\n\t\t\t});\n\t\t}\n\n\t\tmap.push(chunkedContent.contents);\n\t}\n\n\t/**\n\t * Takes a singleton batch, and splits the interior message into chunks, sending the chunks separately and\n\t * returning a new singleton batch containing the last chunk.\n\t *\n\t * A compressed batch is formed by one large op at the first position.\n\t *\n\t * If the op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire\n\t * and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.\n\t *\n\t * This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch.\n\t * This will ensure that the batch semantics of the original (non-compressed) batch are preserved, as the original chunked op\n\t * will be unrolled by the runtime when the first message in the batch is processed (as it is the last chunk).\n\t *\n\t * To illustrate the current functionality, if the input is `[largeOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.\n\t * `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4]` will be returned.\n\t *\n\t * @remarks A side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @privateRemarks\n\t * This maintains support for splitting a compressed batch with multiple messages (empty placeholders after the first),\n\t * but this is only used for Unit Tests so the typing has been updated to preclude that.\n\t * That code should be moved out of this function into a test helper.\n\t *\n\t * @param batch - the compressed batch which needs to be split into chunks before being sent over the wire\n\t * @returns A batch with the last chunk in place of the original complete compressed content\n\t */\n\tpublic splitSingletonBatchMessage(batch: OutboundSingletonBatch): OutboundSingletonBatch {\n\t\tassert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.messages.length > 0,\n\t\t\t0x514 /* Batch needs to be non-empty */,\n\t\t);\n\t\tassert(\n\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t0x58a /* Batch must have a reference sequence number if non-empty */,\n\t\t);\n\t\tassert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);\n\t\tassert(\n\t\t\tthis.chunkSizeInBytes < this.maxBatchSizeInBytes,\n\t\t\t0x516 /* Chunk size needs to be smaller than the max batch size */,\n\t\t);\n\n\t\t// first message is the large compressed op to split, and we expect restOfMessages to be empty\n\t\t// (but we keep it here to support a legacy test case, wherein it contains empty placeholder messages)\n\t\tconst [firstMessage, ...restOfMessages] = batch.messages;\n\t\tassert(\n\t\t\t(firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,\n\t\t\t0x518 /* First message in the batch needs to be chunkable */,\n\t\t);\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tconst chunks = splitOp(\n\t\t\tfirstMessage,\n\t\t\tthis.chunkSizeInBytes,\n\t\t\t// If we estimate that the socket batch size will exceed the batch limit\n\t\t\t// we will inject an empty op to minimize the risk of the payload failing due to\n\t\t\t// the overhead from the trailing empty ops in the batch.\n\t\t\tsocketSize >= this.maxBatchSizeInBytes,\n\t\t);\n\n\t\tassert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);\n\t\t// Send the first N-1 chunks immediately\n\t\tfor (const chunk of chunks.slice(0, -1)) {\n\t\t\tthis.submitBatchFn(\n\t\t\t\t[chunkToBatchMessage(chunk, batch.referenceSequenceNumber)],\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// The last chunk will be part of the new batch and needs to\n\t\t// preserve the batch metadata of the original batch\n\t\tconst lastChunk = chunkToBatchMessage(\n\t\t\tchunks[chunks.length - 1],\n\t\t\tbatch.referenceSequenceNumber,\n\t\t\t{ batch: firstMessage.metadata?.batch },\n\t\t);\n\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\t// Used to be \"Chunked compressed batch\"\n\t\t\teventName: \"CompressedChunkedBatch\",\n\t\t\tlength: batch.messages.length,\n\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\tchunks: chunks.length,\n\t\t\tchunkSizeInBytes: this.chunkSizeInBytes,\n\t\t\tsocketSize,\n\t\t});\n\n\t\treturn {\n\t\t\tmessages: [lastChunk, ...restOfMessages],\n\t\t\tcontentSizeInBytes: lastChunk.contents?.length ?? 0,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\t}\n\n\tpublic processChunk(message: ISequencedDocumentMessage): ProcessChunkResult {\n\t\tassert(isChunkedContents(message.contents), 0x948 /* message not of type ChunkedOp */);\n\t\tconst contents: IChunkedContents = message.contents;\n\n\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\n\t\tconst clientId = message.clientId as string;\n\t\tconst chunkedContent = contents.contents;\n\t\tthis.addChunk(clientId, chunkedContent, message);\n\n\t\tif (chunkedContent.chunkId < chunkedContent.totalChunks) {\n\t\t\t// We are processing the op in chunks but haven't reached\n\t\t\t// the last chunk yet in order to reconstruct the original op\n\t\t\treturn {\n\t\t\t\tisFinalChunk: false,\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst serializedContent = this.chunkMap.get(clientId)!.join(\"\");\n\t\tthis.clearPartialChunks(clientId);\n\n\t\t// The final/complete message will contain the data from all the chunks.\n\t\t// It will have the sequenceNumber of the last chunk\n\t\tconst completeMessage = { ...message };\n\t\tcompleteMessage.contents =\n\t\t\tserializedContent === \"\" ? undefined : JSON.parse(serializedContent);\n\t\t// back-compat with 1.x builds\n\t\t// This is only required / present for non-compressed, chunked ops\n\t\t// For compressed ops, we have op grouping enabled, and type of each op is preserved within compressed content.\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\tcompleteMessage.type = (chunkedContent as any).originalType;\n\t\tcompleteMessage.metadata = chunkedContent.originalMetadata;\n\t\tcompleteMessage.compression = chunkedContent.originalCompression;\n\t\treturn {\n\t\t\tmessage: completeMessage,\n\t\t\tisFinalChunk: true,\n\t\t};\n\t}\n}\n\ntype ProcessChunkResult =\n\t| {\n\t\t\treadonly isFinalChunk: false;\n\t }\n\t| {\n\t\t\treadonly isFinalChunk: true;\n\t\t\treadonly message: ISequencedDocumentMessage;\n\t };\n\nconst chunkToBatchMessage = (\n\tchunk: IChunkedOp,\n\treferenceSequenceNumber: number,\n\tmetadata: Record<string, unknown> | undefined = undefined,\n): OutboundBatchMessage => {\n\tconst payload: ContainerRuntimeChunkedOpMessage = {\n\t\ttype: ContainerMessageType.ChunkedOp,\n\t\tcontents: chunk,\n\t};\n\treturn {\n\t\tcontents: JSON.stringify(payload),\n\t\tmetadata,\n\t\treferenceSequenceNumber,\n\t};\n};\n\n/**\n * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.\n *\n * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload\n * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.\n * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.\n *\n * @param op - the op to be split\n * @param chunkSizeInBytes - how large should the chunks be\n * @param extraOp - should an extra empty op be added to the result\n * @returns an array of chunked ops\n */\nexport const splitOp = (\n\top: OutboundBatchMessage,\n\tchunkSizeInBytes: number,\n\textraOp: boolean = false,\n): IChunkedOp[] => {\n\tconst chunks: IChunkedOp[] = [];\n\tassert(\n\t\top.contents !== undefined && op.contents !== null,\n\t\t0x51a /* We should have something to chunk */,\n\t);\n\n\tconst contentLength = op.contents.length;\n\tconst chunkCount =\n\t\tMath.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);\n\tlet offset = 0;\n\tfor (let chunkId = 1; chunkId <= chunkCount; chunkId++) {\n\t\tconst chunk: IChunkedOp = {\n\t\t\tchunkId,\n\t\t\tcontents: op.contents.slice(offset, offset + chunkSizeInBytes),\n\t\t\ttotalChunks: chunkCount,\n\t\t};\n\n\t\tif (chunkId === chunkCount) {\n\t\t\t// We don't need to port these to all the chunks,\n\t\t\t// as we rebuild the original op when we process the\n\t\t\t// last chunk, therefore it is the only one that needs it.\n\t\t\tchunk.originalMetadata = op.metadata;\n\t\t\tchunk.originalCompression = op.compression;\n\n\t\t\t// back-compat with 1.x builds\n\t\t\t// 2.x builds only do chunking for compressed ops.\n\t\t\t// originalType is no longer used in such cases, as each op preserves its type within compressed payload.\n\t\t\t// But, if 1.x builds see this op, and there is no type on the message, then it will ignore this message silently.\n\t\t\t// This is really bad, as we will crash on later ops and it's very hard to debug these cases.\n\t\t\t// If we put some known type here, then we will crash on it (as 1.x does not understand compression, and thus will not\n\t\t\t// find info on the op like address of the channel to deliver the op)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n\t\t\t(chunk as any).originalType = \"component\";\n\t\t}\n\n\t\tchunks.push(chunk);\n\t\toffset += chunkSizeInBytes;\n\t\tassert(\n\t\t\tchunkId >= chunkCount - 1 || offset <= contentLength,\n\t\t\t0x58b /* Content offset within bounds */,\n\t\t);\n\t}\n\n\tassert(\n\t\toffset >= contentLength,\n\t\t0x58c /* Content offset equal or larger than content length */,\n\t);\n\tassert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);\n\treturn chunks;\n};\n"]}
|
|
@@ -121,7 +121,7 @@ export declare class Outbox {
|
|
|
121
121
|
* message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).
|
|
122
122
|
* This would indicate we expected this case to be precluded by logic elsewhere.
|
|
123
123
|
*
|
|
124
|
-
* @remarks
|
|
124
|
+
* @remarks To detect batch interruption, we compare both the reference sequence number
|
|
125
125
|
* (i.e. last message processed by DeltaManager) and the client sequence number of the
|
|
126
126
|
* last message processed by the ContainerRuntime. In the absence of op reentrancy, this
|
|
127
127
|
* pair will remain stable during a single JS turn during which the batch is being built up.
|
|
@@ -153,7 +153,7 @@ export declare class Outbox {
|
|
|
153
153
|
/**
|
|
154
154
|
* As necessary and enabled, groups / compresses / chunks the given batch.
|
|
155
155
|
*
|
|
156
|
-
* @remarks
|
|
156
|
+
* @remarks If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.
|
|
157
157
|
*
|
|
158
158
|
* @param localBatch - Local Batch to be virtualized - i.e. transformed into an Outbound Batch
|
|
159
159
|
* @param groupingEnabled - If true, Grouped batching is enabled.
|
|
@@ -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":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AACpF,OAAO,KAAK,EACX,oBAAoB,EAEpB,MAAM,iCAAiC,CAAC;AAUzC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EACX,0BAA0B,EAC1B,mBAAmB,EACnB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEN,KAAK,oBAAoB,EAGzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAGhB,UAAU,EACV,aAAa,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACxD;;OAEG;IACH,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,QAAQ,CAAC,aAAa,EACnB,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,uBAAuB,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,GACtE,SAAS,CAAC;IACb,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAC;IAC7D,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,iBAAiB,CAAC;IAC5C,QAAQ,CAAC,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;IAC/D,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClF,QAAQ,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAE,MAAW,GAAG,CAAC,CA0BvE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,EACzC,MAAM,EAAE,OAAO,EAAE,qEAAqE;AACtF,GAAG,UAAU,EACb,EAAE,UAAU,GAAG,aAAa,CAwB5B;AAQD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,UAAW,aAAa,KAAG,MAEzD,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,MAAM;IAiBN,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IAC9C,OAAO,CAAC,qBAAqB,CAAK;gBAEL,MAAM,EAAE,iBAAiB;IAWtD,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED,IAAW,qBAAqB,IAAI,MAAM,CAEzC;IAED,IAAW,2BAA2B,IAAI,MAAM,CAE/C;IAED,IAAW,6BAA6B,IAAI,MAAM,CAEjD;IAED,IAAW,OAAO,IAAI,OAAO,CAE5B;IAEM,mBAAmB,IAAI,OAAO;IAOrC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IAuEvB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAMxC,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAMlD,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAM3D,OAAO,CAAC,wBAAwB;IAWhC;;;;;;OAMG;IACI,KAAK,CAAC,YAAY,CAAC,EAAE,iBAAiB,GAAG,IAAI;IAkBpD,OAAO,CAAC,QAAQ;IAiChB,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,aAAa;IA2DrB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IAiCd,OAAO,CAAC,kBAAkB;IAI1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,eAAe;IA4CvB;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAwCjB,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACI,mBAAmB,IAAI;QAC7B,SAAS,EAAE,gBAAgB,CAAC;QAC5B,iBAAiB,EAAE,gBAAgB,CAAC;QACpC,eAAe,EAAE,gBAAgB,CAAC;KAClC;CAUD"}
|
|
@@ -144,7 +144,7 @@ class Outbox {
|
|
|
144
144
|
* message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).
|
|
145
145
|
* This would indicate we expected this case to be precluded by logic elsewhere.
|
|
146
146
|
*
|
|
147
|
-
* @remarks
|
|
147
|
+
* @remarks To detect batch interruption, we compare both the reference sequence number
|
|
148
148
|
* (i.e. last message processed by DeltaManager) and the client sequence number of the
|
|
149
149
|
* last message processed by the ContainerRuntime. In the absence of op reentrancy, this
|
|
150
150
|
* pair will remain stable during a single JS turn during which the batch is being built up.
|
|
@@ -219,6 +219,13 @@ class Outbox {
|
|
|
219
219
|
* @param resubmitInfo - Key information when flushing a resubmitted batch. Undefined means this is not resubmit.
|
|
220
220
|
*/
|
|
221
221
|
flush(resubmitInfo) {
|
|
222
|
+
// We have nothing to flush if all batchManagers are empty, and we we're not needing to resubmit an empty batch placeholder
|
|
223
|
+
if (this.idAllocationBatch.empty &&
|
|
224
|
+
this.blobAttachBatch.empty &&
|
|
225
|
+
this.mainBatch.empty &&
|
|
226
|
+
resubmitInfo?.batchId === undefined) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
222
229
|
(0, internal_1.assert)(!this.isContextReentrant(), 0xb7b /* Flushing must not happen while incoming changes are being processed */);
|
|
223
230
|
this.flushAll(resubmitInfo);
|
|
224
231
|
}
|
|
@@ -333,7 +340,7 @@ class Outbox {
|
|
|
333
340
|
/**
|
|
334
341
|
* As necessary and enabled, groups / compresses / chunks the given batch.
|
|
335
342
|
*
|
|
336
|
-
* @remarks
|
|
343
|
+
* @remarks If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.
|
|
337
344
|
*
|
|
338
345
|
* @param localBatch - Local Batch to be virtualized - i.e. transformed into an Outbound Batch
|
|
339
346
|
* @param groupingEnabled - If true, Grouped batching is enabled.
|
|
@@ -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 type { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tITelemetryBaseLogger,\n\tITelemetryBaseProperties,\n} from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tDataProcessingError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype IFluidErrorBase,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ICompressionRuntimeOptions } from \"../compressionDefinitions.js\";\nimport type {\n\tPendingMessageResubmitData,\n\tPendingStateManager,\n} from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\ttype BatchSequenceNumbers,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport type {\n\tLocalBatchMessage,\n\tIBatchCheckpoint,\n\tOutboundBatchMessage,\n\tOutboundSingletonBatch,\n\tLocalBatch,\n\tOutboundBatch,\n} from \"./definitions.js\";\nimport type { OpCompressor } from \"./opCompressor.js\";\nimport type { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { serializeOp } from \"./opSerialization.js\";\nimport type { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t/**\n\t * The maximum size of a batch that we can send over the wire.\n\t */\n\treadonly maxBatchSizeInBytes: number;\n\t/**\n\t * If true, maybeFlushPartialBatch will flush the batch if the reference sequence number changed\n\t * since the batch started. Otherwise, it will throw in this case (apart from reentrancy which is handled elsewhere).\n\t * Once the new throw-based flow is proved in a production environment, this option will be removed.\n\t */\n\treadonly flushPartialBatches: 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: OutboundBatch) => number;\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: PendingMessageResubmitData, squash: boolean) => void;\n\treadonly opReentrancy: () => boolean;\n}\n\n/**\n * Info needed to correctly resubmit a batch\n */\nexport interface BatchResubmitInfo {\n\t/**\n\t * If defined, indicates the Batch ID of the batch being resubmitted.\n\t * This must be preserved on the new batch about to be submitted so they can be correlated/deduped in case both are sent.\n\t */\n\tbatchId?: string;\n\t/**\n\t * Indicates whether or not this batch is \"staged\", meaning it should not be sent to the ordering service yet\n\t * This is important on resubmit because we may be in Staging Mode for new changes,\n\t * but resubmitting a non-staged change from before entering Staging Mode\n\t */\n\tstaged: boolean;\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\t// TODO: better typing here\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment\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\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\n/**\n * Convert from local batch to outbound batch, including computing contentSizeInBytes.\n */\nexport function localBatchToOutboundBatch({\n\tstaged: _staged, // Peel this off the incoming batch, it's irrelevant (see Note below)\n\t...localBatch\n}: LocalBatch): OutboundBatch {\n\t// Note: the staged property might be misleading here, in case a pre-staging batch is resubmitted during staging mode.\n\t// It will be set to true, but the batch was not actually staged.\n\n\t// Shallow copy each message as we switch types\n\tconst outboundMessages = localBatch.messages.map<OutboundBatchMessage>(\n\t\t({ runtimeOp, ...message }) => ({\n\t\t\tcontents: serializeOp(runtimeOp),\n\t\t\t...message,\n\t\t}),\n\t);\n\tconst contentSizeInBytes = outboundMessages.reduce(\n\t\t(acc, message) => acc + (message.contents?.length ?? 0),\n\t\t0,\n\t);\n\n\t// Shallow copy the local batch, updating the messages to be outbound messages and adding contentSizeInBytes\n\tconst outboundBatch: OutboundBatch = {\n\t\t...localBatch,\n\t\tmessages: outboundMessages,\n\t\tcontentSizeInBytes,\n\t};\n\n\treturn outboundBatch;\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 * 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 * @remarks\n * Also content will be stringified, and that adds a lot of overhead due to a lot of escape characters.\n * Not taking it into account, as compression work should help there - compressed payload will be\n * initially stored as base64, and that requires only 2 extra escape characters.\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: OutboundBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.messages.length;\n};\n\n/**\n * The Outbox collects messages submitted by the ContainerRuntime into a batch,\n * and then flushes the batch when requested.\n *\n * @remarks There are actually multiple independent batches (some are for a specific message type),\n * to support slight variation in semantics for each batch (e.g. support for rebasing or grouping).\n */\nexport class Outbox {\n\tprivate readonly logger: ITelemetryLoggerExt;\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.logger = createChildLogger({ logger: params.logger, namespace: \"Outbox\" });\n\n\t\tthis.mainBatch = new BatchManager({ canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({\n\t\t\tcanRebase: false,\n\t\t\tignoreBatchId: true,\n\t\t});\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 mainBatchMessageCount(): number {\n\t\treturn this.mainBatch.length;\n\t}\n\n\tpublic get blobAttachBatchMessageCount(): number {\n\t\treturn this.blobAttachBatch.length;\n\t}\n\n\tpublic get idAllocationBatchMessageCount(): number {\n\t\treturn this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\tpublic containsUserChanges(): boolean {\n\t\treturn (\n\t\t\tthis.mainBatch.containsUserChanges() || this.blobAttachBatch.containsUserChanges()\n\t\t\t// ID Allocation ops are not user changes\n\t\t);\n\t}\n\n\t/**\n\t * Detect whether batching has been interrupted by an incoming message being processed. In this case,\n\t * we will flush the accumulated messages to account for that (if allowed) and create a new batch with the new\n\t * message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).\n\t * This would indicate we expected this case to be precluded by logic elsewhere.\n\t *\n\t * @remarks - To detect batch interruption, we compare both the reference sequence number\n\t * (i.e. last message processed by DeltaManager) and the client sequence number of the\n\t * last message processed by the ContainerRuntime. In the absence of op reentrancy, this\n\t * pair will remain stable during a single JS turn during which the batch is being built up.\n\t */\n\tprivate maybeFlushPartialBatch(): void {\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\tsequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\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\t// Reference and/or Client sequence number will be advancing while processing this batch,\n\t\t// so we can't use this check to detect wrongdoing. But we will still log via telemetry.\n\t\t// This is rare, and the reentrancy will be handled during Flush.\n\t\tconst expectedDueToReentrancy = this.isContextReentrant();\n\n\t\tconst errorWrapper = new Lazy(() =>\n\t\t\tgetLongStack(() =>\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"Sequence numbers advanced as if ops were processed while a batch is accumulating\",\n\t\t\t\t\t\"outboxSequenceNumberCoherencyCheck\",\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\t// Only log error if this is truly unexpected\n\t\t\t\t\tcategory:\n\t\t\t\t\t\texpectedDueToReentrancy || this.params.config.flushPartialBatches\n\t\t\t\t\t\t\t? \"generic\"\n\t\t\t\t\t\t\t: \"error\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\texpectedDueToReentrancy,\n\t\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terrorWrapper.value,\n\t\t\t);\n\t\t}\n\n\t\t// If we're configured to flush partial batches, do that now and return (don't throw)\n\t\tif (this.params.config.flushPartialBatches) {\n\t\t\tthis.flushAll();\n\t\t\treturn;\n\t\t}\n\n\t\t// If we are in a reentrant context, we know this can happen without causing any harm.\n\t\tif (expectedDueToReentrancy) {\n\t\t\treturn;\n\t\t}\n\n\t\tthrow errorWrapper.value;\n\t}\n\n\tpublic submit(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\t}\n\n\tpublic submitIdAllocation(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(\n\t\tbatchManager: BatchManager,\n\t\tmessage: LocalBatchMessage,\n\t): void {\n\t\tbatchManager.push(\n\t\t\tmessage,\n\t\t\tthis.isContextReentrant(),\n\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Flush all the batches to the ordering service.\n\t * This method is expected to be called at the end of a batch.\n\t *\n\t * @throws If called from a reentrant context, or if the batch being flushed is too large.\n\t * @param resubmitInfo - Key information when flushing a resubmitted batch. Undefined means this is not resubmit.\n\t */\n\tpublic flush(resubmitInfo?: BatchResubmitInfo): void {\n\t\tassert(\n\t\t\t!this.isContextReentrant(),\n\t\t\t0xb7b /* Flushing must not happen while incoming changes are being processed */,\n\t\t);\n\t\tthis.flushAll(resubmitInfo);\n\t}\n\n\tprivate flushAll(resubmitInfo?: BatchResubmitInfo): void {\n\t\tconst allBatchesEmpty =\n\t\t\tthis.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;\n\t\tif (allBatchesEmpty) {\n\t\t\t// If we're resubmitting with a batchId and all batches are empty, we need to flush an empty batch.\n\t\t\t// Note that we currently resubmit one batch at a time, so on resubmit, 1 of the 2 batches will *always* be empty.\n\t\t\t// It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored\n\t\t\t// by the rest of the system, including remote clients.\n\t\t\t// In some cases we *must* resubmit the empty batch (to match up with a non-empty version tracked locally by a container fork), so we do it always.\n\t\t\tif (resubmitInfo?.batchId !== undefined) {\n\t\t\t\tthis.flushEmptyBatch(resubmitInfo.batchId, resubmitInfo.staged);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so don't pass the resubmitInfo\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.idAllocationBatch,\n\t\t\t// Note: For now, we will never stage ID Allocation messages.\n\t\t\t// They won't contain personal info and no harm in extra allocations in case of discarding the staged changes\n\t\t});\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.blobAttachBatch,\n\t\t\tdisableGroupedBatching: true,\n\t\t\tresubmitInfo,\n\t\t});\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.mainBatch,\n\t\t\tresubmitInfo,\n\t\t});\n\t}\n\n\tprivate flushEmptyBatch(\n\t\tresubmittingBatchId: BatchId,\n\t\tresubmittingStagedBatch: boolean,\n\t): void {\n\t\tconst referenceSequenceNumber =\n\t\t\tthis.params.getCurrentSequenceNumbers().referenceSequenceNumber;\n\t\tassert(\n\t\t\treferenceSequenceNumber !== undefined,\n\t\t\t0xa01 /* reference sequence number should be defined */,\n\t\t);\n\t\tconst { outboundBatch, placeholderMessage } =\n\t\t\tthis.params.groupingManager.createEmptyGroupedBatch(\n\t\t\t\tresubmittingBatchId,\n\t\t\t\treferenceSequenceNumber,\n\t\t\t);\n\t\tlet clientSequenceNumber: number | undefined;\n\t\tif (this.params.shouldSend() && !resubmittingStagedBatch) {\n\t\t\tclientSequenceNumber = this.sendBatch(outboundBatch);\n\t\t}\n\n\t\t// Push the empty batch placeholder to the PendingStateManager\n\t\tthis.params.pendingStateManager.onFlushEmptyBatch(\n\t\t\tplaceholderMessage,\n\t\t\tclientSequenceNumber,\n\t\t\tresubmittingStagedBatch,\n\t\t);\n\t\treturn;\n\t}\n\n\tprivate flushInternal(params: {\n\t\tbatchManager: BatchManager;\n\t\tdisableGroupedBatching?: boolean;\n\t\tresubmitInfo?: BatchResubmitInfo; // undefined if not resubmitting\n\t}): void {\n\t\tconst { batchManager, disableGroupedBatching = false, resubmitInfo } = params;\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmitInfo?.batchId);\n\n\t\t// On resubmit we use the original batch's staged state, so these should match as well.\n\t\tconst staged = rawBatch.staged === true;\n\t\tassert(\n\t\t\tresubmitInfo === undefined || resubmitInfo.staged === staged,\n\t\t\t0xba3 /* Mismatch in staged state tracking */,\n\t\t);\n\n\t\tconst groupingEnabled =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.groupedBatchingEnabled();\n\t\tif (\n\t\t\tbatchManager.options.canRebase &&\n\t\t\trawBatch.hasReentrantOps === true &&\n\t\t\tgroupingEnabled\n\t\t) {\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\t// Note: Since this is happening in the same turn the ops were originally created with,\n\t\t\t// and they haven't gone to PendingStateManager yet, we can just let them respect\n\t\t\t// ContainerRuntime.inStagingMode. So we do not plumb local 'staged' variable through here.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\tlet clientSequenceNumber: number | undefined;\n\t\t// Did we disconnect? (i.e. is shouldSend false?)\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() && !staged) {\n\t\t\tconst virtualizedBatch = this.virtualizeBatch(rawBatch, groupingEnabled);\n\n\t\t\tclientSequenceNumber = this.sendBatch(virtualizedBatch);\n\t\t\tassert(\n\t\t\t\tclientSequenceNumber === undefined || clientSequenceNumber >= 0,\n\t\t\t\t0x9d2 /* unexpected negative clientSequenceNumber (empty batch should yield undefined) */,\n\t\t\t);\n\t\t}\n\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\trawBatch.messages,\n\t\t\tclientSequenceNumber,\n\t\t\tstaged,\n\t\t\tbatchManager.options.ignoreBatchId,\n\t\t);\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: LocalBatch, batchManager: BatchManager): void {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tconst squash = false;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit(\n\t\t\t\t{\n\t\t\t\t\truntimeOp: message.runtimeOp,\n\t\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\t\topMetadata: message.metadata,\n\t\t\t\t},\n\t\t\t\tsquash,\n\t\t\t);\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.messages.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\t/**\n\t * As necessary and enabled, groups / compresses / chunks the given batch.\n\t *\n\t * @remarks - If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @param localBatch - Local Batch to be virtualized - i.e. transformed into an Outbound Batch\n\t * @param groupingEnabled - If true, Grouped batching is enabled.\n\t * @returns One of the following:\n\t * - (A) The original batch (Based on what's enabled)\n\t * - (B) A grouped batch (it's a singleton batch)\n\t * - (C) A compressed singleton batch\n\t * - (D) A singleton batch containing the last chunk.\n\t */\n\tprivate virtualizeBatch(localBatch: LocalBatch, groupingEnabled: boolean): OutboundBatch {\n\t\t// Shallow copy the local batch, updating the messages to be outbound messages\n\t\tconst originalBatch = localBatchToOutboundBatch(localBatch);\n\n\t\tconst originalOrGroupedBatch = groupingEnabled\n\t\t\t? this.params.groupingManager.groupBatch(originalBatch)\n\t\t\t: originalBatch;\n\n\t\tif (originalOrGroupedBatch.messages.length !== 1) {\n\t\t\t// Compression requires a single message, so return early otherwise.\n\t\t\treturn originalOrGroupedBatch;\n\t\t}\n\n\t\t// Regardless of whether we grouped or not, we now have a batch with a single message.\n\t\t// Now proceed to compress/chunk it if necessary.\n\t\tconst singletonBatch = originalOrGroupedBatch as OutboundSingletonBatch;\n\n\t\tif (\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tsingletonBatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if compression is disabled, unnecessary or unsupported.\n\t\t\treturn singletonBatch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(singletonBatch);\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.splitSingletonBatchMessage(compressedBatch);\n\t\t}\n\n\t\t// We want to distinguish this \"BatchTooLarge\" case from the generic \"BatchTooLarge\" case in sendBatch\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow this.makeBatchTooLargeError(compressedBatch, \"CompressionInsufficient\", {\n\t\t\t\tuncompressedSizeInBytes: singletonBatch.contentSizeInBytes,\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 * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: OutboundBatch): number | undefined {\n\t\tconst length = batch.messages.length;\n\t\tif (length === 0) {\n\t\t\treturn undefined; // Nothing submitted\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow this.makeBatchTooLargeError(batch, \"CannotSend\");\n\t\t}\n\n\t\tlet clientSequenceNumber: number;\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.messages[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\tclientSequenceNumber = this.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);\n\t\t\tclientSequenceNumber = this.params.submitBatchFn(\n\t\t\t\tbatch.messages.map<IBatchMessage>((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\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\tprivate makeBatchTooLargeError(\n\t\tbatch: OutboundBatch,\n\t\tcodepath: string,\n\t\tmoreDetails?: ITelemetryBaseProperties,\n\t): IFluidErrorBase {\n\t\treturn DataProcessingError.create(\n\t\t\t\"BatchTooLarge\",\n\t\t\tcodepath,\n\t\t\t/* sequencedMessage */ undefined,\n\t\t\t{\n\t\t\t\terrorDetails: {\n\t\t\t\t\topCount: batch.messages.length,\n\t\t\t\t\tcontentSizeInBytes: batch.contentSizeInBytes,\n\t\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t\t\tmaxBatchSizeInBytes: this.params.config.maxBatchSizeInBytes,\n\t\t\t\t\tgroupedBatchingEnabled: this.params.groupingManager.groupedBatchingEnabled(),\n\t\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\t\tchunkSizeInBytes: this.params.splitter.chunkSizeInBytes,\n\t\t\t\t\t...moreDetails,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Gets a checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints(): {\n\t\tmainBatch: IBatchCheckpoint;\n\t\tidAllocationBatch: IBatchCheckpoint;\n\t\tblobAttachBatch: IBatchCheckpoint;\n\t} {\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\tidAllocationBatch: this.idAllocationBatch.checkpoint(),\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 type { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tITelemetryBaseLogger,\n\tITelemetryBaseProperties,\n} from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tDataProcessingError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype IFluidErrorBase,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ICompressionRuntimeOptions } from \"../compressionDefinitions.js\";\nimport type {\n\tPendingMessageResubmitData,\n\tPendingStateManager,\n} from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\ttype BatchSequenceNumbers,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport type {\n\tLocalBatchMessage,\n\tIBatchCheckpoint,\n\tOutboundBatchMessage,\n\tOutboundSingletonBatch,\n\tLocalBatch,\n\tOutboundBatch,\n} from \"./definitions.js\";\nimport type { OpCompressor } from \"./opCompressor.js\";\nimport type { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { serializeOp } from \"./opSerialization.js\";\nimport type { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t/**\n\t * The maximum size of a batch that we can send over the wire.\n\t */\n\treadonly maxBatchSizeInBytes: number;\n\t/**\n\t * If true, maybeFlushPartialBatch will flush the batch if the reference sequence number changed\n\t * since the batch started. Otherwise, it will throw in this case (apart from reentrancy which is handled elsewhere).\n\t * Once the new throw-based flow is proved in a production environment, this option will be removed.\n\t */\n\treadonly flushPartialBatches: 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: OutboundBatch) => number;\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: PendingMessageResubmitData, squash: boolean) => void;\n\treadonly opReentrancy: () => boolean;\n}\n\n/**\n * Info needed to correctly resubmit a batch\n */\nexport interface BatchResubmitInfo {\n\t/**\n\t * If defined, indicates the Batch ID of the batch being resubmitted.\n\t * This must be preserved on the new batch about to be submitted so they can be correlated/deduped in case both are sent.\n\t */\n\tbatchId?: string;\n\t/**\n\t * Indicates whether or not this batch is \"staged\", meaning it should not be sent to the ordering service yet\n\t * This is important on resubmit because we may be in Staging Mode for new changes,\n\t * but resubmitting a non-staged change from before entering Staging Mode\n\t */\n\tstaged: boolean;\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\t// TODO: better typing here\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment\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\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\n/**\n * Convert from local batch to outbound batch, including computing contentSizeInBytes.\n */\nexport function localBatchToOutboundBatch({\n\tstaged: _staged, // Peel this off the incoming batch, it's irrelevant (see Note below)\n\t...localBatch\n}: LocalBatch): OutboundBatch {\n\t// Note: the staged property might be misleading here, in case a pre-staging batch is resubmitted during staging mode.\n\t// It will be set to true, but the batch was not actually staged.\n\n\t// Shallow copy each message as we switch types\n\tconst outboundMessages = localBatch.messages.map<OutboundBatchMessage>(\n\t\t({ runtimeOp, ...message }) => ({\n\t\t\tcontents: serializeOp(runtimeOp),\n\t\t\t...message,\n\t\t}),\n\t);\n\tconst contentSizeInBytes = outboundMessages.reduce(\n\t\t(acc, message) => acc + (message.contents?.length ?? 0),\n\t\t0,\n\t);\n\n\t// Shallow copy the local batch, updating the messages to be outbound messages and adding contentSizeInBytes\n\tconst outboundBatch: OutboundBatch = {\n\t\t...localBatch,\n\t\tmessages: outboundMessages,\n\t\tcontentSizeInBytes,\n\t};\n\n\treturn outboundBatch;\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 * 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 * @remarks\n * Also content will be stringified, and that adds a lot of overhead due to a lot of escape characters.\n * Not taking it into account, as compression work should help there - compressed payload will be\n * initially stored as base64, and that requires only 2 extra escape characters.\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: OutboundBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.messages.length;\n};\n\n/**\n * The Outbox collects messages submitted by the ContainerRuntime into a batch,\n * and then flushes the batch when requested.\n *\n * @remarks There are actually multiple independent batches (some are for a specific message type),\n * to support slight variation in semantics for each batch (e.g. support for rebasing or grouping).\n */\nexport class Outbox {\n\tprivate readonly logger: ITelemetryLoggerExt;\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.logger = createChildLogger({ logger: params.logger, namespace: \"Outbox\" });\n\n\t\tthis.mainBatch = new BatchManager({ canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({\n\t\t\tcanRebase: false,\n\t\t\tignoreBatchId: true,\n\t\t});\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 mainBatchMessageCount(): number {\n\t\treturn this.mainBatch.length;\n\t}\n\n\tpublic get blobAttachBatchMessageCount(): number {\n\t\treturn this.blobAttachBatch.length;\n\t}\n\n\tpublic get idAllocationBatchMessageCount(): number {\n\t\treturn this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\tpublic containsUserChanges(): boolean {\n\t\treturn (\n\t\t\tthis.mainBatch.containsUserChanges() || this.blobAttachBatch.containsUserChanges()\n\t\t\t// ID Allocation ops are not user changes\n\t\t);\n\t}\n\n\t/**\n\t * Detect whether batching has been interrupted by an incoming message being processed. In this case,\n\t * we will flush the accumulated messages to account for that (if allowed) and create a new batch with the new\n\t * message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).\n\t * This would indicate we expected this case to be precluded by logic elsewhere.\n\t *\n\t * @remarks To detect batch interruption, we compare both the reference sequence number\n\t * (i.e. last message processed by DeltaManager) and the client sequence number of the\n\t * last message processed by the ContainerRuntime. In the absence of op reentrancy, this\n\t * pair will remain stable during a single JS turn during which the batch is being built up.\n\t */\n\tprivate maybeFlushPartialBatch(): void {\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\tsequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\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\t// Reference and/or Client sequence number will be advancing while processing this batch,\n\t\t// so we can't use this check to detect wrongdoing. But we will still log via telemetry.\n\t\t// This is rare, and the reentrancy will be handled during Flush.\n\t\tconst expectedDueToReentrancy = this.isContextReentrant();\n\n\t\tconst errorWrapper = new Lazy(() =>\n\t\t\tgetLongStack(() =>\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"Sequence numbers advanced as if ops were processed while a batch is accumulating\",\n\t\t\t\t\t\"outboxSequenceNumberCoherencyCheck\",\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\t// Only log error if this is truly unexpected\n\t\t\t\t\tcategory:\n\t\t\t\t\t\texpectedDueToReentrancy || this.params.config.flushPartialBatches\n\t\t\t\t\t\t\t? \"generic\"\n\t\t\t\t\t\t\t: \"error\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\texpectedDueToReentrancy,\n\t\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terrorWrapper.value,\n\t\t\t);\n\t\t}\n\n\t\t// If we're configured to flush partial batches, do that now and return (don't throw)\n\t\tif (this.params.config.flushPartialBatches) {\n\t\t\tthis.flushAll();\n\t\t\treturn;\n\t\t}\n\n\t\t// If we are in a reentrant context, we know this can happen without causing any harm.\n\t\tif (expectedDueToReentrancy) {\n\t\t\treturn;\n\t\t}\n\n\t\tthrow errorWrapper.value;\n\t}\n\n\tpublic submit(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\t}\n\n\tpublic submitIdAllocation(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(\n\t\tbatchManager: BatchManager,\n\t\tmessage: LocalBatchMessage,\n\t): void {\n\t\tbatchManager.push(\n\t\t\tmessage,\n\t\t\tthis.isContextReentrant(),\n\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Flush all the batches to the ordering service.\n\t * This method is expected to be called at the end of a batch.\n\t *\n\t * @throws If called from a reentrant context, or if the batch being flushed is too large.\n\t * @param resubmitInfo - Key information when flushing a resubmitted batch. Undefined means this is not resubmit.\n\t */\n\tpublic flush(resubmitInfo?: BatchResubmitInfo): void {\n\t\t// We have nothing to flush if all batchManagers are empty, and we we're not needing to resubmit an empty batch placeholder\n\t\tif (\n\t\t\tthis.idAllocationBatch.empty &&\n\t\t\tthis.blobAttachBatch.empty &&\n\t\t\tthis.mainBatch.empty &&\n\t\t\tresubmitInfo?.batchId === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tassert(\n\t\t\t!this.isContextReentrant(),\n\t\t\t0xb7b /* Flushing must not happen while incoming changes are being processed */,\n\t\t);\n\t\tthis.flushAll(resubmitInfo);\n\t}\n\n\tprivate flushAll(resubmitInfo?: BatchResubmitInfo): void {\n\t\tconst allBatchesEmpty =\n\t\t\tthis.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;\n\t\tif (allBatchesEmpty) {\n\t\t\t// If we're resubmitting with a batchId and all batches are empty, we need to flush an empty batch.\n\t\t\t// Note that we currently resubmit one batch at a time, so on resubmit, 1 of the 2 batches will *always* be empty.\n\t\t\t// It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored\n\t\t\t// by the rest of the system, including remote clients.\n\t\t\t// In some cases we *must* resubmit the empty batch (to match up with a non-empty version tracked locally by a container fork), so we do it always.\n\t\t\tif (resubmitInfo?.batchId !== undefined) {\n\t\t\t\tthis.flushEmptyBatch(resubmitInfo.batchId, resubmitInfo.staged);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so don't pass the resubmitInfo\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.idAllocationBatch,\n\t\t\t// Note: For now, we will never stage ID Allocation messages.\n\t\t\t// They won't contain personal info and no harm in extra allocations in case of discarding the staged changes\n\t\t});\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.blobAttachBatch,\n\t\t\tdisableGroupedBatching: true,\n\t\t\tresubmitInfo,\n\t\t});\n\t\tthis.flushInternal({\n\t\t\tbatchManager: this.mainBatch,\n\t\t\tresubmitInfo,\n\t\t});\n\t}\n\n\tprivate flushEmptyBatch(\n\t\tresubmittingBatchId: BatchId,\n\t\tresubmittingStagedBatch: boolean,\n\t): void {\n\t\tconst referenceSequenceNumber =\n\t\t\tthis.params.getCurrentSequenceNumbers().referenceSequenceNumber;\n\t\tassert(\n\t\t\treferenceSequenceNumber !== undefined,\n\t\t\t0xa01 /* reference sequence number should be defined */,\n\t\t);\n\t\tconst { outboundBatch, placeholderMessage } =\n\t\t\tthis.params.groupingManager.createEmptyGroupedBatch(\n\t\t\t\tresubmittingBatchId,\n\t\t\t\treferenceSequenceNumber,\n\t\t\t);\n\t\tlet clientSequenceNumber: number | undefined;\n\t\tif (this.params.shouldSend() && !resubmittingStagedBatch) {\n\t\t\tclientSequenceNumber = this.sendBatch(outboundBatch);\n\t\t}\n\n\t\t// Push the empty batch placeholder to the PendingStateManager\n\t\tthis.params.pendingStateManager.onFlushEmptyBatch(\n\t\t\tplaceholderMessage,\n\t\t\tclientSequenceNumber,\n\t\t\tresubmittingStagedBatch,\n\t\t);\n\t\treturn;\n\t}\n\n\tprivate flushInternal(params: {\n\t\tbatchManager: BatchManager;\n\t\tdisableGroupedBatching?: boolean;\n\t\tresubmitInfo?: BatchResubmitInfo; // undefined if not resubmitting\n\t}): void {\n\t\tconst { batchManager, disableGroupedBatching = false, resubmitInfo } = params;\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmitInfo?.batchId);\n\n\t\t// On resubmit we use the original batch's staged state, so these should match as well.\n\t\tconst staged = rawBatch.staged === true;\n\t\tassert(\n\t\t\tresubmitInfo === undefined || resubmitInfo.staged === staged,\n\t\t\t0xba3 /* Mismatch in staged state tracking */,\n\t\t);\n\n\t\tconst groupingEnabled =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.groupedBatchingEnabled();\n\t\tif (\n\t\t\tbatchManager.options.canRebase &&\n\t\t\trawBatch.hasReentrantOps === true &&\n\t\t\tgroupingEnabled\n\t\t) {\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\t// Note: Since this is happening in the same turn the ops were originally created with,\n\t\t\t// and they haven't gone to PendingStateManager yet, we can just let them respect\n\t\t\t// ContainerRuntime.inStagingMode. So we do not plumb local 'staged' variable through here.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\tlet clientSequenceNumber: number | undefined;\n\t\t// Did we disconnect? (i.e. is shouldSend false?)\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() && !staged) {\n\t\t\tconst virtualizedBatch = this.virtualizeBatch(rawBatch, groupingEnabled);\n\n\t\t\tclientSequenceNumber = this.sendBatch(virtualizedBatch);\n\t\t\tassert(\n\t\t\t\tclientSequenceNumber === undefined || clientSequenceNumber >= 0,\n\t\t\t\t0x9d2 /* unexpected negative clientSequenceNumber (empty batch should yield undefined) */,\n\t\t\t);\n\t\t}\n\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\trawBatch.messages,\n\t\t\tclientSequenceNumber,\n\t\t\tstaged,\n\t\t\tbatchManager.options.ignoreBatchId,\n\t\t);\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: LocalBatch, batchManager: BatchManager): void {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tconst squash = false;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit(\n\t\t\t\t{\n\t\t\t\t\truntimeOp: message.runtimeOp,\n\t\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\t\topMetadata: message.metadata,\n\t\t\t\t},\n\t\t\t\tsquash,\n\t\t\t);\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.messages.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\t/**\n\t * As necessary and enabled, groups / compresses / chunks the given batch.\n\t *\n\t * @remarks If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @param localBatch - Local Batch to be virtualized - i.e. transformed into an Outbound Batch\n\t * @param groupingEnabled - If true, Grouped batching is enabled.\n\t * @returns One of the following:\n\t * - (A) The original batch (Based on what's enabled)\n\t * - (B) A grouped batch (it's a singleton batch)\n\t * - (C) A compressed singleton batch\n\t * - (D) A singleton batch containing the last chunk.\n\t */\n\tprivate virtualizeBatch(localBatch: LocalBatch, groupingEnabled: boolean): OutboundBatch {\n\t\t// Shallow copy the local batch, updating the messages to be outbound messages\n\t\tconst originalBatch = localBatchToOutboundBatch(localBatch);\n\n\t\tconst originalOrGroupedBatch = groupingEnabled\n\t\t\t? this.params.groupingManager.groupBatch(originalBatch)\n\t\t\t: originalBatch;\n\n\t\tif (originalOrGroupedBatch.messages.length !== 1) {\n\t\t\t// Compression requires a single message, so return early otherwise.\n\t\t\treturn originalOrGroupedBatch;\n\t\t}\n\n\t\t// Regardless of whether we grouped or not, we now have a batch with a single message.\n\t\t// Now proceed to compress/chunk it if necessary.\n\t\tconst singletonBatch = originalOrGroupedBatch as OutboundSingletonBatch;\n\n\t\tif (\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tsingletonBatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if compression is disabled, unnecessary or unsupported.\n\t\t\treturn singletonBatch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(singletonBatch);\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.splitSingletonBatchMessage(compressedBatch);\n\t\t}\n\n\t\t// We want to distinguish this \"BatchTooLarge\" case from the generic \"BatchTooLarge\" case in sendBatch\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow this.makeBatchTooLargeError(compressedBatch, \"CompressionInsufficient\", {\n\t\t\t\tuncompressedSizeInBytes: singletonBatch.contentSizeInBytes,\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 * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: OutboundBatch): number | undefined {\n\t\tconst length = batch.messages.length;\n\t\tif (length === 0) {\n\t\t\treturn undefined; // Nothing submitted\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow this.makeBatchTooLargeError(batch, \"CannotSend\");\n\t\t}\n\n\t\tlet clientSequenceNumber: number;\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.messages[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\tclientSequenceNumber = this.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);\n\t\t\tclientSequenceNumber = this.params.submitBatchFn(\n\t\t\t\tbatch.messages.map<IBatchMessage>((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\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\tprivate makeBatchTooLargeError(\n\t\tbatch: OutboundBatch,\n\t\tcodepath: string,\n\t\tmoreDetails?: ITelemetryBaseProperties,\n\t): IFluidErrorBase {\n\t\treturn DataProcessingError.create(\n\t\t\t\"BatchTooLarge\",\n\t\t\tcodepath,\n\t\t\t/* sequencedMessage */ undefined,\n\t\t\t{\n\t\t\t\terrorDetails: {\n\t\t\t\t\topCount: batch.messages.length,\n\t\t\t\t\tcontentSizeInBytes: batch.contentSizeInBytes,\n\t\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t\t\tmaxBatchSizeInBytes: this.params.config.maxBatchSizeInBytes,\n\t\t\t\t\tgroupedBatchingEnabled: this.params.groupingManager.groupedBatchingEnabled(),\n\t\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\t\tchunkSizeInBytes: this.params.splitter.chunkSizeInBytes,\n\t\t\t\t\t...moreDetails,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Gets a checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints(): {\n\t\tmainBatch: IBatchCheckpoint;\n\t\tidAllocationBatch: IBatchCheckpoint;\n\t\tblobAttachBatch: IBatchCheckpoint;\n\t} {\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\tidAllocationBatch: this.idAllocationBatch.checkpoint(),\n\t\t\tblobAttachBatch: this.blobAttachBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -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.70.0-
|
|
8
|
+
export declare const pkgVersion = "2.70.0-361788";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/container-runtime";
|
|
11
|
-
exports.pkgVersion = "2.70.0-
|
|
11
|
+
exports.pkgVersion = "2.70.0-361788";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,mCAAmC,CAAC;AAC9C,QAAA,UAAU,GAAG,eAAe,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.70.0-
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,mCAAmC,CAAC;AAC9C,QAAA,UAAU,GAAG,eAAe,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.70.0-361788\";\n"]}
|