@fluidframework/container-runtime 2.1.0 → 2.3.0-288113
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/CHANGELOG.md +30 -0
- package/README.md +2 -2
- package/api-report/container-runtime.legacy.alpha.api.md +4 -3
- package/container-runtime.test-files.tar +0 -0
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +9 -0
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +0 -14
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +2 -12
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +34 -6
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +176 -81
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +9 -18
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +40 -78
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +0 -6
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +23 -66
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +11 -34
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +9 -52
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +3 -23
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +2 -6
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +4 -8
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +1 -9
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +3 -25
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +2 -2
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +2 -7
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +6 -5
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/metadata.d.ts +9 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +6 -1
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +8 -0
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +34 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +1 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +20 -0
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +34 -15
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +59 -46
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +28 -27
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +143 -112
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +5 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +3 -4
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +16 -15
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +9 -0
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +0 -14
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +2 -11
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +34 -6
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +176 -81
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +9 -18
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +27 -65
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +0 -6
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +25 -68
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +12 -35
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +9 -52
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +2 -22
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +2 -6
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +4 -8
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +1 -9
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +3 -24
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +2 -2
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +2 -2
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/messageTypes.d.ts +6 -5
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/metadata.d.ts +9 -1
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js +4 -0
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +8 -0
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +34 -2
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +1 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +20 -0
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +34 -15
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +59 -46
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +28 -27
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +144 -113
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +5 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +3 -4
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +16 -15
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/package.json +22 -35
- package/src/batchTracker.ts +4 -2
- package/src/blobManager/blobManager.ts +9 -0
- package/src/channelCollection.ts +2 -11
- package/src/containerRuntime.ts +211 -109
- package/src/dataStoreContext.ts +29 -93
- package/src/gc/garbageCollection.ts +26 -79
- package/src/gc/gcConfigs.ts +12 -45
- package/src/gc/gcDefinitions.ts +10 -55
- package/src/gc/gcHelpers.ts +10 -8
- package/src/gc/gcSummaryStateTracker.ts +6 -9
- package/src/gc/gcTelemetry.ts +3 -38
- package/src/gc/index.ts +2 -6
- package/src/index.ts +0 -1
- package/src/messageTypes.ts +12 -11
- package/src/metadata.ts +16 -2
- package/src/opLifecycle/index.ts +1 -0
- package/src/opLifecycle/opGroupingManager.ts +42 -3
- package/src/opLifecycle/outbox.ts +30 -0
- package/src/opLifecycle/remoteMessageProcessor.ts +98 -62
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +199 -177
- package/src/summary/README.md +31 -28
- package/src/summary/summarizerNode/summarizerNode.ts +6 -1
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +20 -43
- package/src/summary/summaryFormats.md +25 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opGroupingManager.js","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAkB7E,SAAS,eAAe,CAAC,UAAe;IACvC,OAAO,UAAU,EAAE,IAAI,KAAK,iBAAiB,CAAC,cAAc,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAA6B;IAC3D,OAAO,eAAe,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAQD,MAAM,OAAO,iBAAiB;IAI7B,YACkB,MAA+B,EAChD,MAA4B;QADX,WAAM,GAAN,MAAM,CAAyB;QAGhD,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED;;;;;;OAMG;IACI,UAAU,CAAC,KAAa;QAC9B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAE7E,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,IAAI,CAAC,MAAM,CAAC,gBAAgB;gBACvC,SAAS,EAAE,KAAK,CAAC,eAAe;gBAChC,4DAA4D;gBAC5D,oEAAoE;gBACpE,uBAAuB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,uBAAuB;aACnE,CAAC,CAAC;QACJ,CAAC;
|
|
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 { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport { createChildLogger } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { IBatch, type BatchMessage } 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: any): opContents is IGroupedBatchMessageContents {\n\treturn opContents?.type === OpGroupingManager.groupedBatchOp;\n}\n\nexport function isGroupedBatch(op: ISequencedDocumentMessage): boolean {\n\treturn isGroupContents(op.contents);\n}\n\nexport interface OpGroupingManagerConfig {\n\treadonly groupedBatchingEnabled: boolean;\n\treadonly opCountThreshold: number;\n\treadonly reentrantBatchGroupingEnabled: boolean;\n}\n\nexport class OpGroupingManager {\n\tstatic readonly groupedBatchOp = \"groupedBatch\";\n\tprivate readonly logger;\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 - IBatch containing a single empty Grouped Batch op\n\t */\n\tpublic createEmptyGroupedBatch(\n\t\tresubmittingBatchId: string,\n\t\treferenceSequenceNumber: number,\n\t): IBatch<[BatchMessage]> {\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\t\tconst serializedContent = JSON.stringify({\n\t\t\ttype: OpGroupingManager.groupedBatchOp,\n\t\t\tcontents: [],\n\t\t});\n\n\t\treturn {\n\t\t\tcontentSizeInBytes: 0,\n\t\t\tmessages: [\n\t\t\t\t{\n\t\t\t\t\tmetadata: { batchId: resubmittingBatchId },\n\t\t\t\t\tlocalOpMetadata: { emptyBatch: true },\n\t\t\t\t\treferenceSequenceNumber,\n\t\t\t\t\tcontents: serializedContent,\n\t\t\t\t},\n\t\t\t],\n\t\t\treferenceSequenceNumber,\n\t\t};\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 * @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: IBatch): IBatch<[BatchMessage]> {\n\t\tassert(this.shouldGroup(batch), 0x946 /* cannot group the provided batch */);\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\tthreshold: this.config.opCountThreshold,\n\t\t\t\treentrant: batch.hasReentrantOps,\n\t\t\t\t// Non null asserting here because of the length check above\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\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;\n\t\tfor (const message of batch.messages) {\n\t\t\tif (message.metadata) {\n\t\t\t\tconst { batch: _batch, batchId, ...rest } = message.metadata;\n\t\t\t\tif (batchId) {\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: message.contents === undefined ? undefined : JSON.parse(message.contents),\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: IBatch<[BatchMessage]> = {\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\t// TODO why are we non null asserting here?\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\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 shouldGroup(batch: IBatch): boolean {\n\t\treturn (\n\t\t\t// Grouped batching must be enabled\n\t\t\tthis.config.groupedBatchingEnabled &&\n\t\t\t// The number of ops in the batch must surpass the configured threshold\n\t\t\t// or be empty (to allow for empty batches to be grouped)\n\t\t\t(batch.messages.length === 0 || batch.messages.length >= this.config.opCountThreshold) &&\n\t\t\t// Support for reentrant batches must be explicitly enabled\n\t\t\t(this.config.reentrantBatchGroupingEnabled || batch.hasReentrantOps !== true)\n\t\t);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -160,9 +160,29 @@ export class Outbox {
|
|
|
160
160
|
// Don't use resubmittingBatchId for idAllocationBatch.
|
|
161
161
|
// ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.
|
|
162
162
|
this.flushInternal(this.idAllocationBatch);
|
|
163
|
+
// We need to flush an empty batch if the main batch *becomes* empty on resubmission.
|
|
164
|
+
// When resubmitting the main batch, the blobAttach batch will always be empty since we don't resubmit them simultaneously.
|
|
165
|
+
// And conversely, the blobAttach will never *become* empty on resubmit.
|
|
166
|
+
// So if both blobAttachBatch and mainBatch are empty, we must submit an empty main batch.
|
|
167
|
+
if (resubmittingBatchId && this.blobAttachBatch.empty && this.mainBatch.empty) {
|
|
168
|
+
this.flushEmptyBatch(resubmittingBatchId);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
163
171
|
this.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */, resubmittingBatchId);
|
|
164
172
|
this.flushInternal(this.mainBatch, false /* disableGroupedBatching */, resubmittingBatchId);
|
|
165
173
|
}
|
|
174
|
+
flushEmptyBatch(resubmittingBatchId) {
|
|
175
|
+
const referenceSequenceNumber = this.params.getCurrentSequenceNumbers().referenceSequenceNumber;
|
|
176
|
+
assert(referenceSequenceNumber !== undefined, 0xa01 /* reference sequence number should be defined */);
|
|
177
|
+
const emptyGroupedBatch = this.params.groupingManager.createEmptyGroupedBatch(resubmittingBatchId, referenceSequenceNumber);
|
|
178
|
+
let clientSequenceNumber;
|
|
179
|
+
if (this.params.shouldSend()) {
|
|
180
|
+
clientSequenceNumber = this.sendBatch(emptyGroupedBatch);
|
|
181
|
+
}
|
|
182
|
+
this.params.pendingStateManager.onFlushBatch(emptyGroupedBatch.messages, // This is the single empty Grouped Batch message
|
|
183
|
+
clientSequenceNumber);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
166
186
|
flushInternal(batchManager, disableGroupedBatching = false, resubmittingBatchId) {
|
|
167
187
|
if (batchManager.empty) {
|
|
168
188
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAC7D,OAAO,EACN,YAAY,EACZ,UAAU,EACV,iBAAiB,GAEjB,MAAM,0CAA0C,CAAC;AAKlD,OAAO,EACN,YAAY,EAEZ,kBAAkB,EAClB,oBAAoB,GAEpB,MAAM,mBAAmB,CAAC;AA+B3B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAI,MAAe,EAAE,SAAiB,EAAE;IACnE,MAAM,QAAQ,GAAG,KAAY,CAAC;IAC9B;IACC,iEAAiE;IACjE,sEAAsE;IACtE,CACC,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,iBAAiB,CAAC;QAC5D,MAAM,CAAC,wBAAwB,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CACnF,EAAE,QAAQ,KAAK,IAAI;IACpB,gEAAgE;MAC/D,CAAC;QACF,OAAO,MAAM,EAAE,CAAC;IACjB,CAAC;IAED,MAAM,uBAAuB,GAAG,QAAQ,CAAC,eAAe,CAAC;IACzD,IAAI,CAAC;QACJ,QAAQ,CAAC,eAAe,GAAG,MAAM,CAAC;QAClC,OAAO,MAAM,EAAE,CAAC;IACjB,CAAC;YAAS,CAAC;QACV,QAAQ,CAAC,eAAe,GAAG,uBAAuB,CAAC;IACpD,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,MAAM;IAiBlB,YAA6B,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;QAZ9C,yBAAoB,GAAG,CAAC,CAAC;QACzB,aAAQ,GAAG,KAAK,CAAC;QAEzB;;;;;WAKG;QACc,6BAAwB,GAAG,CAAC,CAAC;QACtC,0BAAqB,GAAG,CAAC,CAAC;QAGjC,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEhF,MAAM,oBAAoB,GACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,uBAAuB;YAC7D,MAAM,CAAC,iBAAiB,CAAC;QAC1B,kEAAkE;QAClE,MAAM,SAAS,GAAG,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAE3F,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,eAAe,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,iBAAiB,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,IAAW,YAAY;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;IAC5F,CAAC;IAED,IAAW,OAAO;QACjB,OAAO,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;OASG;IACK,sBAAsB;QAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;QACxD,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC;QAC/D,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC;QAC9D,MAAM,CACL,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB;YACrC,CAAC,oBAAoB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;gBACzD,oBAAoB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,EACzD,KAAK,CAAC,kEAAkE,CACxE,CAAC;QAEF,MAAM,sBAAsB,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,CAAC;QAEvE,IACC,oBAAoB,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;YAC9D,oBAAoB,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;YAC/D,oBAAoB,CAAC,cAAc,EAAE,sBAAsB,CAAC,EAC3D,CAAC;YACF,oEAAoE;YACpE,OAAO;QACR,CAAC;QAED,IAAI,EAAE,IAAI,CAAC,qBAAqB,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC;YACnE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAC7B;gBACC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;gBACtE,SAAS,EAAE,iCAAiC;gBAC5C,2BAA2B,EAAE,gBAAgB,CAAC,uBAAuB;gBACrE,wBAAwB,EAAE,gBAAgB,CAAC,oBAAoB;gBAC/D,iCAAiC,EAAE,iBAAiB,CAAC,uBAAuB;gBAC5E,8BAA8B,EAAE,iBAAiB,CAAC,oBAAoB;gBACtE,8BAA8B,EAAE,sBAAsB,CAAC,uBAAuB;gBAC9E,2BAA2B,EAAE,sBAAsB,CAAC,oBAAoB;aACxE,EACD,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAC,CAC3E,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEM,MAAM,CAAC,OAAqB;QAClC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAE9B,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAEM,gBAAgB,CAAC,OAAqB;QAC5C,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAE9B,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAE7D,iEAAiE;QACjE,6EAA6E;QAC7E,2DAA2D;QAC3D,sEAAsE;QACtE,gEAAgE;QAChE,IACC,IAAI,CAAC,eAAe,CAAC,kBAAkB;YACvC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,uBAAuB,EAC5D,CAAC;YACF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC1C,CAAC;IACF,CAAC;IAEM,kBAAkB,CAAC,OAAqB;QAC9C,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAE9B,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAChE,CAAC;IAEO,wBAAwB,CAAC,YAA0B,EAAE,OAAqB;QACjF,IACC,CAAC,YAAY,CAAC,IAAI,CACjB,OAAO,EACP,IAAI,CAAC,kBAAkB,EAAE,EACzB,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,CAAC,oBAAoB,CAC5D,EACA,CAAC;YACF,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,WAAW,CAAC,SAAS,EAAE;gBAC9D,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;gBACrC,SAAS,EAAE,YAAY,CAAC,kBAAkB;gBAC1C,KAAK,EAAE,YAAY,CAAC,MAAM;gBAC1B,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS;aACrC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,mBAA6B;QACzC,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,qDAAqD,CAAC,CAAC;YACpF,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,KAAK,CAAC;QACb,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAEO,QAAQ,CAAC,mBAA6B;QAC7C,uDAAuD;QACvD,8FAA8F;QAC9F,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC3C,IAAI,CAAC,aAAa,CACjB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,4BAA4B,EACjC,mBAAmB,CACnB,CAAC;QACF,IAAI,CAAC,aAAa,CACjB,IAAI,CAAC,SAAS,EACd,KAAK,CAAC,4BAA4B,EAClC,mBAAmB,CACnB,CAAC;IACH,CAAC;IAEO,aAAa,CACpB,YAA0B,EAC1B,yBAAkC,KAAK,EACvC,mBAA6B;QAE7B,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;QAC5D,MAAM,WAAW,GAChB,CAAC,sBAAsB,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC9E,IAAI,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,eAAe,KAAK,IAAI,IAAI,WAAW,EAAE,CAAC;YACxF,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACpF,yFAAyF;YACzF,qFAAqF;YACrF,6CAA6C;YAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YACpC,OAAO;QACR,CAAC;QAED,IAAI,oBAAwC,CAAC;QAC7C,iDAAiD;QACjD,uFAAuF;QACvF,yGAAyG;QACzG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;YAC9B,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CACxC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CACzE,CAAC;YACF,oBAAoB,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACtD,MAAM,CACL,oBAAoB,KAAK,SAAS,IAAI,oBAAoB,IAAI,CAAC,EAC/D,KAAK,CAAC,mFAAmF,CACzF,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IACvF,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAC,QAAgB,EAAE,YAA0B;QAC1D,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC/C,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAEzF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACpB,oEAAoE;gBACpE,OAAO,EAAE,OAAO,CAAC,QAAS;gBAC1B,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,UAAU,EAAE,OAAO,CAAC,QAAQ;aAC5B,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,oBAAoB,GAAG,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAC7B;gBACC,SAAS,EAAE,aAAa;gBACxB,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;gBAChC,uBAAuB,EAAE,QAAQ,CAAC,uBAAuB;aACzD,EACD,IAAI,UAAU,CAAC,aAAa,CAAC,CAC7B,CAAC;YACF,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACvB,CAAC;IAEO,kBAAkB;QACzB,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IACrD,CAAC;IAED;;;;;;;;OAQG;IACK,aAAa,CAAC,KAAa;QAClC,IACC,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,KAAK,SAAS;YACnD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,uBAAuB;gBAC5D,KAAK,CAAC,kBAAkB;YACzB,IAAI,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,EACtC,CAAC;YACF,sHAAsH;YACtH,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAEpE,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,EAAE,CAAC;YACjD,OAAO,eAAe,CAAC,kBAAkB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB;gBACjF,CAAC,CAAC,eAAe;gBACjB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,eAAe,CAAC,kBAAkB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAClF,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,WAAW,CAAC,SAAS,EAAE;gBAC9D,SAAS,EAAE,KAAK,CAAC,kBAAkB;gBACnC,mBAAmB,EAAE,eAAe,CAAC,kBAAkB;gBACvD,KAAK,EAAE,eAAe,CAAC,QAAQ,CAAC,MAAM;gBACtC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB;gBAC7C,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB;gBAC5D,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBACzE,UAAU,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACrC,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,eAAe,CAAC;IACxB,CAAC;IAED;;;;;OAKG;IACK,SAAS,CAAC,KAAa;QAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QACrC,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC,CAAC,oBAAoB;QACvC,CAAC;QAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,YAAY;gBACvB,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;gBAC7B,WAAW,EAAE,KAAK,CAAC,kBAAkB;gBACrC,UAAU;aACV,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,oBAA4B,CAAC;QACjC,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YAC7C,yFAAyF;YACzF,uDAAuD;YACvD,MAAM;YACL,4DAA4D;YAC5D,oEAAoE;YACpE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,WAAW,KAAK,SAAS,EAC5C,KAAK,CAAC,4EAA4E,CAClF,CAAC;YAEF,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,KAAK,CAAC,uBAAuB,KAAK,SAAS,EAAE,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACzF,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAC/C,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAgB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAC/C,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;aACxD,CAAC,CAAC,EACH,KAAK,CAAC,uBAAuB,CAC7B,CAAC;QACH,CAAC;QAED,2GAA2G;QAC3G,oBAAoB,IAAI,MAAM,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,oBAAoB,IAAI,CAAC,EAAE,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACtF,OAAO,oBAAoB,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,mBAAmB;QACzB,iHAAiH;QACjH,8FAA8F;QAC9F,MAAM,SAAS,GAAqB,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;QAChE,OAAO;YACN,SAAS;YACT,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE;YACtD,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE;SAClD,CAAC;IACH,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tGenericError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { PendingMessageResubmitData, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: IBatch) => 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) => void;\n\treadonly opReentrancy: () => boolean;\n\treadonly closeContainer: (error?: ICriticalContainerError) => void;\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\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\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * 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 and create a new batch with the new\n\t * message as the first message.\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() {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\t(sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\tcategory: this.params.config.disablePartialFlush ? \"error\" : \"generic\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t},\n\t\t\t\tgetLongStack(() => new UsageError(\"Submission of an out of order message\")),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flushAll();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// blobAttach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.blobAttachBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.blobAttachBatch);\n\t\t}\n\t}\n\n\tpublic submitIdAllocation(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\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 * @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch\n\t * with the given Batch ID, which must be preserved\n\t */\n\tpublic flush(resubmittingBatchId?: BatchId) {\n\t\tif (this.isContextReentrant()) {\n\t\t\tconst error = new UsageError(\"Flushing is not supported inside DDS event handlers\");\n\t\t\tthis.params.closeContainer(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tthis.flushAll(resubmittingBatchId);\n\t}\n\n\tprivate flushAll(resubmittingBatchId?: BatchId) {\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\tthis.flushInternal(\n\t\t\tthis.blobAttachBatch,\n\t\t\ttrue /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t\tthis.flushInternal(\n\t\t\tthis.mainBatch,\n\t\t\tfalse /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t}\n\n\tprivate flushInternal(\n\t\tbatchManager: BatchManager,\n\t\tdisableGroupedBatching: boolean = false,\n\t\tresubmittingBatchId?: BatchId,\n\t) {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmittingBatchId);\n\t\tconst shouldGroup =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);\n\t\tif (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\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()) {\n\t\t\tconst processedBatch = this.compressBatch(\n\t\t\t\tshouldGroup ? this.params.groupingManager.groupBatch(rawBatch) : rawBatch,\n\t\t\t);\n\t\t\tclientSequenceNumber = this.sendBatch(processedBatch);\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(rawBatch.messages, clientSequenceNumber);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: IBatch, batchManager: BatchManager) {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tcontent: message.contents!,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.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, compresses and 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 batch - Raw or Grouped batch to consider for compression/chunking\n\t * @returns Either (A) the original batch, (B) a compressed batch (same length as original),\n\t * or (C) a batch containing the last chunk (plus empty placeholders from compression if applicable).\n\t */\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.messages.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitFirstBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.messages.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\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\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.messages.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\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\t// Non null asserting here because of the length check above\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\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\t/**\n\t * @returns A checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints() {\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 { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tGenericError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { PendingMessageResubmitData, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: IBatch) => 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) => void;\n\treadonly opReentrancy: () => boolean;\n\treadonly closeContainer: (error?: ICriticalContainerError) => void;\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\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\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * 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 and create a new batch with the new\n\t * message as the first message.\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() {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\t(sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\tcategory: this.params.config.disablePartialFlush ? \"error\" : \"generic\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t},\n\t\t\t\tgetLongStack(() => new UsageError(\"Submission of an out of order message\")),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flushAll();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// blobAttach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.blobAttachBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.blobAttachBatch);\n\t\t}\n\t}\n\n\tpublic submitIdAllocation(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\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 * @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch\n\t * with the given Batch ID, which must be preserved\n\t */\n\tpublic flush(resubmittingBatchId?: BatchId) {\n\t\tif (this.isContextReentrant()) {\n\t\t\tconst error = new UsageError(\"Flushing is not supported inside DDS event handlers\");\n\t\t\tthis.params.closeContainer(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tthis.flushAll(resubmittingBatchId);\n\t}\n\n\tprivate flushAll(resubmittingBatchId?: BatchId) {\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\t// We need to flush an empty batch if the main batch *becomes* empty on resubmission.\n\t\t// When resubmitting the main batch, the blobAttach batch will always be empty since we don't resubmit them simultaneously.\n\t\t// And conversely, the blobAttach will never *become* empty on resubmit.\n\t\t// So if both blobAttachBatch and mainBatch are empty, we must submit an empty main batch.\n\t\tif (resubmittingBatchId && this.blobAttachBatch.empty && this.mainBatch.empty) {\n\t\t\tthis.flushEmptyBatch(resubmittingBatchId);\n\t\t\treturn;\n\t\t}\n\t\tthis.flushInternal(\n\t\t\tthis.blobAttachBatch,\n\t\t\ttrue /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t\tthis.flushInternal(\n\t\t\tthis.mainBatch,\n\t\t\tfalse /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t}\n\n\tprivate flushEmptyBatch(resubmittingBatchId: BatchId) {\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 emptyGroupedBatch = this.params.groupingManager.createEmptyGroupedBatch(\n\t\t\tresubmittingBatchId,\n\t\t\treferenceSequenceNumber,\n\t\t);\n\t\tlet clientSequenceNumber: number | undefined;\n\t\tif (this.params.shouldSend()) {\n\t\t\tclientSequenceNumber = this.sendBatch(emptyGroupedBatch);\n\t\t}\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\temptyGroupedBatch.messages, // This is the single empty Grouped Batch message\n\t\t\tclientSequenceNumber,\n\t\t);\n\t\treturn;\n\t}\n\n\tprivate flushInternal(\n\t\tbatchManager: BatchManager,\n\t\tdisableGroupedBatching: boolean = false,\n\t\tresubmittingBatchId?: BatchId,\n\t) {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmittingBatchId);\n\t\tconst shouldGroup =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);\n\t\tif (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\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()) {\n\t\t\tconst processedBatch = this.compressBatch(\n\t\t\t\tshouldGroup ? this.params.groupingManager.groupBatch(rawBatch) : rawBatch,\n\t\t\t);\n\t\t\tclientSequenceNumber = this.sendBatch(processedBatch);\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(rawBatch.messages, clientSequenceNumber);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: IBatch, batchManager: BatchManager) {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tcontent: message.contents!,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.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, compresses and 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 batch - Raw or Grouped batch to consider for compression/chunking\n\t * @returns Either (A) the original batch, (B) a compressed batch (same length as original),\n\t * or (C) a batch containing the last chunk (plus empty placeholders from compression if applicable).\n\t */\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.messages.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitFirstBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.messages.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\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\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.messages.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\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\t// Non null asserting here because of the length check above\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\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\t/**\n\t * @returns A checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints() {\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"]}
|
|
@@ -7,6 +7,25 @@ import { type InboundSequencedContainerRuntimeMessage } from "../messageTypes.js
|
|
|
7
7
|
import { OpDecompressor } from "./opDecompressor.js";
|
|
8
8
|
import { OpGroupingManager } from "./opGroupingManager.js";
|
|
9
9
|
import { OpSplitter } from "./opSplitter.js";
|
|
10
|
+
/** Messages being received as a batch, with details needed to process the batch */
|
|
11
|
+
export interface InboundBatch {
|
|
12
|
+
/** Messages in this batch */
|
|
13
|
+
readonly messages: InboundSequencedContainerRuntimeMessage[];
|
|
14
|
+
/** Batch ID, if present */
|
|
15
|
+
readonly batchId: string | undefined;
|
|
16
|
+
/** clientId that sent this batch. Used to compute Batch ID if needed */
|
|
17
|
+
readonly clientId: string;
|
|
18
|
+
/**
|
|
19
|
+
* Client Sequence Number of the first message in the batch.
|
|
20
|
+
* Used to compute Batch ID if needed
|
|
21
|
+
*
|
|
22
|
+
* @remarks For chunked batches, this is the CSN of the "representative" chunk (the final chunk).
|
|
23
|
+
* For grouped batches, clientSequenceNumber on messages is overwritten, so we track this original value here.
|
|
24
|
+
*/
|
|
25
|
+
readonly batchStartCsn: number;
|
|
26
|
+
/** For an empty batch (with no messages), we need to remember the empty grouped batch's sequence number */
|
|
27
|
+
readonly emptyBatchSequenceNumber?: number;
|
|
28
|
+
}
|
|
10
29
|
/**
|
|
11
30
|
* Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,
|
|
12
31
|
* potentially across numerous inbound ops.
|
|
@@ -18,13 +37,11 @@ export declare class RemoteMessageProcessor {
|
|
|
18
37
|
private readonly opDecompressor;
|
|
19
38
|
private readonly opGroupingManager;
|
|
20
39
|
/**
|
|
21
|
-
*
|
|
22
|
-
* If undefined, we are expecting the next message to start a new batch.
|
|
40
|
+
* The current batch being received, with details needed to process it.
|
|
23
41
|
*
|
|
24
|
-
* @remarks
|
|
42
|
+
* @remarks If undefined, we are expecting the next message to start a new batch.
|
|
25
43
|
*/
|
|
26
|
-
private
|
|
27
|
-
private readonly processorBatch;
|
|
44
|
+
private batchInProgress;
|
|
28
45
|
constructor(opSplitter: OpSplitter, opDecompressor: OpDecompressor, opGroupingManager: OpGroupingManager);
|
|
29
46
|
get partialMessages(): ReadonlyMap<string, string[]>;
|
|
30
47
|
clearPartialMessagesFor(clientId: string): void;
|
|
@@ -47,19 +64,21 @@ export declare class RemoteMessageProcessor {
|
|
|
47
64
|
* @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch
|
|
48
65
|
* or undefined if the batch is not yet complete.
|
|
49
66
|
*/
|
|
50
|
-
process(remoteMessageCopy: ISequencedDocumentMessage, logLegacyCase: (codePath: string) => void):
|
|
51
|
-
messages: InboundSequencedContainerRuntimeMessage[];
|
|
52
|
-
batchStartCsn: number;
|
|
53
|
-
} | undefined;
|
|
67
|
+
process(remoteMessageCopy: ISequencedDocumentMessage, logLegacyCase: (codePath: string) => void): InboundBatch | undefined;
|
|
54
68
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* the batch
|
|
69
|
+
* Add the given message to the current batch, and indicate whether the batch is now complete.
|
|
70
|
+
*
|
|
71
|
+
* @returns batchEnded: true if the batch is now complete, batchEnded: false if more messages are expected
|
|
58
72
|
*/
|
|
59
|
-
private
|
|
73
|
+
private addMessageToBatch;
|
|
60
74
|
}
|
|
61
|
-
/**
|
|
62
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Takes an incoming message and if the contents is a string, JSON.parse's it in place
|
|
77
|
+
* @param mutableMessage - op message received
|
|
78
|
+
* @param hasModernRuntimeMessageEnvelope - false if the message does not contain the modern op envelop where message.type is MessageType.Operation
|
|
79
|
+
* @param logLegacyCase - callback to log when legacy op is encountered
|
|
80
|
+
*/
|
|
81
|
+
export declare function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage, hasModernRuntimeMessageEnvelope: boolean, logLegacyCase: (codePath: string) => void): void;
|
|
63
82
|
/**
|
|
64
83
|
* Unpacks runtime messages.
|
|
65
84
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remoteMessageProcessor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEN,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAGN,KAAK,uCAAuC,EAE5C,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAoB,MAAM,iBAAiB,CAAC;AAE/D
|
|
1
|
+
{"version":3,"file":"remoteMessageProcessor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEN,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAGN,KAAK,uCAAuC,EAE5C,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAoB,MAAM,iBAAiB,CAAC;AAE/D,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC5B,6BAA6B;IAC7B,QAAQ,CAAC,QAAQ,EAAE,uCAAuC,EAAE,CAAC;IAC7D,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2GAA2G;IAC3G,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CAC3C;AAWD;;;;;GAKG;AACH,qBAAa,sBAAsB;IASjC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAVnC;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAA2B;gBAGhC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,iBAAiB;IAGtD,IAAW,eAAe,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE1D;IAEM,uBAAuB,CAAC,QAAQ,EAAE,MAAM;IAI/C;;;;;;;;;;;;;;;;;;OAkBG;IACI,OAAO,CACb,iBAAiB,EAAE,yBAAyB,EAC5C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACvC,YAAY,GAAG,SAAS;IAgE3B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAmCzB;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACzC,cAAc,EAAE,yBAAyB,EACzC,+BAA+B,EAAE,OAAO,EACxC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACvC,IAAI,CAmBN;AAyBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,yBAAyB,EAClC,aAAa,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAe,GAClD,OAAO,CAuBT"}
|
|
@@ -8,6 +8,9 @@ import { ContainerMessageType, } from "../messageTypes.js";
|
|
|
8
8
|
import { asBatchMetadata } from "../metadata.js";
|
|
9
9
|
import { isGroupedBatch } from "./opGroupingManager.js";
|
|
10
10
|
import { isChunkedMessage } from "./opSplitter.js";
|
|
11
|
+
function assertHasClientId(message) {
|
|
12
|
+
assert(message.clientId !== null, 0xa02 /* Server-generated message should not reach RemoteMessageProcessor */);
|
|
13
|
+
}
|
|
11
14
|
/**
|
|
12
15
|
* Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,
|
|
13
16
|
* potentially across numerous inbound ops.
|
|
@@ -19,7 +22,6 @@ export class RemoteMessageProcessor {
|
|
|
19
22
|
this.opSplitter = opSplitter;
|
|
20
23
|
this.opDecompressor = opDecompressor;
|
|
21
24
|
this.opGroupingManager = opGroupingManager;
|
|
22
|
-
this.processorBatch = [];
|
|
23
25
|
}
|
|
24
26
|
get partialMessages() {
|
|
25
27
|
return this.opSplitter.chunks;
|
|
@@ -48,11 +50,13 @@ export class RemoteMessageProcessor {
|
|
|
48
50
|
*/
|
|
49
51
|
process(remoteMessageCopy, logLegacyCase) {
|
|
50
52
|
let message = remoteMessageCopy;
|
|
53
|
+
assertHasClientId(message);
|
|
54
|
+
const clientId = message.clientId;
|
|
51
55
|
if (isChunkedMessage(message)) {
|
|
52
56
|
const chunkProcessingResult = this.opSplitter.processChunk(message);
|
|
53
57
|
// Only continue further if current chunk is the final chunk
|
|
54
58
|
if (!chunkProcessingResult.isFinalChunk) {
|
|
55
|
-
return;
|
|
59
|
+
return undefined;
|
|
56
60
|
}
|
|
57
61
|
// This message will always be compressed
|
|
58
62
|
message = chunkProcessingResult.message;
|
|
@@ -68,79 +72,88 @@ export class RemoteMessageProcessor {
|
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
if (isGroupedBatch(message)) {
|
|
71
|
-
// We should be awaiting a new batch (
|
|
72
|
-
assert(this.
|
|
73
|
-
|
|
75
|
+
// We should be awaiting a new batch (batchInProgress undefined)
|
|
76
|
+
assert(this.batchInProgress === undefined, 0x9d3 /* Grouped batch interrupting another batch */);
|
|
77
|
+
const batchId = asBatchMetadata(message.metadata)?.batchId;
|
|
78
|
+
const groupedMessages = this.opGroupingManager.ungroupOp(message).map(unpack);
|
|
74
79
|
return {
|
|
75
|
-
messages:
|
|
80
|
+
messages: groupedMessages, // Will be [] for an empty batch
|
|
76
81
|
batchStartCsn: message.clientSequenceNumber,
|
|
82
|
+
clientId,
|
|
83
|
+
batchId,
|
|
84
|
+
// If the batch is empty, we need to return the sequence number aside
|
|
85
|
+
emptyBatchSequenceNumber: groupedMessages.length === 0 ? message.sequenceNumber : undefined,
|
|
77
86
|
};
|
|
78
87
|
}
|
|
79
|
-
const batchStartCsn = this.getAndUpdateBatchStartCsn(message);
|
|
80
88
|
// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked
|
|
81
89
|
unpackRuntimeMessage(message, logLegacyCase);
|
|
82
|
-
this.
|
|
83
|
-
|
|
84
|
-
// If it's still defined, we're still in the middle of a batch, so we return nothing, letting
|
|
85
|
-
// containerRuntime know that we're waiting for more messages to complete the batch.
|
|
86
|
-
if (this.batchStartCsn !== undefined) {
|
|
90
|
+
const { batchEnded } = this.addMessageToBatch(message);
|
|
91
|
+
if (!batchEnded) {
|
|
87
92
|
// batch not yet complete
|
|
88
93
|
return undefined;
|
|
89
94
|
}
|
|
90
|
-
const
|
|
91
|
-
this.
|
|
92
|
-
return
|
|
93
|
-
messages,
|
|
94
|
-
batchStartCsn,
|
|
95
|
-
};
|
|
95
|
+
const completedBatch = this.batchInProgress;
|
|
96
|
+
this.batchInProgress = undefined;
|
|
97
|
+
return completedBatch;
|
|
96
98
|
}
|
|
97
99
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* the batch
|
|
100
|
+
* Add the given message to the current batch, and indicate whether the batch is now complete.
|
|
101
|
+
*
|
|
102
|
+
* @returns batchEnded: true if the batch is now complete, batchEnded: false if more messages are expected
|
|
101
103
|
*/
|
|
102
|
-
|
|
104
|
+
addMessageToBatch(message) {
|
|
103
105
|
const batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;
|
|
104
|
-
if (this.
|
|
106
|
+
if (this.batchInProgress === undefined) {
|
|
105
107
|
// We are waiting for a new batch
|
|
106
108
|
assert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);
|
|
107
109
|
// Start of a new multi-message batch
|
|
108
110
|
if (batchMetadataFlag === true) {
|
|
109
|
-
this.
|
|
110
|
-
|
|
111
|
+
this.batchInProgress = {
|
|
112
|
+
messages: [message],
|
|
113
|
+
batchId: asBatchMetadata(message.metadata)?.batchId,
|
|
114
|
+
clientId: message.clientId,
|
|
115
|
+
batchStartCsn: message.clientSequenceNumber,
|
|
116
|
+
};
|
|
117
|
+
return { batchEnded: false };
|
|
111
118
|
}
|
|
112
119
|
// Single-message batch (Since metadata flag is undefined)
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
this.batchInProgress = {
|
|
121
|
+
messages: [message],
|
|
122
|
+
batchStartCsn: message.clientSequenceNumber,
|
|
123
|
+
clientId: message.clientId,
|
|
124
|
+
batchId: asBatchMetadata(message.metadata)?.batchId,
|
|
125
|
+
};
|
|
126
|
+
return { batchEnded: true };
|
|
115
127
|
}
|
|
116
|
-
// We are in the middle or end of an existing multi-message batch. Return the current batchStartCsn
|
|
117
|
-
const batchStartCsn = this.batchStartCsn;
|
|
118
128
|
assert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.batchStartCsn = undefined;
|
|
122
|
-
}
|
|
123
|
-
return batchStartCsn;
|
|
129
|
+
this.batchInProgress.messages.push(message);
|
|
130
|
+
return { batchEnded: batchMetadataFlag === false };
|
|
124
131
|
}
|
|
125
132
|
}
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Takes an incoming message and if the contents is a string, JSON.parse's it in place
|
|
135
|
+
* @param mutableMessage - op message received
|
|
136
|
+
* @param hasModernRuntimeMessageEnvelope - false if the message does not contain the modern op envelop where message.type is MessageType.Operation
|
|
137
|
+
* @param logLegacyCase - callback to log when legacy op is encountered
|
|
138
|
+
*/
|
|
139
|
+
export function ensureContentsDeserialized(mutableMessage, hasModernRuntimeMessageEnvelope, logLegacyCase) {
|
|
140
|
+
// Currently the loader layer is parsing the contents of the message as JSON if it is a string,
|
|
141
|
+
// so we never expect to see this case.
|
|
142
|
+
// We intend to remove that logic from the Loader, at which point we will have it here.
|
|
143
|
+
// Only hasModernRuntimeMessageEnvelope true will be expected to have JSON contents.
|
|
144
|
+
let didParseJsonContents;
|
|
132
145
|
if (typeof mutableMessage.contents === "string" && mutableMessage.contents !== "") {
|
|
133
146
|
mutableMessage.contents = JSON.parse(mutableMessage.contents);
|
|
134
|
-
|
|
147
|
+
didParseJsonContents = true;
|
|
135
148
|
}
|
|
136
149
|
else {
|
|
137
|
-
|
|
150
|
+
didParseJsonContents = false;
|
|
138
151
|
}
|
|
139
|
-
//
|
|
140
|
-
//
|
|
152
|
+
// The DeltaManager parses the contents of the message as JSON if it is a string,
|
|
153
|
+
// so we should never end up parsing it here.
|
|
141
154
|
// Let's observe if we are wrong about this to learn about these cases.
|
|
142
|
-
if (
|
|
143
|
-
logLegacyCase("
|
|
155
|
+
if (didParseJsonContents) {
|
|
156
|
+
logLegacyCase("ensureContentsDeserialized_foundJsonContents");
|
|
144
157
|
}
|
|
145
158
|
}
|
|
146
159
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remoteMessageProcessor.js","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.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 { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tMessageType,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n\ttype InboundSequencedRecentlyAddedContainerRuntimeMessage,\n} from \"../messageTypes.js\";\nimport { asBatchMetadata } from \"../metadata.js\";\n\nimport { OpDecompressor } from \"./opDecompressor.js\";\nimport { OpGroupingManager, isGroupedBatch } from \"./opGroupingManager.js\";\nimport { OpSplitter, isChunkedMessage } from \"./opSplitter.js\";\n\n/**\n * Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,\n * potentially across numerous inbound ops.\n *\n * @internal\n */\nexport class RemoteMessageProcessor {\n\t/**\n\t * Client Sequence Number of the first message in the current batch being processed.\n\t * If undefined, we are expecting the next message to start a new batch.\n\t *\n\t * @remarks For chunked batches, this is the CSN of the \"representative\" chunk (the final chunk)\n\t */\n\tprivate batchStartCsn: number | undefined;\n\tprivate readonly processorBatch: InboundSequencedContainerRuntimeMessage[] = [];\n\n\tconstructor(\n\t\tprivate readonly opSplitter: OpSplitter,\n\t\tprivate readonly opDecompressor: OpDecompressor,\n\t\tprivate readonly opGroupingManager: OpGroupingManager,\n\t) {}\n\n\tpublic get partialMessages(): ReadonlyMap<string, string[]> {\n\t\treturn this.opSplitter.chunks;\n\t}\n\n\tpublic clearPartialMessagesFor(clientId: string) {\n\t\tthis.opSplitter.clearPartialChunks(clientId);\n\t}\n\n\t/**\n\t * Ungroups and Unchunks the runtime ops of a batch received over the wire\n\t * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized\n\t * (grouped, compressed, and/or chunked).\n\t * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure\n\t * depends on this object instance.\n\t * Note remoteMessageCopy.contents (and other object props) MUST not be modified,\n\t * but may be overwritten (as is the case with contents).\n\t *\n\t * Incoming messages will always have compression, chunking, and grouped batching happen in a defined order and that order cannot be changed.\n\t * When processing these messages, the order is:\n\t * 1. If chunked, process the chunk and only continue if this is a final chunk\n\t * 2. If compressed, decompress the message and store for further unrolling of the decompressed content\n\t * 3. If grouped, ungroup the message\n\t * For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound\n\t *\n\t * @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch\n\t * or undefined if the batch is not yet complete.\n\t */\n\tpublic process(\n\t\tremoteMessageCopy: ISequencedDocumentMessage,\n\t\tlogLegacyCase: (codePath: string) => void,\n\t):\n\t\t| {\n\t\t\t\tmessages: InboundSequencedContainerRuntimeMessage[];\n\t\t\t\tbatchStartCsn: number;\n\t\t }\n\t\t| undefined {\n\t\tlet message = remoteMessageCopy;\n\n\t\tif (isChunkedMessage(message)) {\n\t\t\tconst chunkProcessingResult = this.opSplitter.processChunk(message);\n\t\t\t// Only continue further if current chunk is the final chunk\n\t\t\tif (!chunkProcessingResult.isFinalChunk) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// This message will always be compressed\n\t\t\tmessage = chunkProcessingResult.message;\n\t\t}\n\n\t\tif (this.opDecompressor.isCompressedMessage(message)) {\n\t\t\tthis.opDecompressor.decompressAndStore(message);\n\t\t}\n\n\t\tif (this.opDecompressor.currentlyUnrolling) {\n\t\t\tmessage = this.opDecompressor.unroll(message);\n\t\t\t// Need to unpack after unrolling if not a groupedBatch\n\t\t\tif (!isGroupedBatch(message)) {\n\t\t\t\tunpack(message);\n\t\t\t}\n\t\t}\n\n\t\tif (isGroupedBatch(message)) {\n\t\t\t// We should be awaiting a new batch (batchStartCsn undefined)\n\t\t\tassert(\n\t\t\t\tthis.batchStartCsn === undefined,\n\t\t\t\t0x9d3 /* Grouped batch interrupting another batch */,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\tthis.processorBatch.length === 0,\n\t\t\t\t0x9d4 /* Processor batch should be empty on grouped batch */,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tmessages: this.opGroupingManager.ungroupOp(message).map(unpack),\n\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t};\n\t\t}\n\n\t\tconst batchStartCsn = this.getAndUpdateBatchStartCsn(message);\n\n\t\t// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked\n\t\tunpackRuntimeMessage(message, logLegacyCase);\n\t\tthis.processorBatch.push(message as InboundSequencedContainerRuntimeMessage);\n\n\t\t// this.batchStartCsn is undefined only if we have processed all messages in the batch.\n\t\t// If it's still defined, we're still in the middle of a batch, so we return nothing, letting\n\t\t// containerRuntime know that we're waiting for more messages to complete the batch.\n\t\tif (this.batchStartCsn !== undefined) {\n\t\t\t// batch not yet complete\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst messages = [...this.processorBatch];\n\t\tthis.processorBatch.length = 0;\n\t\treturn {\n\t\t\tmessages,\n\t\t\tbatchStartCsn,\n\t\t};\n\t}\n\n\t/**\n\t * Based on pre-existing batch tracking info and the current message's batch metadata,\n\t * this will return the starting CSN for this message's batch, and will also update\n\t * the batch tracking info (this.batchStartCsn) based on whether we're still mid-batch.\n\t */\n\tprivate getAndUpdateBatchStartCsn(message: ISequencedDocumentMessage): number {\n\t\tconst batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;\n\t\tif (this.batchStartCsn === undefined) {\n\t\t\t// We are waiting for a new batch\n\t\t\tassert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);\n\n\t\t\t// Start of a new multi-message batch\n\t\t\tif (batchMetadataFlag === true) {\n\t\t\t\tthis.batchStartCsn = message.clientSequenceNumber;\n\t\t\t\treturn this.batchStartCsn;\n\t\t\t}\n\n\t\t\t// Single-message batch (Since metadata flag is undefined)\n\t\t\t// IMPORTANT: Leave this.batchStartCsn undefined, we're ready for the next batch now.\n\t\t\treturn message.clientSequenceNumber;\n\t\t}\n\n\t\t// We are in the middle or end of an existing multi-message batch. Return the current batchStartCsn\n\t\tconst batchStartCsn = this.batchStartCsn;\n\n\t\tassert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);\n\t\tif (batchMetadataFlag === false) {\n\t\t\t// Batch end? Then get ready for the next batch to start\n\t\t\tthis.batchStartCsn = undefined;\n\t\t}\n\n\t\treturn batchStartCsn;\n\t}\n}\n\n/** Takes an incoming message and if the contents is a string, JSON.parse's it in place */\nexport function ensureContentsDeserialized(\n\tmutableMessage: ISequencedDocumentMessage,\n\tmodernRuntimeMessage: boolean,\n\tlogLegacyCase: (codePath: string) => void,\n): void {\n\t// back-compat: ADO #1385: eventually should become unconditional, but only for runtime messages!\n\t// System message may have no contents, or in some cases (mostly for back-compat) they may have actual objects.\n\t// Old ops may contain empty string (I assume noops).\n\tlet parsedJsonContents: boolean;\n\tif (typeof mutableMessage.contents === \"string\" && mutableMessage.contents !== \"\") {\n\t\tmutableMessage.contents = JSON.parse(mutableMessage.contents);\n\t\tparsedJsonContents = true;\n\t} else {\n\t\tparsedJsonContents = false;\n\t}\n\n\t// We expect Modern Runtime Messages to have JSON serialized contents,\n\t// and all other messages not to (system messages and legacy runtime messages without outer \"op\" type envelope)\n\t// Let's observe if we are wrong about this to learn about these cases.\n\tif (modernRuntimeMessage !== parsedJsonContents) {\n\t\tlogLegacyCase(\"ensureContentsDeserialized_unexpectedContentsType\");\n\t}\n}\n\n/**\n * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.\n *\n * The return type illustrates the assumption that the message param\n * becomes a InboundSequencedContainerRuntimeMessage by the time the function returns\n * (but there is no runtime validation of the 'type' or 'compatDetails' values).\n */\nfunction unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRuntimeMessage {\n\t// We assume the contents is an InboundContainerRuntimeMessage (the message is \"packed\")\n\tconst contents = message.contents as InboundContainerRuntimeMessage;\n\n\t// We're going to unpack message in-place (promoting those properties of contents up to message itself)\n\tconst messageUnpacked = message as InboundSequencedContainerRuntimeMessage;\n\n\tmessageUnpacked.type = contents.type;\n\tmessageUnpacked.contents = contents.contents;\n\tif (\"compatDetails\" in contents) {\n\t\t(messageUnpacked as InboundSequencedRecentlyAddedContainerRuntimeMessage).compatDetails =\n\t\t\tcontents.compatDetails;\n\t}\n\treturn messageUnpacked;\n}\n\n/**\n * Unpacks runtime messages.\n *\n * @remarks This API makes no promises regarding backward-compatibility. This is internal API.\n * @param message - message (as it observed in storage / service)\n * @returns whether the given message was unpacked\n *\n * @internal\n */\nexport function unpackRuntimeMessage(\n\tmessage: ISequencedDocumentMessage,\n\tlogLegacyCase: (codePath: string) => void = () => {},\n): boolean {\n\tif (message.type !== MessageType.Operation) {\n\t\t// Legacy format, but it's already \"unpacked\",\n\t\t// i.e. message.type is actually ContainerMessageType.\n\t\t// Or it's non-runtime message.\n\t\t// Nothing to do in such case.\n\t\treturn false;\n\t}\n\n\t// legacy op format?\n\t// TODO: Unsure if this is a real format we should be concerned with. There doesn't appear to be anything prepared to handle the address member.\n\tif (\n\t\t(message.contents as { address?: unknown }).address !== undefined &&\n\t\t(message.contents as { type?: unknown }).type === undefined\n\t) {\n\t\tmessage.type = ContainerMessageType.FluidDataStoreOp;\n\t\tlogLegacyCase(\"unpackRuntimeMessage_contentsWithAddress\");\n\t} else {\n\t\t// new format\n\t\tunpack(message);\n\t}\n\n\treturn true;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"remoteMessageProcessor.js","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.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 { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tMessageType,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n\ttype InboundSequencedRecentlyAddedContainerRuntimeMessage,\n} from \"../messageTypes.js\";\nimport { asBatchMetadata } from \"../metadata.js\";\n\nimport { OpDecompressor } from \"./opDecompressor.js\";\nimport { OpGroupingManager, isGroupedBatch } from \"./opGroupingManager.js\";\nimport { OpSplitter, isChunkedMessage } from \"./opSplitter.js\";\n\n/** Messages being received as a batch, with details needed to process the batch */\nexport interface InboundBatch {\n\t/** Messages in this batch */\n\treadonly messages: InboundSequencedContainerRuntimeMessage[];\n\t/** Batch ID, if present */\n\treadonly batchId: string | undefined;\n\t/** clientId that sent this batch. Used to compute Batch ID if needed */\n\treadonly clientId: string;\n\t/**\n\t * Client Sequence Number of the first message in the batch.\n\t * Used to compute Batch ID if needed\n\t *\n\t * @remarks For chunked batches, this is the CSN of the \"representative\" chunk (the final chunk).\n\t * For grouped batches, clientSequenceNumber on messages is overwritten, so we track this original value here.\n\t */\n\treadonly batchStartCsn: number;\n\t/** For an empty batch (with no messages), we need to remember the empty grouped batch's sequence number */\n\treadonly emptyBatchSequenceNumber?: number;\n}\n\nfunction assertHasClientId(\n\tmessage: ISequencedDocumentMessage,\n): asserts message is ISequencedDocumentMessage & { clientId: string } {\n\tassert(\n\t\tmessage.clientId !== null,\n\t\t0xa02 /* Server-generated message should not reach RemoteMessageProcessor */,\n\t);\n}\n\n/**\n * Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,\n * potentially across numerous inbound ops.\n *\n * @internal\n */\nexport class RemoteMessageProcessor {\n\t/**\n\t * The current batch being received, with details needed to process it.\n\t *\n\t * @remarks If undefined, we are expecting the next message to start a new batch.\n\t */\n\tprivate batchInProgress: InboundBatch | undefined;\n\n\tconstructor(\n\t\tprivate readonly opSplitter: OpSplitter,\n\t\tprivate readonly opDecompressor: OpDecompressor,\n\t\tprivate readonly opGroupingManager: OpGroupingManager,\n\t) {}\n\n\tpublic get partialMessages(): ReadonlyMap<string, string[]> {\n\t\treturn this.opSplitter.chunks;\n\t}\n\n\tpublic clearPartialMessagesFor(clientId: string) {\n\t\tthis.opSplitter.clearPartialChunks(clientId);\n\t}\n\n\t/**\n\t * Ungroups and Unchunks the runtime ops of a batch received over the wire\n\t * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized\n\t * (grouped, compressed, and/or chunked).\n\t * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure\n\t * depends on this object instance.\n\t * Note remoteMessageCopy.contents (and other object props) MUST not be modified,\n\t * but may be overwritten (as is the case with contents).\n\t *\n\t * Incoming messages will always have compression, chunking, and grouped batching happen in a defined order and that order cannot be changed.\n\t * When processing these messages, the order is:\n\t * 1. If chunked, process the chunk and only continue if this is a final chunk\n\t * 2. If compressed, decompress the message and store for further unrolling of the decompressed content\n\t * 3. If grouped, ungroup the message\n\t * For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound\n\t *\n\t * @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch\n\t * or undefined if the batch is not yet complete.\n\t */\n\tpublic process(\n\t\tremoteMessageCopy: ISequencedDocumentMessage,\n\t\tlogLegacyCase: (codePath: string) => void,\n\t): InboundBatch | undefined {\n\t\tlet message = remoteMessageCopy;\n\n\t\tassertHasClientId(message);\n\t\tconst clientId = message.clientId;\n\n\t\tif (isChunkedMessage(message)) {\n\t\t\tconst chunkProcessingResult = this.opSplitter.processChunk(message);\n\t\t\t// Only continue further if current chunk is the final chunk\n\t\t\tif (!chunkProcessingResult.isFinalChunk) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// This message will always be compressed\n\t\t\tmessage = chunkProcessingResult.message;\n\t\t}\n\n\t\tif (this.opDecompressor.isCompressedMessage(message)) {\n\t\t\tthis.opDecompressor.decompressAndStore(message);\n\t\t}\n\n\t\tif (this.opDecompressor.currentlyUnrolling) {\n\t\t\tmessage = this.opDecompressor.unroll(message);\n\t\t\t// Need to unpack after unrolling if not a groupedBatch\n\t\t\tif (!isGroupedBatch(message)) {\n\t\t\t\tunpack(message);\n\t\t\t}\n\t\t}\n\n\t\tif (isGroupedBatch(message)) {\n\t\t\t// We should be awaiting a new batch (batchInProgress undefined)\n\t\t\tassert(\n\t\t\t\tthis.batchInProgress === undefined,\n\t\t\t\t0x9d3 /* Grouped batch interrupting another batch */,\n\t\t\t);\n\t\t\tconst batchId = asBatchMetadata(message.metadata)?.batchId;\n\t\t\tconst groupedMessages = this.opGroupingManager.ungroupOp(message).map(unpack);\n\t\t\treturn {\n\t\t\t\tmessages: groupedMessages, // Will be [] for an empty batch\n\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\tclientId,\n\t\t\t\tbatchId,\n\t\t\t\t// If the batch is empty, we need to return the sequence number aside\n\t\t\t\temptyBatchSequenceNumber:\n\t\t\t\t\tgroupedMessages.length === 0 ? message.sequenceNumber : undefined,\n\t\t\t};\n\t\t}\n\n\t\t// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked\n\t\tunpackRuntimeMessage(message, logLegacyCase);\n\n\t\tconst { batchEnded } = this.addMessageToBatch(\n\t\t\tmessage as InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t\t);\n\n\t\tif (!batchEnded) {\n\t\t\t// batch not yet complete\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst completedBatch = this.batchInProgress;\n\t\tthis.batchInProgress = undefined;\n\t\treturn completedBatch;\n\t}\n\n\t/**\n\t * Add the given message to the current batch, and indicate whether the batch is now complete.\n\t *\n\t * @returns batchEnded: true if the batch is now complete, batchEnded: false if more messages are expected\n\t */\n\tprivate addMessageToBatch(\n\t\tmessage: InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t): { batchEnded: boolean } {\n\t\tconst batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;\n\t\tif (this.batchInProgress === undefined) {\n\t\t\t// We are waiting for a new batch\n\t\t\tassert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);\n\n\t\t\t// Start of a new multi-message batch\n\t\t\tif (batchMetadataFlag === true) {\n\t\t\t\tthis.batchInProgress = {\n\t\t\t\t\tmessages: [message],\n\t\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t\t\tclientId: message.clientId,\n\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t};\n\n\t\t\t\treturn { batchEnded: false };\n\t\t\t}\n\n\t\t\t// Single-message batch (Since metadata flag is undefined)\n\t\t\tthis.batchInProgress = {\n\t\t\t\tmessages: [message],\n\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\tclientId: message.clientId,\n\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t};\n\t\t\treturn { batchEnded: true };\n\t\t}\n\t\tassert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);\n\n\t\tthis.batchInProgress.messages.push(message);\n\n\t\treturn { batchEnded: batchMetadataFlag === false };\n\t}\n}\n\n/**\n * Takes an incoming message and if the contents is a string, JSON.parse's it in place\n * @param mutableMessage - op message received\n * @param hasModernRuntimeMessageEnvelope - false if the message does not contain the modern op envelop where message.type is MessageType.Operation\n * @param logLegacyCase - callback to log when legacy op is encountered\n */\nexport function ensureContentsDeserialized(\n\tmutableMessage: ISequencedDocumentMessage,\n\thasModernRuntimeMessageEnvelope: boolean,\n\tlogLegacyCase: (codePath: string) => void,\n): void {\n\t// Currently the loader layer is parsing the contents of the message as JSON if it is a string,\n\t// so we never expect to see this case.\n\t// We intend to remove that logic from the Loader, at which point we will have it here.\n\t// Only hasModernRuntimeMessageEnvelope true will be expected to have JSON contents.\n\tlet didParseJsonContents: boolean;\n\tif (typeof mutableMessage.contents === \"string\" && mutableMessage.contents !== \"\") {\n\t\tmutableMessage.contents = JSON.parse(mutableMessage.contents);\n\t\tdidParseJsonContents = true;\n\t} else {\n\t\tdidParseJsonContents = false;\n\t}\n\n\t// The DeltaManager parses the contents of the message as JSON if it is a string,\n\t// so we should never end up parsing it here.\n\t// Let's observe if we are wrong about this to learn about these cases.\n\tif (didParseJsonContents) {\n\t\tlogLegacyCase(\"ensureContentsDeserialized_foundJsonContents\");\n\t}\n}\n\n/**\n * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.\n *\n * The return type illustrates the assumption that the message param\n * becomes a InboundSequencedContainerRuntimeMessage by the time the function returns\n * (but there is no runtime validation of the 'type' or 'compatDetails' values).\n */\nfunction unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRuntimeMessage {\n\t// We assume the contents is an InboundContainerRuntimeMessage (the message is \"packed\")\n\tconst contents = message.contents as InboundContainerRuntimeMessage;\n\n\t// We're going to unpack message in-place (promoting those properties of contents up to message itself)\n\tconst messageUnpacked = message as InboundSequencedContainerRuntimeMessage;\n\n\tmessageUnpacked.type = contents.type;\n\tmessageUnpacked.contents = contents.contents;\n\tif (\"compatDetails\" in contents) {\n\t\t(messageUnpacked as InboundSequencedRecentlyAddedContainerRuntimeMessage).compatDetails =\n\t\t\tcontents.compatDetails;\n\t}\n\treturn messageUnpacked;\n}\n\n/**\n * Unpacks runtime messages.\n *\n * @remarks This API makes no promises regarding backward-compatibility. This is internal API.\n * @param message - message (as it observed in storage / service)\n * @returns whether the given message was unpacked\n *\n * @internal\n */\nexport function unpackRuntimeMessage(\n\tmessage: ISequencedDocumentMessage,\n\tlogLegacyCase: (codePath: string) => void = () => {},\n): boolean {\n\tif (message.type !== MessageType.Operation) {\n\t\t// Legacy format, but it's already \"unpacked\",\n\t\t// i.e. message.type is actually ContainerMessageType.\n\t\t// Or it's non-runtime message.\n\t\t// Nothing to do in such case.\n\t\treturn false;\n\t}\n\n\t// legacy op format?\n\t// TODO: Unsure if this is a real format we should be concerned with. There doesn't appear to be anything prepared to handle the address member.\n\tif (\n\t\t(message.contents as { address?: unknown }).address !== undefined &&\n\t\t(message.contents as { type?: unknown }).type === undefined\n\t) {\n\t\tmessage.type = ContainerMessageType.FluidDataStoreOp;\n\t\tlogLegacyCase(\"unpackRuntimeMessage_contentsWithAddress\");\n\t} else {\n\t\t// new format\n\t\tunpack(message);\n\t}\n\n\treturn true;\n}\n"]}
|
package/lib/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.
|
|
8
|
+
export declare const pkgVersion = "2.3.0-288113";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,sCAAsC,CAAC;AAC3D,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,sCAAsC,CAAC;AAC3D,eAAO,MAAM,UAAU,iBAAiB,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,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.3.0-288113\";\n"]}
|