@fluidframework/container-runtime 2.31.0 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/channelCollection.d.ts +0 -14
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +10 -25
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +16 -9
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +137 -103
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -5
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +0 -8
- package/dist/dataStoreContext.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 +3 -7
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +4 -4
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +4 -4
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +40 -6
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +4 -3
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +4 -3
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +10 -11
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +19 -18
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +9 -5
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +18 -22
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSerialization.d.ts +20 -0
- package/dist/opLifecycle/opSerialization.d.ts.map +1 -0
- package/dist/opLifecycle/opSerialization.js +40 -0
- package/dist/opLifecycle/opSerialization.js.map +1 -0
- package/dist/opLifecycle/opSplitter.d.ts +12 -13
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +13 -13
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +16 -18
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +57 -43
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +0 -7
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +1 -15
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +2 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +1 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runtimeLayerCompatState.d.ts.map +1 -1
- package/dist/runtimeLayerCompatState.js +6 -5
- package/dist/runtimeLayerCompatState.js.map +1 -1
- package/dist/summary/index.d.ts +5 -8
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +20 -21
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.js +9 -9
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +0 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js +3 -3
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +3 -75
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js +2 -0
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/{lib/summary/summaryGenerator.d.ts → dist/summary/summarizerUtils.d.ts} +12 -43
- package/dist/summary/summarizerUtils.d.ts.map +1 -0
- package/dist/summary/summarizerUtils.js +71 -0
- package/dist/summary/summarizerUtils.js.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/index.d.ts +10 -0
- package/dist/summary/summaryDelayLoadedModule/index.d.ts.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/index.js +20 -0
- package/dist/summary/summaryDelayLoadedModule/index.js.map +1 -0
- package/dist/summary/{runWhileConnectedCoordinator.d.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts} +1 -1
- package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -0
- package/dist/summary/{runningSummarizer.d.ts → summaryDelayLoadedModule/runningSummarizer.d.ts} +4 -13
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -0
- package/dist/summary/{runningSummarizer.js → summaryDelayLoadedModule/runningSummarizer.js} +17 -24
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -0
- package/dist/summary/{summarizer.d.ts → summaryDelayLoadedModule/summarizer.d.ts} +13 -2
- package/dist/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -0
- package/dist/summary/{summarizer.js → summaryDelayLoadedModule/summarizer.js} +13 -3
- package/dist/summary/summaryDelayLoadedModule/summarizer.js.map +1 -0
- package/{lib/summary → dist/summary/summaryDelayLoadedModule}/summarizerHeuristics.d.ts +3 -3
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +36 -0
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -0
- package/dist/summary/{summaryGenerator.js → summaryDelayLoadedModule/summaryGenerator.js} +14 -99
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts +21 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js +44 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts +80 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts.map +1 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.js +7 -0
- package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.js.map +1 -0
- package/dist/summary/summaryHelpers.d.ts +1 -1
- package/dist/summary/summaryHelpers.d.ts.map +1 -1
- package/dist/summary/summaryHelpers.js +2 -2
- package/dist/summary/summaryHelpers.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +4 -3
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +2 -2
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/channelCollection.d.ts +0 -14
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +6 -21
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +16 -9
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +140 -106
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -5
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +0 -8
- package/lib/dataStoreContext.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 +3 -7
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +4 -4
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +4 -4
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +40 -6
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +4 -3
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +3 -2
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +10 -11
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +20 -19
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +9 -5
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +18 -22
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSerialization.d.ts +20 -0
- package/lib/opLifecycle/opSerialization.d.ts.map +1 -0
- package/lib/opLifecycle/opSerialization.js +35 -0
- package/lib/opLifecycle/opSerialization.js.map +1 -0
- package/lib/opLifecycle/opSplitter.d.ts +12 -13
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +13 -13
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +16 -18
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +56 -41
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +0 -7
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +0 -13
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +2 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +1 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runtimeLayerCompatState.d.ts.map +1 -1
- package/lib/runtimeLayerCompatState.js +3 -2
- package/lib/runtimeLayerCompatState.js.map +1 -1
- package/lib/summary/index.d.ts +5 -8
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +5 -7
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.js +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +0 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +3 -75
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/{dist/summary/summaryGenerator.d.ts → lib/summary/summarizerUtils.d.ts} +12 -43
- package/lib/summary/summarizerUtils.d.ts.map +1 -0
- package/lib/summary/summarizerUtils.js +64 -0
- package/lib/summary/summarizerUtils.js.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/index.d.ts +10 -0
- package/lib/summary/summaryDelayLoadedModule/index.d.ts.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/index.js +9 -0
- package/lib/summary/summaryDelayLoadedModule/index.js.map +1 -0
- package/lib/summary/{runWhileConnectedCoordinator.d.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts} +1 -1
- package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -0
- package/lib/summary/{runningSummarizer.d.ts → summaryDelayLoadedModule/runningSummarizer.d.ts} +4 -13
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -0
- package/lib/summary/{runningSummarizer.js → summaryDelayLoadedModule/runningSummarizer.js} +5 -12
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -0
- package/lib/summary/{summarizer.d.ts → summaryDelayLoadedModule/summarizer.d.ts} +13 -2
- package/lib/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -0
- package/lib/summary/{summarizer.js → summaryDelayLoadedModule/summarizer.js} +11 -1
- package/lib/summary/summaryDelayLoadedModule/summarizer.js.map +1 -0
- package/{dist/summary → lib/summary/summaryDelayLoadedModule}/summarizerHeuristics.d.ts +3 -3
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +36 -0
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -0
- package/lib/summary/{summaryGenerator.js → summaryDelayLoadedModule/summaryGenerator.js} +4 -85
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts +21 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js +40 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts +80 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts.map +1 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.js +6 -0
- package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.js.map +1 -0
- package/lib/summary/summaryHelpers.d.ts +1 -1
- package/lib/summary/summaryHelpers.d.ts.map +1 -1
- package/lib/summary/summaryHelpers.js +1 -1
- package/lib/summary/summaryHelpers.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +4 -3
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +2 -2
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +21 -20
- package/src/channelCollection.ts +5 -20
- package/src/containerRuntime.ts +220 -178
- package/src/dataStoreContext.ts +0 -11
- package/src/index.ts +0 -1
- package/src/messageTypes.ts +5 -19
- package/src/opLifecycle/batchManager.ts +19 -12
- package/src/opLifecycle/definitions.ts +45 -6
- package/src/opLifecycle/index.ts +14 -3
- package/src/opLifecycle/opCompressor.ts +25 -24
- package/src/opLifecycle/opGroupingManager.ts +27 -26
- package/src/opLifecycle/opSerialization.ts +46 -0
- package/src/opLifecycle/opSplitter.ts +20 -16
- package/src/opLifecycle/outbox.ts +101 -66
- package/src/opLifecycle/remoteMessageProcessor.ts +0 -17
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +3 -3
- package/src/runtimeLayerCompatState.ts +3 -2
- package/src/summary/index.ts +35 -31
- package/src/summary/orderedClientElection.ts +1 -1
- package/src/summary/summarizerClientElection.ts +1 -2
- package/src/summary/summarizerTypes.ts +7 -91
- package/src/summary/summarizerUtils.ts +132 -0
- package/src/summary/summaryDelayLoadedModule/index.ts +28 -0
- package/src/summary/{runWhileConnectedCoordinator.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.ts} +1 -1
- package/src/summary/{runningSummarizer.ts → summaryDelayLoadedModule/runningSummarizer.ts} +13 -28
- package/src/summary/{summarizer.ts → summaryDelayLoadedModule/summarizer.ts} +19 -8
- package/src/summary/{summarizerHeuristics.ts → summaryDelayLoadedModule/summarizerHeuristics.ts} +3 -3
- package/src/summary/{summaryGenerator.ts → summaryDelayLoadedModule/summaryGenerator.ts} +13 -179
- package/src/summary/summaryDelayLoadedModule/summaryResultBuilder.ts +70 -0
- package/src/summary/summaryDelayLoadedModule/summaryResultTypes.ts +100 -0
- package/src/summary/summaryHelpers.ts +6 -6
- package/src/summary/summaryManager.ts +8 -6
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/dist/summary/runWhileConnectedCoordinator.js.map +0 -1
- package/dist/summary/runningSummarizer.d.ts.map +0 -1
- package/dist/summary/runningSummarizer.js.map +0 -1
- package/dist/summary/summarizer.d.ts.map +0 -1
- package/dist/summary/summarizer.js.map +0 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +0 -1
- package/dist/summary/summarizerHeuristics.js.map +0 -1
- package/dist/summary/summaryGenerator.d.ts.map +0 -1
- package/dist/summary/summaryGenerator.js.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.js.map +0 -1
- package/lib/summary/runningSummarizer.d.ts.map +0 -1
- package/lib/summary/runningSummarizer.js.map +0 -1
- package/lib/summary/summarizer.d.ts.map +0 -1
- package/lib/summary/summarizer.js.map +0 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +0 -1
- package/lib/summary/summarizerHeuristics.js.map +0 -1
- package/lib/summary/summaryGenerator.d.ts.map +0 -1
- package/lib/summary/summaryGenerator.js.map +0 -1
- /package/dist/summary/{runWhileConnectedCoordinator.js → summaryDelayLoadedModule/runWhileConnectedCoordinator.js} +0 -0
- /package/dist/summary/{summarizerHeuristics.js → summaryDelayLoadedModule/summarizerHeuristics.js} +0 -0
- /package/lib/summary/{runWhileConnectedCoordinator.js → summaryDelayLoadedModule/runWhileConnectedCoordinator.js} +0 -0
- /package/lib/summary/{summarizerHeuristics.js → summaryDelayLoadedModule/summarizerHeuristics.js} +0 -0
package/lib/messageTypes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageTypes.js","sourceRoot":"","sources":["../src/messageTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;GAGG;AACH,MAAM,CAAN,IAAY,oBAoCX;AApCD,WAAY,oBAAoB;IAC/B,iCAAiC;IACjC,sDAA8B,CAAA;IAE9B,sBAAsB;IACtB,yCAAiB,CAAA;IAEjB,qBAAqB;IACrB,+CAAuB,CAAA;IAEvB,yFAAyF;IACzF,iDAAyB,CAAA;IAEzB,oDAAoD;IACpD,yCAAiB,CAAA;IAEjB,sCAAsC;IACtC,uCAAe,CAAA;IAEf;;;;OAIG;IACH,qDAA6B,CAAA;IAE7B;;OAEG;IACH,uDAA+B,CAAA;IAE/B;;;OAGG;IACH,iCAAS,CAAA;AACV,CAAC,EApCW,oBAAoB,KAApB,oBAAoB,QAoC/B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IdCreationRange } from \"@fluidframework/id-compressor/internal\";\nimport {\n\tIAttachMessage,\n\tIEnvelope,\n\tInboundAttachMessage,\n} from \"@fluidframework/runtime-definitions/internal\";\n\nimport { IDataStoreAliasMessage } from \"./dataStore.js\";\nimport { GarbageCollectionMessage } from \"./gc/index.js\";\nimport { IChunkedOp } from \"./opLifecycle/index.js\";\nimport { IDocumentSchemaChangeMessage } from \"./summary/index.js\";\n\n/**\n * @legacy\n * @alpha\n */\nexport enum ContainerMessageType {\n\t// An op to be delivered to store\n\tFluidDataStoreOp = \"component\",\n\n\t// Creates a new store\n\tAttach = \"attach\",\n\n\t// Chunked operation.\n\tChunkedOp = \"chunkedOp\",\n\n\t// Signifies that a blob has been attached and should not be garbage collected by storage\n\tBlobAttach = \"blobAttach\",\n\n\t// Ties our new clientId to our old one on reconnect\n\tRejoin = \"rejoin\",\n\n\t// Sets the alias of a root data store\n\tAlias = \"alias\",\n\n\t/**\n\t * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since\n\t * the last allocation op was sent.\n\t * See the [IdCompressor README](./id-compressor/README.md) for more details.\n\t */\n\tIdAllocation = \"idAllocation\",\n\n\t/**\n\t * An op that changes document schema\n\t */\n\tDocumentSchemaChange = \"schema\",\n\n\t/**\n\t * Garbage collection specific op. This is sent by the summarizer client when GC runs. It's used to synchronize GC\n\t * state across all clients.\n\t */\n\tGC = \"GC\",\n}\n\n/**\n * The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime.\n * Message type are differentiated via a `type` string and contain different contents depending on their type.\n *\n * IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.\n * This way stringified values can be compared.\n */\ninterface TypedContainerRuntimeMessage<TType extends ContainerMessageType, TContents> {\n\t/**\n\t * Type of the op, within the ContainerRuntime's domain\n\t */\n\ttype: TType;\n\t/**\n\t * Domain-specific contents, interpreted according to the type\n\t */\n\tcontents: TContents;\n}\n\nexport type ContainerRuntimeDataStoreOpMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.FluidDataStoreOp,\n\tIEnvelope\n>;\nexport type InboundContainerRuntimeAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Attach,\n\tInboundAttachMessage\n>;\nexport type OutboundContainerRuntimeAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Attach,\n\tIAttachMessage\n>;\nexport type ContainerRuntimeChunkedOpMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.ChunkedOp,\n\tIChunkedOp\n>;\nexport type ContainerRuntimeBlobAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.BlobAttach,\n\tundefined\n>;\nexport type ContainerRuntimeRejoinMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Rejoin,\n\tundefined\n>;\nexport type ContainerRuntimeAliasMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Alias,\n\tIDataStoreAliasMessage\n>;\nexport type ContainerRuntimeIdAllocationMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.IdAllocation,\n\tIdCreationRange\n>;\nexport type ContainerRuntimeGCMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.GC,\n\tGarbageCollectionMessage\n>;\nexport type ContainerRuntimeDocumentSchemaMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.DocumentSchemaChange,\n\tIDocumentSchemaChangeMessage\n>;\n\n/**\n * Represents an unrecognized TypedContainerRuntimeMessage, e.g. a message from a future version of the container runtime.\n * @internal\n */\nexport interface UnknownContainerRuntimeMessage {\n\t/**\n\t * Invalid type of the op, within the ContainerRuntime's domain. This value should never exist at runtime.\n\t * This is useful for type narrowing but should never be used as an actual message type at runtime.\n\t * Actual value will not be \"__unknown...\", but the type `Exclude<string, ContainerMessageType>` is not supported.\n\t */\n\ttype: \"__unknown_container_message_type__never_use_as_value__\";\n\n\t/**\n\t * Domain-specific contents, but not decipherable by an unknown op.\n\t */\n\tcontents: unknown;\n}\n\n/**\n * A {@link TypedContainerRuntimeMessage} that is received from the server and will be processed by the container runtime.\n */\nexport type InboundContainerRuntimeMessage =\n\t| ContainerRuntimeDataStoreOpMessage\n\t| InboundContainerRuntimeAttachMessage\n\t| ContainerRuntimeChunkedOpMessage\n\t| ContainerRuntimeBlobAttachMessage\n\t| ContainerRuntimeRejoinMessage\n\t| ContainerRuntimeAliasMessage\n\t| ContainerRuntimeIdAllocationMessage\n\t| ContainerRuntimeGCMessage\n\t// Inbound messages may include unknown types from other clients, so we include that as a special case here\n\t| UnknownContainerRuntimeMessage
|
|
1
|
+
{"version":3,"file":"messageTypes.js","sourceRoot":"","sources":["../src/messageTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;GAGG;AACH,MAAM,CAAN,IAAY,oBAoCX;AApCD,WAAY,oBAAoB;IAC/B,iCAAiC;IACjC,sDAA8B,CAAA;IAE9B,sBAAsB;IACtB,yCAAiB,CAAA;IAEjB,qBAAqB;IACrB,+CAAuB,CAAA;IAEvB,yFAAyF;IACzF,iDAAyB,CAAA;IAEzB,oDAAoD;IACpD,yCAAiB,CAAA;IAEjB,sCAAsC;IACtC,uCAAe,CAAA;IAEf;;;;OAIG;IACH,qDAA6B,CAAA;IAE7B;;OAEG;IACH,uDAA+B,CAAA;IAE/B;;;OAGG;IACH,iCAAS,CAAA;AACV,CAAC,EApCW,oBAAoB,KAApB,oBAAoB,QAoC/B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IdCreationRange } from \"@fluidframework/id-compressor/internal\";\nimport {\n\tIAttachMessage,\n\tIEnvelope,\n\tInboundAttachMessage,\n} from \"@fluidframework/runtime-definitions/internal\";\n\nimport { IDataStoreAliasMessage } from \"./dataStore.js\";\nimport { GarbageCollectionMessage } from \"./gc/index.js\";\nimport { IChunkedOp } from \"./opLifecycle/index.js\";\nimport { IDocumentSchemaChangeMessage } from \"./summary/index.js\";\n\n/**\n * @legacy\n * @alpha\n */\nexport enum ContainerMessageType {\n\t// An op to be delivered to store\n\tFluidDataStoreOp = \"component\",\n\n\t// Creates a new store\n\tAttach = \"attach\",\n\n\t// Chunked operation.\n\tChunkedOp = \"chunkedOp\",\n\n\t// Signifies that a blob has been attached and should not be garbage collected by storage\n\tBlobAttach = \"blobAttach\",\n\n\t// Ties our new clientId to our old one on reconnect\n\tRejoin = \"rejoin\",\n\n\t// Sets the alias of a root data store\n\tAlias = \"alias\",\n\n\t/**\n\t * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since\n\t * the last allocation op was sent.\n\t * See the [IdCompressor README](./id-compressor/README.md) for more details.\n\t */\n\tIdAllocation = \"idAllocation\",\n\n\t/**\n\t * An op that changes document schema\n\t */\n\tDocumentSchemaChange = \"schema\",\n\n\t/**\n\t * Garbage collection specific op. This is sent by the summarizer client when GC runs. It's used to synchronize GC\n\t * state across all clients.\n\t */\n\tGC = \"GC\",\n}\n\n/**\n * The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime.\n * Message type are differentiated via a `type` string and contain different contents depending on their type.\n *\n * IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.\n * This way stringified values can be compared.\n */\ninterface TypedContainerRuntimeMessage<TType extends ContainerMessageType, TContents> {\n\t/**\n\t * Type of the op, within the ContainerRuntime's domain\n\t */\n\ttype: TType;\n\t/**\n\t * Domain-specific contents, interpreted according to the type\n\t */\n\tcontents: TContents;\n}\n\nexport type ContainerRuntimeDataStoreOpMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.FluidDataStoreOp,\n\tIEnvelope\n>;\nexport type InboundContainerRuntimeAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Attach,\n\tInboundAttachMessage\n>;\nexport type OutboundContainerRuntimeAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Attach,\n\tIAttachMessage\n>;\nexport type ContainerRuntimeChunkedOpMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.ChunkedOp,\n\tIChunkedOp\n>;\nexport type ContainerRuntimeBlobAttachMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.BlobAttach,\n\tundefined\n>;\nexport type ContainerRuntimeRejoinMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Rejoin,\n\tundefined\n>;\nexport type ContainerRuntimeAliasMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.Alias,\n\tIDataStoreAliasMessage\n>;\nexport type ContainerRuntimeIdAllocationMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.IdAllocation,\n\tIdCreationRange\n>;\nexport type ContainerRuntimeGCMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.GC,\n\tGarbageCollectionMessage\n>;\nexport type ContainerRuntimeDocumentSchemaMessage = TypedContainerRuntimeMessage<\n\tContainerMessageType.DocumentSchemaChange,\n\tIDocumentSchemaChangeMessage\n>;\n\n/**\n * Represents an unrecognized TypedContainerRuntimeMessage, e.g. a message from a future version of the container runtime.\n * @internal\n */\nexport interface UnknownContainerRuntimeMessage {\n\t/**\n\t * Invalid type of the op, within the ContainerRuntime's domain. This value should never exist at runtime.\n\t * This is useful for type narrowing but should never be used as an actual message type at runtime.\n\t * Actual value will not be \"__unknown...\", but the type `Exclude<string, ContainerMessageType>` is not supported.\n\t */\n\ttype: \"__unknown_container_message_type__never_use_as_value__\";\n\n\t/**\n\t * Domain-specific contents, but not decipherable by an unknown op.\n\t */\n\tcontents: unknown;\n}\n\n/**\n * A {@link TypedContainerRuntimeMessage} that is received from the server and will be processed by the container runtime.\n */\nexport type InboundContainerRuntimeMessage =\n\t| ContainerRuntimeDataStoreOpMessage\n\t| InboundContainerRuntimeAttachMessage\n\t| ContainerRuntimeChunkedOpMessage\n\t| ContainerRuntimeBlobAttachMessage\n\t| ContainerRuntimeRejoinMessage\n\t| ContainerRuntimeAliasMessage\n\t| ContainerRuntimeIdAllocationMessage\n\t| ContainerRuntimeGCMessage\n\t| ContainerRuntimeDocumentSchemaMessage\n\t// Inbound messages may include unknown types from other clients, so we include that as a special case here\n\t| UnknownContainerRuntimeMessage;\n\n/**\n * A {@link TypedContainerRuntimeMessage} that has been generated by the container runtime, eventually to be sent to the ordering service.\n * These are messages generated by the local runtime, before the outbox's op virtualization step.\n */\nexport type LocalContainerRuntimeMessage =\n\t| ContainerRuntimeDataStoreOpMessage\n\t| OutboundContainerRuntimeAttachMessage\n\t| ContainerRuntimeBlobAttachMessage\n\t| ContainerRuntimeRejoinMessage\n\t| ContainerRuntimeAliasMessage\n\t| ContainerRuntimeIdAllocationMessage\n\t| ContainerRuntimeGCMessage\n\t| ContainerRuntimeDocumentSchemaMessage\n\t// In rare cases (e.g. related to stashed ops) we could have a local message of an unknown type\n\t| UnknownContainerRuntimeMessage;\n\n/**\n * An unpacked ISequencedDocumentMessage with the inner TypedContainerRuntimeMessage type/contents/etc\n * promoted up to the outer object\n */\nexport type InboundSequencedContainerRuntimeMessage = Omit<\n\tISequencedDocumentMessage,\n\t\"type\" | \"contents\"\n> &\n\tInboundContainerRuntimeMessage;\n"]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { ICompressionRuntimeOptions } from "../containerRuntime.js";
|
|
6
6
|
import type { IPendingMessage } from "../pendingStateManager.js";
|
|
7
|
-
import {
|
|
7
|
+
import { LocalBatchMessage, IBatchCheckpoint, type LocalBatch, type OutboundBatch } from "./definitions.js";
|
|
8
8
|
import type { BatchStartInfo } from "./remoteMessageProcessor.js";
|
|
9
9
|
export interface IBatchManagerOptions {
|
|
10
10
|
readonly hardLimit: number;
|
|
@@ -55,12 +55,12 @@ export declare class BatchManager {
|
|
|
55
55
|
*/
|
|
56
56
|
private clientSequenceNumber;
|
|
57
57
|
constructor(options: IBatchManagerOptions);
|
|
58
|
-
push(message:
|
|
58
|
+
push(message: LocalBatchMessage, reentrant: boolean, currentClientSequenceNumber?: number): boolean;
|
|
59
59
|
get empty(): boolean;
|
|
60
60
|
/**
|
|
61
61
|
* Gets the pending batch and clears state for the next batch.
|
|
62
62
|
*/
|
|
63
|
-
popBatch(batchId?: BatchId):
|
|
63
|
+
popBatch(batchId?: BatchId): LocalBatch;
|
|
64
64
|
/**
|
|
65
65
|
* Capture the pending state at this point
|
|
66
66
|
*/
|
|
@@ -74,6 +74,6 @@ export declare class BatchManager {
|
|
|
74
74
|
* @param batch - the batch to inspect
|
|
75
75
|
* @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire
|
|
76
76
|
*/
|
|
77
|
-
export declare const estimateSocketSize: (batch:
|
|
77
|
+
export declare const estimateSocketSize: (batch: OutboundBatch) => number;
|
|
78
78
|
export declare const sequenceNumbersMatch: (seqNums: BatchSequenceNumbers, otherSeqNums: BatchSequenceNumbers) => boolean;
|
|
79
79
|
//# sourceMappingURL=batchManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"batchManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EACN,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B;;GAEG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAExF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,8BAA8B,EAAE,eAAe,GAAG,cAAc,GAC9D,MAAM,CAcR;AAQD;;GAEG;AACH,qBAAa,YAAY;aAgCI,OAAO,EAAE,oBAAoB;IA/BzD,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAEhC,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,kBAAkB,IAAI,MAAM,CAEtC;IAED,IAAW,eAAe,IAAI,oBAAoB,CAKjD;IAED,OAAO,KAAK,uBAAuB,GAKlC;IAED;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAqB;gBAErB,OAAO,EAAE,oBAAoB;IAElD,IAAI,CACV,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,OAAO,EAClB,2BAA2B,CAAC,EAAE,MAAM,GAClC,OAAO;IAyBV,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED;;OAEG;IACI,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU;IAgB9C;;OAEG;IACI,UAAU,IAAI,gBAAgB;CAyBrC;AAgCD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,4BAA2B,MAEzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,YACvB,oBAAoB,gBACf,oBAAoB,KAChC,OASF,CAAC"}
|
|
@@ -60,7 +60,7 @@ export class BatchManager {
|
|
|
60
60
|
this.hasReentrantOps = false;
|
|
61
61
|
}
|
|
62
62
|
push(message, reentrant, currentClientSequenceNumber) {
|
|
63
|
-
const contentSize = this.batchContentSize + (message.
|
|
63
|
+
const contentSize = this.batchContentSize + (message.serializedOp?.length ?? 0);
|
|
64
64
|
const opCount = this.pendingBatch.length;
|
|
65
65
|
this.hasReentrantOps = this.hasReentrantOps || reentrant;
|
|
66
66
|
// Attempt to estimate batch size, aka socket message size.
|
|
@@ -109,15 +109,15 @@ export class BatchManager {
|
|
|
109
109
|
this.clientSequenceNumber = startSequenceNumber;
|
|
110
110
|
const rollbackOpsLifo = this.pendingBatch.splice(startPoint).reverse();
|
|
111
111
|
for (const message of rollbackOpsLifo) {
|
|
112
|
-
this.batchContentSize -= message.
|
|
112
|
+
this.batchContentSize -= message.serializedOp?.length ?? 0;
|
|
113
113
|
process(message);
|
|
114
114
|
}
|
|
115
115
|
const count = this.pendingBatch.length - startPoint;
|
|
116
116
|
if (count !== 0) {
|
|
117
|
-
throw new LoggingError("Ops generated
|
|
117
|
+
throw new LoggingError("Ops generated during rollback", {
|
|
118
118
|
count,
|
|
119
119
|
...tagData(TelemetryDataTag.UserData, {
|
|
120
|
-
ops: JSON.stringify(this.pendingBatch.slice(startPoint).map((b) => b.
|
|
120
|
+
ops: JSON.stringify(this.pendingBatch.slice(startPoint).map((b) => b.serializedOp)),
|
|
121
121
|
}),
|
|
122
122
|
});
|
|
123
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLoggingError,\n\ttagData,\n\tTelemetryDataTag,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { asBatchMetadata, type IBatchMetadata } from \"../metadata.js\";\nimport type { IPendingMessage } from \"../pendingStateManager.js\";\n\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport type { BatchStartInfo } from \"./remoteMessageProcessor.js\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n\n\t/**\n\t * If true, the outbox is allowed to rebase the batch during flushing.\n\t */\n\treadonly canRebase: boolean;\n\n\t/**\n\t * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored\n\t */\n\treadonly ignoreBatchId?: boolean;\n}\n\nexport interface BatchSequenceNumbers {\n\treferenceSequenceNumber?: number;\n\tclientSequenceNumber?: number;\n}\n\n/**\n * Type alias for the batchId stored in batch metadata\n */\nexport type BatchId = string;\n\n/**\n * Compose original client ID and client sequence number into BatchId to stamp on the message during reconnect\n */\nexport function generateBatchId(originalClientId: string, batchStartCsn: number): BatchId {\n\treturn `${originalClientId}_[${batchStartCsn}]`;\n}\n\n/**\n * Get the effective batch ID for the input argument.\n * Supports either an IPendingMessage or BatchStartInfo.\n * If the batch ID is explicitly present, return it.\n * Otherwise, generate a new batch ID using the client ID and batch start CSN.\n */\nexport function getEffectiveBatchId(\n\tpendingMessageOrBatchStartInfo: IPendingMessage | BatchStartInfo,\n): string {\n\tif (\"localOpMetadata\" in pendingMessageOrBatchStartInfo) {\n\t\tconst pendingMessage: IPendingMessage = pendingMessageOrBatchStartInfo;\n\t\treturn (\n\t\t\tasBatchMetadata(pendingMessage.opMetadata)?.batchId ??\n\t\t\tgenerateBatchId(\n\t\t\t\tpendingMessage.batchInfo.clientId,\n\t\t\t\tpendingMessage.batchInfo.batchStartCsn,\n\t\t\t)\n\t\t);\n\t}\n\n\tconst batchStart: BatchStartInfo = pendingMessageOrBatchStartInfo;\n\treturn batchStart.batchId ?? generateBatchId(batchStart.clientId, batchStart.batchStartCsn);\n}\n\n/**\n * Estimated size of the stringification overhead for an op accumulated\n * from runtime to loader to the service.\n */\nconst opOverhead = 200;\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: BatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\tprivate hasReentrantOps = false;\n\n\tpublic get length(): number {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes(): number {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get sequenceNumbers(): BatchSequenceNumbers {\n\t\treturn {\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tclientSequenceNumber: this.clientSequenceNumber,\n\t\t};\n\t}\n\n\tprivate get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: // NOTE: In case of reentrant ops, there could be multiple reference sequence numbers, but we will rebase before submitting.\n\t\t\t\tthis.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\t/**\n\t * The last-processed CSN when this batch started.\n\t * This is used to ensure that while the batch is open, no incoming ops are processed.\n\t */\n\tprivate clientSequenceNumber: number | undefined;\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(\n\t\tmessage: BatchMessage,\n\t\treentrant: boolean,\n\t\tcurrentClientSequenceNumber?: number,\n\t): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.contents?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\t\tthis.hasReentrantOps = this.hasReentrantOps || reentrant;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + opOverhead * opCount;\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.pendingBatch.length === 0) {\n\t\t\tthis.clientSequenceNumber = currentClientSequenceNumber;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty(): boolean {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\t/**\n\t * Gets the pending batch and clears state for the next batch.\n\t */\n\tpublic popBatch(batchId?: BatchId): IBatch {\n\t\tconst batch: IBatch = {\n\t\t\tmessages: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\thasReentrantOps: this.hasReentrantOps,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\t\tthis.clientSequenceNumber = undefined;\n\t\tthis.hasReentrantOps = false;\n\n\t\treturn addBatchMetadata(batch, batchId);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startSequenceNumber = this.clientSequenceNumber;\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: BatchMessage) => void) => {\n\t\t\t\tthis.clientSequenceNumber = startSequenceNumber;\n\t\t\t\tconst rollbackOpsLifo = this.pendingBatch.splice(startPoint).reverse();\n\t\t\t\tfor (const message of rollbackOpsLifo) {\n\t\t\t\t\tthis.batchContentSize -= message.contents?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\t\t\t\tconst count = this.pendingBatch.length - startPoint;\n\t\t\t\tif (count !== 0) {\n\t\t\t\t\tthrow new LoggingError(\"Ops generated durning rollback\", {\n\t\t\t\t\t\tcount,\n\t\t\t\t\t\t...tagData(TelemetryDataTag.UserData, {\n\t\t\t\t\t\t\tops: JSON.stringify(this.pendingBatch.slice(startPoint).map((b) => b.contents)),\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: IBatch, batchId?: BatchId): IBatch => {\n\tconst batchEnd = batch.messages.length - 1;\n\n\tconst firstMsg = batch.messages[0];\n\tconst lastMsg = batch.messages[batchEnd];\n\tassert(\n\t\tfirstMsg !== undefined && lastMsg !== undefined,\n\t\t0x9d1 /* expected non-empty batch */,\n\t);\n\n\tconst firstMetadata: Partial<IBatchMetadata> = firstMsg.metadata ?? {};\n\tconst lastMetadata: Partial<IBatchMetadata> = lastMsg.metadata ?? {};\n\n\t// Multi-message batches: mark the first and last messages with the \"batch\" flag indicating batch start/end\n\tif (batch.messages.length > 1) {\n\t\tfirstMetadata.batch = true;\n\t\tlastMetadata.batch = false;\n\t\tfirstMsg.metadata = firstMetadata;\n\t\tlastMsg.metadata = lastMetadata;\n\t}\n\n\t// If batchId is provided (e.g. in case of resubmit): stamp it on the first message\n\tif (batchId !== undefined) {\n\t\tfirstMetadata.batchId = batchId;\n\t\tfirstMsg.metadata = firstMetadata;\n\t}\n\n\treturn batch;\n};\n\n/**\n * Estimates the real size in bytes on the socket for a given batch. It assumes that\n * the envelope size (and the size of an empty op) is 200 bytes, taking into account\n * extra overhead from stringification.\n *\n * @param batch - the batch to inspect\n * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire\n */\nexport const estimateSocketSize = (batch: IBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.messages.length;\n};\n\nexport const sequenceNumbersMatch = (\n\tseqNums: BatchSequenceNumbers,\n\totherSeqNums: BatchSequenceNumbers,\n): boolean => {\n\treturn (\n\t\t(seqNums.referenceSequenceNumber === undefined ||\n\t\t\totherSeqNums.referenceSequenceNumber === undefined ||\n\t\t\tseqNums.referenceSequenceNumber === otherSeqNums.referenceSequenceNumber) &&\n\t\t(seqNums.clientSequenceNumber === undefined ||\n\t\t\totherSeqNums.clientSequenceNumber === undefined ||\n\t\t\tseqNums.clientSequenceNumber === otherSeqNums.clientSequenceNumber)\n\t);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"batchManager.js","sourceRoot":"","sources":["../../src/opLifecycle/batchManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLoggingError,\n\ttagData,\n\tTelemetryDataTag,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { asBatchMetadata, type IBatchMetadata } from \"../metadata.js\";\nimport type { IPendingMessage } from \"../pendingStateManager.js\";\n\nimport {\n\tLocalBatchMessage,\n\tIBatchCheckpoint,\n\ttype LocalBatch,\n\ttype OutboundBatch,\n} from \"./definitions.js\";\nimport type { BatchStartInfo } from \"./remoteMessageProcessor.js\";\n\nexport interface IBatchManagerOptions {\n\treadonly hardLimit: number;\n\treadonly compressionOptions?: ICompressionRuntimeOptions;\n\n\t/**\n\t * If true, the outbox is allowed to rebase the batch during flushing.\n\t */\n\treadonly canRebase: boolean;\n\n\t/**\n\t * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored\n\t */\n\treadonly ignoreBatchId?: boolean;\n}\n\nexport interface BatchSequenceNumbers {\n\treferenceSequenceNumber?: number;\n\tclientSequenceNumber?: number;\n}\n\n/**\n * Type alias for the batchId stored in batch metadata\n */\nexport type BatchId = string;\n\n/**\n * Compose original client ID and client sequence number into BatchId to stamp on the message during reconnect\n */\nexport function generateBatchId(originalClientId: string, batchStartCsn: number): BatchId {\n\treturn `${originalClientId}_[${batchStartCsn}]`;\n}\n\n/**\n * Get the effective batch ID for the input argument.\n * Supports either an IPendingMessage or BatchStartInfo.\n * If the batch ID is explicitly present, return it.\n * Otherwise, generate a new batch ID using the client ID and batch start CSN.\n */\nexport function getEffectiveBatchId(\n\tpendingMessageOrBatchStartInfo: IPendingMessage | BatchStartInfo,\n): string {\n\tif (\"localOpMetadata\" in pendingMessageOrBatchStartInfo) {\n\t\tconst pendingMessage: IPendingMessage = pendingMessageOrBatchStartInfo;\n\t\treturn (\n\t\t\tasBatchMetadata(pendingMessage.opMetadata)?.batchId ??\n\t\t\tgenerateBatchId(\n\t\t\t\tpendingMessage.batchInfo.clientId,\n\t\t\t\tpendingMessage.batchInfo.batchStartCsn,\n\t\t\t)\n\t\t);\n\t}\n\n\tconst batchStart: BatchStartInfo = pendingMessageOrBatchStartInfo;\n\treturn batchStart.batchId ?? generateBatchId(batchStart.clientId, batchStart.batchStartCsn);\n}\n\n/**\n * Estimated size of the stringification overhead for an op accumulated\n * from runtime to loader to the service.\n */\nconst opOverhead = 200;\n\n/**\n * Helper class that manages partial batch & rollback.\n */\nexport class BatchManager {\n\tprivate pendingBatch: LocalBatchMessage[] = [];\n\tprivate batchContentSize = 0;\n\tprivate hasReentrantOps = false;\n\n\tpublic get length(): number {\n\t\treturn this.pendingBatch.length;\n\t}\n\tpublic get contentSizeInBytes(): number {\n\t\treturn this.batchContentSize;\n\t}\n\n\tpublic get sequenceNumbers(): BatchSequenceNumbers {\n\t\treturn {\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tclientSequenceNumber: this.clientSequenceNumber,\n\t\t};\n\t}\n\n\tprivate get referenceSequenceNumber(): number | undefined {\n\t\treturn this.pendingBatch.length === 0\n\t\t\t? undefined\n\t\t\t: // NOTE: In case of reentrant ops, there could be multiple reference sequence numbers, but we will rebase before submitting.\n\t\t\t\tthis.pendingBatch[this.pendingBatch.length - 1].referenceSequenceNumber;\n\t}\n\n\t/**\n\t * The last-processed CSN when this batch started.\n\t * This is used to ensure that while the batch is open, no incoming ops are processed.\n\t */\n\tprivate clientSequenceNumber: number | undefined;\n\n\tconstructor(public readonly options: IBatchManagerOptions) {}\n\n\tpublic push(\n\t\tmessage: LocalBatchMessage,\n\t\treentrant: boolean,\n\t\tcurrentClientSequenceNumber?: number,\n\t): boolean {\n\t\tconst contentSize = this.batchContentSize + (message.serializedOp?.length ?? 0);\n\t\tconst opCount = this.pendingBatch.length;\n\t\tthis.hasReentrantOps = this.hasReentrantOps || reentrant;\n\n\t\t// Attempt to estimate batch size, aka socket message size.\n\t\t// Each op has pretty large envelope, estimating to be 200 bytes.\n\t\t// Also content will be strigified, and that adds a lot of overhead due to a lot of escape characters.\n\t\t// Not taking it into account, as compression work should help there - compressed payload will be\n\t\t// initially stored as base64, and that requires only 2 extra escape characters.\n\t\tconst socketMessageSize = contentSize + opOverhead * opCount;\n\n\t\tif (socketMessageSize >= this.options.hardLimit) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.pendingBatch.length === 0) {\n\t\t\tthis.clientSequenceNumber = currentClientSequenceNumber;\n\t\t}\n\n\t\tthis.batchContentSize = contentSize;\n\t\tthis.pendingBatch.push(message);\n\t\treturn true;\n\t}\n\n\tpublic get empty(): boolean {\n\t\treturn this.pendingBatch.length === 0;\n\t}\n\n\t/**\n\t * Gets the pending batch and clears state for the next batch.\n\t */\n\tpublic popBatch(batchId?: BatchId): LocalBatch {\n\t\tconst batch: LocalBatch = {\n\t\t\tmessages: this.pendingBatch,\n\t\t\tcontentSizeInBytes: this.batchContentSize,\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\thasReentrantOps: this.hasReentrantOps,\n\t\t};\n\n\t\tthis.pendingBatch = [];\n\t\tthis.batchContentSize = 0;\n\t\tthis.clientSequenceNumber = undefined;\n\t\tthis.hasReentrantOps = false;\n\n\t\treturn addBatchMetadata(batch, batchId);\n\t}\n\n\t/**\n\t * Capture the pending state at this point\n\t */\n\tpublic checkpoint(): IBatchCheckpoint {\n\t\tconst startSequenceNumber = this.clientSequenceNumber;\n\t\tconst startPoint = this.pendingBatch.length;\n\t\treturn {\n\t\t\trollback: (process: (message: LocalBatchMessage) => void) => {\n\t\t\t\tthis.clientSequenceNumber = startSequenceNumber;\n\t\t\t\tconst rollbackOpsLifo = this.pendingBatch.splice(startPoint).reverse();\n\t\t\t\tfor (const message of rollbackOpsLifo) {\n\t\t\t\t\tthis.batchContentSize -= message.serializedOp?.length ?? 0;\n\t\t\t\t\tprocess(message);\n\t\t\t\t}\n\t\t\t\tconst count = this.pendingBatch.length - startPoint;\n\t\t\t\tif (count !== 0) {\n\t\t\t\t\tthrow new LoggingError(\"Ops generated during rollback\", {\n\t\t\t\t\t\tcount,\n\t\t\t\t\t\t...tagData(TelemetryDataTag.UserData, {\n\t\t\t\t\t\t\tops: JSON.stringify(\n\t\t\t\t\t\t\t\tthis.pendingBatch.slice(startPoint).map((b) => b.serializedOp),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n}\n\nconst addBatchMetadata = (batch: LocalBatch, batchId?: BatchId): LocalBatch => {\n\tconst batchEnd = batch.messages.length - 1;\n\n\tconst firstMsg = batch.messages[0];\n\tconst lastMsg = batch.messages[batchEnd];\n\tassert(\n\t\tfirstMsg !== undefined && lastMsg !== undefined,\n\t\t0x9d1 /* expected non-empty batch */,\n\t);\n\n\tconst firstMetadata: Partial<IBatchMetadata> = firstMsg.metadata ?? {};\n\tconst lastMetadata: Partial<IBatchMetadata> = lastMsg.metadata ?? {};\n\n\t// Multi-message batches: mark the first and last messages with the \"batch\" flag indicating batch start/end\n\tif (batch.messages.length > 1) {\n\t\tfirstMetadata.batch = true;\n\t\tlastMetadata.batch = false;\n\t\tfirstMsg.metadata = firstMetadata;\n\t\tlastMsg.metadata = lastMetadata;\n\t}\n\n\t// If batchId is provided (e.g. in case of resubmit): stamp it on the first message\n\tif (batchId !== undefined) {\n\t\tfirstMetadata.batchId = batchId;\n\t\tfirstMsg.metadata = firstMetadata;\n\t}\n\n\treturn batch;\n};\n\n/**\n * Estimates the real size in bytes on the socket for a given batch. It assumes that\n * the envelope size (and the size of an empty op) is 200 bytes, taking into account\n * extra overhead from stringification.\n *\n * @param batch - the batch to inspect\n * @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire\n */\nexport const estimateSocketSize = (batch: OutboundBatch): number => {\n\treturn batch.contentSizeInBytes + opOverhead * batch.messages.length;\n};\n\nexport const sequenceNumbersMatch = (\n\tseqNums: BatchSequenceNumbers,\n\totherSeqNums: BatchSequenceNumbers,\n): boolean => {\n\treturn (\n\t\t(seqNums.referenceSequenceNumber === undefined ||\n\t\t\totherSeqNums.referenceSequenceNumber === undefined ||\n\t\t\tseqNums.referenceSequenceNumber === otherSeqNums.referenceSequenceNumber) &&\n\t\t(seqNums.clientSequenceNumber === undefined ||\n\t\t\totherSeqNums.clientSequenceNumber === undefined ||\n\t\t\tseqNums.clientSequenceNumber === otherSeqNums.clientSequenceNumber)\n\t);\n};\n"]}
|
|
@@ -2,20 +2,53 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { IBatchMessage } from "@fluidframework/container-definitions/internal";
|
|
5
|
+
import type { IBatchMessage } from "@fluidframework/container-definitions/internal";
|
|
6
6
|
import { CompressionAlgorithms } from "../containerRuntime.js";
|
|
7
7
|
/**
|
|
8
|
-
* Batch message
|
|
8
|
+
* Local Batch message, before it is virtualized and sent to the ordering service
|
|
9
9
|
*/
|
|
10
|
-
export
|
|
10
|
+
export interface LocalBatchMessage {
|
|
11
|
+
serializedOp: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
11
13
|
localOpMetadata?: unknown;
|
|
12
14
|
referenceSequenceNumber: number;
|
|
13
15
|
compression?: CompressionAlgorithms;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use serializedOp
|
|
18
|
+
*/
|
|
19
|
+
contents?: never;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Virtualized Batch message, on its way out the door to the ordering service
|
|
23
|
+
*/
|
|
24
|
+
export type OutboundBatchMessage = IBatchMessage & {
|
|
25
|
+
localOpMetadata?: unknown;
|
|
26
|
+
referenceSequenceNumber: number;
|
|
27
|
+
compression?: CompressionAlgorithms;
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated Use contents
|
|
30
|
+
*/
|
|
31
|
+
serializedOp?: never;
|
|
14
32
|
};
|
|
15
33
|
/**
|
|
16
|
-
*
|
|
34
|
+
* A batch of messages we have accumulated locally, but haven't sent to the ordering service yet.
|
|
35
|
+
*/
|
|
36
|
+
export type LocalBatch = IBatch<LocalBatchMessage[]>;
|
|
37
|
+
/**
|
|
38
|
+
* A batch of messages that has been virtualized as needed (grouped, compressed, chunked)
|
|
39
|
+
* and is ready to be sent to the ordering service.
|
|
40
|
+
*/
|
|
41
|
+
export type OutboundBatch = IBatch<OutboundBatchMessage[]>;
|
|
42
|
+
/**
|
|
43
|
+
* An {@link OutboundBatch} with exactly one message
|
|
44
|
+
* This type is helpful as Grouping yields this kind of batch, and Compression only operates on this type of batch.
|
|
45
|
+
*/
|
|
46
|
+
export type OutboundSingletonBatch = IBatch<[OutboundBatchMessage]>;
|
|
47
|
+
/**
|
|
48
|
+
* Base batch interface used internally by the runtime.
|
|
49
|
+
* See {@link LocalBatch} and {@link OutboundBatch} for the concrete types.
|
|
17
50
|
*/
|
|
18
|
-
|
|
51
|
+
interface IBatch<TMessages extends LocalBatchMessage[] | OutboundBatchMessage[]> {
|
|
19
52
|
/**
|
|
20
53
|
* Sum of the in-memory content sizes of all messages in the batch.
|
|
21
54
|
* If the batch is compressed, this number reflects the post-compression size.
|
|
@@ -42,7 +75,7 @@ export interface IBatch<TMessages extends BatchMessage[] = BatchMessage[]> {
|
|
|
42
75
|
readonly hasReentrantOps?: boolean;
|
|
43
76
|
}
|
|
44
77
|
export interface IBatchCheckpoint {
|
|
45
|
-
rollback: (action: (message:
|
|
78
|
+
rollback: (action: (message: LocalBatchMessage) => void) => void;
|
|
46
79
|
}
|
|
47
80
|
/**
|
|
48
81
|
* @internal
|
|
@@ -62,4 +95,5 @@ export interface IChunkedOp {
|
|
|
62
95
|
* will make the processor return `Processed`.
|
|
63
96
|
*/
|
|
64
97
|
export type ProcessingState = "Processed" | "Skipped" | "Accepted";
|
|
98
|
+
export {};
|
|
65
99
|
//# sourceMappingURL=definitions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAEpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;AAErD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAEpE;;;GAGG;AACH,UAAU,MAAM,CAAC,SAAS,SAAS,iBAAiB,EAAE,GAAG,oBAAoB,EAAE;IAC9E;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B;;OAEG;IACH,QAAQ,CAAC,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrD;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,KAAK,IAAI,CAAC;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/opLifecycle/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\n\nimport { CompressionAlgorithms } from \"../containerRuntime.js\";\n\n/**\n * Batch message
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/opLifecycle/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\n\nimport { CompressionAlgorithms } from \"../containerRuntime.js\";\n\n/**\n * Local Batch message, before it is virtualized and sent to the ordering service\n */\nexport interface LocalBatchMessage {\n\tserializedOp: string;\n\tmetadata?: Record<string, unknown>;\n\tlocalOpMetadata?: unknown;\n\treferenceSequenceNumber: number;\n\tcompression?: CompressionAlgorithms;\n\n\t/**\n\t * @deprecated Use serializedOp\n\t */\n\tcontents?: never; // To ensure we don't leave this one when converting from OutboundBatchMessage\n}\n\n/**\n * Virtualized Batch message, on its way out the door to the ordering service\n */\nexport type OutboundBatchMessage = IBatchMessage & {\n\tlocalOpMetadata?: unknown;\n\treferenceSequenceNumber: number;\n\tcompression?: CompressionAlgorithms;\n\n\t/**\n\t * @deprecated Use contents\n\t */\n\tserializedOp?: never; // To ensure we don't leave this one when converting from LocalBatchMessage\n};\n\n/**\n * A batch of messages we have accumulated locally, but haven't sent to the ordering service yet.\n */\nexport type LocalBatch = IBatch<LocalBatchMessage[]>;\n\n/**\n * A batch of messages that has been virtualized as needed (grouped, compressed, chunked)\n * and is ready to be sent to the ordering service.\n */\nexport type OutboundBatch = IBatch<OutboundBatchMessage[]>;\n\n/**\n * An {@link OutboundBatch} with exactly one message\n * This type is helpful as Grouping yields this kind of batch, and Compression only operates on this type of batch.\n */\nexport type OutboundSingletonBatch = IBatch<[OutboundBatchMessage]>;\n\n/**\n * Base batch interface used internally by the runtime.\n * See {@link LocalBatch} and {@link OutboundBatch} for the concrete types.\n */\ninterface IBatch<TMessages extends LocalBatchMessage[] | OutboundBatchMessage[]> {\n\t/**\n\t * Sum of the in-memory content sizes of all messages in the batch.\n\t * If the batch is compressed, this number reflects the post-compression size.\n\t */\n\treadonly contentSizeInBytes: number;\n\t/**\n\t * All the messages in the batch\n\t */\n\treadonly messages: TMessages;\n\t/**\n\t * The reference sequence number for the batch\n\t */\n\treadonly referenceSequenceNumber: number | undefined;\n\t/**\n\t * Wether or not the batch contains at least one op which was produced as the result\n\t * of processing another op. This means that the batch must be rebased before\n\t * submitted, to ensure that all ops have the same reference sequence numbers and a\n\t * consistent view of the data model. This happens when the op is created within a\n\t * 'changed' event handler of a DDS and will have a different reference sequence number\n\t * than the rest of the ops in the batch, meaning that it has a different view of the\n\t * state of the data model, therefore all ops must be resubmitted and rebased to the current\n\t * reference sequence number to be in agreement about the data model state.\n\t */\n\treadonly hasReentrantOps?: boolean;\n}\n\nexport interface IBatchCheckpoint {\n\trollback: (action: (message: LocalBatchMessage) => void) => void;\n}\n\n/**\n * @internal\n */\nexport interface IChunkedOp {\n\tchunkId: number;\n\ttotalChunks: number;\n\tcontents: string;\n\toriginalMetadata?: Record<string, unknown>;\n\toriginalCompression?: string;\n}\n\n/**\n * The state of remote message processing:\n * `Processed` - the message can be considered processed\n * `Skipped` - the message was ignored by the processor\n * `Accepted` - the message was processed partially. Eventually, a message\n * will make the processor return `Processed`.\n */\nexport type ProcessingState = \"Processed\" | \"Skipped\" | \"Accepted\";\n"]}
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
export { BatchId, BatchManager, BatchSequenceNumbers, estimateSocketSize, getEffectiveBatchId, generateBatchId, IBatchManagerOptions, } from "./batchManager.js";
|
|
6
|
-
export {
|
|
6
|
+
export { LocalBatch, LocalBatchMessage, OutboundBatch, OutboundBatchMessage, OutboundSingletonBatch, IBatchCheckpoint, IChunkedOp, } from "./definitions.js";
|
|
7
7
|
export { DuplicateBatchDetector } from "./duplicateBatchDetector.js";
|
|
8
|
-
export {
|
|
8
|
+
export { serializeOp, ensureContentsDeserialized, } from "./opSerialization.js";
|
|
9
|
+
export { Outbox, getLongStack } from "./outbox.js";
|
|
9
10
|
export { OpCompressor } from "./opCompressor.js";
|
|
10
11
|
export { OpDecompressor } from "./opDecompressor.js";
|
|
11
12
|
export { OpSplitter, splitOp, isChunkedMessage } from "./opSplitter.js";
|
|
12
|
-
export {
|
|
13
|
+
export { InboundMessageResult, BatchStartInfo, RemoteMessageProcessor, unpackRuntimeMessage, } from "./remoteMessageProcessor.js";
|
|
13
14
|
export { OpGroupingManager, OpGroupingManagerConfig, isGroupedBatch, } from "./opGroupingManager.js";
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,OAAO,EACP,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,OAAO,EACP,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,UAAU,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,WAAW,EACX,0BAA0B,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,GACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACN,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,GACd,MAAM,wBAAwB,CAAC"}
|
package/lib/opLifecycle/index.js
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { BatchManager, estimateSocketSize, getEffectiveBatchId, generateBatchId, } from "./batchManager.js";
|
|
6
6
|
export { DuplicateBatchDetector } from "./duplicateBatchDetector.js";
|
|
7
|
-
export {
|
|
7
|
+
export { serializeOp, ensureContentsDeserialized, } from "./opSerialization.js";
|
|
8
|
+
export { Outbox, getLongStack } from "./outbox.js";
|
|
8
9
|
export { OpCompressor } from "./opCompressor.js";
|
|
9
10
|
export { OpDecompressor } from "./opDecompressor.js";
|
|
10
11
|
export { OpSplitter, splitOp, isChunkedMessage } from "./opSplitter.js";
|
|
11
|
-
export {
|
|
12
|
+
export { RemoteMessageProcessor, unpackRuntimeMessage, } from "./remoteMessageProcessor.js";
|
|
12
13
|
export { OpGroupingManager, isGroupedBatch, } from "./opGroupingManager.js";
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,YAAY,EAEZ,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,GAEf,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/opLifecycle/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,YAAY,EAEZ,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,GAEf,MAAM,mBAAmB,CAAC;AAU3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,WAAW,EACX,0BAA0B,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAGN,sBAAsB,EACtB,oBAAoB,GACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACN,iBAAiB,EAEjB,cAAc,GACd,MAAM,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tBatchId,\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tgetEffectiveBatchId,\n\tgenerateBatchId,\n\tIBatchManagerOptions,\n} from \"./batchManager.js\";\nexport {\n\tLocalBatch,\n\tLocalBatchMessage,\n\tOutboundBatch,\n\tOutboundBatchMessage,\n\tOutboundSingletonBatch,\n\tIBatchCheckpoint,\n\tIChunkedOp,\n} from \"./definitions.js\";\nexport { DuplicateBatchDetector } from \"./duplicateBatchDetector.js\";\nexport {\n\tserializeOp,\n\tensureContentsDeserialized,\n} from \"./opSerialization.js\";\nexport { Outbox, getLongStack } from \"./outbox.js\";\nexport { OpCompressor } from \"./opCompressor.js\";\nexport { OpDecompressor } from \"./opDecompressor.js\";\nexport { OpSplitter, splitOp, isChunkedMessage } from \"./opSplitter.js\";\nexport {\n\tInboundMessageResult,\n\tBatchStartInfo,\n\tRemoteMessageProcessor,\n\tunpackRuntimeMessage,\n} from \"./remoteMessageProcessor.js\";\nexport {\n\tOpGroupingManager,\n\tOpGroupingManagerConfig,\n\tisGroupedBatch,\n} from \"./opGroupingManager.js\";\n"]}
|
|
@@ -3,24 +3,23 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
6
|
-
import {
|
|
6
|
+
import { type OutboundSingletonBatch } from "./definitions.js";
|
|
7
7
|
/**
|
|
8
|
-
* Compresses batches of ops.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Compresses batches of ops.
|
|
9
|
+
*
|
|
10
|
+
* @remarks Only single-message batches are supported
|
|
11
|
+
* Use opGroupingManager to group a batch into a singleton batch suitable for compression.
|
|
11
12
|
*/
|
|
12
13
|
export declare class OpCompressor {
|
|
13
14
|
private readonly logger;
|
|
14
15
|
constructor(logger: ITelemetryBaseLogger);
|
|
15
16
|
/**
|
|
16
|
-
* Combines the contents of the batch into a single JSON string and compresses it, putting
|
|
17
|
-
* the resulting string as the
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @param batch - The batch to compress
|
|
21
|
-
* @returns A batch of the same length as the input batch, containing a single compressed message followed by empty placeholders
|
|
17
|
+
* Combines the contents of the singleton batch into a single JSON string and compresses it, putting
|
|
18
|
+
* the resulting string as the message contents in place of the original uncompressed payload.
|
|
19
|
+
* @param batch - The batch to compress. Must have only 1 message
|
|
20
|
+
* @returns A singleton batch containing a single compressed message
|
|
22
21
|
*/
|
|
23
|
-
compressBatch(batch:
|
|
22
|
+
compressBatch(batch: OutboundSingletonBatch): OutboundSingletonBatch;
|
|
24
23
|
/**
|
|
25
24
|
* Combine the batch's content strings into a single JSON string (a serialized array)
|
|
26
25
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opCompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAYvE,OAAO,
|
|
1
|
+
{"version":3,"file":"opCompressor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAYvE,OAAO,EAA6B,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1F;;;;;GAKG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAEjC,MAAM,EAAE,oBAAoB;IAIxC;;;;;OAKG;IACI,aAAa,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB;IAyC3E;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAyB9B"}
|
|
@@ -4,26 +4,25 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { IsoBuffer } from "@fluid-internal/client-utils";
|
|
6
6
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
7
|
-
import {
|
|
7
|
+
import { DataProcessingError, createChildLogger, } from "@fluidframework/telemetry-utils/internal";
|
|
8
8
|
import { compress } from "lz4js";
|
|
9
9
|
import { CompressionAlgorithms } from "../containerRuntime.js";
|
|
10
10
|
import { estimateSocketSize } from "./batchManager.js";
|
|
11
11
|
/**
|
|
12
|
-
* Compresses batches of ops.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Compresses batches of ops.
|
|
13
|
+
*
|
|
14
|
+
* @remarks Only single-message batches are supported
|
|
15
|
+
* Use opGroupingManager to group a batch into a singleton batch suitable for compression.
|
|
15
16
|
*/
|
|
16
17
|
export class OpCompressor {
|
|
17
18
|
constructor(logger) {
|
|
18
19
|
this.logger = createChildLogger({ logger, namespace: "OpCompressor" });
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
* Combines the contents of the batch into a single JSON string and compresses it, putting
|
|
22
|
-
* the resulting string as the
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* @param batch - The batch to compress
|
|
26
|
-
* @returns A batch of the same length as the input batch, containing a single compressed message followed by empty placeholders
|
|
22
|
+
* Combines the contents of the singleton batch into a single JSON string and compresses it, putting
|
|
23
|
+
* the resulting string as the message contents in place of the original uncompressed payload.
|
|
24
|
+
* @param batch - The batch to compress. Must have only 1 message
|
|
25
|
+
* @returns A singleton batch containing a single compressed message
|
|
27
26
|
*/
|
|
28
27
|
compressBatch(batch) {
|
|
29
28
|
assert(batch.contentSizeInBytes > 0 && batch.messages.length === 1, 0x5a4 /* Batch should not be empty and should contain a single message */);
|
|
@@ -61,23 +60,25 @@ export class OpCompressor {
|
|
|
61
60
|
* Combine the batch's content strings into a single JSON string (a serialized array)
|
|
62
61
|
*/
|
|
63
62
|
serializeBatchContents(batch) {
|
|
63
|
+
const [message, ...none] = batch.messages;
|
|
64
|
+
assert(none.length === 0, 0xb78 /* Batch should only contain a single message */);
|
|
64
65
|
try {
|
|
65
|
-
//
|
|
66
|
-
return `[${
|
|
66
|
+
// This is expressed as a JSON array, for legacy reasons
|
|
67
|
+
return `[${message.contents}]`;
|
|
67
68
|
}
|
|
68
|
-
catch (
|
|
69
|
-
if (
|
|
70
|
-
// This is how
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.message === "Invalid string length") {
|
|
71
|
+
// This is how string interpolation signals that
|
|
71
72
|
// the content size exceeds its capacity
|
|
72
|
-
const
|
|
73
|
+
const dpe = DataProcessingError.create("Payload too large", "OpCompressor");
|
|
73
74
|
this.logger.sendErrorEvent({
|
|
74
75
|
eventName: "BatchTooLarge",
|
|
75
76
|
size: batch.contentSizeInBytes,
|
|
76
77
|
length: batch.messages.length,
|
|
77
|
-
},
|
|
78
|
-
throw
|
|
78
|
+
}, dpe);
|
|
79
|
+
throw dpe;
|
|
79
80
|
}
|
|
80
|
-
throw
|
|
81
|
+
throw error;
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opCompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAC7D,OAAO,EACN,
|
|
1
|
+
{"version":3,"file":"opCompressor.js","sourceRoot":"","sources":["../../src/opLifecycle/opCompressor.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 { IsoBuffer } from \"@fluid-internal/client-utils\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tDataProcessingError,\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { compress } from \"lz4js\";\n\nimport { CompressionAlgorithms } from \"../containerRuntime.js\";\n\nimport { estimateSocketSize } from \"./batchManager.js\";\nimport { type OutboundBatchMessage, type OutboundSingletonBatch } from \"./definitions.js\";\n\n/**\n * Compresses batches of ops.\n *\n * @remarks Only single-message batches are supported\n * Use opGroupingManager to group a batch into a singleton batch suitable for compression.\n */\nexport class OpCompressor {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(logger: ITelemetryBaseLogger) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpCompressor\" });\n\t}\n\n\t/**\n\t * Combines the contents of the singleton batch into a single JSON string and compresses it, putting\n\t * the resulting string as the message contents in place of the original uncompressed payload.\n\t * @param batch - The batch to compress. Must have only 1 message\n\t * @returns A singleton batch containing a single compressed message\n\t */\n\tpublic compressBatch(batch: OutboundSingletonBatch): OutboundSingletonBatch {\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.messages.length === 1,\n\t\t\t0x5a4 /* Batch should not be empty and should contain a single message */,\n\t\t);\n\n\t\tconst compressionStart = Date.now();\n\t\tconst contentsAsBuffer = new TextEncoder().encode(this.serializeBatchContents(batch));\n\t\tconst compressedContents = compress(contentsAsBuffer);\n\t\tconst compressedContent = IsoBuffer.from(compressedContents).toString(\"base64\");\n\t\tconst duration = Date.now() - compressionStart;\n\n\t\tconst messages: [OutboundBatchMessage] = [\n\t\t\t{\n\t\t\t\t...batch.messages[0],\n\t\t\t\tcontents: JSON.stringify({ packedContents: compressedContent }),\n\t\t\t\tmetadata: batch.messages[0].metadata,\n\t\t\t\tcompression: CompressionAlgorithms.lz4,\n\t\t\t},\n\t\t];\n\n\t\tconst compressedBatch: OutboundSingletonBatch = {\n\t\t\tcontentSizeInBytes: compressedContent.length,\n\t\t\tmessages,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\n\t\tif (batch.contentSizeInBytes > 200000) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"CompressedBatch\",\n\t\t\t\tduration,\n\t\t\t\tsizeBeforeCompression: batch.contentSizeInBytes,\n\t\t\t\tsizeAfterCompression: compressedBatch.contentSizeInBytes,\n\t\t\t\topCount: compressedBatch.messages.length,\n\t\t\t\tsocketSize: estimateSocketSize(compressedBatch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Combine the batch's content strings into a single JSON string (a serialized array)\n\t */\n\tprivate serializeBatchContents(batch: OutboundSingletonBatch): string {\n\t\tconst [message, ...none] = batch.messages;\n\t\tassert(none.length === 0, 0xb78 /* Batch should only contain a single message */);\n\t\ttry {\n\t\t\t// This is expressed as a JSON array, for legacy reasons\n\t\t\treturn `[${message.contents}]`;\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as Partial<Error>).message === \"Invalid string length\") {\n\t\t\t\t// This is how string interpolation signals that\n\t\t\t\t// the content size exceeds its capacity\n\t\t\t\tconst dpe = DataProcessingError.create(\"Payload too large\", \"OpCompressor\");\n\t\t\t\tthis.logger.sendErrorEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"BatchTooLarge\",\n\t\t\t\t\t\tsize: batch.contentSizeInBytes,\n\t\t\t\t\t\tlength: batch.messages.length,\n\t\t\t\t\t},\n\t\t\t\t\tdpe,\n\t\t\t\t);\n\t\t\t\tthrow dpe;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
|
|
7
|
-
import {
|
|
7
|
+
import { type OutboundBatch, type OutboundBatchMessage, type OutboundSingletonBatch } from "./definitions.js";
|
|
8
8
|
export declare function isGroupedBatch(op: ISequencedDocumentMessage): boolean;
|
|
9
9
|
export interface OpGroupingManagerConfig {
|
|
10
10
|
readonly groupedBatchingEnabled: boolean;
|
|
@@ -19,19 +19,23 @@ export declare class OpGroupingManager {
|
|
|
19
19
|
* This is needed as a placeholder if a batch becomes empty on resubmit, but we are tracking batch IDs.
|
|
20
20
|
* @param resubmittingBatchId - batch ID of the resubmitting batch
|
|
21
21
|
* @param referenceSequenceNumber - reference sequence number
|
|
22
|
-
* @returns -
|
|
22
|
+
* @returns - The outbound batch as well as the interior placeholder message
|
|
23
23
|
*/
|
|
24
|
-
createEmptyGroupedBatch(resubmittingBatchId: string, referenceSequenceNumber: number):
|
|
24
|
+
createEmptyGroupedBatch(resubmittingBatchId: string, referenceSequenceNumber: number): {
|
|
25
|
+
outboundBatch: OutboundSingletonBatch;
|
|
26
|
+
placeholderMessage: OutboundBatchMessage;
|
|
27
|
+
};
|
|
25
28
|
/**
|
|
26
29
|
* Converts the given batch into a "grouped batch" - a batch with a single message of type "groupedBatch",
|
|
27
30
|
* with contents being an array of the original batch's messages.
|
|
28
31
|
*
|
|
32
|
+
* If the batch already has only 1 message, it is returned as-is.
|
|
33
|
+
*
|
|
29
34
|
* @remarks - Remember that a BatchMessage has its content JSON serialized, so the incoming batch message contents
|
|
30
35
|
* must be parsed first, and then the type and contents mentioned above are hidden in that JSON serialization.
|
|
31
36
|
*/
|
|
32
|
-
groupBatch(batch:
|
|
37
|
+
groupBatch(batch: OutboundBatch): OutboundSingletonBatch;
|
|
33
38
|
ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[];
|
|
34
|
-
shouldGroup(batch: IBatch): boolean;
|
|
35
39
|
groupedBatchingEnabled(): boolean;
|
|
36
40
|
}
|
|
37
41
|
//# sourceMappingURL=opGroupingManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opGroupingManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAMxF,OAAO,
|
|
1
|
+
{"version":3,"file":"opGroupingManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAMxF,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,MAAM,kBAAkB,CAAC;AAuB1B,wBAAgB,cAAc,CAAC,EAAE,EAAE,yBAAyB,GAAG,OAAO,CAErE;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CACzC;AAED,qBAAa,iBAAiB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,MAAM,CAAC,QAAQ,CAAC,cAAc,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,MAAM,EAAE,uBAAuB,EAChD,MAAM,EAAE,oBAAoB;IAK7B;;;;;;OAMG;IACI,uBAAuB,CAC7B,mBAAmB,EAAE,MAAM,EAC3B,uBAAuB,EAAE,MAAM,GAC7B;QAAE,aAAa,EAAE,sBAAsB,CAAC;QAAC,kBAAkB,EAAE,oBAAoB,CAAA;KAAE;IAwBtF;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,sBAAsB;IAkDxD,SAAS,CAAC,EAAE,EAAE,yBAAyB,GAAG,yBAAyB,EAAE;IAcrE,sBAAsB,IAAI,OAAO;CAGxC"}
|
|
@@ -21,36 +21,42 @@ export class OpGroupingManager {
|
|
|
21
21
|
* This is needed as a placeholder if a batch becomes empty on resubmit, but we are tracking batch IDs.
|
|
22
22
|
* @param resubmittingBatchId - batch ID of the resubmitting batch
|
|
23
23
|
* @param referenceSequenceNumber - reference sequence number
|
|
24
|
-
* @returns -
|
|
24
|
+
* @returns - The outbound batch as well as the interior placeholder message
|
|
25
25
|
*/
|
|
26
26
|
createEmptyGroupedBatch(resubmittingBatchId, referenceSequenceNumber) {
|
|
27
27
|
assert(this.config.groupedBatchingEnabled, 0xa00 /* cannot create empty grouped batch when grouped batching is disabled */);
|
|
28
|
-
const
|
|
28
|
+
const serializedOp = JSON.stringify({
|
|
29
29
|
type: OpGroupingManager.groupedBatchOp,
|
|
30
30
|
contents: [],
|
|
31
31
|
});
|
|
32
|
-
|
|
32
|
+
const placeholderMessage = {
|
|
33
|
+
metadata: { batchId: resubmittingBatchId },
|
|
34
|
+
localOpMetadata: { emptyBatch: true },
|
|
35
|
+
referenceSequenceNumber,
|
|
36
|
+
contents: serializedOp,
|
|
37
|
+
};
|
|
38
|
+
const outboundBatch = {
|
|
33
39
|
contentSizeInBytes: 0,
|
|
34
|
-
messages: [
|
|
35
|
-
{
|
|
36
|
-
metadata: { batchId: resubmittingBatchId },
|
|
37
|
-
localOpMetadata: { emptyBatch: true },
|
|
38
|
-
referenceSequenceNumber,
|
|
39
|
-
contents: serializedContent,
|
|
40
|
-
},
|
|
41
|
-
],
|
|
40
|
+
messages: [placeholderMessage],
|
|
42
41
|
referenceSequenceNumber,
|
|
43
42
|
};
|
|
43
|
+
return { outboundBatch, placeholderMessage };
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Converts the given batch into a "grouped batch" - a batch with a single message of type "groupedBatch",
|
|
47
47
|
* with contents being an array of the original batch's messages.
|
|
48
48
|
*
|
|
49
|
+
* If the batch already has only 1 message, it is returned as-is.
|
|
50
|
+
*
|
|
49
51
|
* @remarks - Remember that a BatchMessage has its content JSON serialized, so the incoming batch message contents
|
|
50
52
|
* must be parsed first, and then the type and contents mentioned above are hidden in that JSON serialization.
|
|
51
53
|
*/
|
|
52
54
|
groupBatch(batch) {
|
|
53
|
-
assert(this.
|
|
55
|
+
assert(this.groupedBatchingEnabled(), 0xb79 /* grouping disabled! */);
|
|
56
|
+
assert(batch.messages.length > 0, 0xb7a /* Unexpected attempt to group an empty batch */);
|
|
57
|
+
if (batch.messages.length === 1) {
|
|
58
|
+
return batch;
|
|
59
|
+
}
|
|
54
60
|
if (batch.messages.length >= 1000) {
|
|
55
61
|
this.logger.sendTelemetryEvent({
|
|
56
62
|
eventName: "GroupLargeBatch",
|
|
@@ -102,16 +108,6 @@ export class OpGroupingManager {
|
|
|
102
108
|
compression: subMessage.compression,
|
|
103
109
|
}));
|
|
104
110
|
}
|
|
105
|
-
shouldGroup(batch) {
|
|
106
|
-
return (
|
|
107
|
-
// Grouped batching must be enabled
|
|
108
|
-
this.config.groupedBatchingEnabled &&
|
|
109
|
-
// The number of ops in the batch must be 2 or more
|
|
110
|
-
// or be empty (to allow for empty batches to be grouped)
|
|
111
|
-
batch.messages.length !== 1
|
|
112
|
-
// Support for reentrant batches will be on by default
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
111
|
groupedBatchingEnabled() {
|
|
116
112
|
return this.config.groupedBatchingEnabled;
|
|
117
113
|
}
|