@fluidframework/container-runtime 2.0.0-internal.3.1.0 → 2.0.0-internal.3.2.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/dist/blobManager.d.ts +6 -0
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +31 -6
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +17 -15
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +158 -121
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +21 -12
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +76 -50
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +9 -10
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +42 -49
- package/dist/dataStores.js.map +1 -1
- package/dist/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +5 -200
- package/dist/gc/garbageCollection.d.ts.map +1 -0
- package/dist/{garbageCollection.js → gc/garbageCollection.js} +77 -353
- package/dist/gc/garbageCollection.js.map +1 -0
- package/dist/gc/gcDefinitions.d.ts +189 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -0
- package/dist/{garbageCollectionConstants.js → gc/gcDefinitions.js} +24 -2
- package/dist/gc/gcDefinitions.js.map +1 -0
- package/{lib/garbageCollectionHelpers.d.ts → dist/gc/gcHelpers.d.ts} +5 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -0
- package/dist/{garbageCollectionHelpers.js → gc/gcHelpers.js} +27 -7
- package/dist/gc/gcHelpers.js.map +1 -0
- package/dist/gc/gcSummaryStateTracker.d.ts +86 -0
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/dist/gc/gcSummaryStateTracker.js +246 -0
- package/dist/gc/gcSummaryStateTracker.js.map +1 -0
- package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
- package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.js +94 -0
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
- package/dist/gc/index.d.ts +11 -0
- package/dist/gc/index.d.ts.map +1 -0
- package/dist/gc/index.js +40 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -9
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +2 -13
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +7 -36
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +4 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +1 -0
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +20 -12
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +19 -3
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +59 -28
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +1 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +14 -9
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/index.d.ts +17 -0
- package/dist/summary/index.d.ts.map +1 -0
- package/dist/summary/index.js +47 -0
- package/dist/summary/index.js.map +1 -0
- package/dist/summary/orderedClientElection.d.ts.map +1 -0
- package/dist/summary/orderedClientElection.js.map +1 -0
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
- package/dist/summary/runningSummarizer.d.ts.map +1 -0
- package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +158 -56
- package/dist/summary/runningSummarizer.js.map +1 -0
- package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +2 -4
- package/dist/summary/summarizer.d.ts.map +1 -0
- package/dist/{summarizer.js → summary/summarizer.js} +1 -61
- package/dist/summary/summarizer.js.map +1 -0
- package/dist/summary/summarizerClientElection.d.ts.map +1 -0
- package/dist/summary/summarizerClientElection.js.map +1 -0
- package/dist/summary/summarizerHandle.d.ts.map +1 -0
- package/dist/summary/summarizerHandle.js.map +1 -0
- package/dist/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +1 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
- package/dist/summary/summarizerHeuristics.js.map +1 -0
- package/{lib → dist/summary}/summarizerTypes.d.ts +1 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -0
- package/dist/summary/summarizerTypes.js.map +1 -0
- package/dist/summary/summaryCollection.d.ts.map +1 -0
- package/dist/summary/summaryCollection.js.map +1 -0
- package/{lib → dist/summary}/summaryFormat.d.ts +1 -43
- package/dist/summary/summaryFormat.d.ts.map +1 -0
- package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
- package/dist/summary/summaryFormat.js.map +1 -0
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +1 -2
- package/dist/summary/summaryGenerator.js.map +1 -0
- package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -0
- package/dist/summary/summaryManager.js.map +1 -0
- package/lib/blobManager.d.ts +6 -0
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +28 -3
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +17 -15
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +127 -90
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +21 -12
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +64 -38
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +9 -10
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +33 -40
- package/lib/dataStores.js.map +1 -1
- package/lib/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +5 -200
- package/lib/gc/garbageCollection.d.ts.map +1 -0
- package/lib/{garbageCollection.js → gc/garbageCollection.js} +44 -319
- package/lib/gc/garbageCollection.js.map +1 -0
- package/lib/gc/gcDefinitions.d.ts +189 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -0
- package/lib/{garbageCollectionConstants.js → gc/gcDefinitions.js} +23 -1
- package/lib/gc/gcDefinitions.js.map +1 -0
- package/{dist/garbageCollectionHelpers.d.ts → lib/gc/gcHelpers.d.ts} +5 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -0
- package/lib/{garbageCollectionHelpers.js → gc/gcHelpers.js} +20 -2
- package/lib/gc/gcHelpers.js.map +1 -0
- package/lib/gc/gcSummaryStateTracker.d.ts +86 -0
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/lib/gc/gcSummaryStateTracker.js +242 -0
- package/lib/gc/gcSummaryStateTracker.js.map +1 -0
- package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
- package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
- package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.js +90 -0
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
- package/lib/gc/index.d.ts +11 -0
- package/lib/gc/index.d.ts.map +1 -0
- package/lib/gc/index.js +11 -0
- package/lib/gc/index.js.map +1 -0
- package/lib/index.d.ts +2 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -4
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +2 -13
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +7 -36
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +4 -0
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +1 -0
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +20 -12
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +19 -3
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +60 -29
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +1 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +14 -9
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/index.d.ts +17 -0
- package/lib/summary/index.d.ts.map +1 -0
- package/lib/summary/index.js +16 -0
- package/lib/summary/index.js.map +1 -0
- package/lib/summary/orderedClientElection.d.ts.map +1 -0
- package/lib/summary/orderedClientElection.js.map +1 -0
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
- package/lib/summary/runningSummarizer.d.ts.map +1 -0
- package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +159 -57
- package/lib/summary/runningSummarizer.js.map +1 -0
- package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +2 -4
- package/lib/summary/summarizer.d.ts.map +1 -0
- package/lib/{summarizer.js → summary/summarizer.js} +3 -63
- package/lib/summary/summarizer.js.map +1 -0
- package/lib/summary/summarizerClientElection.d.ts.map +1 -0
- package/lib/summary/summarizerClientElection.js.map +1 -0
- package/lib/summary/summarizerHandle.d.ts.map +1 -0
- package/lib/summary/summarizerHandle.js.map +1 -0
- package/lib/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +1 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
- package/lib/summary/summarizerHeuristics.js.map +1 -0
- package/{dist → lib/summary}/summarizerTypes.d.ts +1 -1
- package/lib/summary/summarizerTypes.d.ts.map +1 -0
- package/lib/summary/summarizerTypes.js.map +1 -0
- package/lib/summary/summaryCollection.d.ts.map +1 -0
- package/lib/summary/summaryCollection.js.map +1 -0
- package/{dist → lib/summary}/summaryFormat.d.ts +1 -43
- package/lib/summary/summaryFormat.d.ts.map +1 -0
- package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
- package/lib/summary/summaryFormat.js.map +1 -0
- package/lib/summary/summaryGenerator.d.ts.map +1 -0
- package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +1 -2
- package/lib/summary/summaryGenerator.js.map +1 -0
- package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -0
- package/lib/summary/summaryManager.js.map +1 -0
- package/package.json +125 -122
- package/src/blobManager.ts +33 -3
- package/src/containerRuntime.ts +178 -106
- package/src/dataStoreContext.ts +90 -49
- package/src/dataStores.ts +44 -51
- package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
- package/src/{garbageCollection.ts → gc/garbageCollection.ts} +90 -560
- package/src/gc/gcDefinitions.ts +244 -0
- package/src/{garbageCollectionHelpers.ts → gc/gcHelpers.ts} +26 -1
- package/src/gc/gcSummaryStateTracker.ts +339 -0
- package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
- package/src/gc/gcUnreferencedStateTracker.ts +114 -0
- package/src/gc/index.ts +40 -0
- package/src/index.ts +10 -14
- package/src/opLifecycle/batchManager.ts +7 -54
- package/src/opLifecycle/definitions.ts +4 -0
- package/src/opLifecycle/opCompressor.ts +1 -0
- package/src/opLifecycle/opSplitter.ts +33 -14
- package/src/opLifecycle/outbox.ts +84 -38
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +26 -14
- package/src/summary/index.ts +99 -0
- package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +279 -139
- package/src/{summarizer.ts → summary/summarizer.ts} +5 -76
- package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +1 -1
- package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +1 -1
- package/src/{summaryFormat.ts → summary/summaryFormat.ts} +1 -53
- package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +9 -9
- package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
- package/dist/garbageCollection.d.ts.map +0 -1
- package/dist/garbageCollection.js.map +0 -1
- package/dist/garbageCollectionConstants.d.ts +0 -26
- package/dist/garbageCollectionConstants.d.ts.map +0 -1
- package/dist/garbageCollectionConstants.js.map +0 -1
- package/dist/garbageCollectionHelpers.d.ts.map +0 -1
- package/dist/garbageCollectionHelpers.js.map +0 -1
- package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/dist/gcSweepReadyUsageDetection.js.map +0 -1
- package/dist/orderedClientElection.d.ts.map +0 -1
- package/dist/orderedClientElection.js.map +0 -1
- package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/dist/runWhileConnectedCoordinator.js.map +0 -1
- package/dist/runningSummarizer.d.ts.map +0 -1
- package/dist/runningSummarizer.js.map +0 -1
- package/dist/summarizer.d.ts.map +0 -1
- 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.map +0 -1
- package/dist/summarizerHandle.js.map +0 -1
- package/dist/summarizerHeuristics.d.ts.map +0 -1
- 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/lib/garbageCollection.d.ts.map +0 -1
- package/lib/garbageCollection.js.map +0 -1
- package/lib/garbageCollectionConstants.d.ts +0 -26
- package/lib/garbageCollectionConstants.d.ts.map +0 -1
- package/lib/garbageCollectionConstants.js.map +0 -1
- package/lib/garbageCollectionHelpers.d.ts.map +0 -1
- package/lib/garbageCollectionHelpers.js.map +0 -1
- package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/lib/gcSweepReadyUsageDetection.js.map +0 -1
- package/lib/orderedClientElection.d.ts.map +0 -1
- package/lib/orderedClientElection.js.map +0 -1
- package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/lib/runWhileConnectedCoordinator.js.map +0 -1
- package/lib/runningSummarizer.d.ts.map +0 -1
- package/lib/runningSummarizer.js.map +0 -1
- package/lib/summarizer.d.ts.map +0 -1
- 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.map +0 -1
- package/lib/summarizerHandle.js.map +0 -1
- package/lib/summarizerHeuristics.d.ts.map +0 -1
- package/lib/summarizerHeuristics.js.map +0 -1
- package/lib/summarizerTypes.d.ts.map +0 -1
- 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.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/src/garbageCollectionConstants.ts +0 -44
- /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
- /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
- /package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
- /package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
- /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
- /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
- /package/dist/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
- /package/dist/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
- /package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +0 -0
- /package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
- /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
- /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
- /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
- /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
- /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
- /package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
- /package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
- /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
- /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
- /package/lib/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
- /package/lib/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
- /package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +0 -0
- /package/lib/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
- /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
- /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
- /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
- /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
- /package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +0 -0
- /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
- /package/src/{summarizerHandle.ts → summary/summarizerHandle.ts} +0 -0
- /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
|
@@ -3,33 +3,71 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { assert } from "@fluidframework/common-utils";
|
|
6
|
-
import { GenericError } from "@fluidframework/container-utils";
|
|
6
|
+
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
7
7
|
import { MessageType } from "@fluidframework/protocol-definitions";
|
|
8
|
+
import { ChildLogger, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
|
|
8
9
|
import { BatchManager } from "./batchManager";
|
|
9
10
|
export class Outbox {
|
|
10
11
|
constructor(params) {
|
|
11
12
|
this.params = params;
|
|
12
|
-
this.defaultAttachFlowSoftLimitInBytes =
|
|
13
|
+
this.defaultAttachFlowSoftLimitInBytes = 320 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Track the number of ops which were detected to have a mismatched
|
|
16
|
+
* reference sequence number, in order to self-throttle the telemetry events.
|
|
17
|
+
*
|
|
18
|
+
* This should be removed as part of ADO:2322
|
|
19
|
+
*/
|
|
20
|
+
this.maxMismatchedOpsToReport = 3;
|
|
21
|
+
this.mismatchedOpsReported = 0;
|
|
22
|
+
this.mc = loggerToMonitoringContext(ChildLogger.create(params.logger, "Outbox"));
|
|
13
23
|
const isCompressionEnabled = this.params.config.compressionOptions.minimumBatchSizeInBytes !==
|
|
14
24
|
Number.POSITIVE_INFINITY;
|
|
15
25
|
// We need to allow infinite size batches if we enable compression
|
|
16
26
|
const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
|
|
17
27
|
const softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;
|
|
18
|
-
this.attachFlowBatch = new BatchManager({
|
|
19
|
-
|
|
20
|
-
softLimit,
|
|
21
|
-
enableOpReentryCheck: params.config.enableOpReentryCheck,
|
|
22
|
-
}, params.logger);
|
|
23
|
-
this.mainBatch = new BatchManager({
|
|
24
|
-
hardLimit,
|
|
25
|
-
enableOpReentryCheck: params.config.enableOpReentryCheck,
|
|
26
|
-
}, params.logger);
|
|
28
|
+
this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
|
|
29
|
+
this.mainBatch = new BatchManager({ hardLimit });
|
|
27
30
|
}
|
|
28
31
|
get isEmpty() {
|
|
29
32
|
return this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;
|
|
30
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* If we detect that the reference sequence number of the incoming message does not match
|
|
36
|
+
* what was already in the batch managers, this means that batching has been interrupted so
|
|
37
|
+
* we will flush the accumulated messages to account for that and create a new batch with the new
|
|
38
|
+
* message as the first message.
|
|
39
|
+
*
|
|
40
|
+
* @param message - the incoming message
|
|
41
|
+
*/
|
|
42
|
+
maybeFlushPartialBatch(message) {
|
|
43
|
+
const mainBatchReference = this.mainBatch.referenceSequenceNumber;
|
|
44
|
+
const attachFlowBatchReference = this.attachFlowBatch.referenceSequenceNumber;
|
|
45
|
+
assert(this.params.config.disablePartialFlush ||
|
|
46
|
+
mainBatchReference === undefined ||
|
|
47
|
+
attachFlowBatchReference === undefined ||
|
|
48
|
+
mainBatchReference === attachFlowBatchReference, 0x58d /* Reference sequence numbers from both batches must be in sync */);
|
|
49
|
+
if ((mainBatchReference === undefined ||
|
|
50
|
+
mainBatchReference === message.referenceSequenceNumber) &&
|
|
51
|
+
(attachFlowBatchReference === undefined ||
|
|
52
|
+
attachFlowBatchReference === message.referenceSequenceNumber)) {
|
|
53
|
+
// The reference sequence numbers are stable, there is nothing to do
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {
|
|
57
|
+
this.mc.logger.sendErrorEvent({
|
|
58
|
+
eventName: "ReferenceSequenceNumberMismatch",
|
|
59
|
+
mainReferenceSequenceNumber: mainBatchReference,
|
|
60
|
+
attachReferenceSequenceNumber: attachFlowBatchReference,
|
|
61
|
+
messageReferenceSequenceNumber: message.referenceSequenceNumber,
|
|
62
|
+
}, new UsageError("Submission of an out of order message"));
|
|
63
|
+
}
|
|
64
|
+
if (!this.params.config.disablePartialFlush) {
|
|
65
|
+
this.flush();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
31
68
|
submit(message) {
|
|
32
69
|
var _a, _b;
|
|
70
|
+
this.maybeFlushPartialBatch(message);
|
|
33
71
|
if (!this.mainBatch.push(message)) {
|
|
34
72
|
throw new GenericError("BatchTooLarge", /* error */ undefined, {
|
|
35
73
|
opSize: (_b = (_a = message.contents) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
@@ -41,6 +79,7 @@ export class Outbox {
|
|
|
41
79
|
}
|
|
42
80
|
submitAttach(message) {
|
|
43
81
|
var _a, _b;
|
|
82
|
+
this.maybeFlushPartialBatch(message);
|
|
44
83
|
if (!this.attachFlowBatch.push(message)) {
|
|
45
84
|
// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
|
|
46
85
|
// when queue is not empty.
|
|
@@ -71,8 +110,8 @@ export class Outbox {
|
|
|
71
110
|
}
|
|
72
111
|
flushInternal(rawBatch) {
|
|
73
112
|
const processedBatch = this.compressBatch(rawBatch);
|
|
74
|
-
|
|
75
|
-
this.persistBatch(
|
|
113
|
+
this.sendBatch(processedBatch);
|
|
114
|
+
this.persistBatch(rawBatch.content);
|
|
76
115
|
}
|
|
77
116
|
compressBatch(batch) {
|
|
78
117
|
if (batch.content.length === 0 ||
|
|
@@ -103,17 +142,14 @@ export class Outbox {
|
|
|
103
142
|
* Sends the batch object to the container context to be sent over the wire.
|
|
104
143
|
*
|
|
105
144
|
* @param batch - batch to be sent
|
|
106
|
-
* @returns the client sequence number of the last batched op which was sent and
|
|
107
|
-
* -1 if there are no ops or the container cannot send ops.
|
|
108
145
|
*/
|
|
109
146
|
sendBatch(batch) {
|
|
110
147
|
var _a;
|
|
111
|
-
let clientSequenceNumber = -1;
|
|
112
148
|
const length = batch.content.length;
|
|
113
149
|
// Did we disconnect in the middle of turn-based batch?
|
|
114
150
|
// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
|
|
115
151
|
if (length === 0 || !this.params.shouldSend()) {
|
|
116
|
-
return
|
|
152
|
+
return;
|
|
117
153
|
}
|
|
118
154
|
if (this.params.containerContext.submitBatchFn === undefined) {
|
|
119
155
|
// Legacy path - supporting old loader versions. Can be removed only when LTS moves above
|
|
@@ -123,31 +159,26 @@ export class Outbox {
|
|
|
123
159
|
if ((_a = message.metadata) === null || _a === void 0 ? void 0 : _a.compressed) {
|
|
124
160
|
delete message.metadata.compressed;
|
|
125
161
|
}
|
|
126
|
-
|
|
162
|
+
this.params.containerContext.submitFn(MessageType.Operation, message.deserializedContent, true, // batch
|
|
127
163
|
message.metadata);
|
|
128
164
|
}
|
|
129
165
|
this.params.containerContext.deltaManager.flush();
|
|
130
166
|
}
|
|
131
167
|
else {
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
assert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);
|
|
169
|
+
this.params.containerContext.submitBatchFn(batch.content.map((message) => ({
|
|
134
170
|
contents: message.contents,
|
|
135
171
|
metadata: message.metadata,
|
|
136
172
|
compression: message.compression,
|
|
137
|
-
|
|
173
|
+
referenceSequenceNumber: message.referenceSequenceNumber,
|
|
174
|
+
})), batch.referenceSequenceNumber);
|
|
138
175
|
}
|
|
139
|
-
// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.
|
|
140
|
-
clientSequenceNumber -= length - 1;
|
|
141
|
-
assert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);
|
|
142
|
-
return clientSequenceNumber;
|
|
143
176
|
}
|
|
144
|
-
persistBatch(
|
|
145
|
-
let clientSequenceNumber = initialClientSequenceNumber;
|
|
177
|
+
persistBatch(batch) {
|
|
146
178
|
// Let the PendingStateManager know that a message was submitted.
|
|
147
179
|
// In future, need to shift toward keeping batch as a whole!
|
|
148
180
|
for (const message of batch) {
|
|
149
|
-
this.params.pendingStateManager.onSubmitMessage(message.deserializedContent.type,
|
|
150
|
-
clientSequenceNumber++;
|
|
181
|
+
this.params.pendingStateManager.onSubmitMessage(message.deserializedContent.type, message.referenceSequenceNumber, message.deserializedContent.contents, message.localOpMetadata, message.metadata);
|
|
151
182
|
}
|
|
152
183
|
}
|
|
153
184
|
checkpoint() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainerContext } from \"@fluidframework/container-definitions\";\nimport { GenericError } from \"@fluidframework/container-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { PendingStateManager } from \"../pendingStateManager\";\nimport { BatchManager } from \"./batchManager\";\nimport { BatchMessage, IBatch } from \"./definitions\";\nimport { OpCompressor } from \"./opCompressor\";\nimport { OpSplitter } from \"./opSplitter\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly enableOpReentryCheck?: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly containerContext: IContainerContext;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryLogger;\n}\n\nexport class Outbox {\n\tprivate readonly attachFlowBatch: BatchManager;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly defaultAttachFlowSoftLimitInBytes = 64 * 1024;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\t\tconst softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;\n\n\t\tthis.attachFlowBatch = new BatchManager(\n\t\t\t{\n\t\t\t\thardLimit,\n\t\t\t\tsoftLimit,\n\t\t\t\tenableOpReentryCheck: params.config.enableOpReentryCheck,\n\t\t\t},\n\t\t\tparams.logger,\n\t\t);\n\t\tthis.mainBatch = new BatchManager(\n\t\t\t{\n\t\t\t\thardLimit,\n\t\t\t\tenableOpReentryCheck: params.config.enableOpReentryCheck,\n\t\t\t},\n\t\t\tparams.logger,\n\t\t);\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tif (!this.mainBatch.push(message)) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: this.mainBatch.contentSizeInBytes,\n\t\t\t\tcount: this.mainBatch.length,\n\t\t\t\tlimit: this.mainBatch.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic submitAttach(message: BatchMessage) {\n\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\t\tbatchSize: this.attachFlowBatch.contentSizeInBytes,\n\t\t\t\t\tcount: this.attachFlowBatch.length,\n\t\t\t\t\tlimit: this.attachFlowBatch.options.hardLimit,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.attachFlowBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\tthis.flushInternal(this.mainBatch.popBatch());\n\t}\n\n\tprivate flushInternal(rawBatch: IBatch) {\n\t\tconst processedBatch = this.compressBatch(rawBatch);\n\t\tconst clientSequenceNumber = this.sendBatch(processedBatch);\n\n\t\tthis.persistBatch(clientSequenceNumber, rawBatch.content);\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes > batch.contentSizeInBytes\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\t\tif (compressedBatch.contentSizeInBytes <= this.params.config.maxBatchSizeInBytes) {\n\t\t\t// If we don't reach the maximum supported size of a batch, it can safely be sent as is\n\t\t\treturn compressedBatch;\n\t\t}\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn this.params.splitter.splitCompressedBatch(compressedBatch);\n\t\t}\n\n\t\t// If we've reached this point, the runtime would attempt to send a batch larger than the allowed size\n\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\tcount: compressedBatch.content.length,\n\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t});\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the client sequence number of the last batched op which was sent and\n\t * -1 if there are no ops or the container cannot send ops.\n\t */\n\tprivate sendBatch(batch: IBatch): number {\n\t\tlet clientSequenceNumber: number = -1;\n\t\tconst length = batch.content.length;\n\n\t\t// Did we disconnect in the middle of turn-based batch?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\tif (length === 0 || !this.params.shouldSend()) {\n\t\t\treturn clientSequenceNumber;\n\t\t}\n\n\t\tif (this.params.containerContext.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tfor (const message of batch.content) {\n\t\t\t\t// Legacy path doesn't support compressed payloads and will submit uncompressed payload anyways\n\t\t\t\tif (message.metadata?.compressed) {\n\t\t\t\t\tdelete message.metadata.compressed;\n\t\t\t\t}\n\n\t\t\t\tclientSequenceNumber = this.params.containerContext.submitFn(\n\t\t\t\t\tMessageType.Operation,\n\t\t\t\t\tmessage.deserializedContent,\n\t\t\t\t\ttrue, // batch\n\t\t\t\t\tmessage.metadata,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.params.containerContext.deltaManager.flush();\n\t\t} else {\n\t\t\t// returns clientSequenceNumber of last message in a batch\n\t\t\tclientSequenceNumber = this.params.containerContext.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t})),\n\t\t\t);\n\t\t}\n\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\tprivate persistBatch(initialClientSequenceNumber: number, batch: BatchMessage[]) {\n\t\tlet clientSequenceNumber = initialClientSequenceNumber;\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\tmessage.deserializedContent.type,\n\t\t\t\tclientSequenceNumber,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.deserializedContent.contents,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\n\t\t\tclientSequenceNumber++;\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\treturn {\n\t\t\tmainBatch: this.mainBatch.checkpoint(),\n\t\t\tattachFlowBatch: this.attachFlowBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainerContext } from \"@fluidframework/container-definitions\";\nimport { GenericError, UsageError } from \"@fluidframework/container-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tChildLogger,\n\tloggerToMonitoringContext,\n\tMonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { PendingStateManager } from \"../pendingStateManager\";\nimport { BatchManager } from \"./batchManager\";\nimport { BatchMessage, IBatch } from \"./definitions\";\nimport { OpCompressor } from \"./opCompressor\";\nimport { OpSplitter } from \"./opSplitter\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly containerContext: IContainerContext;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryLogger;\n}\n\nexport class Outbox {\n\tprivate readonly mc: MonitoringContext;\n\tprivate readonly attachFlowBatch: BatchManager;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.mc = loggerToMonitoringContext(ChildLogger.create(params.logger, \"Outbox\"));\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\t\tconst softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;\n\n\t\tthis.attachFlowBatch = new BatchManager({ hardLimit, softLimit });\n\t\tthis.mainBatch = new BatchManager({ hardLimit });\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;\n\t}\n\n\t/**\n\t * If we detect that the reference sequence number of the incoming message does not match\n\t * what was already in the batch managers, this means that batching has been interrupted so\n\t * we will flush the accumulated messages to account for that and create a new batch with the new\n\t * message as the first message.\n\t *\n\t * @param message - the incoming message\n\t */\n\tprivate maybeFlushPartialBatch(message: BatchMessage) {\n\t\tconst mainBatchReference = this.mainBatch.referenceSequenceNumber;\n\t\tconst attachFlowBatchReference = this.attachFlowBatch.referenceSequenceNumber;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\tmainBatchReference === undefined ||\n\t\t\t\tattachFlowBatchReference === undefined ||\n\t\t\t\tmainBatchReference === attachFlowBatchReference,\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tif (\n\t\t\t(mainBatchReference === undefined ||\n\t\t\t\tmainBatchReference === message.referenceSequenceNumber) &&\n\t\t\t(attachFlowBatchReference === undefined ||\n\t\t\t\tattachFlowBatchReference === message.referenceSequenceNumber)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchReference,\n\t\t\t\t\tattachReferenceSequenceNumber: attachFlowBatchReference,\n\t\t\t\t\tmessageReferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"Submission of an out of order message\"),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flush();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch(message);\n\n\t\tif (!this.mainBatch.push(message)) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: this.mainBatch.contentSizeInBytes,\n\t\t\t\tcount: this.mainBatch.length,\n\t\t\t\tlimit: this.mainBatch.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic submitAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch(message);\n\n\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\t\tbatchSize: this.attachFlowBatch.contentSizeInBytes,\n\t\t\t\t\tcount: this.attachFlowBatch.length,\n\t\t\t\t\tlimit: this.attachFlowBatch.options.hardLimit,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.attachFlowBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\tthis.flushInternal(this.mainBatch.popBatch());\n\t}\n\n\tprivate flushInternal(rawBatch: IBatch) {\n\t\tconst processedBatch = this.compressBatch(rawBatch);\n\t\tthis.sendBatch(processedBatch);\n\n\t\tthis.persistBatch(rawBatch.content);\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes > batch.contentSizeInBytes\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\t\tif (compressedBatch.contentSizeInBytes <= this.params.config.maxBatchSizeInBytes) {\n\t\t\t// If we don't reach the maximum supported size of a batch, it can safely be sent as is\n\t\t\treturn compressedBatch;\n\t\t}\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn this.params.splitter.splitCompressedBatch(compressedBatch);\n\t\t}\n\n\t\t// If we've reached this point, the runtime would attempt to send a batch larger than the allowed size\n\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\tcount: compressedBatch.content.length,\n\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t});\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\n\t\tconst length = batch.content.length;\n\n\t\t// Did we disconnect in the middle of turn-based batch?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\tif (length === 0 || !this.params.shouldSend()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.params.containerContext.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tfor (const message of batch.content) {\n\t\t\t\t// Legacy path doesn't support compressed payloads and will submit uncompressed payload anyways\n\t\t\t\tif (message.metadata?.compressed) {\n\t\t\t\t\tdelete message.metadata.compressed;\n\t\t\t\t}\n\n\t\t\t\tthis.params.containerContext.submitFn(\n\t\t\t\t\tMessageType.Operation,\n\t\t\t\t\tmessage.deserializedContent,\n\t\t\t\t\ttrue, // batch\n\t\t\t\t\tmessage.metadata,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.params.containerContext.deltaManager.flush();\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t\t0x58e /* Batch must not be empty */,\n\t\t\t);\n\t\t\tthis.params.containerContext.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate persistBatch(batch: BatchMessage[]) {\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\tmessage.deserializedContent.type,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.deserializedContent.contents,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\treturn {\n\t\t\tmainBatch: this.mainBatch.checkpoint(),\n\t\t\tattachFlowBatch: this.attachFlowBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/container-runtime";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-internal.3.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-internal.3.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export const pkgName = "@fluidframework/container-runtime";
|
|
8
|
-
export const pkgVersion = "2.0.0-internal.3.
|
|
8
|
+
export const pkgVersion = "2.0.0-internal.3.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-internal.3.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-internal.3.2.0\";\n"]}
|
|
@@ -81,11 +81,10 @@ export declare class PendingStateManager implements IDisposable {
|
|
|
81
81
|
* Called when a message is submitted locally. Adds the message and the associated details to the pending state
|
|
82
82
|
* queue.
|
|
83
83
|
* @param type - The container message type.
|
|
84
|
-
* @param clientSequenceNumber - The clientSequenceNumber associated with the message.
|
|
85
84
|
* @param content - The message content.
|
|
86
85
|
* @param localOpMetadata - The local metadata associated with the message.
|
|
87
86
|
*/
|
|
88
|
-
onSubmitMessage(type: ContainerMessageType,
|
|
87
|
+
onSubmitMessage(type: ContainerMessageType, referenceSequenceNumber: number, content: any, localOpMetadata: unknown, opMetadata: Record<string, unknown> | undefined): void;
|
|
89
88
|
/**
|
|
90
89
|
* Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted
|
|
91
90
|
* @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAEjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAEhF,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,oBAAoB,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,OAAO,CAAC;CACd;AAED;;GAEG;AACH,oBAAY,aAAa,GAAG,eAAe,GAAG,aAAa,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,aAAa,EAAE,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACpC,SAAS,IAAI,OAAO,CAAC;IACrB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC7C,cAAc,EAAE,CACf,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,yBAAyB,KAC9B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,QAAQ,CACP,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,GAAG,EACZ,eAAe,EAAE,OAAO,EACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC7C,IAAI,CAAC;IACR,QAAQ,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI,CAAC;IACnF,iBAAiB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IAoDrD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAnD9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAGzB;IAEH,IAAW,oBAAoB,IAAI,MAAM,CAExC;IAGD,OAAO,CAAC,iBAAiB,CAAkB;IAI3C,OAAO,CAAC,wBAAwB,CAAwC;IAExE,OAAO,CAAC,QAAQ,CAAqB;IAErC;;;OAGG;IACI,kBAAkB,IAAI,OAAO;IAI7B,aAAa,IAAI,kBAAkB,GAAG,SAAS;gBAuBpC,YAAY,EAAE,oBAAoB,EACnD,iBAAiB,EAAE,kBAAkB,GAAG,SAAS;IAmClD,IAAW,QAAQ,YAElB;IACD,SAAgB,OAAO,aAAgC;IAEvD
|
|
1
|
+
{"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -95,15 +95,14 @@ export class PendingStateManager {
|
|
|
95
95
|
* Called when a message is submitted locally. Adds the message and the associated details to the pending state
|
|
96
96
|
* queue.
|
|
97
97
|
* @param type - The container message type.
|
|
98
|
-
* @param clientSequenceNumber - The clientSequenceNumber associated with the message.
|
|
99
98
|
* @param content - The message content.
|
|
100
99
|
* @param localOpMetadata - The local metadata associated with the message.
|
|
101
100
|
*/
|
|
102
|
-
onSubmitMessage(type,
|
|
101
|
+
onSubmitMessage(type, referenceSequenceNumber, content, localOpMetadata, opMetadata) {
|
|
103
102
|
const pendingMessage = {
|
|
104
103
|
type: "message",
|
|
105
104
|
messageType: type,
|
|
106
|
-
clientSequenceNumber,
|
|
105
|
+
clientSequenceNumber: -1,
|
|
107
106
|
referenceSequenceNumber,
|
|
108
107
|
content,
|
|
109
108
|
localOpMetadata,
|
|
@@ -148,12 +147,19 @@ export class PendingStateManager {
|
|
|
148
147
|
const pendingMessage = this.pendingMessages.peekFront();
|
|
149
148
|
assert(pendingMessage !== undefined, 0x169 /* "No pending message found for this remote message" */);
|
|
150
149
|
this.pendingMessages.shift();
|
|
151
|
-
|
|
152
|
-
// The clientSequenceNumber of the incoming message must match that of the pending message.
|
|
153
|
-
if (pendingMessage.clientSequenceNumber !== message.clientSequenceNumber) {
|
|
150
|
+
if (pendingMessage.messageType !== message.type) {
|
|
154
151
|
// Close the container because this could indicate data corruption.
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
this.stateHandler.close(DataProcessingError.create("pending local message type mismatch", "unexpectedAckReceived", message, {
|
|
153
|
+
expectedMessageType: pendingMessage.messageType,
|
|
154
|
+
}));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const pendingMessageContent = JSON.stringify(pendingMessage.content);
|
|
158
|
+
const messageContent = JSON.stringify(message.contents);
|
|
159
|
+
// Stringified content does not match
|
|
160
|
+
if (pendingMessageContent !== messageContent) {
|
|
161
|
+
// Close the container because this could indicate data corruption.
|
|
162
|
+
this.stateHandler.close(DataProcessingError.create("pending local message content mismatch", "unexpectedAckReceived", message));
|
|
157
163
|
return;
|
|
158
164
|
}
|
|
159
165
|
// Post-processing part - If we are processing a batch then this could be the last message in the batch.
|
|
@@ -205,7 +211,6 @@ export class PendingStateManager {
|
|
|
205
211
|
hasBatchStart: batchBeginMetadata === true,
|
|
206
212
|
hasBatchEnd: batchEndMetadata === false,
|
|
207
213
|
messageType: message.type,
|
|
208
|
-
batchStartSequenceNumber: this.pendingBatchBeginMessage.clientSequenceNumber,
|
|
209
214
|
pendingMessagesCount: this.pendingMessagesCount,
|
|
210
215
|
}));
|
|
211
216
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.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 { IDisposable } from \"@fluidframework/common-definitions\";\nimport { assert, Lazy } from \"@fluidframework/common-utils\";\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { DataProcessingError } from \"@fluidframework/container-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport Deque from \"double-ended-queue\";\nimport { ContainerMessageType } from \"./containerRuntime\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\tmessageType: ContainerMessageType;\n\tclientSequenceNumber: number;\n\treferenceSequenceNumber: number;\n\tcontent: any;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n}\n\n/**\n * This represents an explicit flush call and is added to the pending queue when flush is called on the ContainerRuntime\n * to flush pending messages.\n * @deprecated Use batch metadata on IPendingMessage instead. To be removed in 2.0.0-internal.4.0.0 (AB#2496)\n */\nexport interface IPendingFlush {\n\ttype: \"flush\";\n}\n\n/**\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport type IPendingState = IPendingMessage | IPendingFlush;\n\n/**\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingState[];\n}\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tclose(error?: ICriticalContainerError): void;\n\tapplyStashedOp: (\n\t\ttype: ContainerMessageType,\n\t\tcontent: ISequencedDocumentMessage,\n\t) => Promise<unknown>;\n\treSubmit(\n\t\ttype: ContainerMessageType,\n\t\tcontent: any,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t): void;\n\trollback(type: ContainerMessageType, content: any, localOpMetadata: unknown): void;\n\torderSequentially(callback: () => void): void;\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\tprivate readonly initialMessages = new Deque<IPendingMessage>();\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length;\n\t}\n\n\t// Indicates whether we are processing a batch.\n\tprivate isProcessingBatch: boolean = false;\n\n\t// This stores the first message in the batch that we are processing. This is used to verify that we get\n\t// the correct batch metadata.\n\tprivate pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;\n\n\tprivate clientId: string | undefined;\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn !this.pendingMessages.isEmpty() || !this.initialMessages.isEmpty();\n\t}\n\n\tpublic getLocalState(): IPendingLocalState | undefined {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\tif (!this.pendingMessages.isEmpty()) {\n\t\t\treturn {\n\t\t\t\tpendingStates: this.pendingMessages.toArray().reduce((arr, message) => {\n\t\t\t\t\t// delete localOpMetadata since it may not be serializable\n\t\t\t\t\t// and will be regenerated by applyStashedOp()\n\t\t\t\t\tarr.push({ ...message, localOpMetadata: undefined });\n\n\t\t\t\t\t// TODO: Remove in 2.0.0-internal.4.0.0 (AB#2496)\n\t\t\t\t\tif (message.opMetadata?.batch === false) {\n\t\t\t\t\t\tarr.push({ type: \"flush\" });\n\t\t\t\t\t}\n\t\t\t\t\treturn arr;\n\t\t\t\t}, new Array<IPendingState>()),\n\t\t\t};\n\t\t}\n\t}\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tinitialLocalState: IPendingLocalState | undefined,\n\t) {\n\t\t/**\n\t\t * Convert old local state format to the new format\n\t\t * The old format contained \"flush\" messages as the indicator of batch ends\n\t\t * The new format instead uses batch metadata on the last message to indicate batch ends\n\t\t * ! TODO: Remove this conversion in \"2.0.0-internal.4.0.0\" as rollback from future version will be new format\n\t\t * AB#2496 tracks removal\n\t\t */\n\t\tif (initialLocalState?.pendingStates) {\n\t\t\tconst pendingStates = initialLocalState?.pendingStates;\n\t\t\tlet currentlyBatching = false;\n\t\t\tfor (let i = 0; i < pendingStates.length; i++) {\n\t\t\t\tconst initialState = pendingStates[i];\n\n\t\t\t\t// Skip over \"flush\" messages\n\t\t\t\tif (initialState.type === \"message\") {\n\t\t\t\t\tif (initialState.opMetadata?.batch) {\n\t\t\t\t\t\tcurrentlyBatching = true;\n\t\t\t\t\t} else if (initialState.opMetadata?.batch === false) {\n\t\t\t\t\t\tcurrentlyBatching = false;\n\t\t\t\t\t} else if (\n\t\t\t\t\t\t// End of batch if we are currently batching and this is last message or next message is flush\n\t\t\t\t\t\tcurrentlyBatching &&\n\t\t\t\t\t\t(i === pendingStates.length - 1 || pendingStates[i + 1].type === \"flush\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tcurrentlyBatching = false;\n\t\t\t\t\t\tinitialState.opMetadata = { ...initialState.opMetadata, batch: false };\n\t\t\t\t\t}\n\t\t\t\t\tthis.initialMessages.push(initialState);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get disposed() {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = () => this.disposeOnce.value;\n\n\t/**\n\t * Called when a message is submitted locally. Adds the message and the associated details to the pending state\n\t * queue.\n\t * @param type - The container message type.\n\t * @param clientSequenceNumber - The clientSequenceNumber associated with the message.\n\t * @param content - The message content.\n\t * @param localOpMetadata - The local metadata associated with the message.\n\t */\n\tpublic onSubmitMessage(\n\t\ttype: ContainerMessageType,\n\t\tclientSequenceNumber: number,\n\t\treferenceSequenceNumber: number,\n\t\tcontent: any,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t) {\n\t\tconst pendingMessage: IPendingMessage = {\n\t\t\ttype: \"message\",\n\t\t\tmessageType: type,\n\t\t\tclientSequenceNumber,\n\t\t\treferenceSequenceNumber,\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\topMetadata,\n\t\t};\n\n\t\tthis.pendingMessages.push(pendingMessage);\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number) {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.peekFront()!;\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\tif (nextMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (nextMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(\n\t\t\t\tnextMessage.messageType,\n\t\t\t\tnextMessage.content,\n\t\t\t);\n\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\n\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tthis.pendingMessages.push(this.initialMessages.shift()!);\n\t\t}\n\t}\n\n\t/**\n\t * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that\n\t * the batch information was preserved for batch messages.\n\t * @param message - The message that got ack'd and needs to be processed.\n\t */\n\tpublic processPendingLocalMessage(message: ISequencedDocumentMessage): unknown {\n\t\t// Pre-processing part - This may be the start of a batch.\n\t\tthis.maybeProcessBatchBegin(message);\n\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\t\tthis.pendingMessages.shift();\n\n\t\t// Processing part - Verify that there has been no data corruption.\n\t\t// The clientSequenceNumber of the incoming message must match that of the pending message.\n\t\tif (pendingMessage.clientSequenceNumber !== message.clientSequenceNumber) {\n\t\t\t// Close the container because this could indicate data corruption.\n\t\t\tconst error = DataProcessingError.create(\n\t\t\t\t\"pending local message clientSequenceNumber mismatch\",\n\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\tmessage,\n\t\t\t\t{ expectedClientSequenceNumber: pendingMessage.clientSequenceNumber },\n\t\t\t);\n\n\t\t\tthis.stateHandler.close(error);\n\t\t\treturn;\n\t\t}\n\n\t\t// Post-processing part - If we are processing a batch then this could be the last message in the batch.\n\t\tthis.maybeProcessBatchEnd(message);\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchBegin(message: ISequencedDocumentMessage) {\n\t\t// This message is the first in a batch if the \"batch\" property on the metadata is set to true\n\t\tif (message.metadata?.batch) {\n\t\t\t// We should not already be processing a batch and there should be no pending batch begin message.\n\t\t\tassert(\n\t\t\t\t!this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,\n\t\t\t\t0x16b /* \"The pending batch state indicates we are already processing a batch\" */,\n\t\t\t);\n\n\t\t\t// Set the pending batch state indicating we have started processing a batch.\n\t\t\tthis.pendingBatchBeginMessage = message;\n\t\t\tthis.isProcessingBatch = true;\n\t\t}\n\t}\n\n\t/**\n\t * This message could be the last message in batch. If so, clear batch state since the batch is complete.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchEnd(message: ISequencedDocumentMessage) {\n\t\tif (!this.isProcessingBatch) {\n\t\t\treturn;\n\t\t}\n\n\t\t// There should be a pending batch begin message.\n\t\tassert(\n\t\t\tthis.pendingBatchBeginMessage !== undefined,\n\t\t\t0x16d /* \"There is no pending batch begin message\" */,\n\t\t);\n\n\t\tconst batchEndMetadata = message.metadata?.batch;\n\t\tif (this.pendingMessages.isEmpty() || batchEndMetadata === false) {\n\t\t\t// Get the batch begin metadata from the first message in the batch.\n\t\t\tconst batchBeginMetadata = this.pendingBatchBeginMessage.metadata?.batch;\n\n\t\t\t// There could be just a single message in the batch. If so, it should not have any batch metadata. If there\n\t\t\t// are multiple messages in the batch, verify that we got the correct batch begin and end metadata.\n\t\t\tif (this.pendingBatchBeginMessage === message) {\n\t\t\t\tassert(\n\t\t\t\t\tbatchBeginMetadata === undefined,\n\t\t\t\t\t0x16e /* \"Batch with single message should not have batch metadata\" */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tif (batchBeginMetadata !== true || batchEndMetadata !== false) {\n\t\t\t\t\tthis.stateHandler.close(\n\t\t\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\t\t\"Pending batch inconsistency\", // Formerly known as asserts 0x16f and 0x170\n\t\t\t\t\t\t\t\"processPendingLocalMessage\",\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\t\t\tbatchClientId: this.pendingBatchBeginMessage.clientId,\n\t\t\t\t\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t\t\t\t\t\thasBatchStart: batchBeginMetadata === true,\n\t\t\t\t\t\t\t\thasBatchEnd: batchEndMetadata === false,\n\t\t\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t\t\t\tbatchStartSequenceNumber:\n\t\t\t\t\t\t\t\t\tthis.pendingBatchBeginMessage.clientSequenceNumber,\n\t\t\t\t\t\t\t\tpendingMessagesCount: this.pendingMessagesCount,\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\n\t\t\t// Clear the pending batch state now that we have processed the entire batch.\n\t\t\tthis.pendingBatchBeginMessage = undefined;\n\t\t\tthis.isProcessingBatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t */\n\tpublic replayPendingStates() {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientId !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientId = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tlet pendingMessagesCount = this.pendingMessages.length;\n\t\tif (pendingMessagesCount === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (pendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tpendingMessagesCount--;\n\t\t\tassert(\n\t\t\t\tpendingMessage.opMetadata?.batch !== false,\n\t\t\t\t0x41b /* We cannot process batches in chunks */,\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * We want to ensure grouped messages get processed in a batch.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all.\n\t\t\t */\n\t\t\tif (pendingMessage.opMetadata?.batch) {\n\t\t\t\tassert(\n\t\t\t\t\tpendingMessagesCount > 0,\n\t\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t\t);\n\n\t\t\t\tthis.stateHandler.orderSequentially(() => {\n\t\t\t\t\twhile (pendingMessagesCount >= 0) {\n\t\t\t\t\t\t// check is >= because batch end may be last pending message\n\t\t\t\t\t\tthis.stateHandler.reSubmit(\n\t\t\t\t\t\t\tpendingMessage.messageType,\n\t\t\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\t\t\tpendingMessage.localOpMetadata,\n\t\t\t\t\t\t\tpendingMessage.opMetadata,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tassert(pendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\t\t\tpendingMessagesCount--;\n\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.stateHandler.reSubmit(\n\t\t\t\t\tpendingMessage.messageType,\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\tpendingMessage.localOpMetadata,\n\t\t\t\t\tpendingMessage.opMetadata,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.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 { IDisposable } from \"@fluidframework/common-definitions\";\nimport { assert, Lazy } from \"@fluidframework/common-utils\";\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { DataProcessingError } from \"@fluidframework/container-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport Deque from \"double-ended-queue\";\nimport { ContainerMessageType } from \"./containerRuntime\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\tmessageType: ContainerMessageType;\n\tclientSequenceNumber: number;\n\treferenceSequenceNumber: number;\n\tcontent: any;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n}\n\n/**\n * This represents an explicit flush call and is added to the pending queue when flush is called on the ContainerRuntime\n * to flush pending messages.\n * @deprecated Use batch metadata on IPendingMessage instead. To be removed in 2.0.0-internal.4.0.0 (AB#2496)\n */\nexport interface IPendingFlush {\n\ttype: \"flush\";\n}\n\n/**\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport type IPendingState = IPendingMessage | IPendingFlush;\n\n/**\n * @deprecated - This interface will no longer be exported in a future version\n */\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingState[];\n}\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tclose(error?: ICriticalContainerError): void;\n\tapplyStashedOp: (\n\t\ttype: ContainerMessageType,\n\t\tcontent: ISequencedDocumentMessage,\n\t) => Promise<unknown>;\n\treSubmit(\n\t\ttype: ContainerMessageType,\n\t\tcontent: any,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t): void;\n\trollback(type: ContainerMessageType, content: any, localOpMetadata: unknown): void;\n\torderSequentially(callback: () => void): void;\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\tprivate readonly initialMessages = new Deque<IPendingMessage>();\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length;\n\t}\n\n\t// Indicates whether we are processing a batch.\n\tprivate isProcessingBatch: boolean = false;\n\n\t// This stores the first message in the batch that we are processing. This is used to verify that we get\n\t// the correct batch metadata.\n\tprivate pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;\n\n\tprivate clientId: string | undefined;\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn !this.pendingMessages.isEmpty() || !this.initialMessages.isEmpty();\n\t}\n\n\tpublic getLocalState(): IPendingLocalState | undefined {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\tif (!this.pendingMessages.isEmpty()) {\n\t\t\treturn {\n\t\t\t\tpendingStates: this.pendingMessages.toArray().reduce((arr, message) => {\n\t\t\t\t\t// delete localOpMetadata since it may not be serializable\n\t\t\t\t\t// and will be regenerated by applyStashedOp()\n\t\t\t\t\tarr.push({ ...message, localOpMetadata: undefined });\n\n\t\t\t\t\t// TODO: Remove in 2.0.0-internal.4.0.0 (AB#2496)\n\t\t\t\t\tif (message.opMetadata?.batch === false) {\n\t\t\t\t\t\tarr.push({ type: \"flush\" });\n\t\t\t\t\t}\n\t\t\t\t\treturn arr;\n\t\t\t\t}, new Array<IPendingState>()),\n\t\t\t};\n\t\t}\n\t}\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tinitialLocalState: IPendingLocalState | undefined,\n\t) {\n\t\t/**\n\t\t * Convert old local state format to the new format\n\t\t * The old format contained \"flush\" messages as the indicator of batch ends\n\t\t * The new format instead uses batch metadata on the last message to indicate batch ends\n\t\t * ! TODO: Remove this conversion in \"2.0.0-internal.4.0.0\" as rollback from future version will be new format\n\t\t * AB#2496 tracks removal\n\t\t */\n\t\tif (initialLocalState?.pendingStates) {\n\t\t\tconst pendingStates = initialLocalState?.pendingStates;\n\t\t\tlet currentlyBatching = false;\n\t\t\tfor (let i = 0; i < pendingStates.length; i++) {\n\t\t\t\tconst initialState = pendingStates[i];\n\n\t\t\t\t// Skip over \"flush\" messages\n\t\t\t\tif (initialState.type === \"message\") {\n\t\t\t\t\tif (initialState.opMetadata?.batch) {\n\t\t\t\t\t\tcurrentlyBatching = true;\n\t\t\t\t\t} else if (initialState.opMetadata?.batch === false) {\n\t\t\t\t\t\tcurrentlyBatching = false;\n\t\t\t\t\t} else if (\n\t\t\t\t\t\t// End of batch if we are currently batching and this is last message or next message is flush\n\t\t\t\t\t\tcurrentlyBatching &&\n\t\t\t\t\t\t(i === pendingStates.length - 1 || pendingStates[i + 1].type === \"flush\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tcurrentlyBatching = false;\n\t\t\t\t\t\tinitialState.opMetadata = { ...initialState.opMetadata, batch: false };\n\t\t\t\t\t}\n\t\t\t\t\tthis.initialMessages.push(initialState);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get disposed() {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = () => this.disposeOnce.value;\n\n\t/**\n\t * Called when a message is submitted locally. Adds the message and the associated details to the pending state\n\t * queue.\n\t * @param type - The container message type.\n\t * @param content - The message content.\n\t * @param localOpMetadata - The local metadata associated with the message.\n\t */\n\tpublic onSubmitMessage(\n\t\ttype: ContainerMessageType,\n\t\treferenceSequenceNumber: number,\n\t\tcontent: any,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t) {\n\t\tconst pendingMessage: IPendingMessage = {\n\t\t\ttype: \"message\",\n\t\t\tmessageType: type,\n\t\t\tclientSequenceNumber: -1, // dummy value (not to be used anywhere)\n\t\t\treferenceSequenceNumber,\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\topMetadata,\n\t\t};\n\n\t\tthis.pendingMessages.push(pendingMessage);\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number) {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.peekFront()!;\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\tif (nextMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (nextMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(\n\t\t\t\tnextMessage.messageType,\n\t\t\t\tnextMessage.content,\n\t\t\t);\n\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\n\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tthis.pendingMessages.push(this.initialMessages.shift()!);\n\t\t}\n\t}\n\n\t/**\n\t * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that\n\t * the batch information was preserved for batch messages.\n\t * @param message - The message that got ack'd and needs to be processed.\n\t */\n\tpublic processPendingLocalMessage(message: ISequencedDocumentMessage): unknown {\n\t\t// Pre-processing part - This may be the start of a batch.\n\t\tthis.maybeProcessBatchBegin(message);\n\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\t\tthis.pendingMessages.shift();\n\n\t\tif (pendingMessage.messageType !== message.type) {\n\t\t\t// Close the container because this could indicate data corruption.\n\t\t\tthis.stateHandler.close(\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"pending local message type mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\texpectedMessageType: pendingMessage.messageType,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst pendingMessageContent = JSON.stringify(pendingMessage.content);\n\t\tconst messageContent = JSON.stringify(message.contents);\n\n\t\t// Stringified content does not match\n\t\tif (pendingMessageContent !== messageContent) {\n\t\t\t// Close the container because this could indicate data corruption.\n\t\t\tthis.stateHandler.close(\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"pending local message content mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Post-processing part - If we are processing a batch then this could be the last message in the batch.\n\t\tthis.maybeProcessBatchEnd(message);\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchBegin(message: ISequencedDocumentMessage) {\n\t\t// This message is the first in a batch if the \"batch\" property on the metadata is set to true\n\t\tif (message.metadata?.batch) {\n\t\t\t// We should not already be processing a batch and there should be no pending batch begin message.\n\t\t\tassert(\n\t\t\t\t!this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,\n\t\t\t\t0x16b /* \"The pending batch state indicates we are already processing a batch\" */,\n\t\t\t);\n\n\t\t\t// Set the pending batch state indicating we have started processing a batch.\n\t\t\tthis.pendingBatchBeginMessage = message;\n\t\t\tthis.isProcessingBatch = true;\n\t\t}\n\t}\n\n\t/**\n\t * This message could be the last message in batch. If so, clear batch state since the batch is complete.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchEnd(message: ISequencedDocumentMessage) {\n\t\tif (!this.isProcessingBatch) {\n\t\t\treturn;\n\t\t}\n\n\t\t// There should be a pending batch begin message.\n\t\tassert(\n\t\t\tthis.pendingBatchBeginMessage !== undefined,\n\t\t\t0x16d /* \"There is no pending batch begin message\" */,\n\t\t);\n\n\t\tconst batchEndMetadata = message.metadata?.batch;\n\t\tif (this.pendingMessages.isEmpty() || batchEndMetadata === false) {\n\t\t\t// Get the batch begin metadata from the first message in the batch.\n\t\t\tconst batchBeginMetadata = this.pendingBatchBeginMessage.metadata?.batch;\n\n\t\t\t// There could be just a single message in the batch. If so, it should not have any batch metadata. If there\n\t\t\t// are multiple messages in the batch, verify that we got the correct batch begin and end metadata.\n\t\t\tif (this.pendingBatchBeginMessage === message) {\n\t\t\t\tassert(\n\t\t\t\t\tbatchBeginMetadata === undefined,\n\t\t\t\t\t0x16e /* \"Batch with single message should not have batch metadata\" */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tif (batchBeginMetadata !== true || batchEndMetadata !== false) {\n\t\t\t\t\tthis.stateHandler.close(\n\t\t\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\t\t\"Pending batch inconsistency\", // Formerly known as asserts 0x16f and 0x170\n\t\t\t\t\t\t\t\"processPendingLocalMessage\",\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\t\t\tbatchClientId: this.pendingBatchBeginMessage.clientId,\n\t\t\t\t\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t\t\t\t\t\thasBatchStart: batchBeginMetadata === true,\n\t\t\t\t\t\t\t\thasBatchEnd: batchEndMetadata === false,\n\t\t\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t\t\t\tpendingMessagesCount: this.pendingMessagesCount,\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\n\t\t\t// Clear the pending batch state now that we have processed the entire batch.\n\t\t\tthis.pendingBatchBeginMessage = undefined;\n\t\t\tthis.isProcessingBatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t */\n\tpublic replayPendingStates() {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientId !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientId = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tlet pendingMessagesCount = this.pendingMessages.length;\n\t\tif (pendingMessagesCount === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (pendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tpendingMessagesCount--;\n\t\t\tassert(\n\t\t\t\tpendingMessage.opMetadata?.batch !== false,\n\t\t\t\t0x41b /* We cannot process batches in chunks */,\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * We want to ensure grouped messages get processed in a batch.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all.\n\t\t\t */\n\t\t\tif (pendingMessage.opMetadata?.batch) {\n\t\t\t\tassert(\n\t\t\t\t\tpendingMessagesCount > 0,\n\t\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t\t);\n\n\t\t\t\tthis.stateHandler.orderSequentially(() => {\n\t\t\t\t\twhile (pendingMessagesCount >= 0) {\n\t\t\t\t\t\t// check is >= because batch end may be last pending message\n\t\t\t\t\t\tthis.stateHandler.reSubmit(\n\t\t\t\t\t\t\tpendingMessage.messageType,\n\t\t\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\t\t\tpendingMessage.localOpMetadata,\n\t\t\t\t\t\t\tpendingMessage.opMetadata,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tassert(pendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\t\t\tpendingMessagesCount--;\n\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.stateHandler.reSubmit(\n\t\t\t\t\tpendingMessage.messageType,\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\tpendingMessage.localOpMetadata,\n\t\t\t\t\tpendingMessage.opMetadata,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
export { IOrderedClientCollection, IOrderedClientElection, ISerializedElection, ITrackedClient, OrderedClientCollection, OrderedClientElection, } from "./orderedClientElection";
|
|
6
|
+
export { RunningSummarizer } from "./runningSummarizer";
|
|
7
|
+
export { ICancellableSummarizerController, neverCancelledSummaryToken, RunWhileConnectedCoordinator, } from "./runWhileConnectedCoordinator";
|
|
8
|
+
export { Summarizer } from "./summarizer";
|
|
9
|
+
export { ISummarizerClientElection, ISummarizerClientElectionEvents, SummarizerClientElection, summarizerClientType, } from "./summarizerClientElection";
|
|
10
|
+
export { SummarizerHandle } from "./summarizerHandle";
|
|
11
|
+
export { SummarizeHeuristicData, SummarizeHeuristicRunner } from "./summarizerHeuristics";
|
|
12
|
+
export { IConnectableRuntime, IGeneratedSummaryStats, IRefreshSummaryAckOptions, ISubmitSummaryOptions, ISummarizeAttempt, ISummarizeHeuristicData, ISummarizer, ISummarizeResults, ISummarizerEvents, ISummarizerInternalsProvider, ISummarizerRuntime, ISummaryCancellationToken, SubmitSummaryResult, SummarizerStopReason, EnqueueSummarizeResult, IAckSummaryResult, IBaseSummarizeResult, IBroadcastSummaryResult, ICancellationToken, IEnqueueSummarizeOptions, IGenerateSummaryTreeResult, INackSummaryResult, IOnDemandSummarizeOptions, IProvideSummarizer, ISubmitSummaryOpResult, ISummarizeOptions, ISummarizingWarning, IUploadSummaryResult, SummarizeResultPart, } from "./summarizerTypes";
|
|
13
|
+
export { IAckedSummary, ISummaryCollectionOpEvents, ISummaryOpMessage, SummaryCollection, IClientSummaryWatcher, ISummary, ISummaryAckMessage, ISummaryNackMessage, OpActionEventListener, OpActionEventName, } from "./summaryCollection";
|
|
14
|
+
export { aliasBlobName, blobsTreeName, chunksBlobName, dataStoreAttributesBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, getAttributesFormatVersion, getFluidDataStoreAttributes, hasIsolatedChannels, IContainerRuntimeMetadata, ICreateContainerMetadata, ISummaryMetadataMessage, metadataBlobName, nonDataStorePaths, ReadFluidDataStoreAttributes, rootHasIsolatedChannels, WriteFluidDataStoreAttributes, wrapSummaryInChannelsTree, } from "./summaryFormat";
|
|
15
|
+
export { SummarizeReason } from "./summaryGenerator";
|
|
16
|
+
export { IConnectedEvents, IConnectedState, ISummaryManagerConfig, SummaryManager, SummaryManagerState, } from "./summaryManager";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/summary/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,qBAAqB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACN,gCAAgC,EAChC,0BAA0B,EAC1B,4BAA4B,GAC5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACN,yBAAyB,EACzB,+BAA+B,EAC/B,wBAAwB,EACxB,oBAAoB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACN,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,EACvB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,kBAAkB,EAClB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,aAAa,EACb,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,aAAa,EACb,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,4BAA4B,EAC5B,uBAAuB,EACvB,6BAA6B,EAC7B,yBAAyB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACN,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,mBAAmB,GACnB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
export { OrderedClientCollection, OrderedClientElection, } from "./orderedClientElection";
|
|
6
|
+
export { RunningSummarizer } from "./runningSummarizer";
|
|
7
|
+
export { neverCancelledSummaryToken, RunWhileConnectedCoordinator, } from "./runWhileConnectedCoordinator";
|
|
8
|
+
export { Summarizer } from "./summarizer";
|
|
9
|
+
export { SummarizerClientElection, summarizerClientType, } from "./summarizerClientElection";
|
|
10
|
+
export { SummarizerHandle } from "./summarizerHandle";
|
|
11
|
+
export { SummarizeHeuristicData, SummarizeHeuristicRunner } from "./summarizerHeuristics";
|
|
12
|
+
export { ISummarizer, } from "./summarizerTypes";
|
|
13
|
+
export { SummaryCollection, } from "./summaryCollection";
|
|
14
|
+
export { aliasBlobName, blobsTreeName, chunksBlobName, dataStoreAttributesBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, getAttributesFormatVersion, getFluidDataStoreAttributes, hasIsolatedChannels, metadataBlobName, nonDataStorePaths, rootHasIsolatedChannels, wrapSummaryInChannelsTree, } from "./summaryFormat";
|
|
15
|
+
export { SummaryManager, SummaryManagerState, } from "./summaryManager";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/summary/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAKN,uBAAuB,EACvB,qBAAqB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAEN,0BAA0B,EAC1B,4BAA4B,GAC5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAGN,wBAAwB,EACxB,oBAAoB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAON,WAAW,GAuBX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIN,iBAAiB,GAOjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,aAAa,EACb,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EAInB,gBAAgB,EAChB,iBAAiB,EAEjB,uBAAuB,EAEvB,yBAAyB,GACzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAIN,cAAc,EACd,mBAAmB,GACnB,MAAM,kBAAkB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tIOrderedClientCollection,\n\tIOrderedClientElection,\n\tISerializedElection,\n\tITrackedClient,\n\tOrderedClientCollection,\n\tOrderedClientElection,\n} from \"./orderedClientElection\";\nexport { RunningSummarizer } from \"./runningSummarizer\";\nexport {\n\tICancellableSummarizerController,\n\tneverCancelledSummaryToken,\n\tRunWhileConnectedCoordinator,\n} from \"./runWhileConnectedCoordinator\";\nexport { Summarizer } from \"./summarizer\";\nexport {\n\tISummarizerClientElection,\n\tISummarizerClientElectionEvents,\n\tSummarizerClientElection,\n\tsummarizerClientType,\n} from \"./summarizerClientElection\";\nexport { SummarizerHandle } from \"./summarizerHandle\";\nexport { SummarizeHeuristicData, SummarizeHeuristicRunner } from \"./summarizerHeuristics\";\nexport {\n\tIConnectableRuntime,\n\tIGeneratedSummaryStats,\n\tIRefreshSummaryAckOptions,\n\tISubmitSummaryOptions,\n\tISummarizeAttempt,\n\tISummarizeHeuristicData,\n\tISummarizer,\n\tISummarizeResults,\n\tISummarizerEvents,\n\tISummarizerInternalsProvider,\n\tISummarizerRuntime,\n\tISummaryCancellationToken,\n\tSubmitSummaryResult,\n\tSummarizerStopReason,\n\tEnqueueSummarizeResult,\n\tIAckSummaryResult,\n\tIBaseSummarizeResult,\n\tIBroadcastSummaryResult,\n\tICancellationToken,\n\tIEnqueueSummarizeOptions,\n\tIGenerateSummaryTreeResult,\n\tINackSummaryResult,\n\tIOnDemandSummarizeOptions,\n\tIProvideSummarizer,\n\tISubmitSummaryOpResult,\n\tISummarizeOptions,\n\tISummarizingWarning,\n\tIUploadSummaryResult,\n\tSummarizeResultPart,\n} from \"./summarizerTypes\";\nexport {\n\tIAckedSummary,\n\tISummaryCollectionOpEvents,\n\tISummaryOpMessage,\n\tSummaryCollection,\n\tIClientSummaryWatcher,\n\tISummary,\n\tISummaryAckMessage,\n\tISummaryNackMessage,\n\tOpActionEventListener,\n\tOpActionEventName,\n} from \"./summaryCollection\";\nexport {\n\taliasBlobName,\n\tblobsTreeName,\n\tchunksBlobName,\n\tdataStoreAttributesBlobName,\n\telectedSummarizerBlobName,\n\textractSummaryMetadataMessage,\n\tgetAttributesFormatVersion,\n\tgetFluidDataStoreAttributes,\n\thasIsolatedChannels,\n\tIContainerRuntimeMetadata,\n\tICreateContainerMetadata,\n\tISummaryMetadataMessage,\n\tmetadataBlobName,\n\tnonDataStorePaths,\n\tReadFluidDataStoreAttributes,\n\trootHasIsolatedChannels,\n\tWriteFluidDataStoreAttributes,\n\twrapSummaryInChannelsTree,\n} from \"./summaryFormat\";\nexport { SummarizeReason } from \"./summaryGenerator\";\nexport {\n\tIConnectedEvents,\n\tIConnectedState,\n\tISummaryManagerConfig,\n\tSummaryManager,\n\tSummaryManagerState,\n} from \"./summaryManager\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orderedClientElection.d.ts","sourceRoot":"","sources":["../../src/summary/orderedClientElection.ts"],"names":[],"mappings":"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"}
|