@fluidframework/container-runtime 2.0.0-rc.2.0.2 → 2.0.0-rc.3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/api-report/container-runtime.api.md +471 -52
- package/dist/batchTracker.d.ts +1 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +4 -4
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +33 -30
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +82 -107
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +27 -22
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +155 -165
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts +3 -3
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +17 -17
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js +2 -2
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +42 -39
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +425 -292
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +8 -8
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +58 -19
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +169 -114
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +1 -0
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +12 -11
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts +5 -1
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +4 -4
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/deltaScheduler.d.ts +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +6 -6
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/error.d.ts +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +4 -4
- package/dist/error.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +3 -2
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +23 -23
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts +2 -2
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +4 -5
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -5
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +5 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +21 -12
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +2 -2
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +11 -11
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +2 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +11 -9
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +6 -6
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/gc/index.d.ts +1 -1
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +2 -1
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +91 -0
- package/dist/messageTypes.d.ts +11 -5
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js +4 -0
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +2 -20
- 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.map +1 -1
- package/dist/opLifecycle/opCompressor.js +5 -6
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +15 -4
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +62 -63
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +2 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +14 -16
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +12 -4
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +63 -53
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +2 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +30 -29
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +8 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +36 -32
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +1 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +18 -18
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +12 -0
- package/dist/scheduleManager.d.ts +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +28 -24
- package/dist/scheduleManager.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.d.ts +2 -2
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/dist/storageServiceWithAttachBlobs.js +2 -2
- package/dist/storageServiceWithAttachBlobs.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +209 -0
- package/dist/summary/documentSchema.d.ts.map +1 -0
- package/dist/summary/documentSchema.js +390 -0
- package/dist/summary/documentSchema.js.map +1 -0
- package/dist/summary/index.d.ts +2 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +4 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -2
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +12 -7
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +3 -3
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +3 -3
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +16 -16
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +3 -2
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +13 -13
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +2 -2
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.d.ts +1 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js +2 -2
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +3 -2
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +28 -28
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +14 -14
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +5 -3
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +2 -2
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +7 -7
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +6 -17
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +8 -8
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +4 -3
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +17 -17
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +15 -14
- package/dist/summary/summaryManager.js.map +1 -1
- package/internal.d.ts +11 -0
- package/legacy.d.ts +11 -0
- package/lib/batchTracker.d.ts +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -2
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +33 -30
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +48 -73
- package/lib/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +27 -22
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +96 -106
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +3 -3
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +3 -3
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js +1 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +42 -39
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +276 -141
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +3 -3
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +58 -19
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +107 -52
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts +1 -0
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +3 -2
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts +5 -1
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +1 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/deltaScheduler.d.ts +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/error.d.ts +1 -1
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js +2 -2
- package/lib/error.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +3 -2
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +8 -8
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts +2 -2
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +4 -5
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -5
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +5 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +10 -2
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +2 -2
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +2 -2
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +2 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +4 -2
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js +2 -2
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/gc/index.d.ts +1 -1
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +5 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -2
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +91 -0
- package/lib/messageTypes.d.ts +11 -5
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js +4 -0
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +2 -20
- 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.map +1 -1
- package/lib/opLifecycle/opCompressor.js +2 -3
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +15 -4
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +61 -62
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +2 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +9 -12
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +12 -4
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +47 -38
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +2 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +19 -18
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +8 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +36 -32
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +1 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +2 -2
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +12 -0
- package/lib/scheduleManager.d.ts +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +7 -3
- package/lib/scheduleManager.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts +2 -2
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/lib/storageServiceWithAttachBlobs.js +1 -1
- package/lib/storageServiceWithAttachBlobs.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +209 -0
- package/lib/summary/documentSchema.d.ts.map +1 -0
- package/lib/summary/documentSchema.js +386 -0
- package/lib/summary/documentSchema.js.map +1 -0
- package/lib/summary/index.d.ts +2 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -0
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -2
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +7 -2
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +3 -3
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +3 -3
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +3 -2
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +3 -3
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +2 -2
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.d.ts +1 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summarizerHeuristics.js +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +3 -2
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +5 -5
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +5 -3
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +2 -2
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +6 -17
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +3 -3
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +4 -3
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +4 -4
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +9 -8
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +57 -65
- package/src/batchTracker.ts +4 -3
- package/src/blobManager.ts +100 -77
- package/src/channelCollection.ts +180 -165
- package/src/connectionTelemetry.ts +12 -12
- package/src/containerHandleContext.ts +3 -2
- package/src/containerRuntime.ts +481 -277
- package/src/dataStore.ts +9 -4
- package/src/dataStoreContext.ts +195 -93
- package/src/dataStoreContexts.ts +5 -2
- package/src/dataStoreRegistry.ts +3 -2
- package/src/deltaManagerSummarizerProxy.ts +1 -1
- package/src/deltaScheduler.ts +2 -1
- package/src/error.ts +2 -2
- package/src/gc/garbageCollection.ts +21 -20
- package/src/gc/gcConfigs.ts +15 -18
- package/src/gc/gcDefinitions.ts +6 -8
- package/src/gc/gcHelpers.ts +22 -5
- package/src/gc/gcSummaryStateTracker.ts +7 -5
- package/src/gc/gcTelemetry.ts +13 -7
- package/src/gc/gcUnreferencedStateTracker.ts +3 -2
- package/src/gc/index.ts +1 -0
- package/src/index.ts +22 -1
- package/src/messageTypes.ts +20 -6
- package/src/opLifecycle/README.md +89 -0
- package/src/opLifecycle/batchManager.ts +1 -0
- package/src/opLifecycle/definitions.ts +3 -21
- package/src/opLifecycle/index.ts +3 -9
- package/src/opLifecycle/opCompressor.ts +6 -5
- package/src/opLifecycle/opDecompressor.ts +90 -100
- package/src/opLifecycle/opGroupingManager.ts +12 -14
- package/src/opLifecycle/opSplitter.ts +76 -48
- package/src/opLifecycle/outbox.ts +30 -38
- package/src/opLifecycle/remoteMessageProcessor.ts +43 -55
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +6 -6
- package/src/scheduleManager.ts +10 -8
- package/src/storageServiceWithAttachBlobs.ts +2 -2
- package/src/summary/documentSchema.ts +631 -0
- package/src/summary/index.ts +10 -1
- package/src/summary/orderedClientElection.ts +7 -7
- package/src/summary/runWhileConnectedCoordinator.ts +3 -2
- package/src/summary/runningSummarizer.ts +22 -20
- package/src/summary/summarizer.ts +17 -15
- package/src/summary/summarizerClientElection.ts +3 -2
- package/src/summary/summarizerHeuristics.ts +4 -2
- package/src/summary/summarizerNode/summarizerNode.ts +20 -18
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -2
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +16 -8
- package/src/summary/summarizerTypes.ts +7 -3
- package/src/summary/summaryCollection.ts +3 -3
- package/src/summary/summaryFormat.ts +14 -26
- package/src/summary/summaryGenerator.ts +12 -15
- package/src/summary/summaryManager.ts +16 -13
- package/api-extractor-cjs.json +0 -8
- package/dist/container-runtime-alpha.d.ts +0 -1753
- package/dist/container-runtime-beta.d.ts +0 -268
- package/dist/container-runtime-public.d.ts +0 -268
- package/dist/container-runtime-untrimmed.d.ts +0 -1893
- package/lib/container-runtime-alpha.d.ts +0 -1753
- package/lib/container-runtime-beta.d.ts +0 -268
- package/lib/container-runtime-public.d.ts +0 -268
- package/lib/container-runtime-untrimmed.d.ts +0 -1893
- package/lib/test/batchTracker.spec.js +0 -88
- package/lib/test/batchTracker.spec.js.map +0 -1
- package/lib/test/blobManager.spec.js +0 -835
- package/lib/test/blobManager.spec.js.map +0 -1
- package/lib/test/channelCollection.spec.js +0 -141
- package/lib/test/channelCollection.spec.js.map +0 -1
- package/lib/test/containerRuntime.spec.js +0 -1748
- package/lib/test/containerRuntime.spec.js.map +0 -1
- package/lib/test/dataStoreContext.spec.js +0 -801
- package/lib/test/dataStoreContext.spec.js.map +0 -1
- package/lib/test/dataStoreCreation.spec.js +0 -312
- package/lib/test/dataStoreCreation.spec.js.map +0 -1
- package/lib/test/dataStoreRegistry.spec.js +0 -26
- package/lib/test/dataStoreRegistry.spec.js.map +0 -1
- package/lib/test/fuzz/fuzzUtils.js +0 -66
- package/lib/test/fuzz/fuzzUtils.js.map +0 -1
- package/lib/test/fuzz/summarizer.fuzz.spec.js +0 -31
- package/lib/test/fuzz/summarizer.fuzz.spec.js.map +0 -1
- package/lib/test/fuzz/summarizerFuzzMocks.js +0 -162
- package/lib/test/fuzz/summarizerFuzzMocks.js.map +0 -1
- package/lib/test/fuzz/summarizerFuzzSuite.js +0 -106
- package/lib/test/fuzz/summarizerFuzzSuite.js.map +0 -1
- package/lib/test/gc/garbageCollection.spec.js +0 -1465
- package/lib/test/gc/garbageCollection.spec.js.map +0 -1
- package/lib/test/gc/gcConfigs.spec.js +0 -690
- package/lib/test/gc/gcConfigs.spec.js.map +0 -1
- package/lib/test/gc/gcHelpers.spec.js +0 -110
- package/lib/test/gc/gcHelpers.spec.js.map +0 -1
- package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js +0 -68
- package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js.map +0 -1
- package/lib/test/gc/gcStats.spec.js +0 -391
- package/lib/test/gc/gcStats.spec.js.map +0 -1
- package/lib/test/gc/gcSummaryStateTracker.spec.js +0 -228
- package/lib/test/gc/gcSummaryStateTracker.spec.js.map +0 -1
- package/lib/test/gc/gcTelemetry.spec.js +0 -530
- package/lib/test/gc/gcTelemetry.spec.js.map +0 -1
- package/lib/test/gc/gcUnitTestHelpers.js +0 -29
- package/lib/test/gc/gcUnitTestHelpers.js.map +0 -1
- package/lib/test/gc/gcUnreferencedStateTracker.spec.js +0 -192
- package/lib/test/gc/gcUnreferencedStateTracker.spec.js.map +0 -1
- package/lib/test/getPendingBlobs.spec.js +0 -193
- package/lib/test/getPendingBlobs.spec.js.map +0 -1
- package/lib/test/hardwareStats.spec.js +0 -93
- package/lib/test/hardwareStats.spec.js.map +0 -1
- package/lib/test/index.js +0 -6
- package/lib/test/index.js.map +0 -1
- package/lib/test/opLifecycle/OpGroupingManager.spec.js +0 -225
- package/lib/test/opLifecycle/OpGroupingManager.spec.js.map +0 -1
- package/lib/test/opLifecycle/batchManager.spec.js +0 -189
- package/lib/test/opLifecycle/batchManager.spec.js.map +0 -1
- package/lib/test/opLifecycle/opCompressor.spec.js +0 -74
- package/lib/test/opLifecycle/opCompressor.spec.js.map +0 -1
- package/lib/test/opLifecycle/opDecompressor.spec.js +0 -218
- package/lib/test/opLifecycle/opDecompressor.spec.js.map +0 -1
- package/lib/test/opLifecycle/opSplitter.spec.js +0 -272
- package/lib/test/opLifecycle/opSplitter.spec.js.map +0 -1
- package/lib/test/opLifecycle/outbox.spec.js +0 -675
- package/lib/test/opLifecycle/outbox.spec.js.map +0 -1
- package/lib/test/opLifecycle/remoteMessageProcessor.spec.js +0 -196
- package/lib/test/opLifecycle/remoteMessageProcessor.spec.js.map +0 -1
- package/lib/test/pendingStateManager.spec.js +0 -329
- package/lib/test/pendingStateManager.spec.js.map +0 -1
- package/lib/test/scheduleManager.spec.js +0 -270
- package/lib/test/scheduleManager.spec.js.map +0 -1
- package/lib/test/summarizerNode.spec.js +0 -326
- package/lib/test/summarizerNode.spec.js.map +0 -1
- package/lib/test/summarizerNodeWithGc.spec.js +0 -318
- package/lib/test/summarizerNodeWithGc.spec.js.map +0 -1
- package/lib/test/summary/orderedClientElection.spec.js +0 -535
- package/lib/test/summary/orderedClientElection.spec.js.map +0 -1
- package/lib/test/summary/runningSummarizer.spec.js +0 -1349
- package/lib/test/summary/runningSummarizer.spec.js.map +0 -1
- package/lib/test/summary/summarizer.spec.js +0 -29
- package/lib/test/summary/summarizer.spec.js.map +0 -1
- package/lib/test/summary/summarizerClientElection.spec.js +0 -436
- package/lib/test/summary/summarizerClientElection.spec.js.map +0 -1
- package/lib/test/summary/summarizerHeuristics.spec.js +0 -289
- package/lib/test/summary/summarizerHeuristics.spec.js.map +0 -1
- package/lib/test/summary/summaryCollection.spec.js +0 -200
- package/lib/test/summary/summaryCollection.spec.js.map +0 -1
- package/lib/test/summary/summaryManager.spec.js +0 -430
- package/lib/test/summary/summaryManager.spec.js.map +0 -1
- package/lib/test/summary/testQuorumClients.js +0 -34
- package/lib/test/summary/testQuorumClients.js.map +0 -1
- package/lib/test/throttler.spec.js +0 -175
- package/lib/test/throttler.spec.js.map +0 -1
- package/lib/test/types/validateContainerRuntimePrevious.generated.js +0 -180
- package/lib/test/types/validateContainerRuntimePrevious.generated.js.map +0 -1
- /package/{dist → lib}/tsdoc-metadata.json +0 -0
package/dist/containerRuntime.js
CHANGED
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
2
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.
|
|
4
|
-
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
5
|
-
const core_utils_1 = require("@fluidframework/core-utils");
|
|
7
|
+
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
|
|
6
8
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
10
|
+
const internal_1 = require("@fluidframework/container-definitions/internal");
|
|
11
|
+
const internal_2 = require("@fluidframework/core-utils/internal");
|
|
12
|
+
const internal_3 = require("@fluidframework/driver-definitions/internal");
|
|
13
|
+
const internal_4 = require("@fluidframework/driver-utils/internal");
|
|
10
14
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
11
|
-
const
|
|
12
|
-
const
|
|
15
|
+
const internal_5 = require("@fluidframework/runtime-definitions/internal");
|
|
16
|
+
const internal_6 = require("@fluidframework/runtime-utils/internal");
|
|
17
|
+
const internal_7 = require("@fluidframework/telemetry-utils/internal");
|
|
13
18
|
const uuid_1 = require("uuid");
|
|
14
|
-
const
|
|
15
|
-
const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
|
|
16
|
-
const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
|
|
17
|
-
const pendingStateManager_js_1 = require("./pendingStateManager.js");
|
|
18
|
-
const packageVersion_js_1 = require("./packageVersion.js");
|
|
19
|
+
const batchTracker_js_1 = require("./batchTracker.js");
|
|
19
20
|
const blobManager_js_1 = require("./blobManager.js");
|
|
20
21
|
const channelCollection_js_1 = require("./channelCollection.js");
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const index_js_2 = require("./gc/index.js");
|
|
22
|
+
const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
|
|
23
|
+
const containerHandleContext_js_1 = require("./containerHandleContext.js");
|
|
24
24
|
const dataStore_js_1 = require("./dataStore.js");
|
|
25
|
-
const
|
|
26
|
-
const scheduleManager_js_1 = require("./scheduleManager.js");
|
|
27
|
-
const index_js_3 = require("./opLifecycle/index.js");
|
|
25
|
+
const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
|
|
28
26
|
const deltaManagerSummarizerProxy_js_1 = require("./deltaManagerSummarizerProxy.js");
|
|
27
|
+
const index_js_1 = require("./gc/index.js");
|
|
29
28
|
const messageTypes_js_1 = require("./messageTypes.js");
|
|
29
|
+
const index_js_2 = require("./opLifecycle/index.js");
|
|
30
|
+
const packageVersion_js_1 = require("./packageVersion.js");
|
|
31
|
+
const pendingStateManager_js_1 = require("./pendingStateManager.js");
|
|
32
|
+
const scheduleManager_js_1 = require("./scheduleManager.js");
|
|
33
|
+
const index_js_3 = require("./summary/index.js");
|
|
34
|
+
const throttler_js_1 = require("./throttler.js");
|
|
30
35
|
/**
|
|
31
36
|
* Utility to implement compat behaviors given an unknown message type
|
|
32
37
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
@@ -81,8 +86,13 @@ var CompressionAlgorithms;
|
|
|
81
86
|
(function (CompressionAlgorithms) {
|
|
82
87
|
CompressionAlgorithms["lz4"] = "lz4";
|
|
83
88
|
})(CompressionAlgorithms || (exports.CompressionAlgorithms = CompressionAlgorithms = {}));
|
|
89
|
+
/** @alpha */
|
|
90
|
+
exports.disabledCompressionConfig = {
|
|
91
|
+
minimumBatchSizeInBytes: Infinity,
|
|
92
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
93
|
+
};
|
|
84
94
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
85
|
-
const defaultFlushMode =
|
|
95
|
+
const defaultFlushMode = internal_5.FlushMode.TurnBased;
|
|
86
96
|
// The actual limit is 1Mb (socket.io and Kafka limits)
|
|
87
97
|
// We can't estimate it fully, as we
|
|
88
98
|
// - do not know what properties relay service will add
|
|
@@ -104,26 +114,12 @@ exports.defaultPendingOpsRetryDelayMs = 1000;
|
|
|
104
114
|
* This delay's goal is to prevent tight restart loops
|
|
105
115
|
*/
|
|
106
116
|
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
107
|
-
/**
|
|
108
|
-
* @deprecated use ContainerRuntimeMessageType instead
|
|
109
|
-
* @internal
|
|
110
|
-
*/
|
|
111
|
-
var RuntimeMessage;
|
|
112
|
-
(function (RuntimeMessage) {
|
|
113
|
-
RuntimeMessage["FluidDataStoreOp"] = "component";
|
|
114
|
-
RuntimeMessage["Attach"] = "attach";
|
|
115
|
-
RuntimeMessage["ChunkedOp"] = "chunkedOp";
|
|
116
|
-
RuntimeMessage["BlobAttach"] = "blobAttach";
|
|
117
|
-
RuntimeMessage["Rejoin"] = "rejoin";
|
|
118
|
-
RuntimeMessage["Alias"] = "alias";
|
|
119
|
-
RuntimeMessage["Operation"] = "op";
|
|
120
|
-
})(RuntimeMessage || (exports.RuntimeMessage = RuntimeMessage = {}));
|
|
121
117
|
/**
|
|
122
118
|
* @deprecated please use version in driver-utils
|
|
123
119
|
* @internal
|
|
124
120
|
*/
|
|
125
121
|
function isRuntimeMessage(message) {
|
|
126
|
-
return Object.values(
|
|
122
|
+
return Object.values(messageTypes_js_1.ContainerMessageType).includes(message.type);
|
|
127
123
|
}
|
|
128
124
|
exports.isRuntimeMessage = isRuntimeMessage;
|
|
129
125
|
/**
|
|
@@ -169,13 +165,13 @@ const summarizerRequestUrl = "_summarizer";
|
|
|
169
165
|
async function createSummarizer(loader, url) {
|
|
170
166
|
const request = {
|
|
171
167
|
headers: {
|
|
172
|
-
[
|
|
173
|
-
[
|
|
168
|
+
[internal_1.LoaderHeader.cache]: false,
|
|
169
|
+
[internal_1.LoaderHeader.clientDetails]: {
|
|
174
170
|
capabilities: { interactive: false },
|
|
175
|
-
type:
|
|
171
|
+
type: index_js_3.summarizerClientType,
|
|
176
172
|
},
|
|
177
|
-
[
|
|
178
|
-
[
|
|
173
|
+
[internal_3.DriverHeader.summarizingClient]: true,
|
|
174
|
+
[internal_1.LoaderHeader.reconnect]: false,
|
|
179
175
|
},
|
|
180
176
|
url,
|
|
181
177
|
};
|
|
@@ -191,15 +187,26 @@ async function createSummarizer(loader, url) {
|
|
|
191
187
|
url: `/${summarizerRequestUrl}`,
|
|
192
188
|
});
|
|
193
189
|
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
194
|
-
throw (0,
|
|
190
|
+
throw (0, internal_6.responseToException)(response, request);
|
|
195
191
|
}
|
|
196
192
|
fluidObject = response.value;
|
|
197
193
|
}
|
|
198
194
|
if (fluidObject?.ISummarizer === undefined) {
|
|
199
|
-
throw new
|
|
195
|
+
throw new internal_7.UsageError("Fluid object does not implement ISummarizer");
|
|
200
196
|
}
|
|
201
197
|
return fluidObject.ISummarizer;
|
|
202
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Extract last message from the snapshot metadata.
|
|
201
|
+
* Uses legacy property if not using explicit schema control, otherwise uses the new property.
|
|
202
|
+
* This allows new runtime to make documents not openable for old runtimes, one explicit document schema control is enabled.
|
|
203
|
+
* Please see addMetadataToSummary() as well
|
|
204
|
+
*/
|
|
205
|
+
function lastMessageFromMetadata(metadata) {
|
|
206
|
+
return metadata?.documentSchema?.runtime?.explicitSchemaControl
|
|
207
|
+
? metadata?.lastMessage
|
|
208
|
+
: metadata?.message;
|
|
209
|
+
}
|
|
203
210
|
/**
|
|
204
211
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
205
212
|
* It will define the store level mappings.
|
|
@@ -227,8 +234,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
227
234
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
228
235
|
const backCompatContext = context;
|
|
229
236
|
const passLogger = backCompatContext.taggedLogger ??
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
// eslint-disable-next-line import/no-deprecated
|
|
238
|
+
new internal_7.TaggedLoggerAdapter(backCompatContext.logger);
|
|
239
|
+
const logger = (0, internal_7.createChildLogger)({
|
|
232
240
|
logger: passLogger,
|
|
233
241
|
properties: {
|
|
234
242
|
all: {
|
|
@@ -236,42 +244,49 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
236
244
|
},
|
|
237
245
|
},
|
|
238
246
|
});
|
|
239
|
-
const mc = (0,
|
|
240
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor
|
|
247
|
+
const mc = (0, internal_7.loggerToMonitoringContext)(logger);
|
|
248
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, explicitSchemaControl = false, } = runtimeOptions;
|
|
241
249
|
const registry = new dataStoreRegistry_js_1.FluidDataStoreRegistry(registryEntries);
|
|
242
250
|
const tryFetchBlob = async (blobName) => {
|
|
243
251
|
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
244
252
|
if (context.baseSnapshot && blobId) {
|
|
245
253
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
246
254
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
247
|
-
(0,
|
|
248
|
-
return (0,
|
|
255
|
+
(0, internal_2.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
256
|
+
return (0, internal_4.readAndParse)(context.storage, blobId);
|
|
249
257
|
}
|
|
250
258
|
};
|
|
251
259
|
const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
|
|
252
|
-
tryFetchBlob(
|
|
253
|
-
tryFetchBlob(
|
|
254
|
-
tryFetchBlob(
|
|
255
|
-
tryFetchBlob(
|
|
256
|
-
tryFetchBlob(
|
|
260
|
+
tryFetchBlob(index_js_3.chunksBlobName),
|
|
261
|
+
tryFetchBlob(index_js_3.metadataBlobName),
|
|
262
|
+
tryFetchBlob(index_js_3.electedSummarizerBlobName),
|
|
263
|
+
tryFetchBlob(index_js_3.aliasBlobName),
|
|
264
|
+
tryFetchBlob(index_js_3.idCompressorBlobName),
|
|
257
265
|
]);
|
|
258
266
|
// read snapshot blobs needed for BlobManager to load
|
|
259
|
-
const blobManagerSnapshot = await blobManager_js_1.BlobManager.load(context.baseSnapshot?.trees[
|
|
267
|
+
const blobManagerSnapshot = await blobManager_js_1.BlobManager.load(context.baseSnapshot?.trees[index_js_3.blobsTreeName], async (id) => {
|
|
260
268
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
261
269
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
262
|
-
(0,
|
|
263
|
-
return (0,
|
|
270
|
+
(0, internal_2.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
271
|
+
return (0, internal_4.readAndParse)(context.storage, id);
|
|
264
272
|
});
|
|
273
|
+
const messageAtLastSummary = lastMessageFromMetadata(metadata);
|
|
265
274
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
266
|
-
const runtimeSequenceNumber =
|
|
275
|
+
const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
|
|
267
276
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
268
277
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
269
278
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
270
279
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
271
280
|
if (loadSequenceNumberVerification !== "bypass" &&
|
|
272
281
|
runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
282
|
+
// Message to OCEs:
|
|
283
|
+
// You can hit this error with runtimeSequenceNumber === -1 in < 2.0 RC3 builds.
|
|
284
|
+
// This would indicate that explicit schema control is enabled in current (2.0 RC3+) builds and it
|
|
285
|
+
// results in addMetadataToSummary() creating a poison pill for older runtimes in the form of a -1 sequence number.
|
|
286
|
+
// Older runtimes do not understand new schema, and thus could corrupt document if they proceed, thus we are using
|
|
287
|
+
// this poison pill to prevent them from proceeding.
|
|
273
288
|
// "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
|
|
274
|
-
const error = new
|
|
289
|
+
const error = new internal_7.DataCorruptionError(
|
|
275
290
|
// pre-0.58 error message: SummaryMetadataMismatch
|
|
276
291
|
"Summary metadata mismatch", { runtimeVersion: packageVersion_js_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
|
|
277
292
|
if (loadSequenceNumberVerification === "log") {
|
|
@@ -282,8 +297,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
282
297
|
}
|
|
283
298
|
}
|
|
284
299
|
}
|
|
300
|
+
let desiredIdCompressorMode;
|
|
301
|
+
switch (mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) {
|
|
302
|
+
case true:
|
|
303
|
+
desiredIdCompressorMode = "on";
|
|
304
|
+
break;
|
|
305
|
+
case false:
|
|
306
|
+
desiredIdCompressorMode = undefined;
|
|
307
|
+
break;
|
|
308
|
+
default:
|
|
309
|
+
desiredIdCompressorMode = enableRuntimeIdCompressor;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
285
312
|
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
286
|
-
// allow new containers to turn it on
|
|
313
|
+
// allow new containers to turn it on.
|
|
287
314
|
let idCompressorMode;
|
|
288
315
|
if (existing) {
|
|
289
316
|
// This setting has to be sticky for correctness:
|
|
@@ -292,28 +319,30 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
292
319
|
// 2) if it's ON, then all sessions should load compressor right away
|
|
293
320
|
// 3) Same logic applies for "delayed" mode
|
|
294
321
|
// Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
|
|
295
|
-
// We could do "off" -> "on"
|
|
296
|
-
// this will allow clients to eventually
|
|
322
|
+
// We could do "off" -> "on" transition too, if all clients start loading compressor (but not using it initially) and
|
|
323
|
+
// do so for a while - this will allow clients to eventually disregard "off" setting (when it's safe so) and start
|
|
324
|
+
// using compressor in future sessions.
|
|
297
325
|
// Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
|
|
298
|
-
idCompressorMode = metadata?.
|
|
326
|
+
idCompressorMode = metadata?.documentSchema?.runtime
|
|
327
|
+
?.idCompressorMode;
|
|
328
|
+
// This is the only exception to the rule above - we have proper plumbing to load ID compressor on schema change
|
|
329
|
+
// event. It is loaded async (relative to op processing), so this conversion is only safe for off -> delayed conversion!
|
|
330
|
+
// Clients do not expect ID compressor ops unless ID compressor is On for them, and that could be achieved only through
|
|
331
|
+
// explicit schema change, i.e. only if explicitSchemaControl is on.
|
|
332
|
+
// Note: it would be better if we throw on combination of options (explicitSchemaControl = off, desiredIdCompressorMode === "delayed")
|
|
333
|
+
// that is not supported. But our service tests are oblivious to these problems and throwing here will cause a ton of failures
|
|
334
|
+
// We ignored incompatible ID compressor changes from the start (they were sticky), so that's not a new problem being introduced...
|
|
335
|
+
if (idCompressorMode === undefined &&
|
|
336
|
+
desiredIdCompressorMode === "delayed" &&
|
|
337
|
+
explicitSchemaControl) {
|
|
338
|
+
idCompressorMode = desiredIdCompressorMode;
|
|
339
|
+
}
|
|
299
340
|
}
|
|
300
341
|
else {
|
|
301
|
-
|
|
302
|
-
const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
|
|
303
|
-
switch (enabled) {
|
|
304
|
-
case true:
|
|
305
|
-
idCompressorMode = "on";
|
|
306
|
-
break;
|
|
307
|
-
case false:
|
|
308
|
-
idCompressorMode = "off";
|
|
309
|
-
break;
|
|
310
|
-
default:
|
|
311
|
-
idCompressorMode = enableRuntimeIdCompressor;
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
342
|
+
idCompressorMode = desiredIdCompressorMode;
|
|
314
343
|
}
|
|
315
344
|
const createIdCompressorFn = async () => {
|
|
316
|
-
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import("@fluidframework/id-compressor");
|
|
345
|
+
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import("@fluidframework/id-compressor/internal");
|
|
317
346
|
/**
|
|
318
347
|
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
319
348
|
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
@@ -326,7 +355,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
326
355
|
},
|
|
327
356
|
};
|
|
328
357
|
})();
|
|
329
|
-
const compressorLogger = (0,
|
|
358
|
+
const compressorLogger = (0, internal_7.createSampledLogger)(logger, idCompressorEventSampler);
|
|
330
359
|
const pendingLocalState = context.pendingLocalState;
|
|
331
360
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
332
361
|
return deserializeIdCompressor(pendingLocalState.pendingIdCompressorState, compressorLogger);
|
|
@@ -338,6 +367,25 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
338
367
|
return createIdCompressor(compressorLogger);
|
|
339
368
|
}
|
|
340
369
|
};
|
|
370
|
+
const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
|
|
371
|
+
const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
372
|
+
const compressionLz4 = disableCompression !== true &&
|
|
373
|
+
compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
374
|
+
compressionOptions.compressionAlgorithm === "lz4";
|
|
375
|
+
const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
|
|
376
|
+
const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, metadata?.documentSchema, {
|
|
377
|
+
explicitSchemaControl,
|
|
378
|
+
compressionLz4,
|
|
379
|
+
idCompressorMode,
|
|
380
|
+
opGroupingEnabled,
|
|
381
|
+
disallowedVersions: [],
|
|
382
|
+
}, (schema) => {
|
|
383
|
+
runtime.onSchemaChange(schema);
|
|
384
|
+
});
|
|
385
|
+
const featureGatesForTelemetry = {
|
|
386
|
+
disableGroupedBatching,
|
|
387
|
+
disableCompression,
|
|
388
|
+
};
|
|
341
389
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
342
390
|
summaryOptions,
|
|
343
391
|
gcOptions,
|
|
@@ -346,10 +394,19 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
346
394
|
compressionOptions,
|
|
347
395
|
maxBatchSizeInBytes,
|
|
348
396
|
chunkSizeInBytes,
|
|
349
|
-
|
|
397
|
+
// Requires<> drops undefined from IdCompressorType
|
|
398
|
+
enableRuntimeIdCompressor: enableRuntimeIdCompressor,
|
|
350
399
|
enableOpReentryCheck,
|
|
351
400
|
enableGroupedBatching,
|
|
352
|
-
|
|
401
|
+
explicitSchemaControl,
|
|
402
|
+
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, undefined);
|
|
403
|
+
runtime.blobManager.trackPendingStashedUploads().then(() => {
|
|
404
|
+
// make sure we didn't reconnect before the promise resolved
|
|
405
|
+
if (runtime.delayConnectClientId !== undefined && !runtime.disposed) {
|
|
406
|
+
runtime.delayConnectClientId = undefined;
|
|
407
|
+
runtime.setConnectionStateCore(true, runtime.delayConnectClientId);
|
|
408
|
+
}
|
|
409
|
+
}, (error) => runtime.closeFn(error));
|
|
353
410
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
354
411
|
// or zero. This must be done before Container replays saved ops.
|
|
355
412
|
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
@@ -378,6 +435,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
378
435
|
get attachState() {
|
|
379
436
|
return this._getAttachState();
|
|
380
437
|
}
|
|
438
|
+
get documentSchema() {
|
|
439
|
+
return this.documentsSchemaController.sessionSchema.runtime;
|
|
440
|
+
}
|
|
441
|
+
get idCompressorMode() {
|
|
442
|
+
return this.documentSchema.idCompressorMode;
|
|
443
|
+
}
|
|
381
444
|
/**
|
|
382
445
|
* See IContainerRuntimeBase.idCompressor() for details.
|
|
383
446
|
*/
|
|
@@ -387,7 +450,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
387
450
|
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
388
451
|
// to reason over such things as session ID space.
|
|
389
452
|
if (this.idCompressorMode === "on") {
|
|
390
|
-
(0,
|
|
453
|
+
(0, internal_2.assert)(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
391
454
|
return this._idCompressor;
|
|
392
455
|
}
|
|
393
456
|
}
|
|
@@ -428,7 +491,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
428
491
|
return this._disposed;
|
|
429
492
|
}
|
|
430
493
|
get summarizer() {
|
|
431
|
-
(0,
|
|
494
|
+
(0, internal_2.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
432
495
|
return this._summarizer;
|
|
433
496
|
}
|
|
434
497
|
isSummariesDisabled() {
|
|
@@ -458,7 +521,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
458
521
|
return this.garbageCollector.throwOnTombstoneUsage;
|
|
459
522
|
}
|
|
460
523
|
/***/
|
|
461
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, createIdCompressor,
|
|
524
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, createIdCompressor, documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, summaryConfiguration = {
|
|
462
525
|
// the defaults
|
|
463
526
|
...exports.DefaultSummaryConfiguration,
|
|
464
527
|
// the runtime configuration overrides
|
|
@@ -472,18 +535,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
472
535
|
this.logger = logger;
|
|
473
536
|
this._storage = _storage;
|
|
474
537
|
this.createIdCompressor = createIdCompressor;
|
|
475
|
-
this.
|
|
538
|
+
this.documentsSchemaController = documentsSchemaController;
|
|
476
539
|
this.requestHandler = requestHandler;
|
|
477
540
|
this.summaryConfiguration = summaryConfiguration;
|
|
478
541
|
this.imminentClosure = false;
|
|
479
542
|
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
480
543
|
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
481
544
|
this.pendingIdCompressorOps = [];
|
|
482
|
-
/**
|
|
483
|
-
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
484
|
-
* this.idCompressorMode === "delayed" mode
|
|
485
|
-
*/
|
|
486
|
-
this.compressorLoadInitiated = false;
|
|
487
545
|
this.defaultMaxConsecutiveReconnects = 7;
|
|
488
546
|
this._orderSequentiallyCalls = 0;
|
|
489
547
|
this.flushTaskExists = false;
|
|
@@ -509,10 +567,24 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
509
567
|
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
510
568
|
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
511
569
|
*/
|
|
512
|
-
this.snapshotCacheForLoadingGroupIds = new
|
|
570
|
+
this.snapshotCacheForLoadingGroupIds = new internal_2.PromiseCache({
|
|
513
571
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
514
572
|
});
|
|
515
573
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
574
|
+
this.mc = (0, internal_7.createChildMonitoringContext)({
|
|
575
|
+
logger: this.logger,
|
|
576
|
+
namespace: "ContainerRuntime",
|
|
577
|
+
});
|
|
578
|
+
// If we support multiple algorithms in the future, then we would need to manage it here carefully.
|
|
579
|
+
// We can use runtimeOptions.compressionOptions.compressionAlgorithm, but only if it's in the schema list!
|
|
580
|
+
// If it's not in the list, then we will need to either use no compression, or fallback to some other (supported by format)
|
|
581
|
+
// compression.
|
|
582
|
+
const compressionOptions = {
|
|
583
|
+
minimumBatchSizeInBytes: this.documentSchema.compressionLz4
|
|
584
|
+
? runtimeOptions.compressionOptions.minimumBatchSizeInBytes
|
|
585
|
+
: Number.POSITIVE_INFINITY,
|
|
586
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
587
|
+
};
|
|
516
588
|
this.innerDeltaManager = deltaManager;
|
|
517
589
|
this.deltaManager = new deltaManagerSummarizerProxy_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
518
590
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
@@ -525,7 +597,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
525
597
|
// Values are generally expected to be set from the runtime side.
|
|
526
598
|
this.options = options ?? {};
|
|
527
599
|
this.clientDetails = clientDetails;
|
|
528
|
-
this.isSummarizerClient = this.clientDetails.type ===
|
|
600
|
+
this.isSummarizerClient = this.clientDetails.type === index_js_3.summarizerClientType;
|
|
529
601
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
530
602
|
this._getClientId = () => context.clientId;
|
|
531
603
|
this._getAttachState = () => context.attachState;
|
|
@@ -546,10 +618,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
546
618
|
this.disposeFn = disposeFn ?? closeFn;
|
|
547
619
|
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
548
620
|
this.closeFn = this.isSummarizerClient ? this.disposeFn : closeFn;
|
|
549
|
-
this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({
|
|
550
|
-
logger: this.logger,
|
|
551
|
-
namespace: "ContainerRuntime",
|
|
552
|
-
});
|
|
553
621
|
let loadSummaryNumber;
|
|
554
622
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
555
623
|
// get the values from the metadata blob.
|
|
@@ -570,7 +638,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
570
638
|
loadSummaryNumber = 0;
|
|
571
639
|
}
|
|
572
640
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
573
|
-
this.messageAtLastSummary = metadata
|
|
641
|
+
this.messageAtLastSummary = lastMessageFromMetadata(metadata);
|
|
574
642
|
// Note that we only need to pull the *initial* connected state from the context.
|
|
575
643
|
// Later updates come through calls to setConnectionState.
|
|
576
644
|
this._connected = connected;
|
|
@@ -578,20 +646,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
578
646
|
eventName: "GCFeatureMatrix",
|
|
579
647
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
580
648
|
inputs: JSON.stringify({
|
|
581
|
-
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[
|
|
649
|
+
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[index_js_1.gcGenerationOptionName],
|
|
582
650
|
}),
|
|
583
651
|
});
|
|
584
652
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? (0, uuid_1.v4)();
|
|
585
653
|
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
586
654
|
const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
|
|
587
|
-
const opGroupingManager = new
|
|
655
|
+
const opGroupingManager = new index_js_2.OpGroupingManager({
|
|
588
656
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
589
657
|
opCountThreshold: this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
590
658
|
reentrantBatchGroupingEnabled: this.mc.config.getBoolean("Fluid.ContainerRuntime.GroupedBatchingReentrancy") ??
|
|
591
659
|
true,
|
|
592
660
|
}, this.mc.logger);
|
|
593
|
-
const opSplitter = new
|
|
594
|
-
this.remoteMessageProcessor = new
|
|
661
|
+
const opSplitter = new index_js_2.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
662
|
+
this.remoteMessageProcessor = new index_js_2.RemoteMessageProcessor(opSplitter, new index_js_2.OpDecompressor(this.mc.logger), opGroupingManager);
|
|
595
663
|
this.handleContext = new containerHandleContext_js_1.ContainerFluidHandleContext("", this);
|
|
596
664
|
if (this.summaryConfiguration.state === "enabled") {
|
|
597
665
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
@@ -607,11 +675,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
607
675
|
this.maxConsecutiveReconnects =
|
|
608
676
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
609
677
|
this.defaultMaxConsecutiveReconnects;
|
|
610
|
-
if (runtimeOptions.flushMode ===
|
|
678
|
+
if (runtimeOptions.flushMode === internal_5.FlushModeExperimental.Async &&
|
|
611
679
|
supportedFeatures?.get("referenceSequenceNumbers") !== true) {
|
|
612
680
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
613
681
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
614
|
-
this._flushMode =
|
|
682
|
+
this._flushMode = internal_5.FlushMode.TurnBased;
|
|
615
683
|
}
|
|
616
684
|
else {
|
|
617
685
|
this._flushMode = runtimeOptions.flushMode;
|
|
@@ -624,10 +692,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
624
692
|
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
625
693
|
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
626
694
|
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
627
|
-
throw new
|
|
695
|
+
throw new internal_7.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
628
696
|
}
|
|
629
697
|
}
|
|
630
|
-
this.garbageCollector =
|
|
698
|
+
this.garbageCollector = index_js_1.GarbageCollector.create({
|
|
631
699
|
runtime: this,
|
|
632
700
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
633
701
|
baseSnapshot,
|
|
@@ -638,12 +706,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
638
706
|
isSummarizerClient: this.isSummarizerClient,
|
|
639
707
|
getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
|
|
640
708
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
641
|
-
readAndParseBlob: async (id) => (0,
|
|
709
|
+
readAndParseBlob: async (id) => (0, internal_4.readAndParse)(this.storage, id),
|
|
642
710
|
submitMessage: (message) => this.submit(message),
|
|
643
711
|
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
644
712
|
});
|
|
645
713
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
646
|
-
this.summarizerNode = (0,
|
|
714
|
+
this.summarizerNode = (0, index_js_3.createRootSummarizerNodeWithGC)((0, internal_7.createChildLogger)({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
647
715
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
648
716
|
async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
649
717
|
// Latest change sequence number, no changes since summary applied yet
|
|
@@ -673,40 +741,46 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
673
741
|
return this.submitSignalFn(envelope2, targetClientId);
|
|
674
742
|
};
|
|
675
743
|
this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (path, reason, timestampMs, packagePath, request, headerData) => this.garbageCollector.nodeUpdated(path, reason, timestampMs, packagePath, request, headerData), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
676
|
-
this.blobManager = new blobManager_js_1.BlobManager(
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
744
|
+
this.blobManager = new blobManager_js_1.BlobManager({
|
|
745
|
+
routeContext: this.handleContext,
|
|
746
|
+
snapshot: blobManagerSnapshot,
|
|
747
|
+
getStorage: () => this.storage,
|
|
748
|
+
sendBlobAttachOp: (localId, blobId) => {
|
|
749
|
+
if (!this.disposed) {
|
|
750
|
+
this.submit({ type: messageTypes_js_1.ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
|
|
751
|
+
localId,
|
|
752
|
+
blobId,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
|
|
757
|
+
isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
758
|
+
runtime: this,
|
|
759
|
+
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
760
|
+
closeContainer: (error) => this.closeFn(error),
|
|
761
|
+
});
|
|
762
|
+
this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, internal_7.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
685
763
|
this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
|
|
686
764
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
687
765
|
clientId: () => this.clientId,
|
|
688
766
|
close: this.closeFn,
|
|
689
767
|
connected: () => this.connected,
|
|
690
|
-
reSubmit:
|
|
768
|
+
reSubmit: (message) => {
|
|
769
|
+
this.reSubmit(message);
|
|
770
|
+
this.flush();
|
|
771
|
+
},
|
|
691
772
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
692
773
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
693
774
|
isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
|
|
694
775
|
}, pendingRuntimeState?.pending, this.logger);
|
|
695
|
-
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
696
|
-
const compressionOptions = disableCompression === true
|
|
697
|
-
? {
|
|
698
|
-
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
699
|
-
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
700
|
-
}
|
|
701
|
-
: runtimeOptions.compressionOptions;
|
|
702
776
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
703
777
|
const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
|
|
704
|
-
this.outbox = new
|
|
778
|
+
this.outbox = new index_js_2.Outbox({
|
|
705
779
|
shouldSend: () => this.canSendOps(),
|
|
706
780
|
pendingStateManager: this.pendingStateManager,
|
|
707
781
|
submitBatchFn: this.submitBatchFn,
|
|
708
782
|
legacySendBatchFn,
|
|
709
|
-
compressor: new
|
|
783
|
+
compressor: new index_js_2.OpCompressor(this.mc.logger),
|
|
710
784
|
splitter: opSplitter,
|
|
711
785
|
config: {
|
|
712
786
|
compressionOptions,
|
|
@@ -733,7 +807,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
733
807
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
734
808
|
this.validateSummaryBeforeUpload =
|
|
735
809
|
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
736
|
-
this.summaryCollection = new
|
|
810
|
+
this.summaryCollection = new index_js_3.SummaryCollection(this.deltaManager, this.logger);
|
|
737
811
|
this.dirtyContainer =
|
|
738
812
|
this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
|
|
739
813
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
@@ -741,20 +815,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
741
815
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
742
816
|
}
|
|
743
817
|
else {
|
|
744
|
-
const orderedClientLogger = (0,
|
|
818
|
+
const orderedClientLogger = (0, internal_7.createChildLogger)({
|
|
745
819
|
logger: this.logger,
|
|
746
820
|
namespace: "OrderedClientElection",
|
|
747
821
|
});
|
|
748
|
-
const orderedClientCollection = new
|
|
749
|
-
const orderedClientElectionForSummarizer = new
|
|
750
|
-
this.summarizerClientElection = new
|
|
822
|
+
const orderedClientCollection = new index_js_3.OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
823
|
+
const orderedClientElectionForSummarizer = new index_js_3.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, index_js_3.SummarizerClientElection.isClientEligible);
|
|
824
|
+
this.summarizerClientElection = new index_js_3.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
751
825
|
if (this.isSummarizerClient) {
|
|
752
|
-
this._summarizer = new
|
|
826
|
+
this._summarizer = new index_js_3.Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => index_js_3.RunWhileConnectedCoordinator.create(runtime,
|
|
753
827
|
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
754
828
|
// information. The proxy delta manager would always return false for summarizer client.
|
|
755
829
|
() => this.innerDeltaManager.active));
|
|
756
830
|
}
|
|
757
|
-
else if (
|
|
831
|
+
else if (index_js_3.SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
758
832
|
// Only create a SummaryManager and SummarizerClientElection
|
|
759
833
|
// if summaries are enabled and we are not the summarizer client.
|
|
760
834
|
const defaultAction = () => {
|
|
@@ -776,7 +850,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
776
850
|
};
|
|
777
851
|
this.summaryCollection.on("default", defaultAction);
|
|
778
852
|
// Create the SummaryManager and mark the initial state
|
|
779
|
-
this.summaryManager = new
|
|
853
|
+
this.summaryManager = new index_js_3.SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
780
854
|
this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new throttler_js_1.Throttler(60 * 1000, // 60 sec delay window
|
|
781
855
|
30 * 1000, // 30 sec max delay
|
|
782
856
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
@@ -803,10 +877,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
803
877
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
804
878
|
gcVersion: metadata?.gcFeature,
|
|
805
879
|
options: JSON.stringify(runtimeOptions),
|
|
806
|
-
idCompressorModeMetadata: metadata?.idCompressorMode,
|
|
880
|
+
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
807
881
|
idCompressorMode: this.idCompressorMode,
|
|
808
882
|
featureGates: JSON.stringify({
|
|
809
|
-
|
|
883
|
+
...featureGatesForTelemetry,
|
|
810
884
|
disableOpReentryCheck,
|
|
811
885
|
disableChunking,
|
|
812
886
|
disableAttachReorder: this.disableAttachReorder,
|
|
@@ -818,9 +892,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
818
892
|
});
|
|
819
893
|
(0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
|
|
820
894
|
(0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
|
|
821
|
-
this.entryPoint = new
|
|
895
|
+
this.entryPoint = new internal_2.LazyPromise(async () => {
|
|
822
896
|
if (this.isSummarizerClient) {
|
|
823
|
-
(0,
|
|
897
|
+
(0, internal_2.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
824
898
|
return this._summarizer;
|
|
825
899
|
}
|
|
826
900
|
return provideEntryPoint(this);
|
|
@@ -829,14 +903,32 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
829
903
|
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
830
904
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
831
905
|
}
|
|
906
|
+
onSchemaChange(schema) {
|
|
907
|
+
// Most of the settings will be picked up only by new sessions (i.e. after reload).
|
|
908
|
+
// We can make it better in the future (i.e. start to use op compression right away), but for simplicity
|
|
909
|
+
// this is not done.
|
|
910
|
+
// But ID compressor is special. It's possible, that in future, we will remove "stickiness" of ID compressor setting
|
|
911
|
+
// and will allow to start using it. If that were to happen, we want to ensure that we do not break eventual consistency
|
|
912
|
+
// promises. To do so, we need to initialize id compressor right away.
|
|
913
|
+
// As it's implemented right now (with async initialization), this will only work for "off" -> "delayed" transitions.
|
|
914
|
+
// Anything else is too risky, and requires ability to initialize ID compressor synchronously!
|
|
915
|
+
if (schema.runtime.idCompressorMode !== undefined) {
|
|
916
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
917
|
+
this.loadIdCompressor();
|
|
918
|
+
}
|
|
919
|
+
}
|
|
832
920
|
getCreateChildSummarizerNodeFn(id, createParam) {
|
|
833
921
|
return (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn);
|
|
834
922
|
}
|
|
835
923
|
deleteChildSummarizerNode(id) {
|
|
836
924
|
return this.summarizerNode.deleteChild(id);
|
|
837
925
|
}
|
|
926
|
+
/* IFluidParentContext APIs that should not be called on Root */
|
|
838
927
|
makeLocallyVisible() {
|
|
839
|
-
(0,
|
|
928
|
+
(0, internal_2.assert)(false, 0x8eb /* should not be called */);
|
|
929
|
+
}
|
|
930
|
+
setChannelDirty(address) {
|
|
931
|
+
(0, internal_2.assert)(false, 0x909 /* should not be called */);
|
|
840
932
|
}
|
|
841
933
|
/**
|
|
842
934
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
@@ -845,7 +937,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
845
937
|
if (this.idCompressorMode === "on" ||
|
|
846
938
|
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
847
939
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
848
|
-
(0,
|
|
940
|
+
(0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
849
941
|
this._idCompressor = await this.createIdCompressor();
|
|
850
942
|
}
|
|
851
943
|
await this.garbageCollector.initializeBaseState();
|
|
@@ -879,13 +971,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
879
971
|
*/
|
|
880
972
|
async getSnapshotForLoadingGroupId(loadingGroupIds, pathParts) {
|
|
881
973
|
const sortedLoadingGroupIds = loadingGroupIds.sort();
|
|
882
|
-
(0,
|
|
974
|
+
(0, internal_2.assert)(this.storage.getSnapshot !== undefined, 0x8ed /* getSnapshot api should be defined if used */);
|
|
883
975
|
let loadedFromCache = true;
|
|
884
976
|
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
885
977
|
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
886
978
|
// any request, then cache that as same group could be requested in future too.
|
|
887
979
|
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(), async () => {
|
|
888
|
-
(0,
|
|
980
|
+
(0, internal_2.assert)(this.storage.getSnapshot !== undefined, 0x8ee /* getSnapshot api should be defined if used */);
|
|
889
981
|
loadedFromCache = false;
|
|
890
982
|
return this.storage.getSnapshot({
|
|
891
983
|
cacheSnapshot: false,
|
|
@@ -901,16 +993,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
901
993
|
}),
|
|
902
994
|
});
|
|
903
995
|
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
904
|
-
const hasIsolatedChannels = (0,
|
|
996
|
+
const hasIsolatedChannels = (0, index_js_3.rootHasIsolatedChannels)(this.metadata);
|
|
905
997
|
const snapshotTreeForPath = this.getSnapshotTreeForPath(snapshot.snapshotTree, pathParts, hasIsolatedChannels);
|
|
906
|
-
(0,
|
|
998
|
+
(0, internal_2.assert)(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
907
999
|
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
908
|
-
(0,
|
|
1000
|
+
(0, internal_2.assert)(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
|
|
909
1001
|
// This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
|
|
910
1002
|
// Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
|
|
911
1003
|
// the file has been overwritten or service lost data.
|
|
912
1004
|
if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
|
|
913
|
-
throw
|
|
1005
|
+
throw internal_7.DataProcessingError.create("Downloaded snapshot older than snapshot we loaded from", "getSnapshotForLoadingGroupId", undefined, {
|
|
914
1006
|
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
915
1007
|
snapshotSeqNumber,
|
|
916
1008
|
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
@@ -933,7 +1025,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
933
1025
|
targetSequenceNumber: snapshotSeqNumber,
|
|
934
1026
|
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
935
1027
|
};
|
|
936
|
-
const event =
|
|
1028
|
+
const event = internal_7.PerformanceEvent.start(this.mc.logger, {
|
|
937
1029
|
...props,
|
|
938
1030
|
});
|
|
939
1031
|
// If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
|
|
@@ -941,7 +1033,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
941
1033
|
if (this.deltaManager.inbound.paused) {
|
|
942
1034
|
props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
|
|
943
1035
|
}
|
|
944
|
-
const defP = new
|
|
1036
|
+
const defP = new internal_2.Deferred();
|
|
945
1037
|
this.deltaManager.on("op", (message) => {
|
|
946
1038
|
if (message.sequenceNumber >= snapshotSeqNumber) {
|
|
947
1039
|
defP.resolve(true);
|
|
@@ -964,7 +1056,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
964
1056
|
let childTree = snapshotTree;
|
|
965
1057
|
for (const part of pathParts) {
|
|
966
1058
|
if (hasIsolatedChannels) {
|
|
967
|
-
childTree = childTree?.trees[
|
|
1059
|
+
childTree = childTree?.trees[internal_5.channelsTreeName];
|
|
968
1060
|
}
|
|
969
1061
|
childTree = childTree?.trees[part];
|
|
970
1062
|
}
|
|
@@ -978,7 +1070,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
978
1070
|
// @ts-expect-error expected to be used by LTS Loaders and Containers
|
|
979
1071
|
async request(request) {
|
|
980
1072
|
try {
|
|
981
|
-
const parser =
|
|
1073
|
+
const parser = internal_6.RequestParser.create(request);
|
|
982
1074
|
const id = parser.pathParts[0];
|
|
983
1075
|
if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
|
|
984
1076
|
if (this._summarizer !== undefined) {
|
|
@@ -988,16 +1080,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
988
1080
|
value: this.summarizer,
|
|
989
1081
|
};
|
|
990
1082
|
}
|
|
991
|
-
return (0,
|
|
1083
|
+
return (0, internal_6.create404Response)(request);
|
|
992
1084
|
}
|
|
993
1085
|
if (this.requestHandler !== undefined) {
|
|
994
1086
|
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
995
1087
|
return this.requestHandler(parser, this);
|
|
996
1088
|
}
|
|
997
|
-
return (0,
|
|
1089
|
+
return (0, internal_6.create404Response)(request);
|
|
998
1090
|
}
|
|
999
1091
|
catch (error) {
|
|
1000
|
-
return (0,
|
|
1092
|
+
return (0, internal_6.exceptionToResponse)(error);
|
|
1001
1093
|
}
|
|
1002
1094
|
}
|
|
1003
1095
|
/**
|
|
@@ -1006,7 +1098,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1006
1098
|
*/
|
|
1007
1099
|
async resolveHandle(request) {
|
|
1008
1100
|
try {
|
|
1009
|
-
const requestParser =
|
|
1101
|
+
const requestParser = internal_6.RequestParser.create(request);
|
|
1010
1102
|
const id = requestParser.pathParts[0];
|
|
1011
1103
|
if (id === "_channels") {
|
|
1012
1104
|
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
@@ -1020,15 +1112,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1020
1112
|
mimeType: "fluid/object",
|
|
1021
1113
|
value: blob,
|
|
1022
1114
|
}
|
|
1023
|
-
: (0,
|
|
1115
|
+
: (0, internal_6.create404Response)(request);
|
|
1024
1116
|
}
|
|
1025
1117
|
else if (requestParser.pathParts.length > 0) {
|
|
1026
1118
|
return await this.channelCollection.request(request);
|
|
1027
1119
|
}
|
|
1028
|
-
return (0,
|
|
1120
|
+
return (0, internal_6.create404Response)(request);
|
|
1029
1121
|
}
|
|
1030
1122
|
catch (error) {
|
|
1031
|
-
return (0,
|
|
1123
|
+
return (0, internal_6.exceptionToResponse)(error);
|
|
1032
1124
|
}
|
|
1033
1125
|
}
|
|
1034
1126
|
/**
|
|
@@ -1042,48 +1134,60 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1042
1134
|
}
|
|
1043
1135
|
/** Adds the container's metadata to the given summary tree. */
|
|
1044
1136
|
addMetadataToSummary(summaryTree) {
|
|
1137
|
+
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
1138
|
+
// last summary.
|
|
1139
|
+
const message = (0, index_js_3.extractSummaryMetadataMessage)(this.deltaManager.lastMessage) ??
|
|
1140
|
+
this.messageAtLastSummary;
|
|
1141
|
+
const documentSchema = this.documentsSchemaController.summarizeDocumentSchema(this.deltaManager.lastSequenceNumber);
|
|
1142
|
+
// Is document schema explicit control on?
|
|
1143
|
+
const explitiSchemaControl = documentSchema?.runtime.explicitSchemaControl;
|
|
1045
1144
|
const metadata = {
|
|
1046
1145
|
...this.createContainerMetadata,
|
|
1047
1146
|
// Increment the summary number for the next summary that will be generated.
|
|
1048
1147
|
summaryNumber: this.nextSummaryNumber++,
|
|
1049
1148
|
summaryFormatVersion: 1,
|
|
1050
1149
|
...this.garbageCollector.getMetadata(),
|
|
1051
|
-
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
1052
|
-
// last summary.
|
|
1053
|
-
message: (0, index_js_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage) ??
|
|
1054
|
-
this.messageAtLastSummary,
|
|
1055
1150
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1056
|
-
|
|
1151
|
+
// If explicit document schema control is not on, use legacy way to supply last message (using 'message' property).
|
|
1152
|
+
// Otherwise use new 'lastMessage' property, but also put content into the 'message' property that cases old
|
|
1153
|
+
// runtimes (that preceed document schema control capabilities) to close container on load due to mismatch in
|
|
1154
|
+
// last message's sequence number.
|
|
1155
|
+
// See also lastMessageFromMetadata()
|
|
1156
|
+
message: explitiSchemaControl
|
|
1157
|
+
? { sequenceNumber: -1 }
|
|
1158
|
+
: message,
|
|
1159
|
+
lastMessage: explitiSchemaControl ? message : undefined,
|
|
1160
|
+
documentSchema,
|
|
1057
1161
|
};
|
|
1058
|
-
(0,
|
|
1162
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_3.metadataBlobName, JSON.stringify(metadata));
|
|
1059
1163
|
}
|
|
1060
1164
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
1061
1165
|
this.addMetadataToSummary(summaryTree);
|
|
1062
1166
|
if (this._idCompressor) {
|
|
1063
1167
|
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
1064
|
-
(0,
|
|
1168
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_3.idCompressorBlobName, idCompressorState);
|
|
1065
1169
|
}
|
|
1066
1170
|
if (this.remoteMessageProcessor.partialMessages.size > 0) {
|
|
1067
1171
|
const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
|
|
1068
|
-
(0,
|
|
1172
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_3.chunksBlobName, content);
|
|
1069
1173
|
}
|
|
1070
1174
|
const dataStoreAliases = this.channelCollection.aliases;
|
|
1071
1175
|
if (dataStoreAliases.size > 0) {
|
|
1072
|
-
(0,
|
|
1176
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_3.aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
1073
1177
|
}
|
|
1074
1178
|
if (this.summarizerClientElection) {
|
|
1075
1179
|
const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
|
|
1076
|
-
(0,
|
|
1180
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_3.electedSummarizerBlobName, electedSummarizerContent);
|
|
1077
1181
|
}
|
|
1078
1182
|
const blobManagerSummary = this.blobManager.summarize();
|
|
1079
1183
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
1080
1184
|
// and the blob manager can handle the tree not existing when loading
|
|
1081
1185
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
1082
|
-
(0,
|
|
1186
|
+
(0, internal_6.addSummarizeResultToSummary)(summaryTree, index_js_3.blobsTreeName, blobManagerSummary);
|
|
1083
1187
|
}
|
|
1084
1188
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
1085
1189
|
if (gcSummary !== undefined) {
|
|
1086
|
-
(0,
|
|
1190
|
+
(0, internal_6.addSummarizeResultToSummary)(summaryTree, internal_5.gcTreeKey, gcSummary);
|
|
1087
1191
|
}
|
|
1088
1192
|
}
|
|
1089
1193
|
// Track how many times the container tries to reconnect with pending messages.
|
|
@@ -1114,14 +1218,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1114
1218
|
}
|
|
1115
1219
|
return this.consecutiveReconnects < this.maxConsecutiveReconnects;
|
|
1116
1220
|
}
|
|
1117
|
-
resetReconnectCount(
|
|
1118
|
-
|
|
1119
|
-
// in their own batches before the originating batch is sent.
|
|
1120
|
-
// Therefore, receiving them while attempting to send the originating batch
|
|
1121
|
-
// does not mean that the container is making any progress.
|
|
1122
|
-
if (message?.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp) {
|
|
1123
|
-
this.consecutiveReconnects = 0;
|
|
1124
|
-
}
|
|
1221
|
+
resetReconnectCount() {
|
|
1222
|
+
this.consecutiveReconnects = 0;
|
|
1125
1223
|
}
|
|
1126
1224
|
replayPendingStates() {
|
|
1127
1225
|
// We need to be able to send ops to replay states
|
|
@@ -1134,7 +1232,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1134
1232
|
// Save the old state, reset to false, disable event emit
|
|
1135
1233
|
const oldState = this.dirtyContainer;
|
|
1136
1234
|
this.dirtyContainer = false;
|
|
1137
|
-
(0,
|
|
1235
|
+
(0, internal_2.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
|
|
1138
1236
|
this.emitDirtyDocumentEvent = false;
|
|
1139
1237
|
let newState;
|
|
1140
1238
|
try {
|
|
@@ -1156,9 +1254,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1156
1254
|
*/
|
|
1157
1255
|
// TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
|
|
1158
1256
|
parseLocalOpContent(serializedContents) {
|
|
1159
|
-
(0,
|
|
1257
|
+
(0, internal_2.assert)(serializedContents !== undefined, 0x6d5 /* content must be defined */);
|
|
1160
1258
|
const message = JSON.parse(serializedContents);
|
|
1161
|
-
(0,
|
|
1259
|
+
(0, internal_2.assert)(message.type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1162
1260
|
return message;
|
|
1163
1261
|
}
|
|
1164
1262
|
async applyStashedOp(serializedOpContent) {
|
|
@@ -1170,7 +1268,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1170
1268
|
case messageTypes_js_1.ContainerMessageType.Alias:
|
|
1171
1269
|
return this.channelCollection.applyStashedOp(opContents);
|
|
1172
1270
|
case messageTypes_js_1.ContainerMessageType.IdAllocation:
|
|
1173
|
-
|
|
1271
|
+
// IDs allocation ops in stashed state are ignored because the tip state of the compressor
|
|
1272
|
+
// is serialized into the pending state. This is done because generation of new IDs during
|
|
1273
|
+
// stashed op application (or, later, resubmit) must generate new IDs and if the compressor
|
|
1274
|
+
// was loaded from a state serialized at the same time as the summary tree in the stashed state
|
|
1275
|
+
// then it would generate IDs that collide with any in later stashed ops.
|
|
1276
|
+
// In the future, IdCompressor could be extended to have an "applyStashedOp" or similar method
|
|
1277
|
+
// and the runtime could filter out all ID allocation ops from the stashed state and apply them
|
|
1278
|
+
// before applying the rest of the stashed ops. This would accomplish the same thing but with
|
|
1279
|
+
// better performance in future incremental stashed state creation.
|
|
1280
|
+
(0, internal_2.assert)(this.idCompressorMode !== undefined, 0x8f1 /* ID compressor should be in use */);
|
|
1281
|
+
return;
|
|
1282
|
+
case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
|
|
1174
1283
|
return;
|
|
1175
1284
|
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
1176
1285
|
return;
|
|
@@ -1180,14 +1289,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1180
1289
|
throw new Error("rejoin not expected here");
|
|
1181
1290
|
case messageTypes_js_1.ContainerMessageType.GC:
|
|
1182
1291
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
1183
|
-
throw new
|
|
1292
|
+
throw new internal_7.LoggingError("GC op not expected to be stashed in summarizer");
|
|
1184
1293
|
default: {
|
|
1185
1294
|
// This should be extremely rare for stashed ops.
|
|
1186
1295
|
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
1187
1296
|
// e.g. if an app rolled back its container version
|
|
1188
1297
|
const compatBehavior = opContents.compatDetails?.behavior;
|
|
1189
1298
|
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
1190
|
-
const error =
|
|
1299
|
+
const error = internal_7.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1191
1300
|
messageDetails: JSON.stringify({
|
|
1192
1301
|
type: opContents.type,
|
|
1193
1302
|
compatBehavior,
|
|
@@ -1201,12 +1310,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1201
1310
|
}
|
|
1202
1311
|
}
|
|
1203
1312
|
}
|
|
1204
|
-
|
|
1205
|
-
if (
|
|
1206
|
-
this.
|
|
1207
|
-
this.
|
|
1313
|
+
async loadIdCompressor() {
|
|
1314
|
+
if (this._idCompressor === undefined &&
|
|
1315
|
+
this.idCompressorMode !== undefined &&
|
|
1316
|
+
this._loadIdCompressor === undefined) {
|
|
1317
|
+
this._loadIdCompressor = this.createIdCompressor()
|
|
1208
1318
|
.then((compressor) => {
|
|
1209
1319
|
this._idCompressor = compressor;
|
|
1320
|
+
// Finalize any ranges we received while the compressor was turned off.
|
|
1210
1321
|
for (const range of this.pendingIdCompressorOps) {
|
|
1211
1322
|
this._idCompressor.finalizeCreationRange(range);
|
|
1212
1323
|
}
|
|
@@ -1214,8 +1325,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1214
1325
|
})
|
|
1215
1326
|
.catch((error) => {
|
|
1216
1327
|
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1328
|
+
throw error;
|
|
1217
1329
|
});
|
|
1218
1330
|
}
|
|
1331
|
+
return this._loadIdCompressor;
|
|
1332
|
+
}
|
|
1333
|
+
setConnectionState(connected, clientId) {
|
|
1334
|
+
if (connected && this.idCompressorMode === "delayed") {
|
|
1335
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1336
|
+
this.loadIdCompressor();
|
|
1337
|
+
}
|
|
1219
1338
|
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
1220
1339
|
this.delayConnectClientId = undefined;
|
|
1221
1340
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -1224,27 +1343,23 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1224
1343
|
// Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
|
|
1225
1344
|
return;
|
|
1226
1345
|
}
|
|
1346
|
+
if (!connected) {
|
|
1347
|
+
this.documentsSchemaController.onDisconnect();
|
|
1348
|
+
}
|
|
1227
1349
|
// If there are stashed blobs in the pending state, we need to delay
|
|
1228
1350
|
// propagation of the "connected" event until we have uploaded them to
|
|
1229
1351
|
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1230
1352
|
const connecting = connected && !this._connected;
|
|
1231
|
-
if (connecting && this.blobManager.
|
|
1232
|
-
(0,
|
|
1233
|
-
(0,
|
|
1353
|
+
if (connecting && this.blobManager.hasPendingStashedUploads()) {
|
|
1354
|
+
(0, internal_2.assert)(!this.delayConnectClientId, 0x791 /* Connect event delay must be canceled before subsequent connect event */);
|
|
1355
|
+
(0, internal_2.assert)(!!clientId, 0x792 /* Must have clientId when connecting */);
|
|
1234
1356
|
this.delayConnectClientId = clientId;
|
|
1235
|
-
this.blobManager.processStashedChanges().then(() => {
|
|
1236
|
-
// make sure we didn't reconnect before the promise resolved
|
|
1237
|
-
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
1238
|
-
this.delayConnectClientId = undefined;
|
|
1239
|
-
this.setConnectionStateCore(connected, clientId);
|
|
1240
|
-
}
|
|
1241
|
-
}, (error) => this.closeFn(error));
|
|
1242
1357
|
return;
|
|
1243
1358
|
}
|
|
1244
1359
|
this.setConnectionStateCore(connected, clientId);
|
|
1245
1360
|
}
|
|
1246
1361
|
setConnectionStateCore(connected, clientId) {
|
|
1247
|
-
(0,
|
|
1362
|
+
(0, internal_2.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
|
|
1248
1363
|
this.verifyNotClosed();
|
|
1249
1364
|
// There might be no change of state due to Container calling this API after loading runtime.
|
|
1250
1365
|
const changeOfState = this._connected !== connected;
|
|
@@ -1262,13 +1377,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1262
1377
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
1263
1378
|
}
|
|
1264
1379
|
else {
|
|
1265
|
-
(0,
|
|
1380
|
+
(0, internal_2.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
|
|
1266
1381
|
}
|
|
1267
1382
|
// Fail while disconnected
|
|
1268
1383
|
if (reconnection) {
|
|
1269
1384
|
this.consecutiveReconnects++;
|
|
1270
1385
|
if (!this.shouldContinueReconnecting()) {
|
|
1271
|
-
this.closeFn(
|
|
1386
|
+
this.closeFn(internal_7.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
|
|
1272
1387
|
dataLoss: 1,
|
|
1273
1388
|
attempts: this.consecutiveReconnects,
|
|
1274
1389
|
pendingMessages: this.pendingMessagesCount,
|
|
@@ -1281,7 +1396,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1281
1396
|
}
|
|
1282
1397
|
this.channelCollection.setConnectionState(connected, clientId);
|
|
1283
1398
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
1284
|
-
(0,
|
|
1399
|
+
(0, internal_7.raiseConnectedEvent)(this.mc.logger, this, connected, clientId);
|
|
1285
1400
|
}
|
|
1286
1401
|
async notifyOpReplay(message) {
|
|
1287
1402
|
await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
|
|
@@ -1326,10 +1441,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1326
1441
|
this.scheduleManager.beforeOpProcessing(message);
|
|
1327
1442
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1328
1443
|
try {
|
|
1444
|
+
// See commit that added this assert for more details.
|
|
1445
|
+
// These calls should be made for all but chunked ops:
|
|
1446
|
+
// 1) this.pendingStateManager.processPendingLocalMessage() below
|
|
1447
|
+
// 2) this.resetReconnectCount() below
|
|
1448
|
+
(0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, 0x93b /* we should never get here with chunked ops */);
|
|
1329
1449
|
let localOpMetadata;
|
|
1330
|
-
if (local &&
|
|
1331
|
-
messageWithContext.modernRuntimeMessage &&
|
|
1332
|
-
message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp) {
|
|
1450
|
+
if (local && messageWithContext.modernRuntimeMessage) {
|
|
1333
1451
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
|
|
1334
1452
|
}
|
|
1335
1453
|
// If there are no more pending messages after processing a local message,
|
|
@@ -1344,7 +1462,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1344
1462
|
// If we have processed a local op, this means that the container is
|
|
1345
1463
|
// making progress and we can reset the counter for how many times
|
|
1346
1464
|
// we have consecutively replayed the pending states
|
|
1347
|
-
this.resetReconnectCount(
|
|
1465
|
+
this.resetReconnectCount();
|
|
1348
1466
|
}
|
|
1349
1467
|
}
|
|
1350
1468
|
catch (e) {
|
|
@@ -1378,7 +1496,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1378
1496
|
messageWithContext.message.metadata?.savedOp ===
|
|
1379
1497
|
true)) {
|
|
1380
1498
|
const range = messageWithContext.message.contents;
|
|
1499
|
+
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1500
|
+
// put it in a pending queue and delay finalization.
|
|
1381
1501
|
if (this._idCompressor === undefined) {
|
|
1502
|
+
(0, internal_2.assert)(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1382
1503
|
this.pendingIdCompressorOps.push(range);
|
|
1383
1504
|
}
|
|
1384
1505
|
else {
|
|
@@ -1390,8 +1511,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1390
1511
|
this.garbageCollector.processMessage(messageWithContext.message, local);
|
|
1391
1512
|
break;
|
|
1392
1513
|
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
1514
|
+
// From observability POV, we should not exppse the rest of the system (including "op" events on object) to these messages.
|
|
1515
|
+
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
1516
|
+
(0, internal_2.assert)(false, 0x93d /* should not even get here */);
|
|
1393
1517
|
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
1394
1518
|
break;
|
|
1519
|
+
case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
|
|
1520
|
+
this.documentsSchemaController.processDocumentSchemaOp(messageWithContext.message.contents, messageWithContext.local, messageWithContext.message.sequenceNumber);
|
|
1521
|
+
break;
|
|
1395
1522
|
default: {
|
|
1396
1523
|
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
1397
1524
|
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
@@ -1401,7 +1528,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1401
1528
|
const compatBehavior = messageWithContext.message.compatDetails?.behavior;
|
|
1402
1529
|
if (!compatBehaviorAllowsMessageType(messageWithContext.message.type, compatBehavior)) {
|
|
1403
1530
|
const { message } = messageWithContext;
|
|
1404
|
-
const error =
|
|
1531
|
+
const error = internal_7.DataProcessingError.create(
|
|
1405
1532
|
// Former assert 0x3ce
|
|
1406
1533
|
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1407
1534
|
local,
|
|
@@ -1485,9 +1612,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1485
1612
|
* This method is expected to be called at the end of a batch.
|
|
1486
1613
|
*/
|
|
1487
1614
|
flush() {
|
|
1488
|
-
(0,
|
|
1615
|
+
(0, internal_2.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
|
|
1489
1616
|
this.outbox.flush();
|
|
1490
|
-
(0,
|
|
1617
|
+
(0, internal_2.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
1491
1618
|
}
|
|
1492
1619
|
/**
|
|
1493
1620
|
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially}
|
|
@@ -1512,15 +1639,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1512
1639
|
checkpoint.rollback((message) => this.rollback(message.contents, message.localOpMetadata));
|
|
1513
1640
|
}
|
|
1514
1641
|
catch (err) {
|
|
1515
|
-
const error2 = (0,
|
|
1516
|
-
return
|
|
1642
|
+
const error2 = (0, internal_7.wrapError)(err, (message) => {
|
|
1643
|
+
return internal_7.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
|
|
1517
1644
|
});
|
|
1518
1645
|
this.closeFn(error2);
|
|
1519
1646
|
throw error2;
|
|
1520
1647
|
}
|
|
1521
1648
|
}
|
|
1522
1649
|
else {
|
|
1523
|
-
this.closeFn((0,
|
|
1650
|
+
this.closeFn((0, internal_7.wrapError)(error, (errorMessage) => new internal_7.GenericError(`orderSequentially callback exception: ${errorMessage}`, error, {
|
|
1524
1651
|
orderSequentiallyCalls: this._orderSequentiallyCalls,
|
|
1525
1652
|
})));
|
|
1526
1653
|
}
|
|
@@ -1530,7 +1657,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1530
1657
|
this._orderSequentiallyCalls--;
|
|
1531
1658
|
}
|
|
1532
1659
|
// We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
|
|
1533
|
-
if (this.flushMode !==
|
|
1660
|
+
if (this.flushMode !== internal_5.FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
|
|
1534
1661
|
this.flush();
|
|
1535
1662
|
}
|
|
1536
1663
|
return result;
|
|
@@ -1559,16 +1686,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1559
1686
|
}
|
|
1560
1687
|
const channel = await context.realize();
|
|
1561
1688
|
if (channel.entryPoint === undefined) {
|
|
1562
|
-
throw new
|
|
1689
|
+
throw new internal_7.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
|
|
1563
1690
|
}
|
|
1564
1691
|
this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
|
|
1565
1692
|
return channel.entryPoint;
|
|
1566
1693
|
}
|
|
1567
1694
|
createDetachedDataStore(pkg, loadingGroupId) {
|
|
1568
|
-
return this.channelCollection.
|
|
1695
|
+
return this.channelCollection.createDetachedDataStore(pkg, loadingGroupId);
|
|
1569
1696
|
}
|
|
1570
1697
|
async createDataStore(pkg, loadingGroupId) {
|
|
1571
|
-
const context = this.channelCollection.
|
|
1698
|
+
const context = this.channelCollection.createDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], undefined, // props
|
|
1572
1699
|
loadingGroupId);
|
|
1573
1700
|
return (0, dataStore_js_1.channelToDataStore)(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1574
1701
|
}
|
|
@@ -1576,7 +1703,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1576
1703
|
* @deprecated 0.16 Issue #1537, #3631
|
|
1577
1704
|
*/
|
|
1578
1705
|
async _createDataStoreWithProps(pkg, props) {
|
|
1579
|
-
const context = this.channelCollection.
|
|
1706
|
+
const context = this.channelCollection.createDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], props);
|
|
1580
1707
|
return (0, dataStore_js_1.channelToDataStore)(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1581
1708
|
}
|
|
1582
1709
|
canSendOps() {
|
|
@@ -1588,7 +1715,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1588
1715
|
* Are we in the middle of batching ops together?
|
|
1589
1716
|
*/
|
|
1590
1717
|
currentlyBatching() {
|
|
1591
|
-
return this.flushMode !==
|
|
1718
|
+
return this.flushMode !== internal_5.FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
1592
1719
|
}
|
|
1593
1720
|
getQuorum() {
|
|
1594
1721
|
return this._quorum;
|
|
@@ -1621,6 +1748,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1621
1748
|
}
|
|
1622
1749
|
break;
|
|
1623
1750
|
}
|
|
1751
|
+
case messageTypes_js_1.ContainerMessageType.IdAllocation:
|
|
1752
|
+
case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
|
|
1624
1753
|
case messageTypes_js_1.ContainerMessageType.GC: {
|
|
1625
1754
|
return false;
|
|
1626
1755
|
}
|
|
@@ -1647,7 +1776,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1647
1776
|
/**
|
|
1648
1777
|
* Submits the signal to be sent to other clients.
|
|
1649
1778
|
* @param type - Type of the signal.
|
|
1650
|
-
* @param content - Content of the signal.
|
|
1779
|
+
* @param content - Content of the signal. Should be a JSON serializable object or primitive.
|
|
1651
1780
|
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
1652
1781
|
*/
|
|
1653
1782
|
submitSignal(type, content, targetClientId) {
|
|
@@ -1657,10 +1786,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1657
1786
|
}
|
|
1658
1787
|
setAttachState(attachState) {
|
|
1659
1788
|
if (attachState === container_definitions_1.AttachState.Attaching) {
|
|
1660
|
-
(0,
|
|
1789
|
+
(0, internal_2.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
|
|
1661
1790
|
}
|
|
1662
1791
|
else {
|
|
1663
|
-
(0,
|
|
1792
|
+
(0, internal_2.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
|
|
1664
1793
|
this.emit("attached");
|
|
1665
1794
|
}
|
|
1666
1795
|
if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
|
|
@@ -1683,19 +1812,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1683
1812
|
// We can finalize any allocated IDs since we're the only client
|
|
1684
1813
|
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
1685
1814
|
if (idRange !== undefined) {
|
|
1815
|
+
(0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1, 0x93e /* No other ranges should be taken while container is detached. */);
|
|
1686
1816
|
this._idCompressor?.finalizeCreationRange(idRange);
|
|
1687
1817
|
}
|
|
1688
1818
|
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
1689
1819
|
// Wrap data store summaries in .channels subtree.
|
|
1690
|
-
(0,
|
|
1820
|
+
(0, index_js_3.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1691
1821
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
1692
1822
|
return summarizeResult.summary;
|
|
1693
1823
|
}
|
|
1694
1824
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
1695
1825
|
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
1696
1826
|
// Wrap data store summaries in .channels subtree.
|
|
1697
|
-
(0,
|
|
1698
|
-
const pathPartsForChildren = [
|
|
1827
|
+
(0, index_js_3.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1828
|
+
const pathPartsForChildren = [internal_5.channelsTreeName];
|
|
1829
|
+
// Ensure that ID compressor had a chance to load, if we are using delayed mode.
|
|
1830
|
+
await this.loadIdCompressor();
|
|
1699
1831
|
this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
|
|
1700
1832
|
return {
|
|
1701
1833
|
...summarizeResult,
|
|
@@ -1709,7 +1841,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1709
1841
|
async summarize(options) {
|
|
1710
1842
|
this.verifyNotClosed();
|
|
1711
1843
|
const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
|
|
1712
|
-
const telemetryContext = new
|
|
1844
|
+
const telemetryContext = new internal_6.TelemetryContext();
|
|
1713
1845
|
// Add the options that are used to generate this summary to the telemetry context.
|
|
1714
1846
|
telemetryContext.setMultiple("fluid_Summarize", "Options", {
|
|
1715
1847
|
fullTree,
|
|
@@ -1723,7 +1855,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1723
1855
|
await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
|
|
1724
1856
|
}
|
|
1725
1857
|
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
|
|
1726
|
-
(0,
|
|
1858
|
+
(0, internal_2.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1727
1859
|
return { stats, summary };
|
|
1728
1860
|
}
|
|
1729
1861
|
finally {
|
|
@@ -1751,7 +1883,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1751
1883
|
* @see IGarbageCollectionRuntime.getGCData
|
|
1752
1884
|
*/
|
|
1753
1885
|
async getGCData(fullGC) {
|
|
1754
|
-
const builder = new
|
|
1886
|
+
const builder = new internal_6.GCDataBuilder();
|
|
1755
1887
|
const dsGCData = await this.summarizerNode.getGCData(fullGC);
|
|
1756
1888
|
builder.addNodes(dsGCData.gcNodes);
|
|
1757
1889
|
const blobsGCData = this.blobManager.getGCData(fullGC);
|
|
@@ -1771,21 +1903,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1771
1903
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
1772
1904
|
this.channelCollection.updateUsedRoutes(dataStoreRoutes);
|
|
1773
1905
|
}
|
|
1774
|
-
/**
|
|
1775
|
-
* This is called to update objects whose routes are unused.
|
|
1776
|
-
* @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
|
|
1777
|
-
*/
|
|
1778
|
-
updateUnusedRoutes(unusedRoutes) {
|
|
1779
|
-
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
1780
|
-
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1781
|
-
this.channelCollection.updateUnusedRoutes(dataStoreRoutes);
|
|
1782
|
-
}
|
|
1783
|
-
/**
|
|
1784
|
-
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
1785
|
-
*/
|
|
1786
|
-
deleteUnusedNodes(unusedRoutes) {
|
|
1787
|
-
throw new Error("deleteUnusedRoutes should not be called");
|
|
1788
|
-
}
|
|
1789
1906
|
/**
|
|
1790
1907
|
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
1791
1908
|
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
@@ -1823,9 +1940,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1823
1940
|
*/
|
|
1824
1941
|
getNodeType(nodePath) {
|
|
1825
1942
|
if (this.isBlobPath(nodePath)) {
|
|
1826
|
-
return
|
|
1943
|
+
return index_js_1.GCNodeType.Blob;
|
|
1827
1944
|
}
|
|
1828
|
-
return this.channelCollection.getGCNodeType(nodePath) ??
|
|
1945
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? index_js_1.GCNodeType.Other;
|
|
1829
1946
|
}
|
|
1830
1947
|
/**
|
|
1831
1948
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
@@ -1838,13 +1955,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1838
1955
|
return ["_gcRoot"];
|
|
1839
1956
|
}
|
|
1840
1957
|
switch (this.getNodeType(nodePath)) {
|
|
1841
|
-
case
|
|
1958
|
+
case index_js_1.GCNodeType.Blob:
|
|
1842
1959
|
return [blobManager_js_1.BlobManager.basePath];
|
|
1843
|
-
case
|
|
1844
|
-
case
|
|
1960
|
+
case index_js_1.GCNodeType.DataStore:
|
|
1961
|
+
case index_js_1.GCNodeType.SubDataStore:
|
|
1845
1962
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
1846
1963
|
default:
|
|
1847
|
-
(0,
|
|
1964
|
+
(0, internal_2.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
1848
1965
|
}
|
|
1849
1966
|
}
|
|
1850
1967
|
/**
|
|
@@ -1905,16 +2022,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1905
2022
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1906
2023
|
// use it for all events logged during this summary.
|
|
1907
2024
|
const summaryNumber = this.nextSummaryNumber;
|
|
1908
|
-
const summaryNumberLogger = (0,
|
|
2025
|
+
const summaryNumberLogger = (0, internal_7.createChildLogger)({
|
|
1909
2026
|
logger: summaryLogger,
|
|
1910
2027
|
properties: {
|
|
1911
2028
|
all: { summaryNumber },
|
|
1912
2029
|
},
|
|
1913
2030
|
});
|
|
1914
|
-
(0,
|
|
2031
|
+
(0, internal_2.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
1915
2032
|
// We close the summarizer and download a new snapshot and reload the container
|
|
1916
2033
|
if (refreshLatestAck === true) {
|
|
1917
|
-
return this.prefetchLatestSummaryThenClose((0,
|
|
2034
|
+
return this.prefetchLatestSummaryThenClose((0, internal_7.createChildLogger)({
|
|
1918
2035
|
logger: summaryNumberLogger,
|
|
1919
2036
|
properties: { all: { safeSummary: true } },
|
|
1920
2037
|
}));
|
|
@@ -1998,7 +2115,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1998
2115
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
1999
2116
|
// So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
|
|
2000
2117
|
// OR that design changed and we need to remove this check and fix submitSystemMessage.
|
|
2001
|
-
(0,
|
|
2118
|
+
(0, internal_2.assert)(this.connected, 0x258 /* "connected" */);
|
|
2002
2119
|
// Ensure that lastSequenceNumber has not changed after pausing.
|
|
2003
2120
|
// We need the summary op's reference sequence number to match our summary sequence number,
|
|
2004
2121
|
// otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
|
|
@@ -2008,7 +2125,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2008
2125
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
2009
2126
|
};
|
|
2010
2127
|
}
|
|
2011
|
-
(0,
|
|
2128
|
+
(0, internal_2.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
|
|
2012
2129
|
if (lastAck !== this.summaryCollection.latestAck) {
|
|
2013
2130
|
return {
|
|
2014
2131
|
continue: false,
|
|
@@ -2053,7 +2170,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2053
2170
|
const validateResult = this.summarizerNode.validateSummary();
|
|
2054
2171
|
if (!validateResult.success) {
|
|
2055
2172
|
const { success, ...loggingProps } = validateResult;
|
|
2056
|
-
const error = new
|
|
2173
|
+
const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
2057
2174
|
return {
|
|
2058
2175
|
stage: "base",
|
|
2059
2176
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
@@ -2072,11 +2189,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2072
2189
|
// Counting dataStores and handles
|
|
2073
2190
|
// Because handles are unchanged dataStores in the current logic,
|
|
2074
2191
|
// summarized dataStore count is total dataStore count minus handle count
|
|
2075
|
-
const dataStoreTree = summaryTree.tree[
|
|
2076
|
-
(0,
|
|
2192
|
+
const dataStoreTree = summaryTree.tree[internal_5.channelsTreeName];
|
|
2193
|
+
(0, internal_2.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
2077
2194
|
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
|
|
2078
|
-
const gcSummaryTreeStats = summaryTree.tree[
|
|
2079
|
-
? (0,
|
|
2195
|
+
const gcSummaryTreeStats = summaryTree.tree[internal_5.gcTreeKey]
|
|
2196
|
+
? (0, internal_6.calculateStats)(summaryTree.tree[internal_5.gcTreeKey])
|
|
2080
2197
|
: undefined;
|
|
2081
2198
|
const summaryStats = {
|
|
2082
2199
|
dataStoreCount: this.channelCollection.size,
|
|
@@ -2187,7 +2304,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2187
2304
|
// the summarizer.
|
|
2188
2305
|
if (finalAttempt &&
|
|
2189
2306
|
this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
|
|
2190
|
-
const error =
|
|
2307
|
+
const error = internal_7.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
|
|
2191
2308
|
logger.sendErrorEvent({
|
|
2192
2309
|
eventName: "SkipFailingIncorrectSummary",
|
|
2193
2310
|
referenceSequenceNumber,
|
|
@@ -2200,7 +2317,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2200
2317
|
// based on telemetry while we decide on a stable number.
|
|
2201
2318
|
const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
2202
2319
|
exports.defaultPendingOpsRetryDelayMs;
|
|
2203
|
-
const error = new
|
|
2320
|
+
const error = new index_js_3.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
|
|
2204
2321
|
count: this.pendingMessagesCount,
|
|
2205
2322
|
beforeGenerate: beforeSummaryGeneration,
|
|
2206
2323
|
});
|
|
@@ -2220,11 +2337,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2220
2337
|
}
|
|
2221
2338
|
updateDocumentDirtyState(dirty) {
|
|
2222
2339
|
if (this.attachState !== container_definitions_1.AttachState.Attached) {
|
|
2223
|
-
(0,
|
|
2340
|
+
(0, internal_2.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
2224
2341
|
}
|
|
2225
2342
|
else {
|
|
2226
2343
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
2227
|
-
(0,
|
|
2344
|
+
(0, internal_2.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
|
|
2228
2345
|
}
|
|
2229
2346
|
if (this.dirtyContainer === dirty) {
|
|
2230
2347
|
return;
|
|
@@ -2253,19 +2370,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2253
2370
|
const idAllocationBatchMessage = {
|
|
2254
2371
|
contents: JSON.stringify(idAllocationMessage),
|
|
2255
2372
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2256
|
-
metadata: undefined,
|
|
2257
|
-
localOpMetadata: undefined,
|
|
2258
|
-
type: messageTypes_js_1.ContainerMessageType.IdAllocation,
|
|
2259
2373
|
};
|
|
2260
2374
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
2261
2375
|
}
|
|
2262
2376
|
}
|
|
2263
2377
|
}
|
|
2264
|
-
submit(containerRuntimeMessage, localOpMetadata = undefined, metadata
|
|
2378
|
+
submit(containerRuntimeMessage, localOpMetadata = undefined, metadata) {
|
|
2265
2379
|
this.verifyNotClosed();
|
|
2266
2380
|
this.verifyCanSubmitOps();
|
|
2267
2381
|
// There should be no ops in detached container state!
|
|
2268
|
-
(0,
|
|
2382
|
+
(0, internal_2.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
2383
|
+
(0, internal_2.assert)(metadata === undefined ||
|
|
2384
|
+
containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, 0x93f /* metadata */);
|
|
2269
2385
|
const serializedContent = JSON.stringify(containerRuntimeMessage);
|
|
2270
2386
|
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
2271
2387
|
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
@@ -2278,7 +2394,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2278
2394
|
const type = containerRuntimeMessage.type;
|
|
2279
2395
|
const message = {
|
|
2280
2396
|
contents: serializedContent,
|
|
2281
|
-
type,
|
|
2282
2397
|
metadata,
|
|
2283
2398
|
localOpMetadata,
|
|
2284
2399
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
@@ -2293,6 +2408,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2293
2408
|
}
|
|
2294
2409
|
else {
|
|
2295
2410
|
this.submitIdAllocationOpIfNeeded();
|
|
2411
|
+
// Allow document schema controller to send a message if it needs to propose change in document schema.
|
|
2412
|
+
// If it needs to send a message, it will call provided callback with payload of such message and rely
|
|
2413
|
+
// on this callback to do actual sending.
|
|
2414
|
+
const contents = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2415
|
+
if (contents) {
|
|
2416
|
+
const msg = {
|
|
2417
|
+
type: messageTypes_js_1.ContainerMessageType.DocumentSchemaChange,
|
|
2418
|
+
contents,
|
|
2419
|
+
};
|
|
2420
|
+
this.outbox.submit({
|
|
2421
|
+
contents: JSON.stringify(msg),
|
|
2422
|
+
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2296
2425
|
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
2297
2426
|
// Is it safe:
|
|
2298
2427
|
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
@@ -2356,29 +2485,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2356
2485
|
}
|
|
2357
2486
|
};
|
|
2358
2487
|
switch (this.flushMode) {
|
|
2359
|
-
case
|
|
2488
|
+
case internal_5.FlushMode.TurnBased:
|
|
2360
2489
|
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
2361
2490
|
// batch at the end of the turn
|
|
2362
2491
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2363
2492
|
Promise.resolve().then(flush);
|
|
2364
2493
|
break;
|
|
2365
2494
|
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
2366
|
-
case
|
|
2495
|
+
case internal_5.FlushModeExperimental.Async:
|
|
2367
2496
|
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
2368
2497
|
// batch when all micro-tasks are complete.
|
|
2369
2498
|
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
2370
2499
|
setTimeout(flush, 0);
|
|
2371
2500
|
break;
|
|
2372
2501
|
default:
|
|
2373
|
-
(0,
|
|
2502
|
+
(0, internal_2.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
2374
2503
|
break;
|
|
2375
2504
|
}
|
|
2376
2505
|
}
|
|
2377
2506
|
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
2378
2507
|
this.verifyNotClosed();
|
|
2379
|
-
(0,
|
|
2508
|
+
(0, internal_2.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
2380
2509
|
// System message should not be sent in the middle of the batch.
|
|
2381
|
-
(0,
|
|
2510
|
+
(0, internal_2.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
2382
2511
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
2383
2512
|
return this.submitSummaryFn !== undefined
|
|
2384
2513
|
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
@@ -2399,7 +2528,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2399
2528
|
if (this.opReentryCallsToReport > 0) {
|
|
2400
2529
|
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
2401
2530
|
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
2402
|
-
(0,
|
|
2531
|
+
(0, index_js_2.getLongStack)(() => new internal_7.UsageError(errorMessage)));
|
|
2403
2532
|
this.opReentryCallsToReport--;
|
|
2404
2533
|
}
|
|
2405
2534
|
// Creating ops while processing ops can lead
|
|
@@ -2415,7 +2544,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2415
2544
|
// The runtime must enforce op coherence by not allowing ops to be submitted
|
|
2416
2545
|
// while ops are being processed.
|
|
2417
2546
|
if (this.enableOpReentryCheck) {
|
|
2418
|
-
throw new
|
|
2547
|
+
throw new internal_7.UsageError(errorMessage);
|
|
2419
2548
|
}
|
|
2420
2549
|
}
|
|
2421
2550
|
}
|
|
@@ -2440,7 +2569,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2440
2569
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2441
2570
|
*/
|
|
2442
2571
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2443
|
-
(0,
|
|
2572
|
+
(0, internal_2.assert)(!this.isSummarizerClient, 0x8f2 /* Summarizer never reconnects so should never resubmit */);
|
|
2444
2573
|
switch (message.type) {
|
|
2445
2574
|
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp:
|
|
2446
2575
|
case messageTypes_js_1.ContainerMessageType.Attach:
|
|
@@ -2464,6 +2593,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2464
2593
|
case messageTypes_js_1.ContainerMessageType.GC:
|
|
2465
2594
|
this.submit(message);
|
|
2466
2595
|
break;
|
|
2596
|
+
case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
|
|
2597
|
+
// There is no need to resend this message. Document schema controller will properly resend it again (if needed)
|
|
2598
|
+
// on a first occasion (any ops sent after reconnect). There is a good chance, though, that it will not want to
|
|
2599
|
+
// send any ops, as some other client already changed schema.
|
|
2600
|
+
break;
|
|
2467
2601
|
default: {
|
|
2468
2602
|
// This case should be very rare - it would imply an op was stashed from a
|
|
2469
2603
|
// future version of runtime code and now is being applied on an older version.
|
|
@@ -2476,7 +2610,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2476
2610
|
});
|
|
2477
2611
|
}
|
|
2478
2612
|
else {
|
|
2479
|
-
const error =
|
|
2613
|
+
const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
|
|
2480
2614
|
messageDetails: JSON.stringify({
|
|
2481
2615
|
type: message.type,
|
|
2482
2616
|
compatBehavior,
|
|
@@ -2506,8 +2640,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2506
2640
|
async refreshLatestSummaryAck(options) {
|
|
2507
2641
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2508
2642
|
// proposalHandle is always passed from RunningSummarizer.
|
|
2509
|
-
(0,
|
|
2510
|
-
const readAndParseBlob = async (id) => (0,
|
|
2643
|
+
(0, internal_2.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
2644
|
+
const readAndParseBlob = async (id) => (0, internal_4.readAndParse)(this.storage, id);
|
|
2511
2645
|
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
|
|
2512
2646
|
/**
|
|
2513
2647
|
* When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
|
|
@@ -2534,7 +2668,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2534
2668
|
* @returns a generic summarization error
|
|
2535
2669
|
*/
|
|
2536
2670
|
async prefetchLatestSummaryThenClose(summaryLogger) {
|
|
2537
|
-
const readAndParseBlob = async (id) => (0,
|
|
2671
|
+
const readAndParseBlob = async (id) => (0, internal_4.readAndParse)(this.storage, id);
|
|
2538
2672
|
// This is a performance optimization as the same parent is likely to be elected again, and would use its
|
|
2539
2673
|
// cache to fetch the snapshot instead of the network.
|
|
2540
2674
|
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
@@ -2550,7 +2684,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2550
2684
|
}
|
|
2551
2685
|
async closeStaleSummarizer() {
|
|
2552
2686
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2553
|
-
await (0,
|
|
2687
|
+
await (0, internal_2.delay)(this.closeSummarizerDelayMs);
|
|
2554
2688
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
2555
2689
|
this.disposeFn();
|
|
2556
2690
|
}
|
|
@@ -2560,16 +2694,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2560
2694
|
* overridden via options.
|
|
2561
2695
|
*/
|
|
2562
2696
|
async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
|
|
2563
|
-
return
|
|
2697
|
+
return internal_7.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2564
2698
|
const stats = {};
|
|
2565
2699
|
const trace = client_utils_1.Trace.start();
|
|
2566
|
-
const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose",
|
|
2567
|
-
(0,
|
|
2700
|
+
const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose", internal_3.FetchSource.noCache);
|
|
2701
|
+
(0, internal_2.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
2568
2702
|
stats.getVersionDuration = trace.trace().duration;
|
|
2569
2703
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
2570
|
-
(0,
|
|
2704
|
+
(0, internal_2.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
2571
2705
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
2572
|
-
const latestSnapshotRefSeq = await (0,
|
|
2706
|
+
const latestSnapshotRefSeq = await (0, internal_6.seqFromTree)(maybeSnapshot, readAndParseBlob);
|
|
2573
2707
|
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
2574
2708
|
stats.snapshotVersion = versions[0].id;
|
|
2575
2709
|
perfEvent.end(stats);
|
|
@@ -2583,7 +2717,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2583
2717
|
getPendingLocalState(props) {
|
|
2584
2718
|
this.verifyNotClosed();
|
|
2585
2719
|
if (this._orderSequentiallyCalls !== 0) {
|
|
2586
|
-
throw new
|
|
2720
|
+
throw new internal_7.UsageError("can't get state during orderSequentially");
|
|
2587
2721
|
}
|
|
2588
2722
|
this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
|
|
2589
2723
|
const getSyncState = (pendingAttachmentBlobs) => {
|
|
@@ -2615,8 +2749,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2615
2749
|
// to close current batch.
|
|
2616
2750
|
this.flush();
|
|
2617
2751
|
return props?.notifyImminentClosure === true
|
|
2618
|
-
?
|
|
2619
|
-
:
|
|
2752
|
+
? internal_7.PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) => logAndReturnPendingState(event, getSyncState(await this.blobManager.attachAndGetPendingBlobs(props?.stopBlobAttachingSignal))))
|
|
2753
|
+
: internal_7.PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) => logAndReturnPendingState(event, getSyncState()));
|
|
2620
2754
|
}
|
|
2621
2755
|
summarizeOnDemand(options) {
|
|
2622
2756
|
if (this.isSummarizerClient) {
|
|
@@ -2629,7 +2763,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2629
2763
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2630
2764
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
2631
2765
|
// because it is a misuse of the API rather than an expected failure.
|
|
2632
|
-
throw new
|
|
2766
|
+
throw new internal_7.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2633
2767
|
}
|
|
2634
2768
|
}
|
|
2635
2769
|
enqueueSummarize(options) {
|
|
@@ -2643,7 +2777,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2643
2777
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2644
2778
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
2645
2779
|
// because it is a misuse of the API rather than an expected failure.
|
|
2646
|
-
throw new
|
|
2780
|
+
throw new internal_7.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2647
2781
|
}
|
|
2648
2782
|
}
|
|
2649
2783
|
/**
|
|
@@ -2658,16 +2792,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2658
2792
|
// eslint-disable-next-line no-restricted-syntax
|
|
2659
2793
|
for (const prop in configuration) {
|
|
2660
2794
|
if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
|
|
2661
|
-
throw new
|
|
2795
|
+
throw new internal_7.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
|
|
2662
2796
|
}
|
|
2663
2797
|
}
|
|
2664
2798
|
if (configuration.minIdleTime > configuration.maxIdleTime) {
|
|
2665
|
-
throw new
|
|
2799
|
+
throw new internal_7.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
|
|
2666
2800
|
}
|
|
2667
2801
|
}
|
|
2668
2802
|
get groupedBatchingEnabled() {
|
|
2669
|
-
|
|
2670
|
-
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
2803
|
+
return this.documentSchema.opGroupingEnabled === true;
|
|
2671
2804
|
}
|
|
2672
2805
|
}
|
|
2673
2806
|
exports.ContainerRuntime = ContainerRuntime;
|