@fluidframework/container-runtime 1.4.0-115997 → 2.0.0-dev-rc.1.0.0.224419
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/.eslintrc.js +19 -29
- package/.mocharc.js +12 -0
- package/CHANGELOG.md +427 -0
- package/README.md +69 -0
- package/api-extractor-lint.json +4 -0
- package/api-extractor.json +2 -2
- package/api-report/container-runtime.api.md +863 -0
- package/dist/{batchTracker.js → batchTracker.cjs} +9 -8
- package/dist/batchTracker.cjs.map +1 -0
- package/dist/batchTracker.d.ts +6 -6
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/blobManager.cjs +704 -0
- package/dist/blobManager.cjs.map +1 -0
- package/dist/blobManager.d.ts +135 -39
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/connectionTelemetry.cjs +230 -0
- package/dist/connectionTelemetry.cjs.map +1 -0
- package/dist/connectionTelemetry.d.ts +2 -2
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/container-runtime-alpha.d.ts +1677 -0
- package/dist/container-runtime-beta.d.ts +250 -0
- package/dist/container-runtime-public.d.ts +250 -0
- package/dist/container-runtime-untrimmed.d.ts +1792 -0
- package/dist/{containerHandleContext.js → containerHandleContext.cjs} +4 -2
- package/dist/containerHandleContext.cjs.map +1 -0
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerRuntime.cjs +2531 -0
- package/dist/containerRuntime.cjs.map +1 -0
- package/dist/containerRuntime.d.ts +454 -257
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/{dataStore.js → dataStore.cjs} +54 -45
- package/dist/dataStore.cjs.map +1 -0
- package/dist/dataStore.d.ts +2 -2
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/{dataStoreContext.js → dataStoreContext.cjs} +343 -247
- package/dist/dataStoreContext.cjs.map +1 -0
- package/dist/dataStoreContext.d.ts +73 -41
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/{dataStoreContexts.js → dataStoreContexts.cjs} +19 -15
- package/dist/dataStoreContexts.cjs.map +1 -0
- package/dist/dataStoreContexts.d.ts +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/{dataStoreRegistry.js → dataStoreRegistry.cjs} +9 -4
- package/dist/dataStoreRegistry.cjs.map +1 -0
- package/dist/dataStoreRegistry.d.ts +3 -0
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/{dataStores.js → dataStores.cjs} +273 -124
- package/dist/dataStores.cjs.map +1 -0
- package/dist/dataStores.d.ts +53 -23
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/deltaManagerProxyBase.cjs +77 -0
- package/dist/deltaManagerProxyBase.cjs.map +1 -0
- package/dist/deltaManagerProxyBase.d.ts +35 -0
- package/dist/deltaManagerProxyBase.d.ts.map +1 -0
- package/dist/deltaManagerSummarizerProxy.cjs +42 -0
- package/dist/deltaManagerSummarizerProxy.cjs.map +1 -0
- package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/dist/{deltaScheduler.js → deltaScheduler.cjs} +25 -18
- package/dist/deltaScheduler.cjs.map +1 -0
- package/dist/deltaScheduler.d.ts +8 -6
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/error.cjs +21 -0
- package/dist/error.cjs.map +1 -0
- package/dist/error.d.ts +14 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/gc/garbageCollection.cjs +861 -0
- package/dist/gc/garbageCollection.cjs.map +1 -0
- package/dist/gc/garbageCollection.d.ts +224 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -0
- package/dist/gc/gcConfigs.cjs +153 -0
- package/dist/gc/gcConfigs.cjs.map +1 -0
- package/dist/gc/gcConfigs.d.ts +23 -0
- package/dist/gc/gcConfigs.d.ts.map +1 -0
- package/dist/gc/gcDefinitions.cjs +96 -0
- package/dist/gc/gcDefinitions.cjs.map +1 -0
- package/dist/gc/gcDefinitions.d.ts +437 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -0
- package/dist/gc/gcHelpers.cjs +235 -0
- package/dist/gc/gcHelpers.cjs.map +1 -0
- package/dist/gc/gcHelpers.d.ts +71 -0
- package/dist/gc/gcHelpers.d.ts.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.cjs +49 -0
- package/dist/gc/gcReferenceGraphAlgorithm.cjs.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/dist/{summarizerTypes.js → gc/gcSummaryDefinitions.cjs} +1 -6
- package/dist/gc/gcSummaryDefinitions.cjs.map +1 -0
- package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
- package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/dist/gc/gcSummaryStateTracker.cjs +213 -0
- package/dist/gc/gcSummaryStateTracker.cjs.map +1 -0
- package/dist/gc/gcSummaryStateTracker.d.ts +94 -0
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/dist/gc/gcTelemetry.cjs +298 -0
- package/dist/gc/gcTelemetry.cjs.map +1 -0
- package/dist/gc/gcTelemetry.d.ts +92 -0
- package/dist/gc/gcTelemetry.d.ts.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.cjs +118 -0
- package/dist/gc/gcUnreferencedStateTracker.cjs.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts +40 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/dist/gc/index.cjs +44 -0
- package/dist/gc/index.cjs.map +1 -0
- package/dist/gc/index.d.ts +13 -0
- package/dist/gc/index.d.ts.map +1 -0
- package/dist/index.cjs +47 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +19 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/messageTypes.cjs +37 -0
- package/dist/messageTypes.cjs.map +1 -0
- package/dist/messageTypes.d.ts +142 -0
- package/dist/messageTypes.d.ts.map +1 -0
- package/dist/metadata.cjs +7 -0
- package/dist/metadata.cjs.map +1 -0
- package/dist/metadata.d.ts +24 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/opLifecycle/batchManager.cjs +139 -0
- package/dist/opLifecycle/batchManager.cjs.map +1 -0
- package/dist/opLifecycle/batchManager.d.ts +48 -0
- package/dist/opLifecycle/batchManager.d.ts.map +1 -0
- package/dist/opLifecycle/definitions.cjs +7 -0
- package/dist/opLifecycle/definitions.cjs.map +1 -0
- package/dist/opLifecycle/definitions.d.ts +83 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -0
- package/dist/opLifecycle/index.cjs +26 -0
- package/dist/opLifecycle/index.cjs.map +1 -0
- package/dist/opLifecycle/index.d.ts +13 -0
- package/dist/opLifecycle/index.d.ts.map +1 -0
- package/dist/opLifecycle/opCompressor.cjs +84 -0
- package/dist/opLifecycle/opCompressor.cjs.map +1 -0
- package/dist/opLifecycle/opCompressor.d.ts +18 -0
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -0
- package/dist/opLifecycle/opDecompressor.cjs +132 -0
- package/dist/opLifecycle/opDecompressor.cjs.map +1 -0
- package/dist/opLifecycle/opDecompressor.d.ts +25 -0
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -0
- package/dist/opLifecycle/opGroupingManager.cjs +95 -0
- package/dist/opLifecycle/opGroupingManager.cjs.map +1 -0
- package/dist/opLifecycle/opGroupingManager.d.ts +22 -0
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/dist/opLifecycle/opSplitter.cjs +202 -0
- package/dist/opLifecycle/opSplitter.cjs.map +1 -0
- package/dist/opLifecycle/opSplitter.d.ts +61 -0
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -0
- package/dist/opLifecycle/outbox.cjs +323 -0
- package/dist/opLifecycle/outbox.cjs.map +1 -0
- package/dist/opLifecycle/outbox.d.ts +104 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -0
- package/dist/opLifecycle/remoteMessageProcessor.cjs +136 -0
- package/dist/opLifecycle/remoteMessageProcessor.cjs.map +1 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +47 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
- package/dist/opProperties.cjs +17 -0
- package/dist/opProperties.cjs.map +1 -0
- package/dist/opProperties.d.ts +7 -0
- package/dist/opProperties.d.ts.map +1 -0
- package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
- package/dist/packageVersion.cjs.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/pendingStateManager.cjs +282 -0
- package/dist/pendingStateManager.cjs.map +1 -0
- package/dist/pendingStateManager.d.ts +32 -69
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/scheduleManager.cjs +258 -0
- package/dist/scheduleManager.cjs.map +1 -0
- package/dist/scheduleManager.d.ts +31 -0
- package/dist/scheduleManager.d.ts.map +1 -0
- package/dist/storageServiceWithAttachBlobs.cjs +32 -0
- package/dist/storageServiceWithAttachBlobs.cjs.map +1 -0
- package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/dist/summary/index.cjs +51 -0
- package/dist/summary/index.cjs.map +1 -0
- package/dist/summary/index.d.ts +17 -0
- package/dist/summary/index.d.ts.map +1 -0
- package/dist/{orderedClientElection.js → summary/orderedClientElection.cjs} +100 -84
- package/dist/summary/orderedClientElection.cjs.map +1 -0
- package/{lib → dist/summary}/orderedClientElection.d.ts +41 -18
- package/dist/summary/orderedClientElection.d.ts.map +1 -0
- package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.cjs} +12 -10
- package/dist/summary/runWhileConnectedCoordinator.cjs.map +1 -0
- package/{lib → dist/summary}/runWhileConnectedCoordinator.d.ts +8 -2
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/dist/summary/runningSummarizer.cjs +679 -0
- package/dist/summary/runningSummarizer.cjs.map +1 -0
- package/dist/summary/runningSummarizer.d.ts +128 -0
- package/dist/summary/runningSummarizer.d.ts.map +1 -0
- package/dist/summary/summarizer.cjs +263 -0
- package/dist/summary/summarizer.cjs.map +1 -0
- package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +18 -34
- package/dist/summary/summarizer.d.ts.map +1 -0
- package/dist/{summarizerClientElection.js → summary/summarizerClientElection.cjs} +15 -46
- package/dist/summary/summarizerClientElection.cjs.map +1 -0
- package/{lib → dist/summary}/summarizerClientElection.d.ts +4 -4
- package/dist/summary/summarizerClientElection.d.ts.map +1 -0
- package/dist/summary/summarizerHeuristics.cjs +156 -0
- package/dist/summary/summarizerHeuristics.cjs.map +1 -0
- package/{lib → dist/summary}/summarizerHeuristics.d.ts +28 -6
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
- package/dist/summary/summarizerNode/index.cjs +12 -0
- package/dist/summary/summarizerNode/index.cjs.map +1 -0
- package/dist/summary/summarizerNode/index.d.ts +8 -0
- package/dist/summary/summarizerNode/index.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.cjs +526 -0
- package/dist/summary/summarizerNode/summarizerNode.cjs.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts +167 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.cjs +130 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.cjs.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +121 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs +375 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +153 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/dist/summary/summarizerTypes.cjs +7 -0
- package/dist/summary/summarizerTypes.cjs.map +1 -0
- package/{lib → dist/summary}/summarizerTypes.d.ts +233 -83
- package/dist/summary/summarizerTypes.d.ts.map +1 -0
- package/dist/{summaryCollection.js → summary/summaryCollection.cjs} +80 -49
- package/dist/summary/summaryCollection.cjs.map +1 -0
- package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +23 -5
- package/dist/summary/summaryCollection.d.ts.map +1 -0
- package/dist/{summaryFormat.js → summary/summaryFormat.cjs} +29 -26
- package/dist/summary/summaryFormat.cjs.map +1 -0
- package/{lib → dist/summary}/summaryFormat.d.ts +25 -30
- package/dist/summary/summaryFormat.d.ts.map +1 -0
- package/dist/{summaryGenerator.js → summary/summaryGenerator.cjs} +162 -74
- package/dist/summary/summaryGenerator.cjs.map +1 -0
- package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +53 -11
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/{summaryManager.js → summary/summaryManager.cjs} +98 -55
- package/dist/summary/summaryManager.cjs.map +1 -0
- package/{lib → dist/summary}/summaryManager.d.ts +13 -11
- package/dist/summary/summaryManager.d.ts.map +1 -0
- package/dist/{throttler.js → throttler.cjs} +21 -21
- package/dist/throttler.cjs.map +1 -0
- package/dist/throttler.d.ts +2 -2
- package/dist/throttler.d.ts.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/lib/{batchTracker.d.ts → batchTracker.d.mts} +6 -6
- package/lib/batchTracker.d.mts.map +1 -0
- package/lib/{batchTracker.js → batchTracker.mjs} +9 -8
- package/lib/batchTracker.mjs.map +1 -0
- package/lib/blobManager.d.mts +191 -0
- package/lib/blobManager.d.mts.map +1 -0
- package/lib/blobManager.mjs +699 -0
- package/lib/blobManager.mjs.map +1 -0
- package/lib/{connectionTelemetry.d.ts → connectionTelemetry.d.mts} +2 -2
- package/lib/connectionTelemetry.d.mts.map +1 -0
- package/lib/connectionTelemetry.mjs +226 -0
- package/lib/connectionTelemetry.mjs.map +1 -0
- package/lib/container-runtime-alpha.d.mts +1677 -0
- package/lib/container-runtime-beta.d.mts +250 -0
- package/lib/container-runtime-public.d.mts +250 -0
- package/lib/container-runtime-untrimmed.d.mts +1792 -0
- package/lib/{containerHandleContext.d.ts → containerHandleContext.d.mts} +1 -1
- package/lib/containerHandleContext.d.mts.map +1 -0
- package/lib/{containerHandleContext.js → containerHandleContext.mjs} +4 -2
- package/lib/containerHandleContext.mjs.map +1 -0
- package/lib/containerRuntime.d.mts +809 -0
- package/lib/containerRuntime.d.mts.map +1 -0
- package/lib/containerRuntime.mjs +2526 -0
- package/lib/containerRuntime.mjs.map +1 -0
- package/lib/{dataStore.d.ts → dataStore.d.mts} +4 -4
- package/lib/dataStore.d.mts.map +1 -0
- package/lib/{dataStore.js → dataStore.mjs} +52 -43
- package/lib/dataStore.mjs.map +1 -0
- package/lib/{dataStoreContext.d.ts → dataStoreContext.d.mts} +74 -42
- package/lib/dataStoreContext.d.mts.map +1 -0
- package/lib/{dataStoreContext.js → dataStoreContext.mjs} +309 -213
- package/lib/dataStoreContext.mjs.map +1 -0
- package/lib/{dataStoreContexts.d.ts → dataStoreContexts.d.mts} +2 -2
- package/lib/dataStoreContexts.d.mts.map +1 -0
- package/lib/{dataStoreContexts.js → dataStoreContexts.mjs} +12 -8
- package/lib/dataStoreContexts.mjs.map +1 -0
- package/lib/{dataStoreRegistry.d.ts → dataStoreRegistry.d.mts} +3 -0
- package/lib/dataStoreRegistry.d.mts.map +1 -0
- package/lib/{dataStoreRegistry.js → dataStoreRegistry.mjs} +7 -6
- package/lib/dataStoreRegistry.mjs.map +1 -0
- package/lib/{dataStores.d.ts → dataStores.d.mts} +56 -26
- package/lib/dataStores.d.mts.map +1 -0
- package/lib/{dataStores.js → dataStores.mjs} +254 -105
- package/lib/dataStores.mjs.map +1 -0
- package/lib/deltaManagerProxyBase.d.mts +35 -0
- package/lib/deltaManagerProxyBase.d.mts.map +1 -0
- package/lib/deltaManagerProxyBase.mjs +73 -0
- package/lib/deltaManagerProxyBase.mjs.map +1 -0
- package/lib/deltaManagerSummarizerProxy.d.mts +19 -0
- package/lib/deltaManagerSummarizerProxy.d.mts.map +1 -0
- package/lib/deltaManagerSummarizerProxy.mjs +38 -0
- package/lib/deltaManagerSummarizerProxy.mjs.map +1 -0
- package/lib/{deltaScheduler.d.ts → deltaScheduler.d.mts} +8 -6
- package/lib/deltaScheduler.d.mts.map +1 -0
- package/lib/{deltaScheduler.js → deltaScheduler.mjs} +22 -15
- package/lib/deltaScheduler.mjs.map +1 -0
- package/lib/error.d.mts +14 -0
- package/lib/error.d.mts.map +1 -0
- package/lib/error.mjs +17 -0
- package/lib/error.mjs.map +1 -0
- package/lib/gc/garbageCollection.d.mts +224 -0
- package/lib/gc/garbageCollection.d.mts.map +1 -0
- package/lib/gc/garbageCollection.mjs +857 -0
- package/lib/gc/garbageCollection.mjs.map +1 -0
- package/lib/gc/gcConfigs.d.mts +23 -0
- package/lib/gc/gcConfigs.d.mts.map +1 -0
- package/lib/gc/gcConfigs.mjs +149 -0
- package/lib/gc/gcConfigs.mjs.map +1 -0
- package/lib/gc/gcDefinitions.d.mts +437 -0
- package/lib/gc/gcDefinitions.d.mts.map +1 -0
- package/lib/gc/gcDefinitions.mjs +93 -0
- package/lib/gc/gcDefinitions.mjs.map +1 -0
- package/lib/gc/gcHelpers.d.mts +71 -0
- package/lib/gc/gcHelpers.d.mts.map +1 -0
- package/lib/gc/gcHelpers.mjs +222 -0
- package/lib/gc/gcHelpers.mjs.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.mts +16 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.mts.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.mjs +45 -0
- package/lib/gc/gcReferenceGraphAlgorithm.mjs.map +1 -0
- package/lib/gc/gcSummaryDefinitions.d.mts +52 -0
- package/lib/gc/gcSummaryDefinitions.d.mts.map +1 -0
- package/lib/gc/gcSummaryDefinitions.mjs +6 -0
- package/lib/gc/gcSummaryDefinitions.mjs.map +1 -0
- package/lib/gc/gcSummaryStateTracker.d.mts +94 -0
- package/lib/gc/gcSummaryStateTracker.d.mts.map +1 -0
- package/lib/gc/gcSummaryStateTracker.mjs +209 -0
- package/lib/gc/gcSummaryStateTracker.mjs.map +1 -0
- package/lib/gc/gcTelemetry.d.mts +92 -0
- package/lib/gc/gcTelemetry.d.mts.map +1 -0
- package/lib/gc/gcTelemetry.mjs +293 -0
- package/lib/gc/gcTelemetry.mjs.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.d.mts +40 -0
- package/lib/gc/gcUnreferencedStateTracker.d.mts.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.mjs +114 -0
- package/lib/gc/gcUnreferencedStateTracker.mjs.map +1 -0
- package/lib/gc/index.d.mts +13 -0
- package/lib/gc/index.d.mts.map +1 -0
- package/lib/gc/index.mjs +12 -0
- package/lib/gc/index.mjs.map +1 -0
- package/lib/index.d.mts +25 -0
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +24 -0
- package/lib/index.mjs.map +1 -0
- package/lib/messageTypes.d.mts +142 -0
- package/lib/messageTypes.d.mts.map +1 -0
- package/lib/messageTypes.mjs +34 -0
- package/lib/messageTypes.mjs.map +1 -0
- package/lib/metadata.d.mts +24 -0
- package/lib/metadata.d.mts.map +1 -0
- package/lib/metadata.mjs +6 -0
- package/lib/metadata.mjs.map +1 -0
- package/lib/opLifecycle/batchManager.d.mts +48 -0
- package/lib/opLifecycle/batchManager.d.mts.map +1 -0
- package/lib/opLifecycle/batchManager.mjs +133 -0
- package/lib/opLifecycle/batchManager.mjs.map +1 -0
- package/lib/opLifecycle/definitions.d.mts +83 -0
- package/lib/opLifecycle/definitions.d.mts.map +1 -0
- package/lib/opLifecycle/definitions.mjs +6 -0
- package/lib/opLifecycle/definitions.mjs.map +1 -0
- package/lib/opLifecycle/index.d.mts +13 -0
- package/lib/opLifecycle/index.d.mts.map +1 -0
- package/lib/opLifecycle/index.mjs +12 -0
- package/lib/opLifecycle/index.mjs.map +1 -0
- package/lib/opLifecycle/opCompressor.d.mts +18 -0
- package/lib/opLifecycle/opCompressor.d.mts.map +1 -0
- package/lib/opLifecycle/opCompressor.mjs +80 -0
- package/lib/opLifecycle/opCompressor.mjs.map +1 -0
- package/lib/opLifecycle/opDecompressor.d.mts +25 -0
- package/lib/opLifecycle/opDecompressor.d.mts.map +1 -0
- package/lib/opLifecycle/opDecompressor.mjs +128 -0
- package/lib/opLifecycle/opDecompressor.mjs.map +1 -0
- package/lib/opLifecycle/opGroupingManager.d.mts +22 -0
- package/lib/opLifecycle/opGroupingManager.d.mts.map +1 -0
- package/lib/opLifecycle/opGroupingManager.mjs +91 -0
- package/lib/opLifecycle/opGroupingManager.mjs.map +1 -0
- package/lib/opLifecycle/opSplitter.d.mts +61 -0
- package/lib/opLifecycle/opSplitter.d.mts.map +1 -0
- package/lib/opLifecycle/opSplitter.mjs +197 -0
- package/lib/opLifecycle/opSplitter.mjs.map +1 -0
- package/lib/opLifecycle/outbox.d.mts +104 -0
- package/lib/opLifecycle/outbox.d.mts.map +1 -0
- package/lib/opLifecycle/outbox.mjs +318 -0
- package/lib/opLifecycle/outbox.mjs.map +1 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.mts +47 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +1 -0
- package/lib/opLifecycle/remoteMessageProcessor.mjs +131 -0
- package/lib/opLifecycle/remoteMessageProcessor.mjs.map +1 -0
- package/lib/opProperties.d.mts +7 -0
- package/lib/opProperties.d.mts.map +1 -0
- package/lib/opProperties.mjs +13 -0
- package/lib/opProperties.mjs.map +1 -0
- package/lib/{packageVersion.d.ts → packageVersion.d.mts} +1 -1
- package/lib/{packageVersion.d.ts.map → packageVersion.d.mts.map} +1 -1
- package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
- package/lib/packageVersion.mjs.map +1 -0
- package/lib/{pendingStateManager.d.ts → pendingStateManager.d.mts} +32 -69
- package/lib/pendingStateManager.d.mts.map +1 -0
- package/lib/pendingStateManager.mjs +275 -0
- package/lib/pendingStateManager.mjs.map +1 -0
- package/lib/scheduleManager.d.mts +27 -0
- package/lib/scheduleManager.d.mts.map +1 -0
- package/lib/scheduleManager.mjs +254 -0
- package/lib/scheduleManager.mjs.map +1 -0
- package/lib/storageServiceWithAttachBlobs.d.mts +17 -0
- package/lib/storageServiceWithAttachBlobs.d.mts.map +1 -0
- package/lib/storageServiceWithAttachBlobs.mjs +28 -0
- package/lib/storageServiceWithAttachBlobs.mjs.map +1 -0
- package/lib/summary/index.d.mts +17 -0
- package/lib/summary/index.d.mts.map +1 -0
- package/lib/summary/index.mjs +16 -0
- package/lib/summary/index.mjs.map +1 -0
- package/{dist/orderedClientElection.d.ts → lib/summary/orderedClientElection.d.mts} +41 -22
- package/lib/summary/orderedClientElection.d.mts.map +1 -0
- package/lib/{orderedClientElection.js → summary/orderedClientElection.mjs} +95 -79
- package/lib/summary/orderedClientElection.mjs.map +1 -0
- package/{dist/runWhileConnectedCoordinator.d.ts → lib/summary/runWhileConnectedCoordinator.d.mts} +9 -3
- package/lib/summary/runWhileConnectedCoordinator.d.mts.map +1 -0
- package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.mjs} +12 -10
- package/lib/summary/runWhileConnectedCoordinator.mjs.map +1 -0
- package/lib/summary/runningSummarizer.d.mts +128 -0
- package/lib/summary/runningSummarizer.d.mts.map +1 -0
- package/lib/summary/runningSummarizer.mjs +675 -0
- package/lib/summary/runningSummarizer.mjs.map +1 -0
- package/lib/{summarizer.d.ts → summary/summarizer.d.mts} +20 -36
- package/lib/summary/summarizer.d.mts.map +1 -0
- package/lib/summary/summarizer.mjs +257 -0
- package/lib/summary/summarizer.mjs.map +1 -0
- package/{dist/summarizerClientElection.d.ts → lib/summary/summarizerClientElection.d.mts} +6 -6
- package/lib/summary/summarizerClientElection.d.mts.map +1 -0
- package/lib/{summarizerClientElection.js → summary/summarizerClientElection.mjs} +14 -45
- package/lib/summary/summarizerClientElection.mjs.map +1 -0
- package/{dist/summarizerHeuristics.d.ts → lib/summary/summarizerHeuristics.d.mts} +29 -7
- package/lib/summary/summarizerHeuristics.d.mts.map +1 -0
- package/lib/summary/summarizerHeuristics.mjs +151 -0
- package/lib/summary/summarizerHeuristics.mjs.map +1 -0
- package/lib/summary/summarizerNode/index.d.mts +8 -0
- package/lib/summary/summarizerNode/index.d.mts.map +1 -0
- package/lib/summary/summarizerNode/index.mjs +7 -0
- package/lib/summary/summarizerNode/index.mjs.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.d.mts +167 -0
- package/lib/summary/summarizerNode/summarizerNode.d.mts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.mjs +521 -0
- package/lib/summary/summarizerNode/summarizerNode.mjs.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts +121 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs +123 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts +153 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs +370 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +1 -0
- package/{dist/summarizerTypes.d.ts → lib/summary/summarizerTypes.d.mts} +234 -84
- package/lib/summary/summarizerTypes.d.mts.map +1 -0
- package/lib/summary/summarizerTypes.mjs +6 -0
- package/lib/summary/summarizerTypes.mjs.map +1 -0
- package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.mts} +23 -5
- package/lib/summary/summaryCollection.d.mts.map +1 -0
- package/lib/{summaryCollection.js → summary/summaryCollection.mjs} +76 -45
- package/lib/summary/summaryCollection.mjs.map +1 -0
- package/{dist/summaryFormat.d.ts → lib/summary/summaryFormat.d.mts} +25 -30
- package/lib/summary/summaryFormat.d.mts.map +1 -0
- package/lib/{summaryFormat.js → summary/summaryFormat.mjs} +30 -26
- package/lib/summary/summaryFormat.mjs.map +1 -0
- package/lib/summary/summaryGenerator.d.mts +127 -0
- package/lib/summary/summaryGenerator.d.mts.map +1 -0
- package/lib/{summaryGenerator.js → summary/summaryGenerator.mjs} +153 -67
- package/lib/summary/summaryGenerator.mjs.map +1 -0
- package/{dist/summaryManager.d.ts → lib/summary/summaryManager.d.mts} +15 -13
- package/lib/summary/summaryManager.d.mts.map +1 -0
- package/lib/{summaryManager.js → summary/summaryManager.mjs} +94 -51
- package/lib/summary/summaryManager.mjs.map +1 -0
- package/lib/{throttler.d.ts → throttler.d.mts} +2 -2
- package/lib/throttler.d.mts.map +1 -0
- package/lib/{throttler.js → throttler.mjs} +21 -21
- package/lib/throttler.mjs.map +1 -0
- package/package.json +174 -73
- package/prettier.config.cjs +8 -0
- package/src/batchTracker.ts +60 -55
- package/src/blobManager.ts +937 -294
- package/src/connectionTelemetry.ts +342 -252
- package/src/containerHandleContext.ts +27 -29
- package/src/containerRuntime.ts +3879 -3143
- package/src/dataStore.ts +170 -140
- package/src/dataStoreContext.ts +1166 -986
- package/src/dataStoreContexts.ts +176 -163
- package/src/dataStoreRegistry.ts +29 -21
- package/src/dataStores.ts +921 -678
- package/src/deltaManagerProxyBase.ts +111 -0
- package/src/deltaManagerSummarizerProxy.ts +49 -0
- package/src/deltaScheduler.ts +161 -156
- package/src/error.ts +21 -0
- package/src/gc/garbageCollection.md +106 -0
- package/src/gc/garbageCollection.ts +1153 -0
- package/src/gc/gcConfigs.ts +216 -0
- package/src/gc/gcDefinitions.ts +502 -0
- package/src/gc/gcHelpers.ts +284 -0
- package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
- package/src/gc/gcSummaryDefinitions.ts +54 -0
- package/src/gc/gcSummaryStateTracker.ts +299 -0
- package/src/gc/gcTelemetry.ts +423 -0
- package/src/gc/gcUnreferencedStateTracker.ts +153 -0
- package/src/gc/index.ts +59 -0
- package/src/index.ts +101 -74
- package/src/messageTypes.ts +238 -0
- package/src/metadata.ts +26 -0
- package/src/opLifecycle/README.md +321 -0
- package/src/opLifecycle/batchManager.ts +179 -0
- package/src/opLifecycle/definitions.ts +89 -0
- package/src/opLifecycle/index.ts +19 -0
- package/src/opLifecycle/opCompressor.ts +99 -0
- package/src/opLifecycle/opDecompressor.ts +190 -0
- package/src/opLifecycle/opGroupingManager.ts +133 -0
- package/src/opLifecycle/opSplitter.ts +279 -0
- package/src/opLifecycle/outbox.ts +471 -0
- package/src/opLifecycle/remoteMessageProcessor.ts +175 -0
- package/src/opProperties.ts +21 -0
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +396 -465
- package/src/scheduleManager.ts +358 -0
- package/src/storageServiceWithAttachBlobs.ts +38 -0
- package/src/summary/index.ts +109 -0
- package/src/summary/orderedClientElection.ts +571 -0
- package/src/summary/runWhileConnectedCoordinator.ts +117 -0
- package/src/summary/runningSummarizer.ts +920 -0
- package/src/summary/summarizer.ts +352 -0
- package/src/summary/summarizerClientElection.ts +140 -0
- package/src/summary/summarizerHeuristics.ts +227 -0
- package/src/summary/summarizerNode/index.ts +12 -0
- package/src/summary/summarizerNode/summarizerNode.ts +725 -0
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +206 -0
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +571 -0
- package/src/summary/summarizerTypes.ts +631 -0
- package/src/summary/summaryCollection.ts +474 -0
- package/src/summary/summaryFormat.ts +249 -0
- package/src/summary/summaryGenerator.ts +539 -0
- package/src/summary/summaryManager.ts +452 -0
- package/src/throttler.ts +131 -122
- package/tsc-multi.test.json +4 -0
- package/tsconfig.json +11 -13
- package/dist/batchTracker.js.map +0 -1
- package/dist/blobManager.js +0 -249
- package/dist/blobManager.js.map +0 -1
- package/dist/connectionTelemetry.js +0 -178
- package/dist/connectionTelemetry.js.map +0 -1
- package/dist/containerHandleContext.js.map +0 -1
- package/dist/containerRuntime.js +0 -2174
- package/dist/containerRuntime.js.map +0 -1
- package/dist/dataStore.js.map +0 -1
- package/dist/dataStoreContext.js.map +0 -1
- package/dist/dataStoreContexts.js.map +0 -1
- package/dist/dataStoreRegistry.js.map +0 -1
- package/dist/dataStores.js.map +0 -1
- package/dist/deltaScheduler.js.map +0 -1
- package/dist/garbageCollection.d.ts +0 -319
- package/dist/garbageCollection.d.ts.map +0 -1
- package/dist/garbageCollection.js +0 -993
- package/dist/garbageCollection.js.map +0 -1
- package/dist/index.js +0 -33
- package/dist/index.js.map +0 -1
- package/dist/opTelemetry.d.ts +0 -22
- package/dist/opTelemetry.d.ts.map +0 -1
- package/dist/opTelemetry.js +0 -60
- package/dist/opTelemetry.js.map +0 -1
- package/dist/orderedClientElection.d.ts.map +0 -1
- package/dist/orderedClientElection.js.map +0 -1
- package/dist/packageVersion.js.map +0 -1
- package/dist/pendingStateManager.js +0 -346
- package/dist/pendingStateManager.js.map +0 -1
- package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/dist/runWhileConnectedCoordinator.js.map +0 -1
- package/dist/runningSummarizer.d.ts +0 -93
- package/dist/runningSummarizer.d.ts.map +0 -1
- package/dist/runningSummarizer.js +0 -384
- package/dist/runningSummarizer.js.map +0 -1
- package/dist/serializedSnapshotStorage.d.ts +0 -58
- package/dist/serializedSnapshotStorage.d.ts.map +0 -1
- package/dist/serializedSnapshotStorage.js +0 -108
- package/dist/serializedSnapshotStorage.js.map +0 -1
- package/dist/summarizer.d.ts.map +0 -1
- package/dist/summarizer.js +0 -348
- package/dist/summarizer.js.map +0 -1
- package/dist/summarizerClientElection.d.ts.map +0 -1
- package/dist/summarizerClientElection.js.map +0 -1
- package/dist/summarizerHandle.d.ts +0 -12
- package/dist/summarizerHandle.d.ts.map +0 -1
- package/dist/summarizerHandle.js +0 -22
- package/dist/summarizerHandle.js.map +0 -1
- package/dist/summarizerHeuristics.d.ts.map +0 -1
- package/dist/summarizerHeuristics.js +0 -84
- package/dist/summarizerHeuristics.js.map +0 -1
- package/dist/summarizerTypes.d.ts.map +0 -1
- package/dist/summarizerTypes.js.map +0 -1
- package/dist/summaryCollection.d.ts.map +0 -1
- package/dist/summaryCollection.js.map +0 -1
- package/dist/summaryFormat.d.ts.map +0 -1
- package/dist/summaryFormat.js.map +0 -1
- package/dist/summaryGenerator.d.ts.map +0 -1
- package/dist/summaryGenerator.js.map +0 -1
- package/dist/summaryManager.d.ts.map +0 -1
- package/dist/summaryManager.js.map +0 -1
- package/dist/throttler.js.map +0 -1
- package/garbageCollection.md +0 -41
- package/lib/batchTracker.d.ts.map +0 -1
- package/lib/batchTracker.js.map +0 -1
- package/lib/blobManager.d.ts +0 -95
- package/lib/blobManager.d.ts.map +0 -1
- package/lib/blobManager.js +0 -244
- package/lib/blobManager.js.map +0 -1
- package/lib/connectionTelemetry.d.ts.map +0 -1
- package/lib/connectionTelemetry.js +0 -174
- package/lib/connectionTelemetry.js.map +0 -1
- package/lib/containerHandleContext.d.ts.map +0 -1
- package/lib/containerHandleContext.js.map +0 -1
- package/lib/containerRuntime.d.ts +0 -616
- package/lib/containerRuntime.d.ts.map +0 -1
- package/lib/containerRuntime.js +0 -2166
- package/lib/containerRuntime.js.map +0 -1
- package/lib/dataStore.d.ts.map +0 -1
- package/lib/dataStore.js.map +0 -1
- package/lib/dataStoreContext.d.ts.map +0 -1
- package/lib/dataStoreContext.js.map +0 -1
- package/lib/dataStoreContexts.d.ts.map +0 -1
- package/lib/dataStoreContexts.js.map +0 -1
- package/lib/dataStoreRegistry.d.ts.map +0 -1
- package/lib/dataStoreRegistry.js.map +0 -1
- package/lib/dataStores.d.ts.map +0 -1
- package/lib/dataStores.js.map +0 -1
- package/lib/deltaScheduler.d.ts.map +0 -1
- package/lib/deltaScheduler.js.map +0 -1
- package/lib/garbageCollection.d.ts +0 -319
- package/lib/garbageCollection.d.ts.map +0 -1
- package/lib/garbageCollection.js +0 -989
- package/lib/garbageCollection.js.map +0 -1
- package/lib/index.d.ts +0 -14
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -13
- package/lib/index.js.map +0 -1
- package/lib/opTelemetry.d.ts +0 -22
- package/lib/opTelemetry.d.ts.map +0 -1
- package/lib/opTelemetry.js +0 -56
- package/lib/opTelemetry.js.map +0 -1
- package/lib/orderedClientElection.d.ts.map +0 -1
- package/lib/orderedClientElection.js.map +0 -1
- package/lib/packageVersion.js.map +0 -1
- package/lib/pendingStateManager.d.ts.map +0 -1
- package/lib/pendingStateManager.js +0 -339
- package/lib/pendingStateManager.js.map +0 -1
- package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/lib/runWhileConnectedCoordinator.js.map +0 -1
- package/lib/runningSummarizer.d.ts +0 -93
- package/lib/runningSummarizer.d.ts.map +0 -1
- package/lib/runningSummarizer.js +0 -380
- package/lib/runningSummarizer.js.map +0 -1
- package/lib/serializedSnapshotStorage.d.ts +0 -58
- package/lib/serializedSnapshotStorage.d.ts.map +0 -1
- package/lib/serializedSnapshotStorage.js +0 -104
- package/lib/serializedSnapshotStorage.js.map +0 -1
- package/lib/summarizer.d.ts.map +0 -1
- package/lib/summarizer.js +0 -342
- package/lib/summarizer.js.map +0 -1
- package/lib/summarizerClientElection.d.ts.map +0 -1
- package/lib/summarizerClientElection.js.map +0 -1
- package/lib/summarizerHandle.d.ts +0 -12
- package/lib/summarizerHandle.d.ts.map +0 -1
- package/lib/summarizerHandle.js +0 -18
- package/lib/summarizerHandle.js.map +0 -1
- package/lib/summarizerHeuristics.d.ts.map +0 -1
- package/lib/summarizerHeuristics.js +0 -79
- package/lib/summarizerHeuristics.js.map +0 -1
- package/lib/summarizerTypes.d.ts.map +0 -1
- package/lib/summarizerTypes.js +0 -9
- package/lib/summarizerTypes.js.map +0 -1
- package/lib/summaryCollection.d.ts.map +0 -1
- package/lib/summaryCollection.js.map +0 -1
- package/lib/summaryFormat.d.ts.map +0 -1
- package/lib/summaryFormat.js.map +0 -1
- package/lib/summaryGenerator.d.ts +0 -85
- package/lib/summaryGenerator.d.ts.map +0 -1
- package/lib/summaryGenerator.js.map +0 -1
- package/lib/summaryManager.d.ts.map +0 -1
- package/lib/summaryManager.js.map +0 -1
- package/lib/throttler.d.ts.map +0 -1
- package/lib/throttler.js.map +0 -1
- package/src/garbageCollection.ts +0 -1434
- package/src/opTelemetry.ts +0 -71
- package/src/orderedClientElection.ts +0 -511
- package/src/runWhileConnectedCoordinator.ts +0 -106
- package/src/runningSummarizer.ts +0 -550
- package/src/serializedSnapshotStorage.ts +0 -146
- package/src/summarizer.ts +0 -438
- package/src/summarizerClientElection.ts +0 -161
- package/src/summarizerHandle.ts +0 -21
- package/src/summarizerHeuristics.ts +0 -108
- package/src/summarizerTypes.ts +0 -462
- package/src/summaryCollection.ts +0 -406
- package/src/summaryFormat.ts +0 -239
- package/src/summaryGenerator.ts +0 -427
- package/src/summaryManager.ts +0 -368
- package/tsconfig.esnext.json +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opDecompressor.mjs","sourceRoot":"","sources":["../../src/opLifecycle/opDecompressor.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 { decompress } from \"lz4js\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { IsoBuffer, Uint8ArrayToString } from \"@fluid-internal/client-utils\";\nimport { createChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { CompressionAlgorithms } from \"../containerRuntime\";\nimport { IBatchMetadata } from \"../metadata\";\nimport { IMessageProcessingResult } from \"./definitions\";\n\n/**\n * Compression makes assumptions about the shape of message contents. This interface codifies those assumptions, but does not validate them.\n */\ninterface IPackedContentsContents {\n\tpackedContents: string;\n}\n\n/**\n * State machine that \"unrolls\" contents of compressed batches of ops after decompressing them.\n * This class relies on some implicit contracts defined below:\n * 1. A compressed batch will have its first message with batch metadata set to true and compressed set to true\n * 2. Messages in the middle of a compressed batch will have neither batch metadata nor the compression property set\n * 3. The final message of a batch will have batch metadata set to false\n * 4. An individually compressed op will have undefined batch metadata and compression set to true\n */\nexport class OpDecompressor {\n\tprivate activeBatch = false;\n\tprivate rootMessageContents: any | undefined;\n\tprivate processedCount = 0;\n\tprivate readonly logger;\n\n\tconstructor(logger: ITelemetryBaseLogger) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpDecompressor\" });\n\t}\n\n\tpublic processMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tassert(\n\t\t\tmessage.compression === undefined || message.compression === CompressionAlgorithms.lz4,\n\t\t\t0x511 /* Only lz4 compression is supported */,\n\t\t);\n\n\t\tif (\n\t\t\t(message.metadata as IBatchMetadata | undefined)?.batch === true &&\n\t\t\tthis.isCompressed(message)\n\t\t) {\n\t\t\t// Beginning of a compressed batch\n\t\t\tassert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);\n\t\t\tthis.activeBatch = true;\n\n\t\t\tconst contents = IsoBuffer.from(\n\t\t\t\t(message.contents as IPackedContentsContents).packedContents,\n\t\t\t\t\"base64\",\n\t\t\t);\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = Uint8ArrayToString(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\t\t\tthis.rootMessageContents = asObj;\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\tthis.rootMessageContents !== undefined &&\n\t\t\t(message.metadata as IBatchMetadata | undefined)?.batch === undefined &&\n\t\t\tthis.activeBatch\n\t\t) {\n\t\t\tassert(message.contents === undefined, 0x512 /* Expecting empty message */);\n\n\t\t\t// Continuation of compressed batch\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, this.rootMessageContents[this.processedCount++]),\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\tthis.rootMessageContents !== undefined &&\n\t\t\t(message.metadata as IBatchMetadata | undefined)?.batch === false\n\t\t) {\n\t\t\t// End of compressed batch\n\t\t\tconst returnMessage = newMessage(\n\t\t\t\tmessage,\n\t\t\t\tthis.rootMessageContents[this.processedCount++],\n\t\t\t);\n\n\t\t\tthis.activeBatch = false;\n\t\t\tthis.rootMessageContents = undefined;\n\t\t\tthis.processedCount = 0;\n\n\t\t\treturn {\n\t\t\t\tmessage: returnMessage,\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\tif (\n\t\t\t(message.metadata as IBatchMetadata | undefined)?.batch === undefined &&\n\t\t\tthis.isCompressed(message)\n\t\t) {\n\t\t\t// Single compressed message\n\t\t\tassert(\n\t\t\t\tthis.activeBatch === false,\n\t\t\t\t0x4ba /* shouldn't receive compressed message in middle of a batch */,\n\t\t\t);\n\n\t\t\tconst contents = IsoBuffer.from(\n\t\t\t\t(message.contents as IPackedContentsContents).packedContents,\n\t\t\t\t\"base64\",\n\t\t\t);\n\t\t\tconst decompressedMessage = decompress(contents);\n\t\t\tconst intoString = new TextDecoder().decode(decompressedMessage);\n\t\t\tconst asObj = JSON.parse(intoString);\n\n\t\t\treturn {\n\t\t\t\tmessage: newMessage(message, asObj[0]),\n\t\t\t\tstate: \"Processed\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmessage,\n\t\t\tstate: \"Skipped\",\n\t\t};\n\t}\n\n\tprivate isCompressed(message: ISequencedDocumentMessage) {\n\t\tif (message.compression === CompressionAlgorithms.lz4) {\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * Back-compat self healing mechanism for ADO:3538, as loaders from\n\t\t * version client_v2.0.0-internal.1.2.0 to client_v2.0.0-internal.2.2.0 do not\n\t\t * support adding the proper compression metadata to compressed messages submitted\n\t\t * by the runtime. Should be removed after the loader reaches sufficient saturation\n\t\t * for a version greater or equal than client_v2.0.0-internal.2.2.0.\n\t\t *\n\t\t * The condition holds true for compressed messages, regardless of metadata. We are ultimately\n\t\t * looking for a message with a single property `packedContents` inside `contents`, of type 'string'\n\t\t * with a base64 encoded value.\n\t\t */\n\t\ttry {\n\t\t\tif (\n\t\t\t\tmessage.contents !== null &&\n\t\t\t\ttypeof message.contents === \"object\" &&\n\t\t\t\tObject.keys(message.contents).length === 1 &&\n\t\t\t\ttypeof (message.contents as { packedContents?: unknown }).packedContents ===\n\t\t\t\t\t\"string\" &&\n\t\t\t\t(message.contents as IPackedContentsContents).packedContents.length > 0 &&\n\t\t\t\tIsoBuffer.from(\n\t\t\t\t\t(message.contents as IPackedContentsContents).packedContents,\n\t\t\t\t\t\"base64\",\n\t\t\t\t).toString(\"base64\") ===\n\t\t\t\t\t(message.contents as IPackedContentsContents).packedContents\n\t\t\t) {\n\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"LegacyCompression\",\n\t\t\t\t\ttype: message.type,\n\t\t\t\t\tbatch: (message.metadata as IBatchMetadata | undefined)?.batch,\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n\n// We should not be mutating the input message nor its metadata\nconst newMessage = (\n\toriginalMessage: ISequencedDocumentMessage,\n\tcontents: any,\n): ISequencedDocumentMessage => ({\n\t...originalMessage,\n\tcontents,\n\tcompression: undefined,\n\t// TODO: It should already be the case that we're not modifying any metadata, not clear if/why this shallow clone should be required.\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\tmetadata: { ...(originalMessage.metadata as any) },\n});\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
6
|
+
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
7
|
+
import { IBatch } from "./definitions.mjs";
|
|
8
|
+
export interface OpGroupingManagerConfig {
|
|
9
|
+
readonly groupedBatchingEnabled: boolean;
|
|
10
|
+
readonly opCountThreshold: number;
|
|
11
|
+
readonly reentrantBatchGroupingEnabled: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class OpGroupingManager {
|
|
14
|
+
private readonly config;
|
|
15
|
+
static readonly groupedBatchOp = "groupedBatch";
|
|
16
|
+
private readonly logger;
|
|
17
|
+
constructor(config: OpGroupingManagerConfig, logger: ITelemetryBaseLogger);
|
|
18
|
+
groupBatch(batch: IBatch): IBatch;
|
|
19
|
+
ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[];
|
|
20
|
+
shouldGroup(batch: IBatch): boolean;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=opGroupingManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opGroupingManager.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opGroupingManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAGI,EAAE,yBAAyB,EAAE,MAAM,sCAAsC;OAEzE,EAAE,oBAAoB,EAAE,MAAM,iCAAiC;OAE/D,EAAE,MAAM,EAAE;AAoBjB,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,6BAA6B,EAAE,OAAO,CAAC;CAChD;AAED,qBAAa,iBAAiB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,MAAM,CAAC,QAAQ,CAAC,cAAc,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAGN,MAAM,EAAE,uBAAuB,EAChD,MAAM,EAAE,oBAAoB;IAKtB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAkDjC,SAAS,CAAC,EAAE,EAAE,yBAAyB,GAAG,yBAAyB,EAAE;IAyBrE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAU1C"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { assert } from "@fluidframework/core-utils";
|
|
6
|
+
import { createChildLogger } from "@fluidframework/telemetry-utils";
|
|
7
|
+
function isGroupContents(opContents) {
|
|
8
|
+
return opContents?.type === OpGroupingManager.groupedBatchOp;
|
|
9
|
+
}
|
|
10
|
+
export class OpGroupingManager {
|
|
11
|
+
constructor(config, logger) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.logger = createChildLogger({ logger, namespace: "OpGroupingManager" });
|
|
14
|
+
}
|
|
15
|
+
groupBatch(batch) {
|
|
16
|
+
if (!this.shouldGroup(batch)) {
|
|
17
|
+
return batch;
|
|
18
|
+
}
|
|
19
|
+
if (batch.content.length >= 1000) {
|
|
20
|
+
this.logger.sendTelemetryEvent({
|
|
21
|
+
eventName: "GroupLargeBatch",
|
|
22
|
+
length: batch.content.length,
|
|
23
|
+
threshold: this.config.opCountThreshold,
|
|
24
|
+
reentrant: batch.hasReentrantOps,
|
|
25
|
+
referenceSequenceNumber: batch.content[0].referenceSequenceNumber,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
for (const message of batch.content) {
|
|
29
|
+
if (message.metadata) {
|
|
30
|
+
const keys = Object.keys(message.metadata);
|
|
31
|
+
assert(keys.length < 2, 0x5dd /* cannot group ops with metadata */);
|
|
32
|
+
assert(keys.length === 0 || keys[0] === "batch", 0x5de /* unexpected op metadata */);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const serializedContent = JSON.stringify({
|
|
36
|
+
type: OpGroupingManager.groupedBatchOp,
|
|
37
|
+
contents: batch.content.map((message) => ({
|
|
38
|
+
contents: message.contents === undefined ? undefined : JSON.parse(message.contents),
|
|
39
|
+
metadata: message.metadata,
|
|
40
|
+
compression: message.compression,
|
|
41
|
+
})),
|
|
42
|
+
});
|
|
43
|
+
const groupedBatch = {
|
|
44
|
+
...batch,
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
localOpMetadata: undefined,
|
|
48
|
+
metadata: undefined,
|
|
49
|
+
referenceSequenceNumber: batch.content[0].referenceSequenceNumber,
|
|
50
|
+
contents: serializedContent,
|
|
51
|
+
type: OpGroupingManager.groupedBatchOp,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
return groupedBatch;
|
|
56
|
+
}
|
|
57
|
+
ungroupOp(op) {
|
|
58
|
+
let fakeCsn = 1;
|
|
59
|
+
if (!isGroupContents(op.contents)) {
|
|
60
|
+
// Align the worlds of what clientSequenceNumber represents when grouped batching is enabled
|
|
61
|
+
if (this.config.groupedBatchingEnabled) {
|
|
62
|
+
return [
|
|
63
|
+
{
|
|
64
|
+
...op,
|
|
65
|
+
clientSequenceNumber: fakeCsn,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
return [op];
|
|
70
|
+
}
|
|
71
|
+
const messages = op.contents.contents;
|
|
72
|
+
return messages.map((subMessage) => ({
|
|
73
|
+
...op,
|
|
74
|
+
clientSequenceNumber: fakeCsn++,
|
|
75
|
+
contents: subMessage.contents,
|
|
76
|
+
metadata: subMessage.metadata,
|
|
77
|
+
compression: subMessage.compression,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
shouldGroup(batch) {
|
|
81
|
+
return (
|
|
82
|
+
// Grouped batching must be enabled
|
|
83
|
+
this.config.groupedBatchingEnabled &&
|
|
84
|
+
// The number of ops in the batch must surpass the configured threshold
|
|
85
|
+
batch.content.length >= this.config.opCountThreshold &&
|
|
86
|
+
// Support for reentrant batches must be explicitly enabled
|
|
87
|
+
(this.config.reentrantBatchGroupingEnabled || batch.hasReentrantOps !== true));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
OpGroupingManager.groupedBatchOp = "groupedBatch";
|
|
91
|
+
//# sourceMappingURL=opGroupingManager.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opGroupingManager.mjs","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 { assert } from \"@fluidframework/core-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { createChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { ContainerMessageType } from \"../messageTypes\";\nimport { IBatch } from \"./definitions\";\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 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\tpublic groupBatch(batch: IBatch): IBatch {\n\t\tif (!this.shouldGroup(batch)) {\n\t\t\treturn batch;\n\t\t}\n\n\t\tif (batch.content.length >= 1000) {\n\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"GroupLargeBatch\",\n\t\t\t\tlength: batch.content.length,\n\t\t\t\tthreshold: this.config.opCountThreshold,\n\t\t\t\treentrant: batch.hasReentrantOps,\n\t\t\t\treferenceSequenceNumber: batch.content[0].referenceSequenceNumber,\n\t\t\t});\n\t\t}\n\n\t\tfor (const message of batch.content) {\n\t\t\tif (message.metadata) {\n\t\t\t\tconst keys = Object.keys(message.metadata);\n\t\t\t\tassert(keys.length < 2, 0x5dd /* cannot group ops with metadata */);\n\t\t\t\tassert(\n\t\t\t\t\tkeys.length === 0 || keys[0] === \"batch\",\n\t\t\t\t\t0x5de /* unexpected op metadata */,\n\t\t\t\t);\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.content.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 = {\n\t\t\t...batch,\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\tlocalOpMetadata: undefined,\n\t\t\t\t\tmetadata: undefined,\n\t\t\t\t\treferenceSequenceNumber: batch.content[0].referenceSequenceNumber,\n\t\t\t\t\tcontents: serializedContent,\n\t\t\t\t\ttype: OpGroupingManager.groupedBatchOp as ContainerMessageType,\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\tlet fakeCsn = 1;\n\t\tif (!isGroupContents(op.contents)) {\n\t\t\t// Align the worlds of what clientSequenceNumber represents when grouped batching is enabled\n\t\t\tif (this.config.groupedBatchingEnabled) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\t...op,\n\t\t\t\t\t\tclientSequenceNumber: fakeCsn,\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [op];\n\t\t}\n\n\t\tconst messages = op.contents.contents;\n\t\treturn messages.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\tbatch.content.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"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { IBatchMessage } from "@fluidframework/container-definitions";
|
|
6
|
+
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
7
|
+
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
8
|
+
import { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from "./definitions.mjs";
|
|
9
|
+
/**
|
|
10
|
+
* Responsible for creating and reconstructing chunked messages.
|
|
11
|
+
*/
|
|
12
|
+
export declare class OpSplitter {
|
|
13
|
+
private readonly submitBatchFn;
|
|
14
|
+
readonly chunkSizeInBytes: number;
|
|
15
|
+
private readonly maxBatchSizeInBytes;
|
|
16
|
+
private readonly chunkMap;
|
|
17
|
+
private readonly logger;
|
|
18
|
+
constructor(chunks: [string, string[]][], submitBatchFn: ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number) | undefined, chunkSizeInBytes: number, maxBatchSizeInBytes: number, logger: ITelemetryBaseLogger);
|
|
19
|
+
get isBatchChunkingEnabled(): boolean;
|
|
20
|
+
get chunks(): ReadonlyMap<string, string[]>;
|
|
21
|
+
processRemoteMessage(message: ISequencedDocumentMessage): IMessageProcessingResult;
|
|
22
|
+
clearPartialChunks(clientId: string): void;
|
|
23
|
+
private addChunk;
|
|
24
|
+
/**
|
|
25
|
+
* Splits the first op of a compressed batch in chunks, sends the chunks separately and
|
|
26
|
+
* returns a new batch composed of the last chunk and the rest of the ops in the original batch.
|
|
27
|
+
*
|
|
28
|
+
* A compressed batch is formed by one large op at the first position, followed by a series of placeholder ops
|
|
29
|
+
* which are used in order to reserve the sequence numbers for when the first op gets unrolled into the original
|
|
30
|
+
* uncompressed ops at ingestion in the runtime.
|
|
31
|
+
*
|
|
32
|
+
* If the first op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire
|
|
33
|
+
* and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.
|
|
34
|
+
*
|
|
35
|
+
* This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch
|
|
36
|
+
* and then appends the original placeholder ops. This will ensure that the batch semantics of the original (non-compressed) batch
|
|
37
|
+
* are preserved, as the original chunked op will be unrolled by the runtime when the first message in the batch is processed
|
|
38
|
+
* (as it is the last chunk).
|
|
39
|
+
*
|
|
40
|
+
* To illustrate, if the input is `[largeOp, emptyOp, emptyOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.
|
|
41
|
+
* `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4, emptyOp, emptyOp]` will be returned.
|
|
42
|
+
*
|
|
43
|
+
* @param batch - the compressed batch which needs to be processed
|
|
44
|
+
* @returns A new adjusted batch which can be sent over the wire
|
|
45
|
+
*/
|
|
46
|
+
splitFirstBatchMessage(batch: IBatch): IBatch;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.
|
|
50
|
+
*
|
|
51
|
+
* The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload
|
|
52
|
+
* exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.
|
|
53
|
+
* To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.
|
|
54
|
+
*
|
|
55
|
+
* @param op - the op to be split
|
|
56
|
+
* @param chunkSizeInBytes - how large should the chunks be
|
|
57
|
+
* @param extraOp - should an extra empty op be added to the result
|
|
58
|
+
* @returns an array of chunked ops
|
|
59
|
+
*/
|
|
60
|
+
export declare const splitOp: (op: BatchMessage, chunkSizeInBytes: number, extraOp?: boolean) => IChunkedOp[];
|
|
61
|
+
//# sourceMappingURL=opSplitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opSplitter.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAQI,EAAE,aAAa,EAAE,MAAM,uCAAuC;OAC9D,EAAE,yBAAyB,EAAE,MAAM,sCAAsC;OACzE,EAAE,oBAAoB,EAAE,MAAM,iCAAiC;OAG/D,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,wBAAwB,EAAE;AAErE;;GAEG;AACH,qBAAa,UAAU;IAOrB,OAAO,CAAC,QAAQ,CAAC,aAAa;aAGd,gBAAgB,EAAE,MAAM;IACxC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IATrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAGvB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,EACX,aAAa,EAC3B,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,uBAAuB,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,GACtE,SAAS,EACI,gBAAgB,EAAE,MAAM,EACvB,mBAAmB,EAAE,MAAM,EAC5C,MAAM,EAAE,oBAAoB;IAM7B,IAAW,sBAAsB,IAAI,OAAO,CAE3C;IAED,IAAW,MAAM,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAEjD;IAEM,oBAAoB,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB;IAsClF,kBAAkB,CAAC,QAAQ,EAAE,MAAM;IAM1C,OAAO,CAAC,QAAQ;IA0BhB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAkEpD;AAoBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,OACf,YAAY,oBACE,MAAM,YACf,OAAO,KACd,UAAU,EAqCZ,CAAC"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { createChildLogger, DataCorruptionError, extractSafePropertiesFromMessage, } from "@fluidframework/telemetry-utils";
|
|
6
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
|
+
import { ContainerMessageType } from "../messageTypes.mjs";
|
|
8
|
+
import { estimateSocketSize } from "./batchManager.mjs";
|
|
9
|
+
/**
|
|
10
|
+
* Responsible for creating and reconstructing chunked messages.
|
|
11
|
+
*/
|
|
12
|
+
export class OpSplitter {
|
|
13
|
+
constructor(chunks, submitBatchFn, chunkSizeInBytes, maxBatchSizeInBytes, logger) {
|
|
14
|
+
this.submitBatchFn = submitBatchFn;
|
|
15
|
+
this.chunkSizeInBytes = chunkSizeInBytes;
|
|
16
|
+
this.maxBatchSizeInBytes = maxBatchSizeInBytes;
|
|
17
|
+
this.chunkMap = new Map(chunks);
|
|
18
|
+
this.logger = createChildLogger({ logger, namespace: "OpSplitter" });
|
|
19
|
+
}
|
|
20
|
+
get isBatchChunkingEnabled() {
|
|
21
|
+
return this.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined;
|
|
22
|
+
}
|
|
23
|
+
get chunks() {
|
|
24
|
+
return this.chunkMap;
|
|
25
|
+
}
|
|
26
|
+
processRemoteMessage(message) {
|
|
27
|
+
if (message.type !== ContainerMessageType.ChunkedOp) {
|
|
28
|
+
return {
|
|
29
|
+
message,
|
|
30
|
+
state: "Skipped",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
35
|
+
const clientId = message.clientId;
|
|
36
|
+
const chunkedContent = message.contents;
|
|
37
|
+
this.addChunk(clientId, chunkedContent, message);
|
|
38
|
+
if (chunkedContent.chunkId < chunkedContent.totalChunks) {
|
|
39
|
+
// We are processing the op in chunks but haven't reached
|
|
40
|
+
// the last chunk yet in order to reconstruct the original op
|
|
41
|
+
return {
|
|
42
|
+
message,
|
|
43
|
+
state: "Accepted",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
47
|
+
const serializedContent = this.chunkMap.get(clientId).join("");
|
|
48
|
+
this.clearPartialChunks(clientId);
|
|
49
|
+
const newMessage = { ...message };
|
|
50
|
+
newMessage.contents = serializedContent === "" ? undefined : JSON.parse(serializedContent);
|
|
51
|
+
newMessage.type = chunkedContent.originalType;
|
|
52
|
+
newMessage.metadata = chunkedContent.originalMetadata;
|
|
53
|
+
newMessage.compression = chunkedContent.originalCompression;
|
|
54
|
+
return {
|
|
55
|
+
message: newMessage,
|
|
56
|
+
state: "Processed",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
clearPartialChunks(clientId) {
|
|
60
|
+
if (this.chunkMap.has(clientId)) {
|
|
61
|
+
this.chunkMap.delete(clientId);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
addChunk(clientId, chunkedContent, originalMessage) {
|
|
65
|
+
let map = this.chunkMap.get(clientId);
|
|
66
|
+
if (map === undefined) {
|
|
67
|
+
map = [];
|
|
68
|
+
this.chunkMap.set(clientId, map);
|
|
69
|
+
}
|
|
70
|
+
if (chunkedContent.chunkId !== map.length + 1) {
|
|
71
|
+
// We are expecting the chunks to be processed sequentially, in the same order as they are sent.
|
|
72
|
+
// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)
|
|
73
|
+
// holding the existing chunks for that particular clientId.
|
|
74
|
+
throw new DataCorruptionError("Chunk Id mismatch", {
|
|
75
|
+
...extractSafePropertiesFromMessage(originalMessage),
|
|
76
|
+
chunkMapLength: map.length,
|
|
77
|
+
chunkId: chunkedContent.chunkId,
|
|
78
|
+
totalChunks: chunkedContent.totalChunks,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
map.push(chunkedContent.contents);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Splits the first op of a compressed batch in chunks, sends the chunks separately and
|
|
85
|
+
* returns a new batch composed of the last chunk and the rest of the ops in the original batch.
|
|
86
|
+
*
|
|
87
|
+
* A compressed batch is formed by one large op at the first position, followed by a series of placeholder ops
|
|
88
|
+
* which are used in order to reserve the sequence numbers for when the first op gets unrolled into the original
|
|
89
|
+
* uncompressed ops at ingestion in the runtime.
|
|
90
|
+
*
|
|
91
|
+
* If the first op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire
|
|
92
|
+
* and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.
|
|
93
|
+
*
|
|
94
|
+
* This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch
|
|
95
|
+
* and then appends the original placeholder ops. This will ensure that the batch semantics of the original (non-compressed) batch
|
|
96
|
+
* are preserved, as the original chunked op will be unrolled by the runtime when the first message in the batch is processed
|
|
97
|
+
* (as it is the last chunk).
|
|
98
|
+
*
|
|
99
|
+
* To illustrate, if the input is `[largeOp, emptyOp, emptyOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.
|
|
100
|
+
* `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4, emptyOp, emptyOp]` will be returned.
|
|
101
|
+
*
|
|
102
|
+
* @param batch - the compressed batch which needs to be processed
|
|
103
|
+
* @returns A new adjusted batch which can be sent over the wire
|
|
104
|
+
*/
|
|
105
|
+
splitFirstBatchMessage(batch) {
|
|
106
|
+
assert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);
|
|
107
|
+
assert(batch.contentSizeInBytes > 0 && batch.content.length > 0, 0x514 /* Batch needs to be non-empty */);
|
|
108
|
+
assert(batch.referenceSequenceNumber !== undefined, 0x58a /* Batch must have a reference sequence number if non-empty */);
|
|
109
|
+
assert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);
|
|
110
|
+
assert(this.chunkSizeInBytes < this.maxBatchSizeInBytes, 0x516 /* Chunk size needs to be smaller than the max batch size */);
|
|
111
|
+
const firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split
|
|
112
|
+
assert((firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes, 0x518 /* First message in the batch needs to be chunkable */);
|
|
113
|
+
const restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers
|
|
114
|
+
const socketSize = estimateSocketSize(batch);
|
|
115
|
+
const chunks = splitOp(firstMessage, this.chunkSizeInBytes,
|
|
116
|
+
// If we estimate that the socket batch size will exceed the batch limit
|
|
117
|
+
// we will inject an empty op to minimize the risk of the payload failing due to
|
|
118
|
+
// the overhead from the trailing empty ops in the batch.
|
|
119
|
+
socketSize >= this.maxBatchSizeInBytes);
|
|
120
|
+
assert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);
|
|
121
|
+
// Send the first N-1 chunks immediately
|
|
122
|
+
for (const chunk of chunks.slice(0, -1)) {
|
|
123
|
+
this.submitBatchFn([chunkToBatchMessage(chunk, batch.referenceSequenceNumber)], batch.referenceSequenceNumber);
|
|
124
|
+
}
|
|
125
|
+
// The last chunk will be part of the new batch and needs to
|
|
126
|
+
// preserve the batch metadata of the original batch
|
|
127
|
+
const lastChunk = chunkToBatchMessage(chunks[chunks.length - 1], batch.referenceSequenceNumber, { batch: firstMessage.metadata?.batch });
|
|
128
|
+
this.logger.sendPerformanceEvent({
|
|
129
|
+
// Used to be "Chunked compressed batch"
|
|
130
|
+
eventName: "CompressedChunkedBatch",
|
|
131
|
+
length: batch.content.length,
|
|
132
|
+
sizeInBytes: batch.contentSizeInBytes,
|
|
133
|
+
chunks: chunks.length,
|
|
134
|
+
chunkSizeInBytes: this.chunkSizeInBytes,
|
|
135
|
+
socketSize,
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
content: [lastChunk, ...restOfMessages],
|
|
139
|
+
contentSizeInBytes: lastChunk.contents?.length ?? 0,
|
|
140
|
+
referenceSequenceNumber: batch.referenceSequenceNumber,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const chunkToBatchMessage = (chunk, referenceSequenceNumber, metadata = undefined) => {
|
|
145
|
+
const payload = {
|
|
146
|
+
type: ContainerMessageType.ChunkedOp,
|
|
147
|
+
contents: chunk,
|
|
148
|
+
};
|
|
149
|
+
return {
|
|
150
|
+
contents: JSON.stringify(payload),
|
|
151
|
+
type: payload.type,
|
|
152
|
+
metadata,
|
|
153
|
+
localOpMetadata: undefined,
|
|
154
|
+
referenceSequenceNumber,
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.
|
|
159
|
+
*
|
|
160
|
+
* The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload
|
|
161
|
+
* exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.
|
|
162
|
+
* To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.
|
|
163
|
+
*
|
|
164
|
+
* @param op - the op to be split
|
|
165
|
+
* @param chunkSizeInBytes - how large should the chunks be
|
|
166
|
+
* @param extraOp - should an extra empty op be added to the result
|
|
167
|
+
* @returns an array of chunked ops
|
|
168
|
+
*/
|
|
169
|
+
export const splitOp = (op, chunkSizeInBytes, extraOp = false) => {
|
|
170
|
+
const chunks = [];
|
|
171
|
+
assert(op.contents !== undefined && op.contents !== null, 0x51a /* We should have something to chunk */);
|
|
172
|
+
const contentLength = op.contents.length;
|
|
173
|
+
const chunkCount = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);
|
|
174
|
+
let offset = 0;
|
|
175
|
+
for (let chunkId = 1; chunkId <= chunkCount; chunkId++) {
|
|
176
|
+
const chunk = {
|
|
177
|
+
chunkId,
|
|
178
|
+
contents: op.contents.substr(offset, chunkSizeInBytes),
|
|
179
|
+
originalType: op.type,
|
|
180
|
+
totalChunks: chunkCount,
|
|
181
|
+
};
|
|
182
|
+
if (chunkId === chunkCount) {
|
|
183
|
+
// We don't need to port these to all the chunks,
|
|
184
|
+
// as we rebuild the original op when we process the
|
|
185
|
+
// last chunk, therefore it is the only one that needs it.
|
|
186
|
+
chunk.originalMetadata = op.metadata;
|
|
187
|
+
chunk.originalCompression = op.compression;
|
|
188
|
+
}
|
|
189
|
+
chunks.push(chunk);
|
|
190
|
+
offset += chunkSizeInBytes;
|
|
191
|
+
assert(chunkId >= chunkCount - 1 || offset <= contentLength, 0x58b /* Content offset within bounds */);
|
|
192
|
+
}
|
|
193
|
+
assert(offset >= contentLength, 0x58c /* Content offset equal or larger than content length */);
|
|
194
|
+
assert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);
|
|
195
|
+
return chunks;
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=opSplitter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opSplitter.mjs","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EACN,iBAAiB,EACjB,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,iCAAiC;OACjC,EAAE,MAAM,EAAE,MAAM,4BAA4B;OAI5C,EAAE,oBAAoB,EAAoC;OAC1D,EAAE,kBAAkB,EAAE;AAG7B;;GAEG;AACH,MAAM,OAAO,UAAU;IAKtB,YACC,MAA4B,EACX,aAEL,EACI,gBAAwB,EACvB,mBAA2B,EAC5C,MAA4B;QALX,kBAAa,GAAb,aAAa,CAElB;QACI,qBAAgB,GAAhB,gBAAgB,CAAQ;QACvB,wBAAmB,GAAnB,mBAAmB,CAAQ;QAG5C,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAmB,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,IAAW,sBAAsB;QAChC,OAAO,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,iBAAiB,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC;IAC7F,CAAC;IAED,IAAW,MAAM;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,oBAAoB,CAAC,OAAkC;QAC7D,IAAI,OAAO,CAAC,IAAI,KAAK,oBAAoB,CAAC,SAAS,EAAE;YACpD,OAAO;gBACN,OAAO;gBACP,KAAK,EAAE,SAAS;aAChB,CAAC;SACF;QAED,+FAA+F;QAC/F,4EAA4E;QAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAkB,CAAC;QAC5C,MAAM,cAAc,GAAG,OAAO,CAAC,QAAsB,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEjD,IAAI,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,WAAW,EAAE;YACxD,yDAAyD;YACzD,6DAA6D;YAC7D,OAAO;gBACN,OAAO;gBACP,KAAK,EAAE,UAAU;aACjB,CAAC;SACF;QAED,oEAAoE;QACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAElC,MAAM,UAAU,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;QAClC,UAAU,CAAC,QAAQ,GAAG,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC3F,UAAU,CAAC,IAAI,GAAG,cAAc,CAAC,YAAY,CAAC;QAC9C,UAAU,CAAC,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC;QACtD,UAAU,CAAC,WAAW,GAAG,cAAc,CAAC,mBAAmB,CAAC;QAC5D,OAAO;YACN,OAAO,EAAE,UAAU;YACnB,KAAK,EAAE,WAAW;SAClB,CAAC;IACH,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAChC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;SAC/B;IACF,CAAC;IAEO,QAAQ,CACf,QAAgB,EAChB,cAA0B,EAC1B,eAA0C;QAE1C,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS,EAAE;YACtB,GAAG,GAAG,EAAE,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;SACjC;QAED,IAAI,cAAc,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9C,gGAAgG;YAChG,sGAAsG;YACtG,4DAA4D;YAC5D,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,EAAE;gBAClD,GAAG,gCAAgC,CAAC,eAAe,CAAC;gBACpD,cAAc,EAAE,GAAG,CAAC,MAAM;gBAC1B,OAAO,EAAE,cAAc,CAAC,OAAO;gBAC/B,WAAW,EAAE,cAAc,CAAC,WAAW;aACvC,CAAC,CAAC;SACH;QAED,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,sBAAsB,CAAC,KAAa;QAC1C,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC9E,MAAM,CACL,KAAK,CAAC,kBAAkB,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EACxD,KAAK,CAAC,iCAAiC,CACvC,CAAC;QACF,MAAM,CACL,KAAK,CAAC,uBAAuB,KAAK,SAAS,EAC3C,KAAK,CAAC,8DAA8D,CACpE,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,EAAE,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACjF,MAAM,CACL,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,EAChD,KAAK,CAAC,4DAA4D,CAClE,CAAC;QAEF,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,wEAAwE;QAC/G,MAAM,CACL,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAC7D,KAAK,CAAC,sDAAsD,CAC5D,CAAC;QAEF,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,uEAAuE;QACtH,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,OAAO,CACrB,YAAY,EACZ,IAAI,CAAC,gBAAgB;QACrB,wEAAwE;QACxE,gFAAgF;QAChF,yDAAyD;QACzD,UAAU,IAAI,IAAI,CAAC,mBAAmB,CACtC,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACnF,wCAAwC;QACxC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACxC,IAAI,CAAC,aAAa,CACjB,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC,EAC3D,KAAK,CAAC,uBAAuB,CAC7B,CAAC;SACF;QAED,4DAA4D;QAC5D,oDAAoD;QACpD,MAAM,SAAS,GAAG,mBAAmB,CACpC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EACzB,KAAK,CAAC,uBAAuB,EAC7B,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,CACvC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,wCAAwC;YACxC,SAAS,EAAE,wBAAwB;YACnC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;YAC5B,WAAW,EAAE,KAAK,CAAC,kBAAkB;YACrC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,UAAU;SACV,CAAC,CAAC;QAEH,OAAO;YACN,OAAO,EAAE,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC;YACvC,kBAAkB,EAAE,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;YACnD,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;SACtD,CAAC;IACH,CAAC;CACD;AAED,MAAM,mBAAmB,GAAG,CAC3B,KAAiB,EACjB,uBAA+B,EAC/B,WAAgD,SAAS,EAC1C,EAAE;IACjB,MAAM,OAAO,GAAqC;QACjD,IAAI,EAAE,oBAAoB,CAAC,SAAS;QACpC,QAAQ,EAAE,KAAK;KACf,CAAC;IACF,OAAO;QACN,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QACjC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ;QACR,eAAe,EAAE,SAAS;QAC1B,uBAAuB;KACvB,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACtB,EAAgB,EAChB,gBAAwB,EACxB,UAAmB,KAAK,EACT,EAAE;IACjB,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,MAAM,CACL,EAAE,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,CAAC,QAAQ,KAAK,IAAI,EACjD,KAAK,CAAC,uCAAuC,CAC7C,CAAC;IAEF,MAAM,aAAa,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE;QACvD,MAAM,KAAK,GAAe;YACzB,OAAO;YACP,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC;YACtD,YAAY,EAAE,EAAE,CAAC,IAAI;YACrB,WAAW,EAAE,UAAU;SACvB,CAAC;QAEF,IAAI,OAAO,KAAK,UAAU,EAAE;YAC3B,iDAAiD;YACjD,oDAAoD;YACpD,0DAA0D;YAC1D,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,QAAQ,CAAC;YACrC,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,WAAW,CAAC;SAC3C;QAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,MAAM,IAAI,gBAAgB,CAAC;QAC3B,MAAM,CACL,OAAO,IAAI,UAAU,GAAG,CAAC,IAAI,MAAM,IAAI,aAAa,EACpD,KAAK,CAAC,kCAAkC,CACxC,CAAC;KACF;IAED,MAAM,CAAC,MAAM,IAAI,aAAa,EAAE,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAChG,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tcreateChildLogger,\n\tDataCorruptionError,\n\textractSafePropertiesFromMessage,\n} from \"@fluidframework/telemetry-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { ContainerMessageType, ContainerRuntimeChunkedOpMessage } from \"../messageTypes\";\nimport { estimateSocketSize } from \"./batchManager\";\nimport { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from \"./definitions\";\n\n/**\n * Responsible for creating and reconstructing chunked messages.\n */\nexport class OpSplitter {\n\t// Local copy of incomplete received chunks.\n\tprivate readonly chunkMap: Map<string, string[]>;\n\tprivate readonly logger;\n\n\tconstructor(\n\t\tchunks: [string, string[]][],\n\t\tprivate readonly submitBatchFn:\n\t\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t\t| undefined,\n\t\tpublic readonly chunkSizeInBytes: number,\n\t\tprivate readonly maxBatchSizeInBytes: number,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.chunkMap = new Map<string, string[]>(chunks);\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpSplitter\" });\n\t}\n\n\tpublic get isBatchChunkingEnabled(): boolean {\n\t\treturn this.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined;\n\t}\n\n\tpublic get chunks(): ReadonlyMap<string, string[]> {\n\t\treturn this.chunkMap;\n\t}\n\n\tpublic processRemoteMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tif (message.type !== ContainerMessageType.ChunkedOp) {\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Skipped\",\n\t\t\t};\n\t\t}\n\n\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\tconst clientId = message.clientId as string;\n\t\tconst chunkedContent = message.contents as IChunkedOp;\n\t\tthis.addChunk(clientId, chunkedContent, message);\n\n\t\tif (chunkedContent.chunkId < chunkedContent.totalChunks) {\n\t\t\t// We are processing the op in chunks but haven't reached\n\t\t\t// the last chunk yet in order to reconstruct the original op\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst serializedContent = this.chunkMap.get(clientId)!.join(\"\");\n\t\tthis.clearPartialChunks(clientId);\n\n\t\tconst newMessage = { ...message };\n\t\tnewMessage.contents = serializedContent === \"\" ? undefined : JSON.parse(serializedContent);\n\t\tnewMessage.type = chunkedContent.originalType;\n\t\tnewMessage.metadata = chunkedContent.originalMetadata;\n\t\tnewMessage.compression = chunkedContent.originalCompression;\n\t\treturn {\n\t\t\tmessage: newMessage,\n\t\t\tstate: \"Processed\",\n\t\t};\n\t}\n\n\tpublic clearPartialChunks(clientId: string) {\n\t\tif (this.chunkMap.has(clientId)) {\n\t\t\tthis.chunkMap.delete(clientId);\n\t\t}\n\t}\n\n\tprivate addChunk(\n\t\tclientId: string,\n\t\tchunkedContent: IChunkedOp,\n\t\toriginalMessage: ISequencedDocumentMessage,\n\t) {\n\t\tlet map = this.chunkMap.get(clientId);\n\t\tif (map === undefined) {\n\t\t\tmap = [];\n\t\t\tthis.chunkMap.set(clientId, map);\n\t\t}\n\n\t\tif (chunkedContent.chunkId !== map.length + 1) {\n\t\t\t// We are expecting the chunks to be processed sequentially, in the same order as they are sent.\n\t\t\t// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)\n\t\t\t// holding the existing chunks for that particular clientId.\n\t\t\tthrow new DataCorruptionError(\"Chunk Id mismatch\", {\n\t\t\t\t...extractSafePropertiesFromMessage(originalMessage),\n\t\t\t\tchunkMapLength: map.length,\n\t\t\t\tchunkId: chunkedContent.chunkId,\n\t\t\t\ttotalChunks: chunkedContent.totalChunks,\n\t\t\t});\n\t\t}\n\n\t\tmap.push(chunkedContent.contents);\n\t}\n\n\t/**\n\t * Splits the first op of a compressed batch in chunks, sends the chunks separately and\n\t * returns a new batch composed of the last chunk and the rest of the ops in the original batch.\n\t *\n\t * A compressed batch is formed by one large op at the first position, followed by a series of placeholder ops\n\t * which are used in order to reserve the sequence numbers for when the first op gets unrolled into the original\n\t * uncompressed ops at ingestion in the runtime.\n\t *\n\t * If the first op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire\n\t * and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.\n\t *\n\t * This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch\n\t * and then appends the original placeholder ops. This will ensure that the batch semantics of the original (non-compressed) batch\n\t * are preserved, as the original chunked op will be unrolled by the runtime when the first message in the batch is processed\n\t * (as it is the last chunk).\n\t *\n\t * To illustrate, if the input is `[largeOp, emptyOp, emptyOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.\n\t * `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4, emptyOp, emptyOp]` will be returned.\n\t *\n\t * @param batch - the compressed batch which needs to be processed\n\t * @returns A new adjusted batch which can be sent over the wire\n\t */\n\tpublic splitFirstBatchMessage(batch: IBatch): IBatch {\n\t\tassert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.content.length > 0,\n\t\t\t0x514 /* Batch needs to be non-empty */,\n\t\t);\n\t\tassert(\n\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t0x58a /* Batch must have a reference sequence number if non-empty */,\n\t\t);\n\t\tassert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);\n\t\tassert(\n\t\t\tthis.chunkSizeInBytes < this.maxBatchSizeInBytes,\n\t\t\t0x516 /* Chunk size needs to be smaller than the max batch size */,\n\t\t);\n\n\t\tconst firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split\n\t\tassert(\n\t\t\t(firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,\n\t\t\t0x518 /* First message in the batch needs to be chunkable */,\n\t\t);\n\n\t\tconst restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tconst chunks = splitOp(\n\t\t\tfirstMessage,\n\t\t\tthis.chunkSizeInBytes,\n\t\t\t// If we estimate that the socket batch size will exceed the batch limit\n\t\t\t// we will inject an empty op to minimize the risk of the payload failing due to\n\t\t\t// the overhead from the trailing empty ops in the batch.\n\t\t\tsocketSize >= this.maxBatchSizeInBytes,\n\t\t);\n\n\t\tassert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);\n\t\t// Send the first N-1 chunks immediately\n\t\tfor (const chunk of chunks.slice(0, -1)) {\n\t\t\tthis.submitBatchFn(\n\t\t\t\t[chunkToBatchMessage(chunk, batch.referenceSequenceNumber)],\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// The last chunk will be part of the new batch and needs to\n\t\t// preserve the batch metadata of the original batch\n\t\tconst lastChunk = chunkToBatchMessage(\n\t\t\tchunks[chunks.length - 1],\n\t\t\tbatch.referenceSequenceNumber,\n\t\t\t{ batch: firstMessage.metadata?.batch },\n\t\t);\n\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\t// Used to be \"Chunked compressed batch\"\n\t\t\teventName: \"CompressedChunkedBatch\",\n\t\t\tlength: batch.content.length,\n\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\tchunks: chunks.length,\n\t\t\tchunkSizeInBytes: this.chunkSizeInBytes,\n\t\t\tsocketSize,\n\t\t});\n\n\t\treturn {\n\t\t\tcontent: [lastChunk, ...restOfMessages],\n\t\t\tcontentSizeInBytes: lastChunk.contents?.length ?? 0,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\t}\n}\n\nconst chunkToBatchMessage = (\n\tchunk: IChunkedOp,\n\treferenceSequenceNumber: number,\n\tmetadata: Record<string, unknown> | undefined = undefined,\n): BatchMessage => {\n\tconst payload: ContainerRuntimeChunkedOpMessage = {\n\t\ttype: ContainerMessageType.ChunkedOp,\n\t\tcontents: chunk,\n\t};\n\treturn {\n\t\tcontents: JSON.stringify(payload),\n\t\ttype: payload.type,\n\t\tmetadata,\n\t\tlocalOpMetadata: undefined,\n\t\treferenceSequenceNumber,\n\t};\n};\n\n/**\n * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.\n *\n * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload\n * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.\n * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.\n *\n * @param op - the op to be split\n * @param chunkSizeInBytes - how large should the chunks be\n * @param extraOp - should an extra empty op be added to the result\n * @returns an array of chunked ops\n */\nexport const splitOp = (\n\top: BatchMessage,\n\tchunkSizeInBytes: number,\n\textraOp: boolean = false,\n): IChunkedOp[] => {\n\tconst chunks: IChunkedOp[] = [];\n\tassert(\n\t\top.contents !== undefined && op.contents !== null,\n\t\t0x51a /* We should have something to chunk */,\n\t);\n\n\tconst contentLength = op.contents.length;\n\tconst chunkCount = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);\n\tlet offset = 0;\n\tfor (let chunkId = 1; chunkId <= chunkCount; chunkId++) {\n\t\tconst chunk: IChunkedOp = {\n\t\t\tchunkId,\n\t\t\tcontents: op.contents.substr(offset, chunkSizeInBytes),\n\t\t\toriginalType: op.type,\n\t\t\ttotalChunks: chunkCount,\n\t\t};\n\n\t\tif (chunkId === chunkCount) {\n\t\t\t// We don't need to port these to all the chunks,\n\t\t\t// as we rebuild the original op when we process the\n\t\t\t// last chunk, therefore it is the only one that needs it.\n\t\t\tchunk.originalMetadata = op.metadata;\n\t\t\tchunk.originalCompression = op.compression;\n\t\t}\n\n\t\tchunks.push(chunk);\n\t\toffset += chunkSizeInBytes;\n\t\tassert(\n\t\t\tchunkId >= chunkCount - 1 || offset <= contentLength,\n\t\t\t0x58b /* Content offset within bounds */,\n\t\t);\n\t}\n\n\tassert(offset >= contentLength, 0x58c /* Content offset equal or larger than content length */);\n\tassert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);\n\treturn chunks;\n};\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { IBatchMessage, ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
6
|
+
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
7
|
+
import { ICompressionRuntimeOptions } from "../containerRuntime.mjs";
|
|
8
|
+
import { IPendingBatchMessage, PendingStateManager } from "../pendingStateManager.mjs";
|
|
9
|
+
import { BatchSequenceNumbers } from "./batchManager.mjs";
|
|
10
|
+
import { BatchMessage, IBatch } from "./definitions.mjs";
|
|
11
|
+
import { OpCompressor } from "./opCompressor.mjs";
|
|
12
|
+
import { OpGroupingManager } from "./opGroupingManager.mjs";
|
|
13
|
+
import { OpSplitter } from "./opSplitter.mjs";
|
|
14
|
+
export interface IOutboxConfig {
|
|
15
|
+
readonly compressionOptions: ICompressionRuntimeOptions;
|
|
16
|
+
readonly maxBatchSizeInBytes: number;
|
|
17
|
+
readonly disablePartialFlush: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface IOutboxParameters {
|
|
20
|
+
readonly shouldSend: () => boolean;
|
|
21
|
+
readonly pendingStateManager: PendingStateManager;
|
|
22
|
+
readonly submitBatchFn: ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number) | undefined;
|
|
23
|
+
readonly legacySendBatchFn: (batch: IBatch) => void;
|
|
24
|
+
readonly config: IOutboxConfig;
|
|
25
|
+
readonly compressor: OpCompressor;
|
|
26
|
+
readonly splitter: OpSplitter;
|
|
27
|
+
readonly logger: ITelemetryBaseLogger;
|
|
28
|
+
readonly groupingManager: OpGroupingManager;
|
|
29
|
+
readonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;
|
|
30
|
+
readonly reSubmit: (message: IPendingBatchMessage) => void;
|
|
31
|
+
readonly opReentrancy: () => boolean;
|
|
32
|
+
readonly closeContainer: (error?: ICriticalContainerError) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Temporarily increase the stack limit while executing the provided action.
|
|
36
|
+
* If a negative value is provided for `length`, no stack frames will be collected.
|
|
37
|
+
* If Infinity is provided, all frames will be collected.
|
|
38
|
+
*
|
|
39
|
+
* ADO:4663 - add this to the common packages.
|
|
40
|
+
*
|
|
41
|
+
* @param action - action which returns an error
|
|
42
|
+
* @param length - number of stack frames to collect, 50 if unspecified.
|
|
43
|
+
* @returns the result of the action provided
|
|
44
|
+
*/
|
|
45
|
+
export declare function getLongStack<T>(action: () => T, length?: number): T;
|
|
46
|
+
export declare class Outbox {
|
|
47
|
+
private readonly params;
|
|
48
|
+
private readonly mc;
|
|
49
|
+
private readonly attachFlowBatch;
|
|
50
|
+
private readonly mainBatch;
|
|
51
|
+
private readonly blobAttachBatch;
|
|
52
|
+
private readonly idAllocationBatch;
|
|
53
|
+
private readonly defaultAttachFlowSoftLimitInBytes;
|
|
54
|
+
private batchRebasesToReport;
|
|
55
|
+
private rebasing;
|
|
56
|
+
/**
|
|
57
|
+
* Track the number of ops which were detected to have a mismatched
|
|
58
|
+
* reference sequence number, in order to self-throttle the telemetry events.
|
|
59
|
+
*
|
|
60
|
+
* This should be removed as part of ADO:2322
|
|
61
|
+
*/
|
|
62
|
+
private readonly maxMismatchedOpsToReport;
|
|
63
|
+
private mismatchedOpsReported;
|
|
64
|
+
constructor(params: IOutboxParameters);
|
|
65
|
+
get messageCount(): number;
|
|
66
|
+
get isEmpty(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* If we detect that the reference sequence number of the incoming message does not match
|
|
69
|
+
* what was already in the batch managers, this means that batching has been interrupted so
|
|
70
|
+
* we will flush the accumulated messages to account for that and create a new batch with the new
|
|
71
|
+
* message as the first message.
|
|
72
|
+
*/
|
|
73
|
+
private maybeFlushPartialBatch;
|
|
74
|
+
submit(message: BatchMessage): void;
|
|
75
|
+
submitAttach(message: BatchMessage): void;
|
|
76
|
+
submitBlobAttach(message: BatchMessage): void;
|
|
77
|
+
submitIdAllocation(message: BatchMessage): void;
|
|
78
|
+
private addMessageToBatchManager;
|
|
79
|
+
flush(): void;
|
|
80
|
+
private flushAll;
|
|
81
|
+
private flushInternal;
|
|
82
|
+
/**
|
|
83
|
+
* Rebases a batch. All the ops in the batch are resubmitted to the runtime and
|
|
84
|
+
* they will end up back in the same batch manager they were flushed from and subsequently flushed.
|
|
85
|
+
*
|
|
86
|
+
* @param rawBatch - the batch to be rebased
|
|
87
|
+
*/
|
|
88
|
+
private rebase;
|
|
89
|
+
private isContextReentrant;
|
|
90
|
+
private compressBatch;
|
|
91
|
+
/**
|
|
92
|
+
* Sends the batch object to the container context to be sent over the wire.
|
|
93
|
+
*
|
|
94
|
+
* @param batch - batch to be sent
|
|
95
|
+
*/
|
|
96
|
+
private sendBatch;
|
|
97
|
+
private persistBatch;
|
|
98
|
+
checkpoint(): {
|
|
99
|
+
mainBatch: import("./definitions").IBatchCheckpoint;
|
|
100
|
+
attachFlowBatch: import("./definitions").IBatchCheckpoint;
|
|
101
|
+
blobAttachBatch: import("./definitions").IBatchCheckpoint;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=outbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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"}
|