@fluidframework/container-runtime 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +21 -10
- package/.mocharc.js +2 -2
- package/api-extractor.json +2 -2
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +2 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +74 -42
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +321 -152
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +11 -9
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js +3 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +148 -114
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +534 -342
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +11 -9
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +40 -13
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +146 -66
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -3
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +3 -1
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.d.ts +39 -12
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +164 -76
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/dist/deltaManagerSummarizerProxy.js +40 -0
- package/dist/deltaManagerSummarizerProxy.js.map +1 -0
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +8 -3
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +204 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -0
- package/dist/gc/garbageCollection.js +926 -0
- package/dist/gc/garbageCollection.js.map +1 -0
- package/dist/gc/gcConfigs.d.ts +22 -0
- package/dist/gc/gcConfigs.d.ts.map +1 -0
- package/dist/gc/gcConfigs.js +143 -0
- package/dist/gc/gcConfigs.js.map +1 -0
- package/dist/gc/gcDefinitions.d.ts +320 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -0
- package/dist/gc/gcDefinitions.js +81 -0
- package/dist/gc/gcDefinitions.js.map +1 -0
- package/dist/gc/gcHelpers.d.ts +86 -0
- package/dist/gc/gcHelpers.d.ts.map +1 -0
- package/dist/gc/gcHelpers.js +268 -0
- package/dist/gc/gcHelpers.js.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
- package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/dist/gc/gcSummaryDefinitions.js +7 -0
- package/dist/gc/gcSummaryDefinitions.js.map +1 -0
- package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/dist/gc/gcSummaryStateTracker.js +239 -0
- package/dist/gc/gcSummaryStateTracker.js.map +1 -0
- package/{lib → dist/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
- package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
- 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 +13 -0
- package/dist/gc/index.d.ts.map +1 -0
- package/dist/gc/index.js +50 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/index.d.ts +3 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -13
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +10 -0
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +37 -8
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +29 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +3 -3
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +3 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +46 -17
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +6 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +72 -18
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +46 -2
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +142 -5
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +23 -2
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +101 -51
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +17 -2
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/opProperties.d.ts.map +1 -1
- package/dist/opProperties.js +1 -3
- package/dist/opProperties.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 +6 -15
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +137 -165
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts +0 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +11 -21
- package/dist/scheduleManager.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/dist/storageServiceWithAttachBlobs.js +32 -0
- package/dist/storageServiceWithAttachBlobs.js.map +1 -0
- package/dist/summary/index.d.ts +17 -0
- package/dist/summary/index.d.ts.map +1 -0
- package/dist/summary/index.js +46 -0
- package/dist/summary/index.js.map +1 -0
- package/dist/summary/orderedClientElection.d.ts.map +1 -0
- package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
- package/dist/summary/orderedClientElection.js.map +1 -0
- package/{lib → dist/summary}/runWhileConnectedCoordinator.d.ts +3 -2
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
- 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} +191 -77
- package/dist/summary/runningSummarizer.js.map +1 -0
- package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +6 -12
- package/dist/summary/summarizer.d.ts.map +1 -0
- package/dist/{summarizer.js → summary/summarizer.js} +32 -76
- package/dist/summary/summarizer.js.map +1 -0
- package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +1 -2
- package/dist/summary/summarizerClientElection.d.ts.map +1 -0
- package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +3 -30
- package/dist/summary/summarizerClientElection.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/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +9 -12
- package/dist/summary/summarizerHeuristics.js.map +1 -0
- package/dist/summary/summarizerNode/index.d.ts +8 -0
- package/dist/summary/summarizerNode/index.d.ts.map +1 -0
- package/dist/summary/summarizerNode/index.js +12 -0
- package/dist/summary/summarizerNode/index.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.js +531 -0
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +423 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/{lib → dist/summary}/summarizerTypes.d.ts +29 -42
- package/dist/summary/summarizerTypes.d.ts.map +1 -0
- package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
- package/dist/summary/summarizerTypes.js.map +1 -0
- package/dist/summary/summaryCollection.d.ts.map +1 -0
- package/dist/{summaryCollection.js → summary/summaryCollection.js} +18 -8
- package/dist/summary/summaryCollection.js.map +1 -0
- package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
- package/dist/summary/summaryFormat.d.ts.map +1 -0
- package/dist/{summaryFormat.js → summary/summaryFormat.js} +19 -21
- package/dist/summary/summaryFormat.js.map +1 -0
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +34 -16
- 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/{summaryManager.js → summary/summaryManager.js} +21 -9
- package/dist/summary/summaryManager.js.map +1 -0
- package/dist/throttler.d.ts +2 -2
- package/dist/throttler.d.ts.map +1 -1
- package/dist/throttler.js +4 -4
- package/dist/throttler.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +74 -42
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +322 -153
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +11 -9
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js +3 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +148 -114
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +506 -314
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +11 -9
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +40 -13
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +136 -56
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -3
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +3 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.d.ts +39 -12
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +162 -74
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/lib/deltaManagerSummarizerProxy.js +36 -0
- package/lib/deltaManagerSummarizerProxy.js.map +1 -0
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +9 -4
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +204 -0
- package/lib/gc/garbageCollection.d.ts.map +1 -0
- package/lib/gc/garbageCollection.js +922 -0
- package/lib/gc/garbageCollection.js.map +1 -0
- package/lib/gc/gcConfigs.d.ts +22 -0
- package/lib/gc/gcConfigs.d.ts.map +1 -0
- package/lib/gc/gcConfigs.js +139 -0
- package/lib/gc/gcConfigs.js.map +1 -0
- package/lib/gc/gcDefinitions.d.ts +320 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -0
- package/lib/gc/gcDefinitions.js +78 -0
- package/lib/gc/gcDefinitions.js.map +1 -0
- package/lib/gc/gcHelpers.d.ts +86 -0
- package/lib/gc/gcHelpers.d.ts.map +1 -0
- package/lib/gc/gcHelpers.js +254 -0
- package/lib/gc/gcHelpers.js.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
- package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
- package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/lib/gc/gcSummaryDefinitions.js +6 -0
- package/lib/gc/gcSummaryDefinitions.js.map +1 -0
- package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/lib/gc/gcSummaryStateTracker.js +235 -0
- package/lib/gc/gcSummaryStateTracker.js.map +1 -0
- package/{dist → lib/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
- package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
- 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 +13 -0
- package/lib/gc/index.d.ts.map +1 -0
- package/lib/gc/index.js +12 -0
- package/lib/gc/index.js.map +1 -0
- package/lib/index.d.ts +3 -8
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -6
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +10 -0
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +35 -7
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +29 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +3 -3
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +2 -2
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +47 -18
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +6 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +72 -18
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +46 -2
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +141 -5
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +23 -2
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +103 -53
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +17 -2
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/opProperties.d.ts.map +1 -1
- package/lib/opProperties.js +1 -3
- package/lib/opProperties.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 +6 -15
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +137 -165
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.d.ts +0 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +11 -21
- package/lib/scheduleManager.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/lib/storageServiceWithAttachBlobs.js +28 -0
- package/lib/storageServiceWithAttachBlobs.js.map +1 -0
- package/lib/summary/index.d.ts +17 -0
- package/lib/summary/index.d.ts.map +1 -0
- package/lib/summary/index.js +15 -0
- package/lib/summary/index.js.map +1 -0
- package/lib/summary/orderedClientElection.d.ts.map +1 -0
- package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
- package/lib/summary/orderedClientElection.js.map +1 -0
- package/{dist → lib/summary}/runWhileConnectedCoordinator.d.ts +3 -2
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
- 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} +193 -79
- package/lib/summary/runningSummarizer.js.map +1 -0
- package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +6 -12
- package/lib/summary/summarizer.d.ts.map +1 -0
- package/lib/{summarizer.js → summary/summarizer.js} +34 -78
- package/lib/summary/summarizer.js.map +1 -0
- package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +1 -2
- package/lib/summary/summarizerClientElection.d.ts.map +1 -0
- package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +3 -30
- package/lib/summary/summarizerClientElection.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/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +9 -12
- package/lib/summary/summarizerHeuristics.js.map +1 -0
- package/lib/summary/summarizerNode/index.d.ts +8 -0
- package/lib/summary/summarizerNode/index.d.ts.map +1 -0
- package/lib/summary/summarizerNode/index.js +7 -0
- package/lib/summary/summarizerNode/index.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.js +526 -0
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/{dist → lib/summary}/summarizerTypes.d.ts +29 -42
- package/lib/summary/summarizerTypes.d.ts.map +1 -0
- package/lib/summary/summarizerTypes.js +6 -0
- package/lib/summary/summarizerTypes.js.map +1 -0
- package/lib/summary/summaryCollection.d.ts.map +1 -0
- package/lib/{summaryCollection.js → summary/summaryCollection.js} +18 -8
- package/lib/summary/summaryCollection.js.map +1 -0
- package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
- package/lib/summary/summaryFormat.d.ts.map +1 -0
- package/lib/{summaryFormat.js → summary/summaryFormat.js} +20 -21
- package/lib/summary/summaryFormat.js.map +1 -0
- package/lib/summary/summaryGenerator.d.ts.map +1 -0
- package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +34 -16
- 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/{summaryManager.js → summary/summaryManager.js} +21 -9
- package/lib/summary/summaryManager.js.map +1 -0
- package/lib/throttler.d.ts +2 -2
- package/lib/throttler.d.ts.map +1 -1
- package/lib/throttler.js +4 -4
- package/lib/throttler.js.map +1 -1
- package/package.json +67 -61
- package/prettier.config.cjs +1 -1
- package/src/batchTracker.ts +55 -50
- package/src/blobManager.ts +863 -594
- package/src/connectionTelemetry.ts +280 -249
- package/src/containerHandleContext.ts +27 -29
- package/src/containerRuntime.ts +3174 -2805
- package/src/dataStore.ts +172 -159
- package/src/dataStoreContext.ts +1141 -993
- package/src/dataStoreContexts.ts +178 -161
- package/src/dataStoreRegistry.ts +25 -20
- package/src/dataStores.ts +887 -716
- package/src/deltaManagerSummarizerProxy.ts +46 -0
- package/src/deltaScheduler.ts +158 -150
- package/{garbageCollection.md → src/gc/garbageCollection.md} +16 -3
- package/src/gc/garbageCollection.ts +1250 -0
- package/src/gc/gcConfigs.ts +193 -0
- package/src/gc/gcDefinitions.ts +387 -0
- package/src/gc/gcHelpers.ts +332 -0
- package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
- package/src/gc/gcSummaryDefinitions.ts +54 -0
- package/src/gc/gcSummaryStateTracker.ts +329 -0
- package/src/gc/gcSweepReadyUsageDetection.ts +145 -0
- package/src/gc/gcUnreferencedStateTracker.ts +114 -0
- package/src/gc/index.ts +65 -0
- package/src/index.ts +61 -75
- package/src/opLifecycle/README.md +157 -0
- package/src/opLifecycle/batchManager.ts +119 -86
- package/src/opLifecycle/definitions.ts +49 -19
- package/src/opLifecycle/index.ts +7 -6
- package/src/opLifecycle/opCompressor.ts +78 -40
- package/src/opLifecycle/opDecompressor.ts +148 -64
- package/src/opLifecycle/opSplitter.ts +269 -66
- package/src/opLifecycle/outbox.ts +268 -184
- package/src/opLifecycle/remoteMessageProcessor.ts +63 -47
- package/src/opProperties.ts +11 -9
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +386 -381
- package/src/scheduleManager.ts +299 -280
- package/src/storageServiceWithAttachBlobs.ts +38 -0
- package/src/summary/index.ts +105 -0
- package/src/summary/orderedClientElection.ts +564 -0
- package/src/summary/runWhileConnectedCoordinator.ts +113 -0
- package/src/summary/runningSummarizer.ts +788 -0
- package/src/summary/summarizer.ts +372 -0
- package/src/summary/summarizerClientElection.ts +139 -0
- package/src/summary/summarizerHeuristics.ts +224 -0
- package/src/summary/summarizerNode/index.ts +12 -0
- package/src/summary/summarizerNode/summarizerNode.ts +766 -0
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
- package/src/summary/summarizerTypes.ts +507 -0
- package/src/summary/summaryCollection.ts +450 -0
- package/src/summary/summaryFormat.ts +228 -0
- package/src/summary/summaryGenerator.ts +505 -0
- package/src/summary/summaryManager.ts +423 -0
- package/src/throttler.ts +131 -122
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
- package/dist/garbageCollection.d.ts +0 -387
- package/dist/garbageCollection.d.ts.map +0 -1
- package/dist/garbageCollection.js +0 -1138
- package/dist/garbageCollection.js.map +0 -1
- package/dist/garbageCollectionConstants.d.ts +0 -19
- package/dist/garbageCollectionConstants.d.ts.map +0 -1
- package/dist/garbageCollectionConstants.js +0 -34
- package/dist/garbageCollectionConstants.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/serializedSnapshotStorage.d.ts +0 -58
- package/dist/serializedSnapshotStorage.d.ts.map +0 -1
- package/dist/serializedSnapshotStorage.js +0 -108
- package/dist/serializedSnapshotStorage.js.map +0 -1
- package/dist/summarizer.d.ts.map +0 -1
- package/dist/summarizer.js.map +0 -1
- package/dist/summarizerClientElection.d.ts.map +0 -1
- package/dist/summarizerClientElection.js.map +0 -1
- package/dist/summarizerHandle.d.ts +0 -12
- package/dist/summarizerHandle.d.ts.map +0 -1
- package/dist/summarizerHandle.js +0 -22
- package/dist/summarizerHandle.js.map +0 -1
- package/dist/summarizerHeuristics.d.ts.map +0 -1
- package/dist/summarizerHeuristics.js.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 +0 -387
- package/lib/garbageCollection.d.ts.map +0 -1
- package/lib/garbageCollection.js +0 -1133
- package/lib/garbageCollection.js.map +0 -1
- package/lib/garbageCollectionConstants.d.ts +0 -19
- package/lib/garbageCollectionConstants.d.ts.map +0 -1
- package/lib/garbageCollectionConstants.js +0 -31
- package/lib/garbageCollectionConstants.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/serializedSnapshotStorage.d.ts +0 -58
- package/lib/serializedSnapshotStorage.d.ts.map +0 -1
- package/lib/serializedSnapshotStorage.js +0 -104
- package/lib/serializedSnapshotStorage.js.map +0 -1
- package/lib/summarizer.d.ts.map +0 -1
- package/lib/summarizer.js.map +0 -1
- package/lib/summarizerClientElection.d.ts.map +0 -1
- package/lib/summarizerClientElection.js.map +0 -1
- package/lib/summarizerHandle.d.ts +0 -12
- package/lib/summarizerHandle.d.ts.map +0 -1
- package/lib/summarizerHandle.js +0 -18
- package/lib/summarizerHandle.js.map +0 -1
- package/lib/summarizerHeuristics.d.ts.map +0 -1
- package/lib/summarizerHeuristics.js.map +0 -1
- package/lib/summarizerTypes.d.ts.map +0 -1
- package/lib/summarizerTypes.js +0 -9
- package/lib/summarizerTypes.js.map +0 -1
- package/lib/summaryCollection.d.ts.map +0 -1
- package/lib/summaryCollection.js.map +0 -1
- package/lib/summaryFormat.d.ts.map +0 -1
- package/lib/summaryFormat.js.map +0 -1
- package/lib/summaryGenerator.d.ts.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/garbageCollection.ts +0 -1646
- package/src/garbageCollectionConstants.ts +0 -35
- package/src/gcSweepReadyUsageDetection.ts +0 -139
- package/src/orderedClientElection.ts +0 -532
- package/src/runWhileConnectedCoordinator.ts +0 -106
- package/src/runningSummarizer.ts +0 -611
- package/src/serializedSnapshotStorage.ts +0 -146
- package/src/summarizer.ts +0 -421
- package/src/summarizerClientElection.ts +0 -161
- package/src/summarizerHandle.ts +0 -21
- package/src/summarizerHeuristics.ts +0 -222
- package/src/summarizerTypes.ts +0 -510
- package/src/summaryCollection.ts +0 -421
- package/src/summaryFormat.ts +0 -235
- package/src/summaryGenerator.ts +0 -446
- package/src/summaryManager.ts +0 -394
- /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
- /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
package/lib/containerRuntime.js
CHANGED
|
@@ -1,36 +1,28 @@
|
|
|
1
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
2
|
-
import { assert, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
|
|
2
|
+
import { assert, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
|
|
3
3
|
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
|
|
4
4
|
import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
5
5
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
6
6
|
import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
|
|
7
7
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
8
|
-
import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
9
|
-
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary,
|
|
10
|
-
import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
|
|
8
|
+
import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
9
|
+
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
|
|
11
10
|
import { v4 as uuid } from "uuid";
|
|
12
11
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
13
12
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { ReportOpPerfTelemetry, } from "./connectionTelemetry";
|
|
17
|
-
import { PendingStateManager, } from "./pendingStateManager";
|
|
13
|
+
import { ReportOpPerfTelemetry } from "./connectionTelemetry";
|
|
14
|
+
import { PendingStateManager } from "./pendingStateManager";
|
|
18
15
|
import { pkgVersion } from "./packageVersion";
|
|
19
16
|
import { BlobManager } from "./blobManager";
|
|
20
17
|
import { DataStores, getSummaryForDatastores } from "./dataStores";
|
|
21
|
-
import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./
|
|
22
|
-
import { SummaryCollection } from "./summaryCollection";
|
|
23
|
-
import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
|
|
24
|
-
import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
|
|
18
|
+
import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
|
|
25
19
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { gcTreeKey, } from "./garbageCollectionConstants";
|
|
29
|
-
import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
|
|
20
|
+
import { GarbageCollector, GCNodeType, gcTombstoneGenerationOptionName, shouldAllowGcTombstoneEnforcement, trimLeadingAndTrailingSlashes, } from "./gc";
|
|
21
|
+
import { channelToDataStore, isDataStoreAliasMessage } from "./dataStore";
|
|
30
22
|
import { BindBatchTracker } from "./batchTracker";
|
|
31
|
-
import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
|
|
32
23
|
import { ScheduleManager } from "./scheduleManager";
|
|
33
24
|
import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, } from "./opLifecycle";
|
|
25
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
34
26
|
export var ContainerMessageType;
|
|
35
27
|
(function (ContainerMessageType) {
|
|
36
28
|
// An op to be delivered to store
|
|
@@ -56,7 +48,6 @@ export const DefaultSummaryConfiguration = {
|
|
|
56
48
|
maxAckWaitTime: 10 * 60 * 1000,
|
|
57
49
|
maxOpsSinceLastSummary: 7000,
|
|
58
50
|
initialSummarizerDelayMs: 5 * 1000,
|
|
59
|
-
summarizerClientElection: false,
|
|
60
51
|
nonRuntimeOpWeight: 0.1,
|
|
61
52
|
runtimeOpWeight: 1.0,
|
|
62
53
|
nonRuntimeHeuristicThreshold: 20,
|
|
@@ -68,14 +59,19 @@ export var RuntimeHeaders;
|
|
|
68
59
|
(function (RuntimeHeaders) {
|
|
69
60
|
/** True to wait for a data store to be created and loaded before returning it. */
|
|
70
61
|
RuntimeHeaders["wait"] = "wait";
|
|
71
|
-
/**
|
|
72
|
-
* True if the request is from an external app. Used for GC to handle scenarios where a data store
|
|
73
|
-
* is deleted and requested via an external app.
|
|
74
|
-
*/
|
|
75
|
-
RuntimeHeaders["externalRequest"] = "externalRequest";
|
|
76
62
|
/** True if the request is coming from an IFluidHandle. */
|
|
77
63
|
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
78
64
|
})(RuntimeHeaders || (RuntimeHeaders = {}));
|
|
65
|
+
/** True if a tombstoned object should be returned without erroring */
|
|
66
|
+
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
67
|
+
/** Tombstone error responses will have this header set to true */
|
|
68
|
+
export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
69
|
+
/** Default values for Runtime Headers */
|
|
70
|
+
export const defaultRuntimeHeaderData = {
|
|
71
|
+
wait: true,
|
|
72
|
+
viaHandle: false,
|
|
73
|
+
allowTombstone: false,
|
|
74
|
+
};
|
|
79
75
|
/**
|
|
80
76
|
* Available compression algorithms for op compression.
|
|
81
77
|
*/
|
|
@@ -89,7 +85,13 @@ const defaultFlushMode = FlushMode.TurnBased;
|
|
|
89
85
|
// We can't estimate it fully, as we
|
|
90
86
|
// - do not know what properties relay service will add
|
|
91
87
|
// - we do not stringify final op, thus we do not know how much escaping will be added.
|
|
92
|
-
const defaultMaxBatchSizeInBytes =
|
|
88
|
+
const defaultMaxBatchSizeInBytes = 700 * 1024;
|
|
89
|
+
const defaultCompressionConfig = {
|
|
90
|
+
// Batches with content size exceeding this value will be compressed
|
|
91
|
+
minimumBatchSizeInBytes: 614400,
|
|
92
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
93
|
+
};
|
|
94
|
+
const defaultChunkSizeInBytes = 204800;
|
|
93
95
|
/**
|
|
94
96
|
* @deprecated - use ContainerRuntimeMessage instead
|
|
95
97
|
*/
|
|
@@ -125,8 +127,7 @@ export function getDeviceSpec() {
|
|
|
125
127
|
};
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
|
-
catch (_a) {
|
|
129
|
-
}
|
|
130
|
+
catch (_a) { }
|
|
130
131
|
return {};
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
@@ -137,8 +138,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
137
138
|
/**
|
|
138
139
|
* @internal
|
|
139
140
|
*/
|
|
140
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
|
|
141
|
-
var _a, _b, _c, _d, _e, _f;
|
|
141
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
|
|
142
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
142
143
|
if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
|
|
143
144
|
super();
|
|
144
145
|
this.context = context;
|
|
@@ -151,9 +152,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
151
152
|
this.summaryConfiguration = summaryConfiguration;
|
|
152
153
|
this.defaultMaxConsecutiveReconnects = 7;
|
|
153
154
|
this._orderSequentiallyCalls = 0;
|
|
154
|
-
this.
|
|
155
|
-
this.savedOps = [];
|
|
155
|
+
this.flushTaskExists = false;
|
|
156
156
|
this.consecutiveReconnects = 0;
|
|
157
|
+
this.ensureNoDataModelChangesCalls = 0;
|
|
158
|
+
/**
|
|
159
|
+
* Tracks the number of detected reentrant ops to report,
|
|
160
|
+
* in order to self-throttle the telemetry events.
|
|
161
|
+
*
|
|
162
|
+
* This should be removed as part of ADO:2322
|
|
163
|
+
*/
|
|
164
|
+
this.opReentryCallsToReport = 5;
|
|
157
165
|
this._disposed = false;
|
|
158
166
|
this.emitDirtyDocumentEvent = true;
|
|
159
167
|
this.defaultTelemetrySignalSampleCount = 100;
|
|
@@ -191,6 +199,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
191
199
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
192
200
|
}
|
|
193
201
|
};
|
|
202
|
+
this.innerDeltaManager = context.deltaManager;
|
|
203
|
+
this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
|
|
194
204
|
let loadSummaryNumber;
|
|
195
205
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
196
206
|
// get the values from the metadata blob.
|
|
@@ -213,24 +223,48 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
213
223
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
214
224
|
this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
|
|
215
225
|
this._connected = this.context.connected;
|
|
216
|
-
this.
|
|
217
|
-
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
226
|
+
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
|
|
218
227
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
228
|
+
this.mc.logger.sendTelemetryEvent({
|
|
229
|
+
eventName: "GCFeatureMatrix",
|
|
230
|
+
metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
|
|
231
|
+
inputs: JSON.stringify({
|
|
232
|
+
gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : uuid();
|
|
236
|
+
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
237
|
+
const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
|
|
238
|
+
const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
239
|
+
this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger));
|
|
240
|
+
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
219
241
|
if (this.summaryConfiguration.state === "enabled") {
|
|
220
242
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
221
243
|
}
|
|
244
|
+
const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
|
|
245
|
+
this.enableOpReentryCheck =
|
|
246
|
+
runtimeOptions.enableOpReentryCheck === true &&
|
|
247
|
+
// Allow for a break-glass config to override the options
|
|
248
|
+
disableOpReentryCheck !== true;
|
|
222
249
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
223
250
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
224
|
-
this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
|
|
225
251
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
226
252
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
227
253
|
this.maxConsecutiveReconnects =
|
|
228
|
-
(
|
|
229
|
-
|
|
254
|
+
(_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
|
|
255
|
+
if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
|
|
256
|
+
((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
|
|
257
|
+
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
258
|
+
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
259
|
+
this._flushMode = FlushMode.TurnBased;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
263
|
+
}
|
|
230
264
|
const pendingRuntimeState = context.pendingLocalState;
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
265
|
+
const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
|
|
266
|
+
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
267
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
|
|
234
268
|
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
235
269
|
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
236
270
|
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
@@ -239,7 +273,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
239
273
|
this.garbageCollector = GarbageCollector.create({
|
|
240
274
|
runtime: this,
|
|
241
275
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
242
|
-
baseSnapshot,
|
|
276
|
+
baseSnapshot: context.baseSnapshot,
|
|
243
277
|
baseLogger: this.mc.logger,
|
|
244
278
|
existing,
|
|
245
279
|
metadata,
|
|
@@ -249,7 +283,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
249
283
|
getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
|
|
250
284
|
readAndParseBlob: async (id) => readAndParse(this.storage, id),
|
|
251
285
|
getContainerDiagnosticId: () => this.context.id,
|
|
252
|
-
|
|
286
|
+
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
287
|
+
// delta manager would always return false for summarizer client.
|
|
288
|
+
activeConnection: () => this.innerDeltaManager.active,
|
|
253
289
|
});
|
|
254
290
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
255
291
|
this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
|
|
@@ -258,7 +294,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
258
294
|
// Latest change sequence number, no changes since summary applied yet
|
|
259
295
|
loadedFromSequenceNumber,
|
|
260
296
|
// Summary reference sequence number, undefined if no summary yet
|
|
261
|
-
baseSnapshot ? loadedFromSequenceNumber : undefined, {
|
|
297
|
+
context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
|
|
262
298
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
263
299
|
// a summary with an older protocol state.
|
|
264
300
|
canReuseHandle: false,
|
|
@@ -267,43 +303,61 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
267
303
|
throwOnFailure: true,
|
|
268
304
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
269
305
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
270
|
-
}
|
|
271
|
-
if
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
306
|
+
},
|
|
307
|
+
// Function to get GC data if needed. This will always be called by the root summarizer node to get GC data.
|
|
308
|
+
async (fullGC) => this.getGCDataInternal(fullGC),
|
|
309
|
+
// Function to get the GC details from the base snapshot we loaded from.
|
|
310
|
+
async () => this.garbageCollector.getBaseGCDetails());
|
|
311
|
+
if (context.baseSnapshot) {
|
|
312
|
+
this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
|
|
313
|
+
}
|
|
314
|
+
this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
|
|
315
|
+
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
276
316
|
if (!this.disposed) {
|
|
277
|
-
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
|
|
317
|
+
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
|
|
318
|
+
localId,
|
|
319
|
+
blobId,
|
|
320
|
+
});
|
|
278
321
|
}
|
|
279
|
-
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
|
|
322
|
+
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, () => this.getCurrentReferenceTimestampMs());
|
|
280
323
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
|
|
281
324
|
this.pendingStateManager = new PendingStateManager({
|
|
282
325
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
283
326
|
clientId: () => this.clientId,
|
|
284
327
|
close: this.closeFn,
|
|
285
328
|
connected: () => this.connected,
|
|
286
|
-
flush: this.flush.bind(this),
|
|
287
329
|
reSubmit: this.reSubmit.bind(this),
|
|
288
330
|
rollback: this.rollback.bind(this),
|
|
289
331
|
orderSequentially: this.orderSequentially.bind(this),
|
|
290
332
|
}, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
|
|
333
|
+
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
334
|
+
const compressionOptions = disableCompression === true
|
|
335
|
+
? {
|
|
336
|
+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
337
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
338
|
+
}
|
|
339
|
+
: runtimeOptions.compressionOptions;
|
|
340
|
+
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
291
341
|
this.outbox = new Outbox({
|
|
292
342
|
shouldSend: () => this.canSendOps(),
|
|
293
343
|
pendingStateManager: this.pendingStateManager,
|
|
294
344
|
containerContext: this.context,
|
|
295
345
|
compressor: new OpCompressor(this.mc.logger),
|
|
346
|
+
splitter: opSplitter,
|
|
296
347
|
config: {
|
|
297
|
-
compressionOptions
|
|
348
|
+
compressionOptions,
|
|
298
349
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
350
|
+
disablePartialFlush: disablePartialFlush === true,
|
|
299
351
|
},
|
|
352
|
+
logger: this.mc.logger,
|
|
300
353
|
});
|
|
301
354
|
this.context.quorum.on("removeMember", (clientId) => {
|
|
302
355
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
303
356
|
});
|
|
304
357
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
305
|
-
this.dirtyContainer =
|
|
306
|
-
|
|
358
|
+
this.dirtyContainer =
|
|
359
|
+
this.context.attachState !== AttachState.Attached ||
|
|
360
|
+
this.pendingStateManager.hasPendingMessages();
|
|
307
361
|
this.context.updateDirtyContainerState(this.dirtyContainer);
|
|
308
362
|
if (this.summariesDisabled) {
|
|
309
363
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
@@ -312,9 +366,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
312
366
|
const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
|
|
313
367
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
|
|
314
368
|
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
315
|
-
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary
|
|
369
|
+
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
316
370
|
if (this.context.clientDetails.type === summarizerClientType) {
|
|
317
|
-
this._summarizer = new Summarizer(
|
|
371
|
+
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
372
|
+
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
373
|
+
// information. The proxy delta manager would always return false for summarizer client.
|
|
374
|
+
() => this.innerDeltaManager.active));
|
|
318
375
|
}
|
|
319
376
|
else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
|
|
320
377
|
// Only create a SummaryManager and SummarizerClientElection
|
|
@@ -349,7 +406,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
349
406
|
this.deltaManager.on("readonly", (readonly) => {
|
|
350
407
|
// we accumulate ops while being in read-only state.
|
|
351
408
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
352
|
-
|
|
409
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
410
|
+
assert(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
353
411
|
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
354
412
|
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
355
413
|
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
@@ -367,13 +425,31 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
367
425
|
});
|
|
368
426
|
// logging hardware telemetry
|
|
369
427
|
logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
|
|
370
|
-
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature
|
|
428
|
+
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
|
|
429
|
+
disableCompression,
|
|
430
|
+
disableOpReentryCheck,
|
|
431
|
+
disableChunking,
|
|
432
|
+
disableAttachReorder: this.disableAttachReorder,
|
|
433
|
+
disablePartialFlush,
|
|
434
|
+
}), telemetryDocumentId: this.telemetryDocumentId }));
|
|
371
435
|
ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
372
436
|
BindBatchTracker(this, this.logger);
|
|
437
|
+
this.entryPoint = new LazyPromise(async () => {
|
|
438
|
+
if (this.context.clientDetails.type === summarizerClientType) {
|
|
439
|
+
assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
440
|
+
return this._summarizer;
|
|
441
|
+
}
|
|
442
|
+
return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
get IContainerRuntime() {
|
|
446
|
+
return this;
|
|
447
|
+
}
|
|
448
|
+
get IFluidRouter() {
|
|
449
|
+
return this;
|
|
373
450
|
}
|
|
374
|
-
get IContainerRuntime() { return this; }
|
|
375
|
-
get IFluidRouter() { return this; }
|
|
376
451
|
/**
|
|
452
|
+
* @deprecated - use loadRuntime instead.
|
|
377
453
|
* Load the stores from a snapshot and returns the runtime.
|
|
378
454
|
* @param context - Context of the container.
|
|
379
455
|
* @param registryEntries - Mapping to the stores.
|
|
@@ -384,7 +460,38 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
384
460
|
* allows mixin classes to leverage this method to define their own async initializer.
|
|
385
461
|
*/
|
|
386
462
|
static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
|
|
387
|
-
|
|
463
|
+
let existingFlag = true;
|
|
464
|
+
if (!existing) {
|
|
465
|
+
existingFlag = false;
|
|
466
|
+
}
|
|
467
|
+
return this.loadRuntime({
|
|
468
|
+
context,
|
|
469
|
+
registryEntries,
|
|
470
|
+
existing: existingFlag,
|
|
471
|
+
requestHandler,
|
|
472
|
+
runtimeOptions,
|
|
473
|
+
containerScope,
|
|
474
|
+
containerRuntimeCtor,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Load the stores from a snapshot and returns the runtime.
|
|
479
|
+
* @param params - An object housing the runtime properties:
|
|
480
|
+
* - context - Context of the container.
|
|
481
|
+
* - registryEntries - Mapping from data store types to their corresponding factories.
|
|
482
|
+
* - existing - Pass 'true' if loading from an existing snapshot.
|
|
483
|
+
* - requestHandler - (optional) Request handler for the request() method of the container runtime.
|
|
484
|
+
* Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
|
|
485
|
+
* - runtimeOptions - Additional options to be passed to the runtime
|
|
486
|
+
* - containerScope - runtime services provided with context
|
|
487
|
+
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
488
|
+
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
489
|
+
* - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
490
|
+
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
491
|
+
*/
|
|
492
|
+
static async loadRuntime(params) {
|
|
493
|
+
var _a, _b, _c, _d;
|
|
494
|
+
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
|
|
388
495
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
389
496
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
390
497
|
const backCompatContext = context;
|
|
@@ -394,23 +501,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
394
501
|
runtimeVersion: pkgVersion,
|
|
395
502
|
},
|
|
396
503
|
});
|
|
397
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode,
|
|
398
|
-
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
399
|
-
compressionAlgorithm: CompressionAlgorithms.lz4
|
|
400
|
-
}, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, } = runtimeOptions;
|
|
401
|
-
const pendingRuntimeState = context.pendingLocalState;
|
|
402
|
-
const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
|
|
403
|
-
const storage = !pendingRuntimeState ?
|
|
404
|
-
context.storage :
|
|
405
|
-
new SerializedSnapshotStorage(() => { return context.storage; }, pendingRuntimeState.snapshotBlobs);
|
|
504
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, } = runtimeOptions;
|
|
406
505
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
407
506
|
const tryFetchBlob = async (blobName) => {
|
|
408
|
-
|
|
409
|
-
|
|
507
|
+
var _a;
|
|
508
|
+
const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
|
|
509
|
+
if (context.baseSnapshot && blobId) {
|
|
410
510
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
411
511
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
412
|
-
assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
413
|
-
return readAndParse(storage, blobId);
|
|
512
|
+
assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
513
|
+
return readAndParse(context.storage, blobId);
|
|
414
514
|
}
|
|
415
515
|
};
|
|
416
516
|
const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
|
|
@@ -421,19 +521,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
421
521
|
]);
|
|
422
522
|
const loadExisting = existing === true || context.existing === true;
|
|
423
523
|
// read snapshot blobs needed for BlobManager to load
|
|
424
|
-
const blobManagerSnapshot = await BlobManager.load(baseSnapshot === null ||
|
|
524
|
+
const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
|
|
425
525
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
426
526
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
427
|
-
assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
428
|
-
return readAndParse(storage, id);
|
|
527
|
+
assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
528
|
+
return readAndParse(context.storage, id);
|
|
429
529
|
});
|
|
430
530
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
431
531
|
const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
|
|
432
532
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
433
|
-
if (!
|
|
533
|
+
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
434
534
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
435
535
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
436
|
-
if (loadSequenceNumberVerification !== "bypass" &&
|
|
536
|
+
if (loadSequenceNumberVerification !== "bypass" &&
|
|
537
|
+
runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
437
538
|
// "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
|
|
438
539
|
const error = new DataCorruptionError(
|
|
439
540
|
// pre-0.58 error message: SummaryMetadataMismatch
|
|
@@ -442,7 +543,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
442
543
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
443
544
|
}
|
|
444
545
|
else {
|
|
546
|
+
// Call both close and dispose as closeFn implementation will no longer dispose runtime in future
|
|
445
547
|
context.closeFn(error);
|
|
548
|
+
(_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
|
|
446
549
|
}
|
|
447
550
|
}
|
|
448
551
|
}
|
|
@@ -451,15 +554,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
451
554
|
gcOptions,
|
|
452
555
|
loadSequenceNumberVerification,
|
|
453
556
|
flushMode,
|
|
454
|
-
enableOfflineLoad,
|
|
455
557
|
compressionOptions,
|
|
456
558
|
maxBatchSizeInBytes,
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
559
|
+
chunkSizeInBytes,
|
|
560
|
+
enableOpReentryCheck,
|
|
561
|
+
}, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
|
|
562
|
+
initializeEntryPoint);
|
|
563
|
+
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
564
|
+
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
565
|
+
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
463
566
|
// Initialize the base state of the runtime before it's returned.
|
|
464
567
|
await runtime.initializeBaseState();
|
|
465
568
|
return runtime;
|
|
@@ -473,9 +576,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
473
576
|
get clientDetails() {
|
|
474
577
|
return this.context.clientDetails;
|
|
475
578
|
}
|
|
476
|
-
get deltaManager() {
|
|
477
|
-
return this.context.deltaManager;
|
|
478
|
-
}
|
|
479
579
|
get storage() {
|
|
480
580
|
return this._storage;
|
|
481
581
|
}
|
|
@@ -483,8 +583,18 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
483
583
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
484
584
|
return this.reSubmit;
|
|
485
585
|
}
|
|
586
|
+
get disposeFn() {
|
|
587
|
+
var _a;
|
|
588
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
589
|
+
return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
|
|
590
|
+
}
|
|
486
591
|
get closeFn() {
|
|
487
|
-
|
|
592
|
+
// Also call disposeFn to retain functionality of runtime being disposed on close
|
|
593
|
+
return (error) => {
|
|
594
|
+
var _a, _b;
|
|
595
|
+
this.context.closeFn(error);
|
|
596
|
+
(_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
|
|
597
|
+
};
|
|
488
598
|
}
|
|
489
599
|
get flushMode() {
|
|
490
600
|
return this._flushMode;
|
|
@@ -501,6 +611,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
501
611
|
get IFluidHandleContext() {
|
|
502
612
|
return this.handleContext;
|
|
503
613
|
}
|
|
614
|
+
/**
|
|
615
|
+
* Invokes the given callback and expects that no ops are submitted
|
|
616
|
+
* until execution finishes. If an op is submitted, an error will be raised.
|
|
617
|
+
*
|
|
618
|
+
* Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
|
|
619
|
+
*
|
|
620
|
+
* @param callback - the callback to be invoked
|
|
621
|
+
*/
|
|
622
|
+
ensureNoDataModelChanges(callback) {
|
|
623
|
+
this.ensureNoDataModelChangesCalls++;
|
|
624
|
+
try {
|
|
625
|
+
return callback();
|
|
626
|
+
}
|
|
627
|
+
finally {
|
|
628
|
+
this.ensureNoDataModelChangesCalls--;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
504
631
|
get connected() {
|
|
505
632
|
return this._connected;
|
|
506
633
|
}
|
|
@@ -509,48 +636,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
509
636
|
var _a;
|
|
510
637
|
return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
|
|
511
638
|
}
|
|
512
|
-
get disposed() {
|
|
639
|
+
get disposed() {
|
|
640
|
+
return this._disposed;
|
|
641
|
+
}
|
|
513
642
|
get summarizer() {
|
|
514
643
|
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
515
644
|
return this._summarizer;
|
|
516
645
|
}
|
|
517
646
|
isSummariesDisabled() {
|
|
518
|
-
// back-compat: disableSummaries was moved from ISummaryRuntimeOptions
|
|
519
|
-
// to ISummaryConfiguration in 0.60.
|
|
520
|
-
if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
647
|
return this.summaryConfiguration.state === "disabled";
|
|
524
648
|
}
|
|
525
649
|
isHeuristicsDisabled() {
|
|
526
|
-
var _a;
|
|
527
|
-
// back-compat: disableHeuristics was moved from ISummarizerOptions
|
|
528
|
-
// to ISummaryConfiguration in 0.60.
|
|
529
|
-
if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
|
|
530
|
-
return true;
|
|
531
|
-
}
|
|
532
650
|
return this.summaryConfiguration.state === "disableHeuristics";
|
|
533
651
|
}
|
|
534
|
-
isSummarizerClientElectionEnabled() {
|
|
535
|
-
var _a;
|
|
536
|
-
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
|
|
537
|
-
return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
|
|
538
|
-
}
|
|
539
|
-
// back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
|
|
540
|
-
// to ISummaryConfiguration in 0.60.
|
|
541
|
-
if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
|
|
542
|
-
return true;
|
|
543
|
-
}
|
|
544
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
545
|
-
? this.summaryConfiguration.summarizerClientElection === true
|
|
546
|
-
: false;
|
|
547
|
-
}
|
|
548
652
|
getMaxOpsSinceLastSummary() {
|
|
549
|
-
// back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
|
|
550
|
-
// to ISummaryConfiguration in 0.60.
|
|
551
|
-
if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
|
|
552
|
-
return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
|
|
553
|
-
}
|
|
554
653
|
return this.summaryConfiguration.state !== "disabled"
|
|
555
654
|
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
556
655
|
: 0;
|
|
@@ -569,7 +668,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
569
668
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
570
669
|
*/
|
|
571
670
|
async initializeBaseState() {
|
|
572
|
-
await this.initializeBaseSnapshotBlobs();
|
|
573
671
|
await this.garbageCollector.initializeBaseState();
|
|
574
672
|
}
|
|
575
673
|
dispose(error) {
|
|
@@ -594,16 +692,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
594
692
|
this.emit("dispose");
|
|
595
693
|
this.removeAllListeners();
|
|
596
694
|
}
|
|
597
|
-
get IFluidTokenProvider() {
|
|
598
|
-
var _a;
|
|
599
|
-
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
|
|
600
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
601
|
-
return {
|
|
602
|
-
intelligence: this.options.intelligence,
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
return undefined;
|
|
606
|
-
}
|
|
607
695
|
/**
|
|
608
696
|
* Notifies this object about the request made to the container.
|
|
609
697
|
* @param request - Request made to the handler.
|
|
@@ -649,7 +737,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
649
737
|
status: 200,
|
|
650
738
|
mimeType: "fluid/object",
|
|
651
739
|
value: blob,
|
|
652
|
-
}
|
|
740
|
+
}
|
|
741
|
+
: create404Response(request);
|
|
653
742
|
}
|
|
654
743
|
else if (requestParser.pathParts.length > 0) {
|
|
655
744
|
const dataStore = await this.getDataStoreFromRequest(id, request);
|
|
@@ -665,37 +754,31 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
665
754
|
return exceptionToResponse(error);
|
|
666
755
|
}
|
|
667
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
|
|
759
|
+
*/
|
|
760
|
+
async getEntryPoint() {
|
|
761
|
+
return this.entryPoint;
|
|
762
|
+
}
|
|
668
763
|
internalId(maybeAlias) {
|
|
669
764
|
var _a;
|
|
670
765
|
return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
|
|
671
766
|
}
|
|
672
767
|
async getDataStoreFromRequest(id, request) {
|
|
673
|
-
var _a, _b, _c
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
768
|
+
var _a, _b, _c;
|
|
769
|
+
const headerData = {};
|
|
770
|
+
if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
|
|
771
|
+
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
772
|
+
}
|
|
773
|
+
if (typeof ((_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.viaHandle]) === "boolean") {
|
|
774
|
+
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
775
|
+
}
|
|
776
|
+
if (typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[AllowTombstoneRequestHeaderKey]) === "boolean") {
|
|
777
|
+
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
778
|
+
}
|
|
680
779
|
await this.dataStores.waitIfPendingAlias(id);
|
|
681
780
|
const internalId = this.internalId(id);
|
|
682
|
-
const dataStoreContext = await this.dataStores.getDataStore(internalId,
|
|
683
|
-
/**
|
|
684
|
-
* If GC should run and this an external app request with "externalRequest" header, we need to return
|
|
685
|
-
* an error if the data store being requested is marked as unreferenced as per the data store's base
|
|
686
|
-
* GC data.
|
|
687
|
-
*
|
|
688
|
-
* This is a workaround to handle scenarios where a data store shared with an external app is deleted
|
|
689
|
-
* and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
|
|
690
|
-
*/
|
|
691
|
-
if (((_e = request.headers) === null || _e === void 0 ? void 0 : _e[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
|
|
692
|
-
// The data store is referenced if used routes in the base summary has a route to self.
|
|
693
|
-
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
694
|
-
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
695
|
-
if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
|
|
696
|
-
throw responseToException(create404Response(request), request);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
781
|
+
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
699
782
|
const dataStoreChannel = await dataStoreContext.realize();
|
|
700
783
|
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
701
784
|
// the same as GC nodes id.
|
|
@@ -711,7 +794,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
711
794
|
summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
|
|
712
795
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
713
796
|
// last summary.
|
|
714
|
-
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
|
|
797
|
+
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
|
|
715
798
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
716
799
|
}
|
|
717
800
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
@@ -827,7 +910,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
827
910
|
// If attachment blobs were added while disconnected, we need to delay
|
|
828
911
|
// propagation of the "connected" event until we have uploaded them to
|
|
829
912
|
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
830
|
-
|
|
913
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
914
|
+
const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
831
915
|
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
832
916
|
assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
|
|
833
917
|
assert(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
@@ -862,9 +946,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
862
946
|
if (reconnection) {
|
|
863
947
|
this.consecutiveReconnects++;
|
|
864
948
|
if (!this.shouldContinueReconnecting()) {
|
|
865
|
-
this.closeFn(DataProcessingError.create(
|
|
866
|
-
// eslint-disable-next-line max-len
|
|
867
|
-
"Runtime detected too many reconnects with no progress syncing local ops. Batch of ops is likely too large (over 1Mb)", "setConnectionState", undefined, {
|
|
949
|
+
this.closeFn(DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
|
|
868
950
|
dataLoss: 1,
|
|
869
951
|
attempts: this.consecutiveReconnects,
|
|
870
952
|
pendingMessages: this.pendingStateManager.pendingMessagesCount,
|
|
@@ -879,12 +961,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
879
961
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
880
962
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
881
963
|
}
|
|
964
|
+
async notifyOpReplay(message) {
|
|
965
|
+
await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
|
|
966
|
+
}
|
|
882
967
|
process(messageArg, local) {
|
|
883
968
|
var _a;
|
|
884
969
|
this.verifyNotClosed();
|
|
885
|
-
if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
|
|
886
|
-
this.savedOps.push(messageArg);
|
|
887
|
-
}
|
|
888
970
|
// Whether or not the message is actually a runtime message.
|
|
889
971
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
890
972
|
// or something different, like a system message.
|
|
@@ -898,7 +980,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
898
980
|
this.scheduleManager.beforeOpProcessing(message);
|
|
899
981
|
try {
|
|
900
982
|
let localOpMetadata;
|
|
901
|
-
if (local && runtimeMessage) {
|
|
983
|
+
if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
|
|
902
984
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
|
|
903
985
|
}
|
|
904
986
|
// If there are no more pending messages after processing a local message,
|
|
@@ -924,7 +1006,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
924
1006
|
case ContainerMessageType.Rejoin:
|
|
925
1007
|
break;
|
|
926
1008
|
default:
|
|
927
|
-
|
|
1009
|
+
if (runtimeMessage) {
|
|
1010
|
+
const error = DataProcessingError.create(
|
|
1011
|
+
// Former assert 0x3ce
|
|
1012
|
+
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1013
|
+
local,
|
|
1014
|
+
type: message.type,
|
|
1015
|
+
contentType: typeof message.contents,
|
|
1016
|
+
batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
|
|
1017
|
+
compression: message.compression,
|
|
1018
|
+
});
|
|
1019
|
+
this.closeFn(error);
|
|
1020
|
+
throw error;
|
|
1021
|
+
}
|
|
928
1022
|
}
|
|
929
1023
|
// For back-compat, notify only about runtime messages for now.
|
|
930
1024
|
if (runtimeMessage) {
|
|
@@ -971,7 +1065,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
971
1065
|
if (message.clientId === this.clientId && this.connected) {
|
|
972
1066
|
// Check to see if the signal was lost.
|
|
973
1067
|
if (this._perfSignalData.trackingSignalSequenceNumber !== undefined &&
|
|
974
|
-
envelope.clientSignalSequenceNumber >
|
|
1068
|
+
envelope.clientSignalSequenceNumber >
|
|
1069
|
+
this._perfSignalData.trackingSignalSequenceNumber) {
|
|
975
1070
|
this._perfSignalData.signalsLost++;
|
|
976
1071
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
977
1072
|
this.logger.sendErrorEvent({
|
|
@@ -982,8 +1077,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
982
1077
|
clientSignalSequenceNumber: envelope.clientSignalSequenceNumber,
|
|
983
1078
|
});
|
|
984
1079
|
}
|
|
985
|
-
else if (envelope.clientSignalSequenceNumber ===
|
|
986
|
-
this.
|
|
1080
|
+
else if (envelope.clientSignalSequenceNumber ===
|
|
1081
|
+
this._perfSignalData.trackingSignalSequenceNumber) {
|
|
1082
|
+
// only logging for the first connection and the trackingSignalSequenceNUmber.
|
|
1083
|
+
if (this.consecutiveReconnects === 0) {
|
|
1084
|
+
this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
|
|
1085
|
+
}
|
|
987
1086
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
988
1087
|
}
|
|
989
1088
|
}
|
|
@@ -1000,7 +1099,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1000
1099
|
async getRootDataStoreChannel(id, wait = true) {
|
|
1001
1100
|
await this.dataStores.waitIfPendingAlias(id);
|
|
1002
1101
|
const internalId = this.internalId(id);
|
|
1003
|
-
const context = await this.dataStores.getDataStore(internalId, wait
|
|
1102
|
+
const context = await this.dataStores.getDataStore(internalId, { wait });
|
|
1004
1103
|
assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
|
|
1005
1104
|
return context.realize();
|
|
1006
1105
|
}
|
|
@@ -1049,7 +1148,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1049
1148
|
finally {
|
|
1050
1149
|
this._orderSequentiallyCalls--;
|
|
1051
1150
|
}
|
|
1052
|
-
|
|
1151
|
+
// We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
|
|
1152
|
+
if (this.flushMode !== FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
|
|
1053
1153
|
this.flush();
|
|
1054
1154
|
}
|
|
1055
1155
|
return result;
|
|
@@ -1068,7 +1168,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1068
1168
|
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
1069
1169
|
}
|
|
1070
1170
|
async _createDataStoreWithProps(pkg, props, id = uuid()) {
|
|
1071
|
-
const fluidDataStore = await this.dataStores
|
|
1171
|
+
const fluidDataStore = await this.dataStores
|
|
1172
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
|
|
1173
|
+
.realize();
|
|
1072
1174
|
return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
|
|
1073
1175
|
}
|
|
1074
1176
|
async _createDataStore(pkg, id = uuid(), props) {
|
|
@@ -1077,13 +1179,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1077
1179
|
.realize();
|
|
1078
1180
|
}
|
|
1079
1181
|
canSendOps() {
|
|
1080
|
-
|
|
1182
|
+
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
1183
|
+
// container runtime's ability to send ops depend on the actual readonly state of the delta manager.
|
|
1184
|
+
return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1081
1185
|
}
|
|
1082
1186
|
/**
|
|
1083
1187
|
* Are we in the middle of batching ops together?
|
|
1084
1188
|
*/
|
|
1085
1189
|
currentlyBatching() {
|
|
1086
|
-
return this.flushMode
|
|
1190
|
+
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
1087
1191
|
}
|
|
1088
1192
|
getQuorum() {
|
|
1089
1193
|
return this.context.quorum;
|
|
@@ -1199,81 +1303,98 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1199
1303
|
async summarize(options) {
|
|
1200
1304
|
this.verifyNotClosed();
|
|
1201
1305
|
const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
|
|
1306
|
+
const telemetryContext = new TelemetryContext();
|
|
1307
|
+
// Add the options that are used to generate this summary to the telemetry context.
|
|
1308
|
+
telemetryContext.setMultiple("fluid_Summarize", "Options", {
|
|
1309
|
+
fullTree,
|
|
1310
|
+
trackState,
|
|
1311
|
+
runGC,
|
|
1312
|
+
fullGC,
|
|
1313
|
+
runSweep,
|
|
1314
|
+
});
|
|
1202
1315
|
let gcStats;
|
|
1203
1316
|
if (runGC) {
|
|
1204
|
-
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1317
|
+
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
|
|
1205
1318
|
}
|
|
1206
|
-
const telemetryContext = new TelemetryContext();
|
|
1207
1319
|
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
|
|
1208
|
-
this.logger.sendTelemetryEvent({
|
|
1320
|
+
this.logger.sendTelemetryEvent({
|
|
1321
|
+
eventName: "SummarizeTelemetry",
|
|
1322
|
+
details: telemetryContext.serialize(),
|
|
1323
|
+
});
|
|
1209
1324
|
assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1210
1325
|
return { stats, summary, gcStats };
|
|
1211
1326
|
}
|
|
1212
1327
|
/**
|
|
1213
|
-
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
1214
1328
|
* Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
|
|
1215
1329
|
* the garbage collector of references detected since the last GC run. Most references are notified immediately
|
|
1216
1330
|
* but there can be some for which async operation is required (such as detecting new root data stores).
|
|
1331
|
+
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
1217
1332
|
*/
|
|
1218
1333
|
async updateStateBeforeGC() {
|
|
1219
1334
|
return this.dataStores.updateStateBeforeGC();
|
|
1220
1335
|
}
|
|
1336
|
+
async getGCDataInternal(fullGC) {
|
|
1337
|
+
return this.dataStores.getGCData(fullGC);
|
|
1338
|
+
}
|
|
1221
1339
|
/**
|
|
1222
|
-
* Implementation of IGarbageCollectionRuntime::getGCData.
|
|
1223
1340
|
* Generates and returns the GC data for this container.
|
|
1224
1341
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
1342
|
+
* @see IGarbageCollectionRuntime.getGCData
|
|
1225
1343
|
*/
|
|
1226
1344
|
async getGCData(fullGC) {
|
|
1227
1345
|
const builder = new GCDataBuilder();
|
|
1228
|
-
const dsGCData = await this.
|
|
1346
|
+
const dsGCData = await this.summarizerNode.getGCData(fullGC);
|
|
1229
1347
|
builder.addNodes(dsGCData.gcNodes);
|
|
1230
1348
|
const blobsGCData = this.blobManager.getGCData(fullGC);
|
|
1231
1349
|
builder.addNodes(blobsGCData.gcNodes);
|
|
1232
1350
|
return builder.getGCData();
|
|
1233
1351
|
}
|
|
1234
1352
|
/**
|
|
1235
|
-
* Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
|
|
1236
1353
|
* After GC has run, called to notify this container's nodes of routes that are used in it.
|
|
1237
1354
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
1355
|
+
* @see IGarbageCollectionRuntime.updateUsedRoutes
|
|
1238
1356
|
*/
|
|
1239
1357
|
updateUsedRoutes(usedRoutes) {
|
|
1240
1358
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
1241
1359
|
// summarizing is required and asserted by the the summarizer node. We are the root and are
|
|
1242
1360
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1243
1361
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
for (const route of usedRoutes) {
|
|
1247
|
-
if (this.isBlobPath(route)) {
|
|
1248
|
-
blobManagerUsedRoutes.push(route);
|
|
1249
|
-
}
|
|
1250
|
-
else {
|
|
1251
|
-
dataStoreUsedRoutes.push(route);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
this.blobManager.updateUsedRoutes(blobManagerUsedRoutes);
|
|
1255
|
-
this.dataStores.updateUsedRoutes(dataStoreUsedRoutes);
|
|
1362
|
+
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
1363
|
+
this.dataStores.updateUsedRoutes(dataStoreRoutes);
|
|
1256
1364
|
}
|
|
1257
1365
|
/**
|
|
1258
|
-
* This is called to update objects whose routes are unused.
|
|
1259
|
-
*
|
|
1260
|
-
* @param unusedRoutes - The routes that are unused in all data stores and attachment blobs in this Container.
|
|
1261
|
-
* @param tombstone - if true, the objects corresponding to unused routes are marked tombstones. Otherwise, they
|
|
1262
|
-
* are deleted.
|
|
1366
|
+
* This is called to update objects whose routes are unused.
|
|
1367
|
+
* @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
|
|
1263
1368
|
*/
|
|
1264
|
-
updateUnusedRoutes(unusedRoutes
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1369
|
+
updateUnusedRoutes(unusedRoutes) {
|
|
1370
|
+
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
1371
|
+
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1372
|
+
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* @deprecated - Replaced by deleteSweepReadyNodes.
|
|
1376
|
+
*/
|
|
1377
|
+
deleteUnusedNodes(unusedRoutes) {
|
|
1378
|
+
throw new Error("deleteUnusedRoutes should not be called");
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
1382
|
+
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
1383
|
+
* @returns - The routes of nodes that were deleted.
|
|
1384
|
+
*/
|
|
1385
|
+
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
1386
|
+
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
1387
|
+
const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
|
|
1388
|
+
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* This is called to update objects that are tombstones.
|
|
1392
|
+
* @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
|
|
1393
|
+
*/
|
|
1394
|
+
updateTombstonedRoutes(tombstonedRoutes) {
|
|
1395
|
+
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
1396
|
+
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
1397
|
+
this.dataStores.updateTombstonedRoutes(dataStoreRoutes);
|
|
1277
1398
|
}
|
|
1278
1399
|
/**
|
|
1279
1400
|
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
@@ -1302,7 +1423,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1302
1423
|
async getGCNodePackagePath(nodePath) {
|
|
1303
1424
|
switch (this.getNodeType(nodePath)) {
|
|
1304
1425
|
case GCNodeType.Blob:
|
|
1305
|
-
return [
|
|
1426
|
+
return [BlobManager.basePath];
|
|
1306
1427
|
case GCNodeType.DataStore:
|
|
1307
1428
|
case GCNodeType.SubDataStore:
|
|
1308
1429
|
return this.dataStores.getDataStorePackagePath(nodePath);
|
|
@@ -1320,12 +1441,31 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1320
1441
|
}
|
|
1321
1442
|
return true;
|
|
1322
1443
|
}
|
|
1444
|
+
/**
|
|
1445
|
+
* From a given list of routes, separate and return routes that belong to blob manager and data stores.
|
|
1446
|
+
* @param routes - A list of routes that can belong to data stores or blob manager.
|
|
1447
|
+
* @returns - Two route lists - One that contains routes for blob manager and another one that contains routes
|
|
1448
|
+
* for data stores.
|
|
1449
|
+
*/
|
|
1450
|
+
getDataStoreAndBlobManagerRoutes(routes) {
|
|
1451
|
+
const blobManagerRoutes = [];
|
|
1452
|
+
const dataStoreRoutes = [];
|
|
1453
|
+
for (const route of routes) {
|
|
1454
|
+
if (this.isBlobPath(route)) {
|
|
1455
|
+
blobManagerRoutes.push(route);
|
|
1456
|
+
}
|
|
1457
|
+
else {
|
|
1458
|
+
dataStoreRoutes.push(route);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return { blobManagerRoutes, dataStoreRoutes };
|
|
1462
|
+
}
|
|
1323
1463
|
/**
|
|
1324
1464
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
1325
1465
|
* @returns the statistics of the garbage collection run; undefined if GC did not run.
|
|
1326
1466
|
*/
|
|
1327
|
-
async collectGarbage(options) {
|
|
1328
|
-
return this.garbageCollector.collectGarbage(options);
|
|
1467
|
+
async collectGarbage(options, telemetryContext) {
|
|
1468
|
+
return this.garbageCollector.collectGarbage(options, telemetryContext);
|
|
1329
1469
|
}
|
|
1330
1470
|
/**
|
|
1331
1471
|
* Called when a new outbound reference is added to another node. This is used by garbage collection to identify
|
|
@@ -1346,7 +1486,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1346
1486
|
*/
|
|
1347
1487
|
async submitSummary(options) {
|
|
1348
1488
|
var _a, _b;
|
|
1349
|
-
const { fullTree, refreshLatestAck, summaryLogger } = options;
|
|
1489
|
+
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
1350
1490
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1351
1491
|
// use it for all events logged during this summary.
|
|
1352
1492
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1362,8 +1502,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1362
1502
|
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
1363
1503
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
1364
1504
|
}
|
|
1505
|
+
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1365
1506
|
try {
|
|
1366
1507
|
await this.deltaManager.inbound.pause();
|
|
1508
|
+
if (shouldPauseInboundSignal) {
|
|
1509
|
+
await this.deltaManager.inboundSignal.pause();
|
|
1510
|
+
}
|
|
1367
1511
|
const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
1368
1512
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1369
1513
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
@@ -1391,7 +1535,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1391
1535
|
if (this.deltaManager.lastSequenceNumber !== summaryRefSeqNum) {
|
|
1392
1536
|
return {
|
|
1393
1537
|
continue: false,
|
|
1394
|
-
// eslint-disable-next-line max-len
|
|
1395
1538
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
1396
1539
|
};
|
|
1397
1540
|
}
|
|
@@ -1399,7 +1542,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1399
1542
|
if (lastAck !== this.summaryCollection.latestAck) {
|
|
1400
1543
|
return {
|
|
1401
1544
|
continue: false,
|
|
1402
|
-
// eslint-disable-next-line max-len
|
|
1403
1545
|
error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
|
|
1404
1546
|
};
|
|
1405
1547
|
}
|
|
@@ -1421,7 +1563,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1421
1563
|
const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
|
|
1422
1564
|
try {
|
|
1423
1565
|
summarizeResult = await this.summarize({
|
|
1424
|
-
fullTree: fullTree
|
|
1566
|
+
fullTree: fullTree || forcedFullTree,
|
|
1425
1567
|
trackState: true,
|
|
1426
1568
|
summaryLogger: summaryNumberLogger,
|
|
1427
1569
|
runGC: this.garbageCollector.shouldRunGC,
|
|
@@ -1466,8 +1608,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1466
1608
|
// latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
|
|
1467
1609
|
// the one fetched from storage as parent as that is the latest.
|
|
1468
1610
|
let summaryContext;
|
|
1469
|
-
if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
|
|
1470
|
-
|
|
1611
|
+
if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId &&
|
|
1612
|
+
latestSnapshotVersionId !== undefined) {
|
|
1471
1613
|
summaryContext = {
|
|
1472
1614
|
proposalHandle: undefined,
|
|
1473
1615
|
ackHandle: latestSnapshotVersionId,
|
|
@@ -1510,7 +1652,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1510
1652
|
}
|
|
1511
1653
|
let clientSequenceNumber;
|
|
1512
1654
|
try {
|
|
1513
|
-
clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
|
|
1655
|
+
clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
|
|
1514
1656
|
}
|
|
1515
1657
|
catch (error) {
|
|
1516
1658
|
return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
|
|
@@ -1524,6 +1666,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1524
1666
|
this.summarizerNode.clearSummary();
|
|
1525
1667
|
// Restart the delta manager
|
|
1526
1668
|
this.deltaManager.inbound.resume();
|
|
1669
|
+
if (shouldPauseInboundSignal) {
|
|
1670
|
+
this.deltaManager.inboundSignal.resume();
|
|
1671
|
+
}
|
|
1527
1672
|
}
|
|
1528
1673
|
}
|
|
1529
1674
|
hasPendingMessages() {
|
|
@@ -1566,16 +1711,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1566
1711
|
}
|
|
1567
1712
|
submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
|
|
1568
1713
|
this.verifyNotClosed();
|
|
1714
|
+
this.verifyCanSubmitOps();
|
|
1569
1715
|
// There should be no ops in detached container state!
|
|
1570
1716
|
assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
1571
|
-
const
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1717
|
+
const serializedContent = JSON.stringify({ type, contents });
|
|
1718
|
+
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
1719
|
+
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
1720
|
+
if (this.innerDeltaManager.readOnlyInfo.readonly) {
|
|
1721
|
+
this.logger.sendTelemetryEvent({
|
|
1722
|
+
eventName: "SubmitOpInReadonly",
|
|
1723
|
+
connected: this.connected,
|
|
1724
|
+
});
|
|
1575
1725
|
}
|
|
1576
1726
|
const message = {
|
|
1577
1727
|
contents: serializedContent,
|
|
1578
|
-
deserializedContent,
|
|
1728
|
+
deserializedContent: JSON.parse(serializedContent),
|
|
1579
1729
|
metadata,
|
|
1580
1730
|
localOpMetadata,
|
|
1581
1731
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
@@ -1601,8 +1751,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1601
1751
|
// issue than sending.
|
|
1602
1752
|
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
1603
1753
|
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
1604
|
-
if (this.currentlyBatching() &&
|
|
1605
|
-
|
|
1754
|
+
if (this.currentlyBatching() &&
|
|
1755
|
+
type === ContainerMessageType.Attach &&
|
|
1756
|
+
this.disableAttachReorder !== true) {
|
|
1606
1757
|
this.outbox.submitAttach(message);
|
|
1607
1758
|
}
|
|
1608
1759
|
else {
|
|
@@ -1611,14 +1762,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1611
1762
|
if (!this.currentlyBatching()) {
|
|
1612
1763
|
this.flush();
|
|
1613
1764
|
}
|
|
1614
|
-
else
|
|
1615
|
-
this.
|
|
1616
|
-
// Queue a microtask to detect the end of the turn and force a flush.
|
|
1617
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1618
|
-
Promise.resolve().then(() => {
|
|
1619
|
-
this.flushMicroTaskExists = false;
|
|
1620
|
-
this.flush();
|
|
1621
|
-
}).catch((error) => { this.closeFn(error); });
|
|
1765
|
+
else {
|
|
1766
|
+
this.scheduleFlush();
|
|
1622
1767
|
}
|
|
1623
1768
|
}
|
|
1624
1769
|
catch (error) {
|
|
@@ -1629,14 +1774,47 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1629
1774
|
this.updateDocumentDirtyState(true);
|
|
1630
1775
|
}
|
|
1631
1776
|
}
|
|
1632
|
-
|
|
1777
|
+
scheduleFlush() {
|
|
1778
|
+
if (this.flushTaskExists) {
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
this.flushTaskExists = true;
|
|
1782
|
+
const flush = () => {
|
|
1783
|
+
this.flushTaskExists = false;
|
|
1784
|
+
try {
|
|
1785
|
+
this.flush();
|
|
1786
|
+
}
|
|
1787
|
+
catch (error) {
|
|
1788
|
+
this.closeFn(error);
|
|
1789
|
+
}
|
|
1790
|
+
};
|
|
1791
|
+
switch (this.flushMode) {
|
|
1792
|
+
case FlushMode.TurnBased:
|
|
1793
|
+
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
1794
|
+
// batch at the end of the turn
|
|
1795
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1796
|
+
Promise.resolve().then(flush);
|
|
1797
|
+
break;
|
|
1798
|
+
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
1799
|
+
case FlushModeExperimental.Async:
|
|
1800
|
+
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
1801
|
+
// batch when all micro-tasks are complete.
|
|
1802
|
+
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
1803
|
+
setTimeout(flush, 0);
|
|
1804
|
+
break;
|
|
1805
|
+
default:
|
|
1806
|
+
assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
1807
|
+
break;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
1633
1811
|
this.verifyNotClosed();
|
|
1634
1812
|
assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
1635
1813
|
// System message should not be sent in the middle of the batch.
|
|
1636
1814
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
1637
1815
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
1638
1816
|
return this.context.submitSummaryFn !== undefined
|
|
1639
|
-
? this.context.submitSummaryFn(contents)
|
|
1817
|
+
? this.context.submitSummaryFn(contents, referenceSequenceNumber)
|
|
1640
1818
|
: this.context.submitFn(MessageType.Summarize, contents, false);
|
|
1641
1819
|
}
|
|
1642
1820
|
/**
|
|
@@ -1648,6 +1826,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1648
1826
|
throw new Error("Runtime is closed");
|
|
1649
1827
|
}
|
|
1650
1828
|
}
|
|
1829
|
+
verifyCanSubmitOps() {
|
|
1830
|
+
if (this.ensureNoDataModelChangesCalls > 0) {
|
|
1831
|
+
const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
|
|
1832
|
+
if (this.opReentryCallsToReport > 0) {
|
|
1833
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
1834
|
+
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
1835
|
+
new UsageError(errorMessage));
|
|
1836
|
+
this.opReentryCallsToReport--;
|
|
1837
|
+
}
|
|
1838
|
+
// Creating ops while processing ops can lead
|
|
1839
|
+
// to undefined behavior and events observed in the wrong order.
|
|
1840
|
+
// For example, we have two callbacks registered for a DDS, A and B.
|
|
1841
|
+
// Then if on change #1 callback A creates change #2, the invocation flow will be:
|
|
1842
|
+
//
|
|
1843
|
+
// A because of #1
|
|
1844
|
+
// A because of #2
|
|
1845
|
+
// B because of #2
|
|
1846
|
+
// B because of #1
|
|
1847
|
+
//
|
|
1848
|
+
// The runtime must enforce op coherence by not allowing ops to be submitted
|
|
1849
|
+
// while ops are being processed.
|
|
1850
|
+
if (this.enableOpReentryCheck) {
|
|
1851
|
+
throw new UsageError(errorMessage);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1651
1855
|
/**
|
|
1652
1856
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
1653
1857
|
* reconnect and there are pending messages.
|
|
@@ -1706,28 +1910,50 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1706
1910
|
// The call to fetch the snapshot is very expensive and not always needed.
|
|
1707
1911
|
// It should only be done by the summarizerNode, if required.
|
|
1708
1912
|
// When fetching from storage we will always get the latest version and do not use the ackHandle.
|
|
1709
|
-
const
|
|
1710
|
-
|
|
1711
|
-
eventName: "
|
|
1913
|
+
const fetchLatestSnapshot = async () => {
|
|
1914
|
+
let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1915
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
1712
1916
|
ackHandle,
|
|
1713
|
-
summaryRefSeq,
|
|
1714
|
-
fetchLatest: true,
|
|
1715
|
-
});
|
|
1716
|
-
const latestSnapshotRefSeq = await seqFromTree(fetchResult.snapshotTree, readAndParseBlob);
|
|
1717
|
-
summaryLogger.sendTelemetryEvent({
|
|
1718
|
-
eventName: "LatestSummaryRetrieved",
|
|
1719
|
-
ackHandle,
|
|
1720
|
-
lastSequenceNumber: latestSnapshotRefSeq,
|
|
1721
1917
|
targetSequenceNumber: summaryRefSeq,
|
|
1722
|
-
});
|
|
1918
|
+
}, readAndParseBlob);
|
|
1919
|
+
/**
|
|
1920
|
+
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
1921
|
+
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
1922
|
+
* However, there are couple of scenarios where it's possible:
|
|
1923
|
+
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
1924
|
+
* the document being unusable and we should not proceed.
|
|
1925
|
+
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
1926
|
+
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
1927
|
+
* state.
|
|
1928
|
+
*/
|
|
1929
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
1930
|
+
/* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
|
|
1931
|
+
fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
1932
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
1933
|
+
ackHandle,
|
|
1934
|
+
targetSequenceNumber: summaryRefSeq,
|
|
1935
|
+
}, readAndParseBlob, ackHandle);
|
|
1936
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
1937
|
+
const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
1938
|
+
ackHandle,
|
|
1939
|
+
summaryRefSeq,
|
|
1940
|
+
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
1941
|
+
});
|
|
1942
|
+
this.closeFn(error);
|
|
1943
|
+
throw error;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1723
1946
|
// In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
|
|
1724
1947
|
// wait for the delta manager to catch up before refreshing the latest Summary.
|
|
1725
|
-
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
|
|
1726
|
-
return
|
|
1948
|
+
await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
|
|
1949
|
+
return {
|
|
1950
|
+
snapshotTree: fetchResult.snapshotTree,
|
|
1951
|
+
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
1952
|
+
};
|
|
1727
1953
|
};
|
|
1728
|
-
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq,
|
|
1954
|
+
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
1729
1955
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1730
|
-
await this.garbageCollector.
|
|
1956
|
+
await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
|
|
1731
1957
|
}
|
|
1732
1958
|
/**
|
|
1733
1959
|
* Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
|
|
@@ -1736,76 +1962,55 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1736
1962
|
* @returns downloaded snapshot's reference sequence number
|
|
1737
1963
|
*/
|
|
1738
1964
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
1739
|
-
const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
|
|
1740
|
-
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
1741
|
-
fetchLatest: true,
|
|
1742
|
-
}, FetchSource.noCache);
|
|
1743
1965
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
1744
|
-
const latestSnapshotRefSeq = await
|
|
1745
|
-
|
|
1966
|
+
const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1967
|
+
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
1968
|
+
}, readAndParseBlob);
|
|
1969
|
+
const fetchLatestSnapshot = {
|
|
1970
|
+
snapshotTree,
|
|
1971
|
+
snapshotRefSeq: latestSnapshotRefSeq,
|
|
1972
|
+
};
|
|
1973
|
+
const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
1746
1974
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1747
|
-
await this.garbageCollector.
|
|
1975
|
+
await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
|
|
1748
1976
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
1749
1977
|
}
|
|
1750
|
-
async
|
|
1978
|
+
async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
|
|
1979
|
+
return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
|
|
1980
|
+
}
|
|
1981
|
+
async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
|
|
1751
1982
|
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
1752
1983
|
const stats = {};
|
|
1753
1984
|
const trace = Trace.start();
|
|
1754
|
-
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer",
|
|
1985
|
+
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
|
|
1755
1986
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
1756
1987
|
stats.getVersionDuration = trace.trace().duration;
|
|
1757
1988
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
1758
1989
|
assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
1759
1990
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
1991
|
+
const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
|
|
1992
|
+
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
1993
|
+
stats.snapshotVersion = versions[0].id;
|
|
1760
1994
|
perfEvent.end(stats);
|
|
1761
|
-
return {
|
|
1995
|
+
return {
|
|
1996
|
+
snapshotTree: maybeSnapshot,
|
|
1997
|
+
versionId: versions[0].id,
|
|
1998
|
+
latestSnapshotRefSeq,
|
|
1999
|
+
};
|
|
1762
2000
|
});
|
|
1763
2001
|
}
|
|
1764
|
-
notifyAttaching(
|
|
1765
|
-
var _a;
|
|
1766
|
-
if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
|
|
1767
|
-
this.baseSnapshotBlobs = SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
async initializeBaseSnapshotBlobs() {
|
|
1771
|
-
var _a;
|
|
1772
|
-
if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
|
|
1773
|
-
this.attachState !== AttachState.Attached || this.context.pendingLocalState) {
|
|
1774
|
-
return;
|
|
1775
|
-
}
|
|
1776
|
-
assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
|
|
1777
|
-
this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
|
|
1778
|
-
}
|
|
2002
|
+
notifyAttaching() { } // do nothing (deprecated method)
|
|
1779
2003
|
getPendingLocalState() {
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
throw new UsageError("can't get state when offline load disabled");
|
|
2004
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
2005
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
1783
2006
|
}
|
|
1784
2007
|
// Flush pending batch.
|
|
1785
2008
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
1786
2009
|
// to close current batch.
|
|
1787
2010
|
this.flush();
|
|
1788
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
1789
|
-
throw new UsageError("can't get state during orderSequentially");
|
|
1790
|
-
}
|
|
1791
|
-
const previousPendingState = this.context.pendingLocalState;
|
|
1792
|
-
if (previousPendingState) {
|
|
1793
|
-
return {
|
|
1794
|
-
pending: this.pendingStateManager.getLocalState(),
|
|
1795
|
-
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
1796
|
-
snapshotBlobs: previousPendingState.snapshotBlobs,
|
|
1797
|
-
baseSnapshot: previousPendingState.baseSnapshot,
|
|
1798
|
-
savedOps: this.savedOps,
|
|
1799
|
-
};
|
|
1800
|
-
}
|
|
1801
|
-
assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
|
|
1802
|
-
assert(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
|
|
1803
2011
|
return {
|
|
1804
2012
|
pending: this.pendingStateManager.getLocalState(),
|
|
1805
2013
|
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
1806
|
-
snapshotBlobs: this.baseSnapshotBlobs,
|
|
1807
|
-
baseSnapshot: this.context.baseSnapshot,
|
|
1808
|
-
savedOps: this.savedOps,
|
|
1809
2014
|
};
|
|
1810
2015
|
}
|
|
1811
2016
|
/**
|
|
@@ -1834,20 +2039,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1834
2039
|
return summarizer;
|
|
1835
2040
|
};
|
|
1836
2041
|
}
|
|
1837
|
-
async processSavedOps(state) {
|
|
1838
|
-
for (const op of state.savedOps) {
|
|
1839
|
-
this.process(op, false);
|
|
1840
|
-
await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
|
|
1841
|
-
}
|
|
1842
|
-
// we may not have seen every sequence number (because of system ops) so apply everything once we
|
|
1843
|
-
// don't have any more saved ops
|
|
1844
|
-
await this.pendingStateManager.applyStashedOpsAt();
|
|
1845
|
-
// If it's not the case, we should take it into account when calculating dirty state.
|
|
1846
|
-
assert(this.context.attachState === AttachState.Attached, 0x3d5 /* this function is called for attached containers only */);
|
|
1847
|
-
if (!this.hasPendingMessages()) {
|
|
1848
|
-
this.updateDocumentDirtyState(false);
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
2042
|
validateSummaryHeuristicConfiguration(configuration) {
|
|
1852
2043
|
// eslint-disable-next-line no-restricted-syntax
|
|
1853
2044
|
for (const prop in configuration) {
|
|
@@ -1867,6 +2058,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1867
2058
|
const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
|
|
1868
2059
|
// TODO: remove cast to any when actual event is determined
|
|
1869
2060
|
deltaManager.on("closed", reject);
|
|
2061
|
+
deltaManager.on("disposed", reject);
|
|
1870
2062
|
// If we already reached target sequence number, simply resolve the promise.
|
|
1871
2063
|
if (deltaManager.lastSequenceNumber >= targetSeq) {
|
|
1872
2064
|
resolve();
|