@fluidframework/container-runtime 2.0.0-rc.1.0.3 → 2.0.0-rc.2.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/{.eslintrc.js → .eslintrc.cjs} +5 -5
- package/{.mocharc.js → .mocharc.cjs} +1 -1
- package/CHANGELOG.md +54 -0
- package/README.md +45 -0
- package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
- package/api-extractor-lint.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.api.md +68 -30
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +223 -0
- package/dist/channelCollection.d.ts.map +1 -0
- package/dist/{dataStores.js → channelCollection.js} +399 -83
- package/dist/channelCollection.js.map +1 -0
- package/dist/connectionTelemetry.d.ts +11 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +42 -4
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/container-runtime-alpha.d.ts +98 -40
- package/dist/container-runtime-beta.d.ts +27 -9
- package/dist/container-runtime-public.d.ts +27 -9
- package/dist/container-runtime-untrimmed.d.ts +123 -40
- package/dist/containerHandleContext.d.ts +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +79 -55
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +541 -411
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +2 -3
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +12 -11
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +71 -30
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +182 -141
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts +29 -4
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +91 -5
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +22 -5
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +134 -75
- 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 +21 -21
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +29 -6
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +5 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +2 -2
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +12 -5
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +18 -6
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +7 -7
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +20 -20
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.d.ts +6 -1
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +22 -11
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/gc/index.d.ts +8 -8
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +40 -38
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +8 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -40
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +4 -4
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +2 -2
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +2 -2
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +8 -8
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +18 -18
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +4 -4
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +3 -3
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +1 -10
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +5 -5
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +7 -7
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +20 -12
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -4
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +2 -2
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/package.json +3 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +2 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +18 -10
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts +1 -2
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +5 -5
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/index.d.ts +12 -12
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +43 -43
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.js +8 -8
- 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.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +11 -10
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +114 -81
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +4 -4
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +6 -6
- 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 +3 -3
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/index.d.ts +3 -3
- package/dist/summary/summarizerNode/index.d.ts.map +1 -1
- package/dist/summary/summarizerNode/index.js +4 -4
- package/dist/summary/summarizerNode/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +17 -7
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +45 -57
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +10 -19
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +1 -21
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +5 -6
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +16 -16
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +10 -21
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +15 -2
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +6 -5
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +10 -1
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +5 -6
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +4 -5
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/{batchTracker.d.mts → batchTracker.d.ts} +2 -3
- package/lib/batchTracker.d.ts.map +1 -0
- package/lib/{batchTracker.mjs → batchTracker.js} +1 -1
- package/lib/batchTracker.js.map +1 -0
- package/lib/{blobManager.d.mts → blobManager.d.ts} +1 -1
- package/lib/blobManager.d.ts.map +1 -0
- package/lib/{blobManager.mjs → blobManager.js} +1 -1
- package/lib/blobManager.js.map +1 -0
- package/lib/channelCollection.d.ts +223 -0
- package/lib/channelCollection.d.ts.map +1 -0
- package/lib/{dataStores.mjs → channelCollection.js} +384 -71
- package/lib/channelCollection.js.map +1 -0
- package/lib/{connectionTelemetry.d.mts → connectionTelemetry.d.ts} +12 -2
- package/lib/connectionTelemetry.d.ts.map +1 -0
- package/lib/{connectionTelemetry.mjs → connectionTelemetry.js} +43 -5
- package/lib/connectionTelemetry.js.map +1 -0
- package/lib/{container-runtime-alpha.d.mts → container-runtime-alpha.d.ts} +98 -40
- package/lib/{container-runtime-public.d.mts → container-runtime-beta.d.ts} +27 -9
- package/lib/{container-runtime-beta.d.mts → container-runtime-public.d.ts} +27 -9
- package/lib/{container-runtime-untrimmed.d.mts → container-runtime-untrimmed.d.ts} +123 -40
- package/lib/{containerHandleContext.d.mts → containerHandleContext.d.ts} +2 -2
- package/lib/containerHandleContext.d.ts.map +1 -0
- package/lib/{containerHandleContext.mjs → containerHandleContext.js} +1 -1
- package/lib/containerHandleContext.js.map +1 -0
- package/lib/{containerRuntime.d.mts → containerRuntime.d.ts} +84 -56
- package/lib/containerRuntime.d.ts.map +1 -0
- package/lib/{containerRuntime.mjs → containerRuntime.js} +460 -332
- package/lib/containerRuntime.js.map +1 -0
- package/lib/{dataStore.d.mts → dataStore.d.ts} +3 -4
- package/lib/dataStore.d.ts.map +1 -0
- package/lib/{dataStore.mjs → dataStore.js} +13 -12
- package/lib/dataStore.js.map +1 -0
- package/lib/{dataStoreContext.d.mts → dataStoreContext.d.ts} +72 -31
- package/lib/dataStoreContext.d.ts.map +1 -0
- package/lib/{dataStoreContext.mjs → dataStoreContext.js} +174 -133
- package/lib/dataStoreContext.js.map +1 -0
- package/lib/{dataStoreContexts.d.mts → dataStoreContexts.d.ts} +2 -2
- package/lib/dataStoreContexts.d.ts.map +1 -0
- package/lib/{dataStoreContexts.mjs → dataStoreContexts.js} +1 -1
- package/lib/dataStoreContexts.js.map +1 -0
- package/lib/{dataStoreRegistry.d.mts → dataStoreRegistry.d.ts} +1 -1
- package/lib/dataStoreRegistry.d.ts.map +1 -0
- package/lib/{dataStoreRegistry.mjs → dataStoreRegistry.js} +5 -1
- package/lib/dataStoreRegistry.js.map +1 -0
- package/{dist/deltaManagerProxyBase.d.ts → lib/deltaManagerSummarizerProxy.d.ts} +16 -7
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/lib/deltaManagerSummarizerProxy.js +124 -0
- package/lib/deltaManagerSummarizerProxy.js.map +1 -0
- package/lib/{deltaScheduler.d.mts → deltaScheduler.d.ts} +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -0
- package/lib/{deltaScheduler.mjs → deltaScheduler.js} +1 -1
- package/lib/deltaScheduler.js.map +1 -0
- package/lib/{error.d.mts → error.d.ts} +1 -1
- package/lib/error.d.ts.map +1 -0
- package/lib/{error.mjs → error.js} +1 -1
- package/lib/error.js.map +1 -0
- package/lib/gc/{garbageCollection.d.mts → garbageCollection.d.ts} +23 -6
- package/lib/gc/garbageCollection.d.ts.map +1 -0
- package/lib/gc/{garbageCollection.mjs → garbageCollection.js} +103 -44
- package/lib/gc/garbageCollection.js.map +1 -0
- package/lib/gc/{gcConfigs.d.mts → gcConfigs.d.ts} +3 -3
- package/lib/gc/gcConfigs.d.ts.map +1 -0
- package/lib/gc/{gcConfigs.mjs → gcConfigs.js} +3 -3
- package/lib/gc/gcConfigs.js.map +1 -0
- package/lib/gc/{gcDefinitions.d.mts → gcDefinitions.d.ts} +30 -7
- package/lib/gc/gcDefinitions.d.ts.map +1 -0
- package/lib/gc/{gcDefinitions.mjs → gcDefinitions.js} +5 -1
- package/lib/gc/gcDefinitions.js.map +1 -0
- package/lib/gc/{gcHelpers.d.mts → gcHelpers.d.ts} +3 -3
- package/lib/gc/{gcHelpers.d.mts.map → gcHelpers.d.ts.map} +1 -1
- package/lib/gc/{gcHelpers.mjs → gcHelpers.js} +1 -1
- package/lib/gc/gcHelpers.js.map +1 -0
- package/lib/gc/{gcReferenceGraphAlgorithm.d.mts → gcReferenceGraphAlgorithm.d.ts} +2 -2
- package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/lib/gc/{gcReferenceGraphAlgorithm.mjs → gcReferenceGraphAlgorithm.js} +1 -1
- package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/lib/gc/{gcSummaryDefinitions.d.mts → gcSummaryDefinitions.d.ts} +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/lib/gc/{gcSummaryDefinitions.mjs → gcSummaryDefinitions.js} +1 -1
- package/lib/gc/gcSummaryDefinitions.js.map +1 -0
- package/lib/gc/{gcSummaryStateTracker.d.mts → gcSummaryStateTracker.d.ts} +13 -6
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/lib/gc/{gcSummaryStateTracker.mjs → gcSummaryStateTracker.js} +17 -5
- package/lib/gc/gcSummaryStateTracker.js.map +1 -0
- package/lib/gc/{gcTelemetry.d.mts → gcTelemetry.d.ts} +8 -8
- package/lib/gc/gcTelemetry.d.ts.map +1 -0
- package/lib/gc/{gcTelemetry.mjs → gcTelemetry.js} +5 -5
- package/lib/gc/gcTelemetry.js.map +1 -0
- package/lib/gc/{gcUnreferencedStateTracker.d.mts → gcUnreferencedStateTracker.d.ts} +7 -2
- package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/lib/gc/{gcUnreferencedStateTracker.mjs → gcUnreferencedStateTracker.js} +12 -2
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
- package/lib/gc/{index.d.mts → index.d.ts} +9 -9
- package/lib/gc/index.d.ts.map +1 -0
- package/lib/gc/{index.mjs → index.js} +8 -8
- package/lib/gc/index.js.map +1 -0
- package/lib/{index.d.mts → index.d.ts} +9 -21
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/lib/{messageTypes.d.mts → messageTypes.d.ts} +5 -5
- package/lib/messageTypes.d.ts.map +1 -0
- package/lib/{messageTypes.mjs → messageTypes.js} +1 -1
- package/lib/messageTypes.js.map +1 -0
- package/lib/{metadata.d.mts → metadata.d.ts} +1 -1
- package/lib/metadata.d.ts.map +1 -0
- package/lib/{metadata.mjs → metadata.js} +1 -1
- package/lib/metadata.js.map +1 -0
- package/lib/opLifecycle/{batchManager.d.mts → batchManager.d.ts} +3 -3
- package/lib/opLifecycle/batchManager.d.ts.map +1 -0
- package/lib/opLifecycle/{batchManager.mjs → batchManager.js} +1 -1
- package/lib/opLifecycle/batchManager.js.map +1 -0
- package/lib/opLifecycle/{definitions.d.mts → definitions.d.ts} +3 -3
- package/lib/opLifecycle/definitions.d.ts.map +1 -0
- package/lib/opLifecycle/{definitions.mjs → definitions.js} +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -0
- package/lib/opLifecycle/index.d.ts +13 -0
- package/lib/opLifecycle/index.d.ts.map +1 -0
- package/lib/opLifecycle/index.js +12 -0
- package/lib/opLifecycle/index.js.map +1 -0
- package/lib/opLifecycle/{opCompressor.d.mts → opCompressor.d.ts} +2 -2
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -0
- package/lib/opLifecycle/{opCompressor.mjs → opCompressor.js} +3 -3
- package/lib/opLifecycle/opCompressor.js.map +1 -0
- package/lib/opLifecycle/{opDecompressor.d.mts → opDecompressor.d.ts} +2 -2
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -0
- package/lib/opLifecycle/{opDecompressor.mjs → opDecompressor.js} +2 -2
- package/lib/opLifecycle/opDecompressor.js.map +1 -0
- package/lib/opLifecycle/{opGroupingManager.d.mts → opGroupingManager.d.ts} +2 -2
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/lib/opLifecycle/{opGroupingManager.mjs → opGroupingManager.js} +2 -11
- package/lib/opLifecycle/opGroupingManager.js.map +1 -0
- package/lib/opLifecycle/{opSplitter.d.mts → opSplitter.d.ts} +2 -2
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -0
- package/lib/opLifecycle/{opSplitter.mjs → opSplitter.js} +3 -3
- package/lib/opLifecycle/opSplitter.js.map +1 -0
- package/lib/opLifecycle/{outbox.d.mts → outbox.d.ts} +8 -8
- package/lib/opLifecycle/outbox.d.ts.map +1 -0
- package/lib/opLifecycle/{outbox.mjs → outbox.js} +12 -4
- package/lib/opLifecycle/outbox.js.map +1 -0
- package/lib/opLifecycle/{remoteMessageProcessor.d.mts → remoteMessageProcessor.d.ts} +5 -5
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
- package/lib/opLifecycle/{remoteMessageProcessor.mjs → remoteMessageProcessor.js} +2 -2
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -0
- package/lib/{opProperties.d.mts → opProperties.d.ts} +1 -1
- package/lib/opProperties.d.ts.map +1 -0
- package/lib/{opProperties.mjs → opProperties.js} +1 -1
- package/lib/opProperties.js.map +1 -0
- package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
- package/lib/packageVersion.js.map +1 -0
- package/lib/{pendingStateManager.d.mts → pendingStateManager.d.ts} +3 -2
- package/lib/pendingStateManager.d.ts.map +1 -0
- package/lib/{pendingStateManager.mjs → pendingStateManager.js} +18 -10
- package/lib/pendingStateManager.js.map +1 -0
- package/lib/{scheduleManager.d.mts → scheduleManager.d.ts} +6 -3
- package/lib/scheduleManager.d.ts.map +1 -0
- package/lib/{scheduleManager.mjs → scheduleManager.js} +3 -3
- package/lib/scheduleManager.js.map +1 -0
- package/lib/{storageServiceWithAttachBlobs.d.mts → storageServiceWithAttachBlobs.d.ts} +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/lib/{storageServiceWithAttachBlobs.mjs → storageServiceWithAttachBlobs.js} +1 -1
- package/lib/storageServiceWithAttachBlobs.js.map +1 -0
- package/lib/summary/{index.d.mts → index.d.ts} +13 -13
- package/lib/summary/index.d.ts.map +1 -0
- package/lib/summary/{index.mjs → index.js} +12 -12
- package/lib/summary/index.js.map +1 -0
- package/lib/summary/{orderedClientElection.d.mts → orderedClientElection.d.ts} +5 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -0
- package/lib/summary/{orderedClientElection.mjs → orderedClientElection.js} +2 -2
- package/lib/summary/orderedClientElection.js.map +1 -0
- package/lib/summary/{runWhileConnectedCoordinator.d.mts → runWhileConnectedCoordinator.d.ts} +2 -2
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/lib/summary/{runWhileConnectedCoordinator.mjs → runWhileConnectedCoordinator.js} +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/lib/summary/{runningSummarizer.d.mts → runningSummarizer.d.ts} +12 -11
- package/lib/summary/runningSummarizer.d.ts.map +1 -0
- package/lib/summary/{runningSummarizer.mjs → runningSummarizer.js} +108 -75
- package/lib/summary/runningSummarizer.js.map +1 -0
- package/lib/summary/{summarizer.d.mts → summarizer.d.ts} +5 -5
- package/lib/summary/summarizer.d.ts.map +1 -0
- package/lib/summary/{summarizer.mjs → summarizer.js} +4 -4
- package/lib/summary/summarizer.js.map +1 -0
- package/lib/summary/{summarizerClientElection.d.mts → summarizerClientElection.d.ts} +3 -3
- package/lib/summary/summarizerClientElection.d.ts.map +1 -0
- package/lib/summary/{summarizerClientElection.mjs → summarizerClientElection.js} +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -0
- package/lib/summary/{summarizerHeuristics.d.mts → summarizerHeuristics.d.ts} +4 -4
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
- package/lib/summary/{summarizerHeuristics.mjs → summarizerHeuristics.js} +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -0
- package/lib/summary/summarizerNode/{index.d.mts → index.d.ts} +4 -4
- package/lib/summary/summarizerNode/index.d.ts.map +1 -0
- package/lib/summary/summarizerNode/index.js +7 -0
- package/lib/summary/summarizerNode/index.js.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNode.d.mts → summarizerNode.d.ts} +18 -8
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNode.mjs → summarizerNode.js} +41 -53
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNodeUtils.d.mts → summarizerNodeUtils.d.ts} +11 -20
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNodeUtils.mjs → summarizerNodeUtils.js} +1 -20
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNodeWithGc.d.mts → summarizerNodeWithGc.d.ts} +6 -7
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/lib/summary/summarizerNode/{summarizerNodeWithGc.mjs → summarizerNodeWithGc.js} +12 -12
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/lib/summary/{summarizerTypes.d.mts → summarizerTypes.d.ts} +11 -22
- package/lib/summary/summarizerTypes.d.ts.map +1 -0
- package/lib/summary/{summarizerTypes.mjs → summarizerTypes.js} +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -0
- package/lib/summary/{summaryCollection.d.mts → summaryCollection.d.ts} +1 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -0
- package/lib/summary/{summaryCollection.mjs → summaryCollection.js} +1 -1
- package/lib/summary/summaryCollection.js.map +1 -0
- package/lib/summary/{summaryFormat.d.mts → summaryFormat.d.ts} +16 -3
- package/lib/summary/summaryFormat.d.ts.map +1 -0
- package/lib/summary/{summaryFormat.mjs → summaryFormat.js} +1 -1
- package/lib/summary/summaryFormat.js.map +1 -0
- package/lib/summary/{summaryGenerator.d.mts → summaryGenerator.d.ts} +7 -6
- package/lib/summary/summaryGenerator.d.ts.map +1 -0
- package/lib/summary/{summaryGenerator.mjs → summaryGenerator.js} +11 -2
- package/lib/summary/summaryGenerator.js.map +1 -0
- package/lib/summary/{summaryManager.d.mts → summaryManager.d.ts} +6 -7
- package/lib/summary/summaryManager.d.ts.map +1 -0
- package/lib/summary/{summaryManager.mjs → summaryManager.js} +4 -5
- package/lib/summary/summaryManager.js.map +1 -0
- package/lib/test/batchTracker.spec.js +88 -0
- package/lib/test/batchTracker.spec.js.map +1 -0
- package/lib/test/blobManager.spec.js +835 -0
- package/lib/test/blobManager.spec.js.map +1 -0
- package/lib/test/channelCollection.spec.js +141 -0
- package/lib/test/channelCollection.spec.js.map +1 -0
- package/lib/test/containerRuntime.spec.js +1748 -0
- package/lib/test/containerRuntime.spec.js.map +1 -0
- package/lib/test/dataStoreContext.spec.js +801 -0
- package/lib/test/dataStoreContext.spec.js.map +1 -0
- package/lib/test/dataStoreCreation.spec.js +312 -0
- package/lib/test/dataStoreCreation.spec.js.map +1 -0
- package/lib/test/dataStoreRegistry.spec.js +26 -0
- package/lib/test/dataStoreRegistry.spec.js.map +1 -0
- package/lib/test/fuzz/fuzzUtils.js +66 -0
- package/lib/test/fuzz/fuzzUtils.js.map +1 -0
- package/lib/test/fuzz/summarizer.fuzz.spec.js +31 -0
- package/lib/test/fuzz/summarizer.fuzz.spec.js.map +1 -0
- package/lib/test/fuzz/summarizerFuzzMocks.js +162 -0
- package/lib/test/fuzz/summarizerFuzzMocks.js.map +1 -0
- package/lib/test/fuzz/summarizerFuzzSuite.js +106 -0
- package/lib/test/fuzz/summarizerFuzzSuite.js.map +1 -0
- package/lib/test/gc/garbageCollection.spec.js +1465 -0
- package/lib/test/gc/garbageCollection.spec.js.map +1 -0
- package/lib/test/gc/gcConfigs.spec.js +690 -0
- package/lib/test/gc/gcConfigs.spec.js.map +1 -0
- package/lib/test/gc/gcHelpers.spec.js +110 -0
- package/lib/test/gc/gcHelpers.spec.js.map +1 -0
- package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js +68 -0
- package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js.map +1 -0
- package/lib/test/gc/gcStats.spec.js +391 -0
- package/lib/test/gc/gcStats.spec.js.map +1 -0
- package/lib/test/gc/gcSummaryStateTracker.spec.js +228 -0
- package/lib/test/gc/gcSummaryStateTracker.spec.js.map +1 -0
- package/lib/test/gc/gcTelemetry.spec.js +530 -0
- package/lib/test/gc/gcTelemetry.spec.js.map +1 -0
- package/lib/test/gc/gcUnitTestHelpers.js +29 -0
- package/lib/test/gc/gcUnitTestHelpers.js.map +1 -0
- package/lib/test/gc/gcUnreferencedStateTracker.spec.js +192 -0
- package/lib/test/gc/gcUnreferencedStateTracker.spec.js.map +1 -0
- package/lib/test/getPendingBlobs.spec.js +193 -0
- package/lib/test/getPendingBlobs.spec.js.map +1 -0
- package/lib/test/hardwareStats.spec.js +93 -0
- package/lib/test/hardwareStats.spec.js.map +1 -0
- package/lib/test/index.js +6 -0
- package/lib/test/index.js.map +1 -0
- package/lib/test/opLifecycle/OpGroupingManager.spec.js +225 -0
- package/lib/test/opLifecycle/OpGroupingManager.spec.js.map +1 -0
- package/lib/test/opLifecycle/batchManager.spec.js +189 -0
- package/lib/test/opLifecycle/batchManager.spec.js.map +1 -0
- package/lib/test/opLifecycle/opCompressor.spec.js +74 -0
- package/lib/test/opLifecycle/opCompressor.spec.js.map +1 -0
- package/lib/test/opLifecycle/opDecompressor.spec.js +218 -0
- package/lib/test/opLifecycle/opDecompressor.spec.js.map +1 -0
- package/lib/test/opLifecycle/opSplitter.spec.js +272 -0
- package/lib/test/opLifecycle/opSplitter.spec.js.map +1 -0
- package/lib/test/opLifecycle/outbox.spec.js +675 -0
- package/lib/test/opLifecycle/outbox.spec.js.map +1 -0
- package/lib/test/opLifecycle/remoteMessageProcessor.spec.js +196 -0
- package/lib/test/opLifecycle/remoteMessageProcessor.spec.js.map +1 -0
- package/lib/test/pendingStateManager.spec.js +329 -0
- package/lib/test/pendingStateManager.spec.js.map +1 -0
- package/lib/test/scheduleManager.spec.js +270 -0
- package/lib/test/scheduleManager.spec.js.map +1 -0
- package/lib/test/summarizerNode.spec.js +326 -0
- package/lib/test/summarizerNode.spec.js.map +1 -0
- package/lib/test/summarizerNodeWithGc.spec.js +318 -0
- package/lib/test/summarizerNodeWithGc.spec.js.map +1 -0
- package/lib/test/summary/orderedClientElection.spec.js +535 -0
- package/lib/test/summary/orderedClientElection.spec.js.map +1 -0
- package/lib/test/summary/runningSummarizer.spec.js +1349 -0
- package/lib/test/summary/runningSummarizer.spec.js.map +1 -0
- package/lib/test/summary/summarizer.spec.js +29 -0
- package/lib/test/summary/summarizer.spec.js.map +1 -0
- package/lib/test/summary/summarizerClientElection.spec.js +436 -0
- package/lib/test/summary/summarizerClientElection.spec.js.map +1 -0
- package/lib/test/summary/summarizerHeuristics.spec.js +289 -0
- package/lib/test/summary/summarizerHeuristics.spec.js.map +1 -0
- package/lib/test/summary/summaryCollection.spec.js +200 -0
- package/lib/test/summary/summaryCollection.spec.js.map +1 -0
- package/lib/test/summary/summaryManager.spec.js +430 -0
- package/lib/test/summary/summaryManager.spec.js.map +1 -0
- package/lib/test/summary/testQuorumClients.js +34 -0
- package/lib/test/summary/testQuorumClients.js.map +1 -0
- package/lib/test/throttler.spec.js +175 -0
- package/lib/test/throttler.spec.js.map +1 -0
- package/lib/test/types/validateContainerRuntimePrevious.generated.js +180 -0
- package/lib/test/types/validateContainerRuntimePrevious.generated.js.map +1 -0
- package/lib/{throttler.d.mts → throttler.d.ts} +1 -1
- package/lib/throttler.d.ts.map +1 -0
- package/lib/{throttler.mjs → throttler.js} +1 -1
- package/lib/throttler.js.map +1 -0
- package/package.json +99 -88
- package/src/batchTracker.ts +1 -1
- package/src/blobManager.ts +1 -1
- package/src/{dataStores.ts → channelCollection.ts} +520 -84
- package/src/connectionTelemetry.ts +42 -3
- package/src/containerHandleContext.ts +1 -1
- package/src/containerRuntime.ts +661 -464
- package/src/dataStore.ts +13 -15
- package/src/dataStoreContext.ts +257 -184
- package/src/dataStoreContexts.ts +1 -1
- package/src/deltaManagerSummarizerProxy.ts +132 -7
- package/src/gc/garbageCollection.ts +121 -46
- package/src/gc/gcConfigs.ts +3 -3
- package/src/gc/gcDefinitions.ts +30 -7
- package/src/gc/gcHelpers.ts +2 -2
- package/src/gc/gcReferenceGraphAlgorithm.ts +1 -1
- package/src/gc/gcSummaryStateTracker.ts +19 -7
- package/src/gc/gcTelemetry.ts +10 -9
- package/src/gc/gcUnreferencedStateTracker.ts +12 -1
- package/src/gc/index.ts +10 -8
- package/src/index.ts +16 -27
- package/src/messageTypes.ts +4 -4
- package/src/opLifecycle/README.md +2 -4
- package/src/opLifecycle/batchManager.ts +2 -2
- package/src/opLifecycle/definitions.ts +2 -2
- package/src/opLifecycle/index.ts +8 -8
- package/src/opLifecycle/opCompressor.ts +3 -3
- package/src/opLifecycle/opDecompressor.ts +3 -3
- package/src/opLifecycle/opGroupingManager.ts +3 -12
- package/src/opLifecycle/opSplitter.ts +3 -3
- package/src/opLifecycle/outbox.ts +29 -9
- package/src/opLifecycle/remoteMessageProcessor.ts +4 -4
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +19 -13
- package/src/scheduleManager.ts +4 -4
- package/src/summary/index.ts +13 -12
- package/src/summary/orderedClientElection.ts +1 -1
- package/src/summary/runWhileConnectedCoordinator.ts +1 -1
- package/src/summary/runningSummarizer.ts +141 -93
- package/src/summary/summarizer.ts +7 -7
- package/src/summary/summarizerClientElection.ts +2 -2
- package/src/summary/summarizerHeuristics.ts +3 -3
- package/src/summary/summarizerNode/index.ts +6 -3
- package/src/summary/summarizerNode/summarizerNode.ts +54 -69
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +16 -34
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +11 -17
- package/src/summary/summarizerTypes.ts +12 -24
- package/src/summary/summaryFormat.ts +16 -2
- package/src/summary/summaryGenerator.ts +16 -4
- package/src/summary/summaryManager.ts +6 -7
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +2 -5
- package/dist/dataStores.d.ts +0 -149
- package/dist/dataStores.d.ts.map +0 -1
- package/dist/dataStores.js.map +0 -1
- package/dist/deltaManagerProxyBase.d.ts.map +0 -1
- package/dist/deltaManagerProxyBase.js +0 -77
- package/dist/deltaManagerProxyBase.js.map +0 -1
- package/lib/batchTracker.d.mts.map +0 -1
- package/lib/batchTracker.mjs.map +0 -1
- package/lib/blobManager.d.mts.map +0 -1
- package/lib/blobManager.mjs.map +0 -1
- package/lib/connectionTelemetry.d.mts.map +0 -1
- package/lib/connectionTelemetry.mjs.map +0 -1
- package/lib/containerHandleContext.d.mts.map +0 -1
- package/lib/containerHandleContext.mjs.map +0 -1
- package/lib/containerRuntime.d.mts.map +0 -1
- package/lib/containerRuntime.mjs.map +0 -1
- package/lib/dataStore.d.mts.map +0 -1
- package/lib/dataStore.mjs.map +0 -1
- package/lib/dataStoreContext.d.mts.map +0 -1
- package/lib/dataStoreContext.mjs.map +0 -1
- package/lib/dataStoreContexts.d.mts.map +0 -1
- package/lib/dataStoreContexts.mjs.map +0 -1
- package/lib/dataStoreRegistry.d.mts.map +0 -1
- package/lib/dataStoreRegistry.mjs.map +0 -1
- package/lib/dataStores.d.mts +0 -149
- package/lib/dataStores.d.mts.map +0 -1
- package/lib/dataStores.mjs.map +0 -1
- package/lib/deltaManagerProxyBase.d.mts +0 -35
- package/lib/deltaManagerProxyBase.d.mts.map +0 -1
- package/lib/deltaManagerProxyBase.mjs +0 -73
- package/lib/deltaManagerProxyBase.mjs.map +0 -1
- package/lib/deltaManagerSummarizerProxy.d.mts +0 -19
- package/lib/deltaManagerSummarizerProxy.d.mts.map +0 -1
- package/lib/deltaManagerSummarizerProxy.mjs +0 -38
- package/lib/deltaManagerSummarizerProxy.mjs.map +0 -1
- package/lib/deltaScheduler.d.mts.map +0 -1
- package/lib/deltaScheduler.mjs.map +0 -1
- package/lib/error.d.mts.map +0 -1
- package/lib/error.mjs.map +0 -1
- package/lib/gc/garbageCollection.d.mts.map +0 -1
- package/lib/gc/garbageCollection.mjs.map +0 -1
- package/lib/gc/gcConfigs.d.mts.map +0 -1
- package/lib/gc/gcConfigs.mjs.map +0 -1
- package/lib/gc/gcDefinitions.d.mts.map +0 -1
- package/lib/gc/gcDefinitions.mjs.map +0 -1
- package/lib/gc/gcHelpers.mjs.map +0 -1
- package/lib/gc/gcReferenceGraphAlgorithm.d.mts.map +0 -1
- package/lib/gc/gcReferenceGraphAlgorithm.mjs.map +0 -1
- package/lib/gc/gcSummaryDefinitions.d.mts.map +0 -1
- package/lib/gc/gcSummaryDefinitions.mjs.map +0 -1
- package/lib/gc/gcSummaryStateTracker.d.mts.map +0 -1
- package/lib/gc/gcSummaryStateTracker.mjs.map +0 -1
- package/lib/gc/gcTelemetry.d.mts.map +0 -1
- package/lib/gc/gcTelemetry.mjs.map +0 -1
- package/lib/gc/gcUnreferencedStateTracker.d.mts.map +0 -1
- package/lib/gc/gcUnreferencedStateTracker.mjs.map +0 -1
- package/lib/gc/index.d.mts.map +0 -1
- package/lib/gc/index.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -24
- package/lib/index.mjs.map +0 -1
- package/lib/messageTypes.d.mts.map +0 -1
- package/lib/messageTypes.mjs.map +0 -1
- package/lib/metadata.d.mts.map +0 -1
- package/lib/metadata.mjs.map +0 -1
- package/lib/opLifecycle/batchManager.d.mts.map +0 -1
- package/lib/opLifecycle/batchManager.mjs.map +0 -1
- package/lib/opLifecycle/definitions.d.mts.map +0 -1
- package/lib/opLifecycle/definitions.mjs.map +0 -1
- package/lib/opLifecycle/index.d.mts +0 -13
- package/lib/opLifecycle/index.d.mts.map +0 -1
- package/lib/opLifecycle/index.mjs +0 -12
- package/lib/opLifecycle/index.mjs.map +0 -1
- package/lib/opLifecycle/opCompressor.d.mts.map +0 -1
- package/lib/opLifecycle/opCompressor.mjs.map +0 -1
- package/lib/opLifecycle/opDecompressor.d.mts.map +0 -1
- package/lib/opLifecycle/opDecompressor.mjs.map +0 -1
- package/lib/opLifecycle/opGroupingManager.d.mts.map +0 -1
- package/lib/opLifecycle/opGroupingManager.mjs.map +0 -1
- package/lib/opLifecycle/opSplitter.d.mts.map +0 -1
- package/lib/opLifecycle/opSplitter.mjs.map +0 -1
- package/lib/opLifecycle/outbox.d.mts.map +0 -1
- package/lib/opLifecycle/outbox.mjs.map +0 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +0 -1
- package/lib/opLifecycle/remoteMessageProcessor.mjs.map +0 -1
- package/lib/opProperties.d.mts.map +0 -1
- package/lib/opProperties.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/pendingStateManager.d.mts.map +0 -1
- package/lib/pendingStateManager.mjs.map +0 -1
- package/lib/scheduleManager.d.mts.map +0 -1
- package/lib/scheduleManager.mjs.map +0 -1
- package/lib/storageServiceWithAttachBlobs.d.mts.map +0 -1
- package/lib/storageServiceWithAttachBlobs.mjs.map +0 -1
- package/lib/summary/index.d.mts.map +0 -1
- package/lib/summary/index.mjs.map +0 -1
- package/lib/summary/orderedClientElection.d.mts.map +0 -1
- package/lib/summary/orderedClientElection.mjs.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.d.mts.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.mjs.map +0 -1
- package/lib/summary/runningSummarizer.d.mts.map +0 -1
- package/lib/summary/runningSummarizer.mjs.map +0 -1
- package/lib/summary/summarizer.d.mts.map +0 -1
- package/lib/summary/summarizer.mjs.map +0 -1
- package/lib/summary/summarizerClientElection.d.mts.map +0 -1
- package/lib/summary/summarizerClientElection.mjs.map +0 -1
- package/lib/summary/summarizerHeuristics.d.mts.map +0 -1
- package/lib/summary/summarizerHeuristics.mjs.map +0 -1
- package/lib/summary/summarizerNode/index.d.mts.map +0 -1
- package/lib/summary/summarizerNode/index.mjs +0 -7
- package/lib/summary/summarizerNode/index.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNode.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNode.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +0 -1
- package/lib/summary/summarizerTypes.d.mts.map +0 -1
- package/lib/summary/summarizerTypes.mjs.map +0 -1
- package/lib/summary/summaryCollection.d.mts.map +0 -1
- package/lib/summary/summaryCollection.mjs.map +0 -1
- package/lib/summary/summaryFormat.d.mts.map +0 -1
- package/lib/summary/summaryFormat.mjs.map +0 -1
- package/lib/summary/summaryGenerator.d.mts.map +0 -1
- package/lib/summary/summaryGenerator.mjs.map +0 -1
- package/lib/summary/summaryManager.d.mts.map +0 -1
- package/lib/summary/summaryManager.mjs.map +0 -1
- package/lib/throttler.d.mts.map +0 -1
- package/lib/throttler.mjs.map +0 -1
- package/src/deltaManagerProxyBase.ts +0 -111
package/src/containerRuntime.ts
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
6
|
ITelemetryBaseLogger,
|
|
7
|
-
ITelemetryGenericEvent,
|
|
8
7
|
FluidObject,
|
|
9
8
|
IFluidHandle,
|
|
10
9
|
IFluidHandleContext,
|
|
11
10
|
IRequest,
|
|
12
11
|
IResponse,
|
|
13
12
|
IProvideFluidHandleContext,
|
|
13
|
+
ISignalEnvelope,
|
|
14
14
|
} from "@fluidframework/core-interfaces";
|
|
15
15
|
import {
|
|
16
16
|
IAudience,
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
IRuntime,
|
|
21
21
|
ICriticalContainerError,
|
|
22
22
|
AttachState,
|
|
23
|
-
ILoaderOptions,
|
|
24
23
|
ILoader,
|
|
25
24
|
LoaderHeader,
|
|
26
25
|
IGetPendingLocalStateProps,
|
|
@@ -29,7 +28,7 @@ import {
|
|
|
29
28
|
IContainerRuntime,
|
|
30
29
|
IContainerRuntimeEvents,
|
|
31
30
|
} from "@fluidframework/container-runtime-definitions";
|
|
32
|
-
import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
|
|
31
|
+
import { assert, Deferred, delay, LazyPromise, PromiseCache } from "@fluidframework/core-utils";
|
|
33
32
|
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
34
33
|
import {
|
|
35
34
|
createChildLogger,
|
|
@@ -39,19 +38,22 @@ import {
|
|
|
39
38
|
GenericError,
|
|
40
39
|
raiseConnectedEvent,
|
|
41
40
|
PerformanceEvent,
|
|
42
|
-
// eslint-disable-next-line import/no-deprecated
|
|
43
41
|
TaggedLoggerAdapter,
|
|
44
42
|
MonitoringContext,
|
|
45
43
|
wrapError,
|
|
46
44
|
ITelemetryLoggerExt,
|
|
47
45
|
UsageError,
|
|
48
46
|
LoggingError,
|
|
47
|
+
createSampledLogger,
|
|
48
|
+
IEventSampler,
|
|
49
|
+
type ITelemetryGenericEventExt,
|
|
50
|
+
loggerToMonitoringContext,
|
|
49
51
|
} from "@fluidframework/telemetry-utils";
|
|
50
52
|
import {
|
|
51
53
|
DriverHeader,
|
|
52
54
|
FetchSource,
|
|
53
55
|
IDocumentStorageService,
|
|
54
|
-
|
|
56
|
+
type ISnapshot,
|
|
55
57
|
} from "@fluidframework/driver-definitions";
|
|
56
58
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
57
59
|
import {
|
|
@@ -73,11 +75,8 @@ import {
|
|
|
73
75
|
InboundAttachMessage,
|
|
74
76
|
IFluidDataStoreContextDetached,
|
|
75
77
|
IFluidDataStoreRegistry,
|
|
76
|
-
IFluidDataStoreChannel,
|
|
77
78
|
IGarbageCollectionData,
|
|
78
|
-
IEnvelope,
|
|
79
79
|
IInboundSignalMessage,
|
|
80
|
-
ISignalEnvelope,
|
|
81
80
|
NamedFluidDataStoreRegistryEntries,
|
|
82
81
|
ISummaryTreeWithStats,
|
|
83
82
|
ISummarizeInternalResult,
|
|
@@ -86,18 +85,18 @@ import {
|
|
|
86
85
|
channelsTreeName,
|
|
87
86
|
IDataStore,
|
|
88
87
|
ITelemetryContext,
|
|
88
|
+
IEnvelope,
|
|
89
89
|
} from "@fluidframework/runtime-definitions";
|
|
90
90
|
import type {
|
|
91
91
|
SerializedIdCompressorWithNoSession,
|
|
92
92
|
IIdCompressor,
|
|
93
93
|
IIdCompressorCore,
|
|
94
|
-
IdCreationRange,
|
|
95
94
|
SerializedIdCompressorWithOngoingSession,
|
|
95
|
+
IdCreationRange,
|
|
96
96
|
} from "@fluidframework/id-compressor";
|
|
97
97
|
import {
|
|
98
98
|
addBlobToSummary,
|
|
99
99
|
addSummarizeResultToSummary,
|
|
100
|
-
addTreeToSummary,
|
|
101
100
|
RequestParser,
|
|
102
101
|
create404Response,
|
|
103
102
|
exceptionToResponse,
|
|
@@ -109,17 +108,17 @@ import {
|
|
|
109
108
|
responseToException,
|
|
110
109
|
} from "@fluidframework/runtime-utils";
|
|
111
110
|
import { v4 as uuid } from "uuid";
|
|
112
|
-
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
113
|
-
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
114
|
-
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
|
|
111
|
+
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
112
|
+
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
113
|
+
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry.js";
|
|
115
114
|
import {
|
|
116
115
|
IPendingBatchMessage,
|
|
117
116
|
IPendingLocalState,
|
|
118
117
|
PendingStateManager,
|
|
119
|
-
} from "./pendingStateManager";
|
|
120
|
-
import { pkgVersion } from "./packageVersion";
|
|
121
|
-
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager";
|
|
122
|
-
import {
|
|
118
|
+
} from "./pendingStateManager.js";
|
|
119
|
+
import { pkgVersion } from "./packageVersion.js";
|
|
120
|
+
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager.js";
|
|
121
|
+
import { ChannelCollection, getSummaryForDatastores, wrapContext } from "./channelCollection.js";
|
|
123
122
|
import {
|
|
124
123
|
aliasBlobName,
|
|
125
124
|
blobsTreeName,
|
|
@@ -159,8 +158,10 @@ import {
|
|
|
159
158
|
ISummarizerEvents,
|
|
160
159
|
IBaseSummarizeResult,
|
|
161
160
|
ISummarizer,
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
rootHasIsolatedChannels,
|
|
162
|
+
IdCompressorMode,
|
|
163
|
+
} from "./summary/index.js";
|
|
164
|
+
import { formExponentialFn, Throttler } from "./throttler.js";
|
|
164
165
|
import {
|
|
165
166
|
GarbageCollector,
|
|
166
167
|
GCNodeType,
|
|
@@ -168,11 +169,10 @@ import {
|
|
|
168
169
|
IGarbageCollector,
|
|
169
170
|
IGCRuntimeOptions,
|
|
170
171
|
IGCStats,
|
|
171
|
-
|
|
172
|
-
} from "./
|
|
173
|
-
import {
|
|
174
|
-
import {
|
|
175
|
-
import { ScheduleManager } from "./scheduleManager";
|
|
172
|
+
} from "./gc/index.js";
|
|
173
|
+
import { channelToDataStore } from "./dataStore.js";
|
|
174
|
+
import { BindBatchTracker } from "./batchTracker.js";
|
|
175
|
+
import { ScheduleManager } from "./scheduleManager.js";
|
|
176
176
|
import {
|
|
177
177
|
BatchMessage,
|
|
178
178
|
IBatch,
|
|
@@ -184,9 +184,9 @@ import {
|
|
|
184
184
|
RemoteMessageProcessor,
|
|
185
185
|
OpGroupingManager,
|
|
186
186
|
getLongStack,
|
|
187
|
-
} from "./opLifecycle";
|
|
188
|
-
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
189
|
-
import { IBatchMetadata, IIdAllocationMetadata } from "./metadata";
|
|
187
|
+
} from "./opLifecycle/index.js";
|
|
188
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
|
|
189
|
+
import { IBatchMetadata, IIdAllocationMetadata } from "./metadata.js";
|
|
190
190
|
import {
|
|
191
191
|
ContainerMessageType,
|
|
192
192
|
type InboundSequencedContainerRuntimeMessage,
|
|
@@ -196,7 +196,7 @@ import {
|
|
|
196
196
|
type OutboundContainerRuntimeMessage,
|
|
197
197
|
type UnknownContainerRuntimeMessage,
|
|
198
198
|
ContainerRuntimeGCMessage,
|
|
199
|
-
} from "./messageTypes";
|
|
199
|
+
} from "./messageTypes.js";
|
|
200
200
|
|
|
201
201
|
/**
|
|
202
202
|
* Utility to implement compat behaviors given an unknown message type
|
|
@@ -441,7 +441,7 @@ export interface IContainerRuntimeOptions {
|
|
|
441
441
|
* Enable the IdCompressor in the runtime.
|
|
442
442
|
* @experimental Not ready for use.
|
|
443
443
|
*/
|
|
444
|
-
readonly enableRuntimeIdCompressor?:
|
|
444
|
+
readonly enableRuntimeIdCompressor?: IdCompressorMode;
|
|
445
445
|
|
|
446
446
|
/**
|
|
447
447
|
* If enabled, the runtime will block all attempts to send an op inside the
|
|
@@ -466,27 +466,6 @@ export interface IContainerRuntimeOptions {
|
|
|
466
466
|
readonly enableGroupedBatching?: boolean;
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
-
/**
|
|
470
|
-
* Accepted header keys for requests coming to the runtime.
|
|
471
|
-
* @internal
|
|
472
|
-
*/
|
|
473
|
-
export enum RuntimeHeaders {
|
|
474
|
-
/** True to wait for a data store to be created and loaded before returning it. */
|
|
475
|
-
wait = "wait",
|
|
476
|
-
/** True if the request is coming from an IFluidHandle. */
|
|
477
|
-
viaHandle = "viaHandle",
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/** True if a tombstoned object should be returned without erroring
|
|
481
|
-
* @alpha
|
|
482
|
-
*/
|
|
483
|
-
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
484
|
-
/**
|
|
485
|
-
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
486
|
-
* @internal
|
|
487
|
-
*/
|
|
488
|
-
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
489
|
-
|
|
490
469
|
/**
|
|
491
470
|
* Tombstone error responses will have this header set to true
|
|
492
471
|
* @alpha
|
|
@@ -553,6 +532,11 @@ export interface IPendingRuntimeState {
|
|
|
553
532
|
* Pending idCompressor state
|
|
554
533
|
*/
|
|
555
534
|
pendingIdCompressorState?: SerializedIdCompressorWithOngoingSession;
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Time at which session expiry timer started.
|
|
538
|
+
*/
|
|
539
|
+
sessionExpiryTimerStarted?: number | undefined;
|
|
556
540
|
}
|
|
557
541
|
|
|
558
542
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
@@ -767,7 +751,6 @@ export class ContainerRuntime
|
|
|
767
751
|
const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
|
|
768
752
|
const passLogger =
|
|
769
753
|
backCompatContext.taggedLogger ??
|
|
770
|
-
// eslint-disable-next-line import/no-deprecated
|
|
771
754
|
new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
|
|
772
755
|
const logger = createChildLogger({
|
|
773
756
|
logger: passLogger,
|
|
@@ -778,6 +761,8 @@ export class ContainerRuntime
|
|
|
778
761
|
},
|
|
779
762
|
});
|
|
780
763
|
|
|
764
|
+
const mc = loggerToMonitoringContext(logger);
|
|
765
|
+
|
|
781
766
|
const {
|
|
782
767
|
summaryOptions = {},
|
|
783
768
|
gcOptions = {},
|
|
@@ -785,7 +770,7 @@ export class ContainerRuntime
|
|
|
785
770
|
flushMode = defaultFlushMode,
|
|
786
771
|
compressionOptions = defaultCompressionConfig,
|
|
787
772
|
maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
|
|
788
|
-
enableRuntimeIdCompressor =
|
|
773
|
+
enableRuntimeIdCompressor = "off",
|
|
789
774
|
chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
790
775
|
enableOpReentryCheck = false,
|
|
791
776
|
enableGroupedBatching = false,
|
|
@@ -854,24 +839,72 @@ export class ContainerRuntime
|
|
|
854
839
|
}
|
|
855
840
|
}
|
|
856
841
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
let
|
|
860
|
-
if (
|
|
842
|
+
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
843
|
+
// allow new containers to turn it on
|
|
844
|
+
let idCompressorMode: IdCompressorMode;
|
|
845
|
+
if (existing) {
|
|
846
|
+
// This setting has to be sticky for correctness:
|
|
847
|
+
// 1) if compressior is OFF, it can't be enabled, as already running clients (in given document session) do not know
|
|
848
|
+
// how to process compressor ops
|
|
849
|
+
// 2) if it's ON, then all sessions should load compressor right away
|
|
850
|
+
// 3) Same logic applies for "delayed" mode
|
|
851
|
+
// Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
|
|
852
|
+
// We could do "off" -> "on" transtition too, if all clients start loading compressor (but not using it initially) and do so for a while -
|
|
853
|
+
// this will allow clients to eventually to disregard "off" setting (when it's safe so) and start using compressor in future sessions.
|
|
854
|
+
// Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
|
|
855
|
+
idCompressorMode = metadata?.idCompressorMode ?? "off";
|
|
856
|
+
} else {
|
|
857
|
+
// FG overwrite
|
|
858
|
+
const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
|
|
859
|
+
switch (enabled) {
|
|
860
|
+
case true:
|
|
861
|
+
idCompressorMode = "on";
|
|
862
|
+
break;
|
|
863
|
+
case false:
|
|
864
|
+
idCompressorMode = "off";
|
|
865
|
+
break;
|
|
866
|
+
default:
|
|
867
|
+
idCompressorMode = enableRuntimeIdCompressor;
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const createIdCompressorFn = async () => {
|
|
861
873
|
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import(
|
|
862
874
|
"@fluidframework/id-compressor"
|
|
863
875
|
);
|
|
864
876
|
|
|
877
|
+
/**
|
|
878
|
+
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
879
|
+
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
880
|
+
*/
|
|
881
|
+
const idCompressorEventSampler: IEventSampler = (() => {
|
|
882
|
+
const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
|
|
883
|
+
return {
|
|
884
|
+
sample: () => {
|
|
885
|
+
return isIdCompressorTelemetryEnabled;
|
|
886
|
+
},
|
|
887
|
+
};
|
|
888
|
+
})();
|
|
889
|
+
|
|
890
|
+
const compressorLogger = createSampledLogger(logger, idCompressorEventSampler);
|
|
865
891
|
const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
|
|
866
892
|
|
|
867
893
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
868
|
-
|
|
894
|
+
return deserializeIdCompressor(
|
|
895
|
+
pendingLocalState.pendingIdCompressorState,
|
|
896
|
+
compressorLogger,
|
|
897
|
+
);
|
|
869
898
|
} else if (serializedIdCompressor !== undefined) {
|
|
870
|
-
|
|
899
|
+
return deserializeIdCompressor(
|
|
900
|
+
serializedIdCompressor,
|
|
901
|
+
createSessionId(),
|
|
902
|
+
compressorLogger,
|
|
903
|
+
);
|
|
871
904
|
} else {
|
|
872
|
-
|
|
905
|
+
return createIdCompressor(compressorLogger);
|
|
873
906
|
}
|
|
874
|
-
}
|
|
907
|
+
};
|
|
875
908
|
|
|
876
909
|
const runtime = new containerRuntimeCtor(
|
|
877
910
|
context,
|
|
@@ -897,7 +930,8 @@ export class ContainerRuntime
|
|
|
897
930
|
existing,
|
|
898
931
|
blobManagerSnapshot,
|
|
899
932
|
context.storage,
|
|
900
|
-
|
|
933
|
+
createIdCompressorFn,
|
|
934
|
+
idCompressorMode,
|
|
901
935
|
provideEntryPoint,
|
|
902
936
|
requestHandler,
|
|
903
937
|
undefined, // summaryConfiguration
|
|
@@ -913,7 +947,7 @@ export class ContainerRuntime
|
|
|
913
947
|
return runtime;
|
|
914
948
|
}
|
|
915
949
|
|
|
916
|
-
public readonly options:
|
|
950
|
+
public readonly options: Record<string | number, any>;
|
|
917
951
|
private imminentClosure: boolean = false;
|
|
918
952
|
|
|
919
953
|
private readonly _getClientId: () => string | undefined;
|
|
@@ -927,6 +961,10 @@ export class ContainerRuntime
|
|
|
927
961
|
return this._storage;
|
|
928
962
|
}
|
|
929
963
|
|
|
964
|
+
public get containerRuntime() {
|
|
965
|
+
return this;
|
|
966
|
+
}
|
|
967
|
+
|
|
930
968
|
private readonly submitFn: (
|
|
931
969
|
type: MessageType,
|
|
932
970
|
contents: any,
|
|
@@ -964,7 +1002,47 @@ export class ContainerRuntime
|
|
|
964
1002
|
return this._getAttachState();
|
|
965
1003
|
}
|
|
966
1004
|
|
|
967
|
-
|
|
1005
|
+
private _idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
|
|
1006
|
+
|
|
1007
|
+
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
1008
|
+
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
1009
|
+
private pendingIdCompressorOps: IdCreationRange[] = [];
|
|
1010
|
+
|
|
1011
|
+
// Id Compressor serializes final state (see getPendingLocalState()). As result, it needs to skip all ops that preceeded that state
|
|
1012
|
+
// (such ops will be marked by Loader layer as savedOp === true)
|
|
1013
|
+
// That said, in "delayed" mode it's possible that Id Compressor was never initialized before getPendingLocalState() is called.
|
|
1014
|
+
// In such case we have to process all ops, including those marked with saveOp === true.
|
|
1015
|
+
private readonly skipSavedCompressorOps: boolean;
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* See IContainerRuntimeBase.idCompressor() for details.
|
|
1019
|
+
*/
|
|
1020
|
+
public get idCompressor() {
|
|
1021
|
+
// Expose ID Compressor only if it's On from the start.
|
|
1022
|
+
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
1023
|
+
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
1024
|
+
// to reason over such things as session ID space.
|
|
1025
|
+
if (this.idCompressorMode === "on") {
|
|
1026
|
+
assert(
|
|
1027
|
+
this._idCompressor !== undefined,
|
|
1028
|
+
0x8ea /* compressor should have been loaded */,
|
|
1029
|
+
);
|
|
1030
|
+
return this._idCompressor;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
1036
|
+
* this.idCompressorMode === "delayed" mode
|
|
1037
|
+
*/
|
|
1038
|
+
protected compressorLoadInitiated = false;
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* See IContainerRuntimeBase.generateDocumentUniqueId() for details.
|
|
1042
|
+
*/
|
|
1043
|
+
public generateDocumentUniqueId() {
|
|
1044
|
+
return this._idCompressor?.generateDocumentUniqueId() ?? uuid();
|
|
1045
|
+
}
|
|
968
1046
|
|
|
969
1047
|
public get IFluidHandleContext(): IFluidHandleContext {
|
|
970
1048
|
return this.handleContext;
|
|
@@ -1088,7 +1166,7 @@ export class ContainerRuntime
|
|
|
1088
1166
|
private readonly outbox: Outbox;
|
|
1089
1167
|
private readonly garbageCollector: IGarbageCollector;
|
|
1090
1168
|
|
|
1091
|
-
private readonly
|
|
1169
|
+
private readonly channelCollection: ChannelCollection;
|
|
1092
1170
|
private readonly remoteMessageProcessor: RemoteMessageProcessor;
|
|
1093
1171
|
|
|
1094
1172
|
/** The last message processed at the time of the last summary. */
|
|
@@ -1104,11 +1182,6 @@ export class ContainerRuntime
|
|
|
1104
1182
|
return this.summaryConfiguration.state === "disabled";
|
|
1105
1183
|
}
|
|
1106
1184
|
|
|
1107
|
-
private readonly heuristicsDisabled: boolean;
|
|
1108
|
-
private isHeuristicsDisabled(): boolean {
|
|
1109
|
-
return this.summaryConfiguration.state === "disableHeuristics";
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
1185
|
private readonly maxOpsSinceLastSummary: number;
|
|
1113
1186
|
private getMaxOpsSinceLastSummary(): number {
|
|
1114
1187
|
return this.summaryConfiguration.state !== "disabled"
|
|
@@ -1151,11 +1224,6 @@ export class ContainerRuntime
|
|
|
1151
1224
|
*/
|
|
1152
1225
|
private readonly telemetryDocumentId: string;
|
|
1153
1226
|
|
|
1154
|
-
/**
|
|
1155
|
-
* If true, the runtime has access to an IdCompressor
|
|
1156
|
-
*/
|
|
1157
|
-
private readonly idCompressorEnabled: boolean;
|
|
1158
|
-
|
|
1159
1227
|
/**
|
|
1160
1228
|
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1161
1229
|
*/
|
|
@@ -1166,11 +1234,19 @@ export class ContainerRuntime
|
|
|
1166
1234
|
*/
|
|
1167
1235
|
private readonly loadedFromVersionId: string | undefined;
|
|
1168
1236
|
|
|
1237
|
+
/**
|
|
1238
|
+
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
1239
|
+
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
1240
|
+
*/
|
|
1241
|
+
private readonly snapshotCacheForLoadingGroupIds = new PromiseCache<string, ISnapshot>({
|
|
1242
|
+
expiry: { policy: "absolute", durationMs: 60000 },
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1169
1245
|
/***/
|
|
1170
1246
|
protected constructor(
|
|
1171
1247
|
context: IContainerContext,
|
|
1172
1248
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1173
|
-
metadata: IContainerRuntimeMetadata | undefined,
|
|
1249
|
+
private readonly metadata: IContainerRuntimeMetadata | undefined,
|
|
1174
1250
|
electedSummarizerData: ISerializedElection | undefined,
|
|
1175
1251
|
chunks: [string, string[]][],
|
|
1176
1252
|
dataStoreAliasMap: [string, string][],
|
|
@@ -1180,7 +1256,8 @@ export class ContainerRuntime
|
|
|
1180
1256
|
existing: boolean,
|
|
1181
1257
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1182
1258
|
private readonly _storage: IDocumentStorageService,
|
|
1183
|
-
|
|
1259
|
+
private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
|
|
1260
|
+
private readonly idCompressorMode: IdCompressorMode,
|
|
1184
1261
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1185
1262
|
private readonly requestHandler?: (
|
|
1186
1263
|
request: IRequest,
|
|
@@ -1224,7 +1301,9 @@ export class ContainerRuntime
|
|
|
1224
1301
|
this.submitSummaryFn = submitSummaryFn;
|
|
1225
1302
|
this.submitSignalFn = submitSignalFn;
|
|
1226
1303
|
|
|
1227
|
-
|
|
1304
|
+
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
1305
|
+
// Values are generally expected to be set from the runtime side.
|
|
1306
|
+
this.options = options ?? {};
|
|
1228
1307
|
this.clientDetails = clientDetails;
|
|
1229
1308
|
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1230
1309
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
@@ -1265,20 +1344,12 @@ export class ContainerRuntime
|
|
|
1265
1344
|
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
1266
1345
|
// the count is reset to 0.
|
|
1267
1346
|
loadSummaryNumber = metadata?.summaryNumber ?? 0;
|
|
1268
|
-
|
|
1269
|
-
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
1270
|
-
// allow new containers to turn it on
|
|
1271
|
-
this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
|
|
1272
1347
|
} else {
|
|
1273
1348
|
this.createContainerMetadata = {
|
|
1274
1349
|
createContainerRuntimeVersion: pkgVersion,
|
|
1275
1350
|
createContainerTimestamp: Date.now(),
|
|
1276
1351
|
};
|
|
1277
1352
|
loadSummaryNumber = 0;
|
|
1278
|
-
|
|
1279
|
-
this.idCompressorEnabled =
|
|
1280
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
|
|
1281
|
-
idCompressor !== undefined;
|
|
1282
1353
|
}
|
|
1283
1354
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
1284
1355
|
|
|
@@ -1346,14 +1417,9 @@ export class ContainerRuntime
|
|
|
1346
1417
|
disableOpReentryCheck !== true;
|
|
1347
1418
|
|
|
1348
1419
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
1349
|
-
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
1350
1420
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
1351
1421
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
1352
1422
|
|
|
1353
|
-
if (this.idCompressorEnabled) {
|
|
1354
|
-
this.idCompressor = idCompressor;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
1423
|
this.maxConsecutiveReconnects =
|
|
1358
1424
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
1359
1425
|
this.defaultMaxConsecutiveReconnects;
|
|
@@ -1371,15 +1437,17 @@ export class ContainerRuntime
|
|
|
1371
1437
|
|
|
1372
1438
|
const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
|
|
1373
1439
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1440
|
+
if (context.attachState === AttachState.Attached) {
|
|
1441
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1442
|
+
if (
|
|
1443
|
+
maxSnapshotCacheDurationMs !== undefined &&
|
|
1444
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000
|
|
1445
|
+
) {
|
|
1446
|
+
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
1447
|
+
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
1448
|
+
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
1449
|
+
throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
1450
|
+
}
|
|
1383
1451
|
}
|
|
1384
1452
|
|
|
1385
1453
|
this.garbageCollector = GarbageCollector.create({
|
|
@@ -1395,6 +1463,7 @@ export class ContainerRuntime
|
|
|
1395
1463
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1396
1464
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1397
1465
|
submitMessage: (message: ContainerRuntimeGCMessage) => this.submit(message),
|
|
1466
|
+
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
1398
1467
|
});
|
|
1399
1468
|
|
|
1400
1469
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
@@ -1411,9 +1480,6 @@ export class ContainerRuntime
|
|
|
1411
1480
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1412
1481
|
// a summary with an older protocol state.
|
|
1413
1482
|
canReuseHandle: false,
|
|
1414
|
-
// Must set to true to throw on any data stores failure that was too severe to be handled.
|
|
1415
|
-
// We also are not decoding the base summaries at the root.
|
|
1416
|
-
throwOnFailure: true,
|
|
1417
1483
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
1418
1484
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
1419
1485
|
},
|
|
@@ -1427,28 +1493,44 @@ export class ContainerRuntime
|
|
|
1427
1493
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1428
1494
|
}
|
|
1429
1495
|
|
|
1430
|
-
|
|
1496
|
+
const parentContext = wrapContext(this);
|
|
1497
|
+
|
|
1498
|
+
// Due to a mismatch between different layers in terms of
|
|
1499
|
+
// what is the interface of passing signals, we need the
|
|
1500
|
+
// downstream stores to wrap the signal.
|
|
1501
|
+
parentContext.submitSignal = (type: string, content: any, targetClientId?: string) => {
|
|
1502
|
+
const envelope1 = content as IEnvelope;
|
|
1503
|
+
const envelope2 = this.createNewSignalEnvelope(
|
|
1504
|
+
envelope1.address,
|
|
1505
|
+
type,
|
|
1506
|
+
envelope1.contents,
|
|
1507
|
+
);
|
|
1508
|
+
return this.submitSignalFn(envelope2, targetClientId);
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
this.channelCollection = new ChannelCollection(
|
|
1431
1512
|
getSummaryForDatastores(baseSnapshot, metadata),
|
|
1432
|
-
|
|
1433
|
-
(attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }),
|
|
1434
|
-
(id: string, createParam: CreateChildSummarizerNodeParam) =>
|
|
1435
|
-
(
|
|
1436
|
-
summarizeInternal: SummarizeInternalFn,
|
|
1437
|
-
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1438
|
-
) =>
|
|
1439
|
-
this.summarizerNode.createChild(
|
|
1440
|
-
summarizeInternal,
|
|
1441
|
-
id,
|
|
1442
|
-
createParam,
|
|
1443
|
-
undefined,
|
|
1444
|
-
getGCDataFn,
|
|
1445
|
-
),
|
|
1446
|
-
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1513
|
+
parentContext,
|
|
1447
1514
|
this.mc.logger,
|
|
1448
|
-
(
|
|
1449
|
-
|
|
1515
|
+
(
|
|
1516
|
+
path: string,
|
|
1517
|
+
reason: "Loaded" | "Changed",
|
|
1518
|
+
timestampMs?: number,
|
|
1519
|
+
packagePath?: readonly string[],
|
|
1520
|
+
request?: IRequest,
|
|
1521
|
+
headerData?: RuntimeHeaderData,
|
|
1522
|
+
) =>
|
|
1523
|
+
this.garbageCollector.nodeUpdated(
|
|
1524
|
+
path,
|
|
1525
|
+
reason,
|
|
1526
|
+
timestampMs,
|
|
1527
|
+
packagePath,
|
|
1528
|
+
request,
|
|
1529
|
+
headerData,
|
|
1530
|
+
),
|
|
1450
1531
|
(path: string) => this.garbageCollector.isNodeDeleted(path),
|
|
1451
1532
|
new Map<string, string>(dataStoreAliasMap),
|
|
1533
|
+
async (runtime: ChannelCollection) => provideEntryPoint,
|
|
1452
1534
|
);
|
|
1453
1535
|
|
|
1454
1536
|
this.blobManager = new BlobManager(
|
|
@@ -1490,6 +1572,7 @@ export class ContainerRuntime
|
|
|
1490
1572
|
reSubmit: this.reSubmit.bind(this),
|
|
1491
1573
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1492
1574
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
1575
|
+
isAttached: () => this.attachState !== AttachState.Detached,
|
|
1493
1576
|
},
|
|
1494
1577
|
pendingRuntimeState?.pending,
|
|
1495
1578
|
this.logger,
|
|
@@ -1636,7 +1719,6 @@ export class ContainerRuntime
|
|
|
1636
1719
|
{
|
|
1637
1720
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
1638
1721
|
},
|
|
1639
|
-
this.heuristicsDisabled,
|
|
1640
1722
|
);
|
|
1641
1723
|
this.summaryManager.on("summarize", (eventProps) => {
|
|
1642
1724
|
this.emit("summarize", eventProps);
|
|
@@ -1654,26 +1736,27 @@ export class ContainerRuntime
|
|
|
1654
1736
|
this.mc.logger.sendTelemetryEvent({
|
|
1655
1737
|
eventName: "ContainerLoadStats",
|
|
1656
1738
|
...this.createContainerMetadata,
|
|
1657
|
-
...this.
|
|
1739
|
+
...this.channelCollection.containerLoadStats,
|
|
1658
1740
|
summaryNumber: loadSummaryNumber,
|
|
1659
1741
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1660
1742
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1661
1743
|
gcVersion: metadata?.gcFeature,
|
|
1662
1744
|
options: JSON.stringify(runtimeOptions),
|
|
1745
|
+
idCompressorModeMetadata: metadata?.idCompressorMode,
|
|
1746
|
+
idCompressorMode: this.idCompressorMode,
|
|
1663
1747
|
featureGates: JSON.stringify({
|
|
1664
1748
|
disableCompression,
|
|
1665
1749
|
disableOpReentryCheck,
|
|
1666
1750
|
disableChunking,
|
|
1667
1751
|
disableAttachReorder: this.disableAttachReorder,
|
|
1668
1752
|
disablePartialFlush,
|
|
1669
|
-
idCompressorEnabled: this.idCompressorEnabled,
|
|
1670
1753
|
closeSummarizerDelayOverride,
|
|
1671
1754
|
}),
|
|
1672
1755
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1673
1756
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1674
1757
|
});
|
|
1675
1758
|
|
|
1676
|
-
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
1759
|
+
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this, this.logger);
|
|
1677
1760
|
BindBatchTracker(this, this.logger);
|
|
1678
1761
|
|
|
1679
1762
|
this.entryPoint = new LazyPromise(async () => {
|
|
@@ -1686,12 +1769,47 @@ export class ContainerRuntime
|
|
|
1686
1769
|
}
|
|
1687
1770
|
return provideEntryPoint(this);
|
|
1688
1771
|
});
|
|
1772
|
+
|
|
1773
|
+
// If we loaded from pending state, then we need to skip any ops that are already accounted in such
|
|
1774
|
+
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
1775
|
+
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
public getCreateChildSummarizerNodeFn(id: string, createParam: CreateChildSummarizerNodeParam) {
|
|
1779
|
+
return (
|
|
1780
|
+
summarizeInternal: SummarizeInternalFn,
|
|
1781
|
+
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1782
|
+
) =>
|
|
1783
|
+
this.summarizerNode.createChild(
|
|
1784
|
+
summarizeInternal,
|
|
1785
|
+
id,
|
|
1786
|
+
createParam,
|
|
1787
|
+
undefined,
|
|
1788
|
+
getGCDataFn,
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
public deleteChildSummarizerNode(id: string) {
|
|
1793
|
+
return this.summarizerNode.deleteChild(id);
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
public makeLocallyVisible() {
|
|
1797
|
+
assert(false, 0x8eb /* should not be called */);
|
|
1689
1798
|
}
|
|
1690
1799
|
|
|
1691
1800
|
/**
|
|
1692
1801
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
1693
1802
|
*/
|
|
1694
1803
|
private async initializeBaseState(): Promise<void> {
|
|
1804
|
+
if (
|
|
1805
|
+
this.idCompressorMode === "on" ||
|
|
1806
|
+
(this.idCompressorMode === "delayed" && this.connected)
|
|
1807
|
+
) {
|
|
1808
|
+
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
1809
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
1810
|
+
this._idCompressor = await this.createIdCompressor();
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1695
1813
|
await this.garbageCollector.initializeBaseState();
|
|
1696
1814
|
}
|
|
1697
1815
|
|
|
@@ -1716,12 +1834,145 @@ export class ContainerRuntime
|
|
|
1716
1834
|
}
|
|
1717
1835
|
this.garbageCollector.dispose();
|
|
1718
1836
|
this._summarizer?.dispose();
|
|
1719
|
-
this.
|
|
1837
|
+
this.channelCollection.dispose();
|
|
1720
1838
|
this.pendingStateManager.dispose();
|
|
1721
1839
|
this.emit("dispose");
|
|
1722
1840
|
this.removeAllListeners();
|
|
1723
1841
|
}
|
|
1724
1842
|
|
|
1843
|
+
/**
|
|
1844
|
+
* Api to fetch the snapshot from the service for a loadingGroupIds.
|
|
1845
|
+
* @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for.
|
|
1846
|
+
* @param pathParts - Parts of the path, which we want to extract from the snapshot tree.
|
|
1847
|
+
* @returns - snapshotTree and the sequence number of the snapshot.
|
|
1848
|
+
*/
|
|
1849
|
+
public async getSnapshotForLoadingGroupId(
|
|
1850
|
+
loadingGroupIds: string[],
|
|
1851
|
+
pathParts: string[],
|
|
1852
|
+
): Promise<{ snapshotTree: ISnapshotTree; sequenceNumber: number }> {
|
|
1853
|
+
const sortedLoadingGroupIds = loadingGroupIds.sort();
|
|
1854
|
+
assert(
|
|
1855
|
+
this.storage.getSnapshot !== undefined,
|
|
1856
|
+
0x8ed /* getSnapshot api should be defined if used */,
|
|
1857
|
+
);
|
|
1858
|
+
let loadedFromCache = true;
|
|
1859
|
+
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
1860
|
+
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
1861
|
+
// any request, then cache that as same group could be requested in future too.
|
|
1862
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(
|
|
1863
|
+
sortedLoadingGroupIds.join(),
|
|
1864
|
+
async () => {
|
|
1865
|
+
assert(
|
|
1866
|
+
this.storage.getSnapshot !== undefined,
|
|
1867
|
+
0x8ee /* getSnapshot api should be defined if used */,
|
|
1868
|
+
);
|
|
1869
|
+
loadedFromCache = false;
|
|
1870
|
+
return this.storage.getSnapshot({
|
|
1871
|
+
cacheSnapshot: false,
|
|
1872
|
+
scenarioName: "snapshotForLoadingGroupId",
|
|
1873
|
+
loadingGroupIds: sortedLoadingGroupIds,
|
|
1874
|
+
});
|
|
1875
|
+
},
|
|
1876
|
+
);
|
|
1877
|
+
|
|
1878
|
+
this.logger.sendTelemetryEvent({
|
|
1879
|
+
eventName: "GroupIdSnapshotFetched",
|
|
1880
|
+
details: JSON.stringify({
|
|
1881
|
+
fromCache: loadedFromCache,
|
|
1882
|
+
loadingGroupIds: loadingGroupIds.join(","),
|
|
1883
|
+
}),
|
|
1884
|
+
});
|
|
1885
|
+
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
1886
|
+
const hasIsolatedChannels = rootHasIsolatedChannels(this.metadata);
|
|
1887
|
+
const snapshotTreeForPath = this.getSnapshotTreeForPath(
|
|
1888
|
+
snapshot.snapshotTree,
|
|
1889
|
+
pathParts,
|
|
1890
|
+
hasIsolatedChannels,
|
|
1891
|
+
);
|
|
1892
|
+
assert(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
1893
|
+
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
1894
|
+
assert(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
|
|
1895
|
+
|
|
1896
|
+
// This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
|
|
1897
|
+
// Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
|
|
1898
|
+
// the file has been overwritten or service lost data.
|
|
1899
|
+
if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
|
|
1900
|
+
throw DataProcessingError.create(
|
|
1901
|
+
"Downloaded snapshot older than snapshot we loaded from",
|
|
1902
|
+
"getSnapshotForLoadingGroupId",
|
|
1903
|
+
undefined,
|
|
1904
|
+
{
|
|
1905
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
1906
|
+
snapshotSeqNumber,
|
|
1907
|
+
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
1908
|
+
},
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
// If the snapshot is ahead of the last seq number of the delta manager, then catch up before
|
|
1913
|
+
// returning the snapshot.
|
|
1914
|
+
if (snapshotSeqNumber > this.deltaManager.lastSequenceNumber) {
|
|
1915
|
+
// If this is a summarizer client, which is trying to load a group and it finds that there is
|
|
1916
|
+
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
1917
|
+
// the summarizer state is not up to date.
|
|
1918
|
+
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
1919
|
+
if (this.isSummarizerClient) {
|
|
1920
|
+
throw new Error(
|
|
1921
|
+
"Summarizer client behind, loaded newer snapshot with loadingGroupId",
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
1926
|
+
const props: ITelemetryGenericEventExt = {
|
|
1927
|
+
eventName: "GroupIdSnapshotCatchup",
|
|
1928
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
1929
|
+
targetSequenceNumber: snapshotSeqNumber, // This is so we reuse some columns in telemetry
|
|
1930
|
+
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
const event = PerformanceEvent.start(this.mc.logger, {
|
|
1934
|
+
...props,
|
|
1935
|
+
});
|
|
1936
|
+
// If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
|
|
1937
|
+
// as long as it's not a summarizer client.
|
|
1938
|
+
if (this.deltaManager.inbound.paused) {
|
|
1939
|
+
props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
|
|
1940
|
+
}
|
|
1941
|
+
const defP = new Deferred<boolean>();
|
|
1942
|
+
this.deltaManager.on("op", (message: ISequencedDocumentMessage) => {
|
|
1943
|
+
if (message.sequenceNumber >= snapshotSeqNumber) {
|
|
1944
|
+
defP.resolve(true);
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
await defP.promise;
|
|
1948
|
+
event.end(props);
|
|
1949
|
+
}
|
|
1950
|
+
return { snapshotTree: snapshotTreeForPath, sequenceNumber: snapshotSeqNumber };
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
/**
|
|
1954
|
+
* Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array.
|
|
1955
|
+
* @param snapshotTree - snapshot tree to look into.
|
|
1956
|
+
* @param pathParts - Part of the path, which we want to extract from the snapshot tree.
|
|
1957
|
+
* @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older
|
|
1958
|
+
* snapshots will not have trees inside ".channels", so check that.
|
|
1959
|
+
* @returns - requested snapshot tree based on the path parts.
|
|
1960
|
+
*/
|
|
1961
|
+
private getSnapshotTreeForPath(
|
|
1962
|
+
snapshotTree: ISnapshotTree,
|
|
1963
|
+
pathParts: string[],
|
|
1964
|
+
hasIsolatedChannels: boolean,
|
|
1965
|
+
): ISnapshotTree | undefined {
|
|
1966
|
+
let childTree = snapshotTree;
|
|
1967
|
+
for (const part of pathParts) {
|
|
1968
|
+
if (hasIsolatedChannels) {
|
|
1969
|
+
childTree = childTree?.trees[channelsTreeName];
|
|
1970
|
+
}
|
|
1971
|
+
childTree = childTree?.trees[part];
|
|
1972
|
+
}
|
|
1973
|
+
return childTree;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1725
1976
|
/**
|
|
1726
1977
|
* Notifies this object about the request made to the container.
|
|
1727
1978
|
* @param request - Request made to the handler.
|
|
@@ -1778,19 +2029,7 @@ export class ContainerRuntime
|
|
|
1778
2029
|
}
|
|
1779
2030
|
: create404Response(request);
|
|
1780
2031
|
} else if (requestParser.pathParts.length > 0) {
|
|
1781
|
-
|
|
1782
|
-
const requestForChild = !requestParser.isLeaf(1);
|
|
1783
|
-
const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
|
|
1784
|
-
|
|
1785
|
-
const subRequest = requestParser.createSubRequest(1);
|
|
1786
|
-
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
1787
|
-
// unintentionally modifying the url if that changes.
|
|
1788
|
-
assert(
|
|
1789
|
-
subRequest.url.startsWith("/"),
|
|
1790
|
-
0x126 /* "Expected createSubRequest url to include a leading slash" */,
|
|
1791
|
-
);
|
|
1792
|
-
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1793
|
-
return dataStore.request(subRequest);
|
|
2032
|
+
return await this.channelCollection.request(request);
|
|
1794
2033
|
}
|
|
1795
2034
|
|
|
1796
2035
|
return create404Response(request);
|
|
@@ -1808,54 +2047,7 @@ export class ContainerRuntime
|
|
|
1808
2047
|
private readonly entryPoint: LazyPromise<FluidObject>;
|
|
1809
2048
|
|
|
1810
2049
|
private internalId(maybeAlias: string): string {
|
|
1811
|
-
return this.
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
private async getDataStoreFromRequest(
|
|
1815
|
-
id: string,
|
|
1816
|
-
request: IRequest,
|
|
1817
|
-
requestForChild: boolean,
|
|
1818
|
-
): Promise<IFluidDataStoreChannel> {
|
|
1819
|
-
const headerData: RuntimeHeaderData = {};
|
|
1820
|
-
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
1821
|
-
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
1822
|
-
}
|
|
1823
|
-
if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
|
|
1824
|
-
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
1825
|
-
}
|
|
1826
|
-
if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
|
|
1827
|
-
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
1828
|
-
}
|
|
1829
|
-
if (typeof request.headers?.[AllowInactiveRequestHeaderKey] === "boolean") {
|
|
1830
|
-
headerData.allowInactive = request.headers[AllowInactiveRequestHeaderKey];
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
// We allow Tombstone requests for sub-DataStore objects
|
|
1834
|
-
if (requestForChild) {
|
|
1835
|
-
headerData.allowTombstone = true;
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
await this.dataStores.waitIfPendingAlias(id);
|
|
1839
|
-
const internalId = this.internalId(id);
|
|
1840
|
-
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
1841
|
-
|
|
1842
|
-
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
1843
|
-
// the same as GC nodes id.
|
|
1844
|
-
const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
|
|
1845
|
-
// Get the initial snapshot details which contain the data store package path.
|
|
1846
|
-
const details = await dataStoreContext.getInitialSnapshotDetails();
|
|
1847
|
-
|
|
1848
|
-
// Note that this will throw if the data store is inactive or tombstoned and throwing on incorrect usage
|
|
1849
|
-
// is configured.
|
|
1850
|
-
this.garbageCollector.nodeUpdated(
|
|
1851
|
-
`/${urlWithoutQuery}`,
|
|
1852
|
-
"Loaded",
|
|
1853
|
-
undefined /* timestampMs */,
|
|
1854
|
-
details.pkg,
|
|
1855
|
-
request,
|
|
1856
|
-
headerData,
|
|
1857
|
-
);
|
|
1858
|
-
return dataStoreContext.realize();
|
|
2050
|
+
return this.channelCollection.internalId(maybeAlias);
|
|
1859
2051
|
}
|
|
1860
2052
|
|
|
1861
2053
|
/** Adds the container's metadata to the given summary tree. */
|
|
@@ -1872,7 +2064,7 @@ export class ContainerRuntime
|
|
|
1872
2064
|
extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
|
|
1873
2065
|
this.messageAtLastSummary,
|
|
1874
2066
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1875
|
-
|
|
2067
|
+
idCompressorMode: this.idCompressorMode,
|
|
1876
2068
|
};
|
|
1877
2069
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
1878
2070
|
}
|
|
@@ -1885,12 +2077,8 @@ export class ContainerRuntime
|
|
|
1885
2077
|
) {
|
|
1886
2078
|
this.addMetadataToSummary(summaryTree);
|
|
1887
2079
|
|
|
1888
|
-
if (this.
|
|
1889
|
-
|
|
1890
|
-
this.idCompressor !== undefined,
|
|
1891
|
-
0x67a /* IdCompressor should be defined if enabled */,
|
|
1892
|
-
);
|
|
1893
|
-
const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
|
|
2080
|
+
if (this._idCompressor) {
|
|
2081
|
+
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
1894
2082
|
addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
|
|
1895
2083
|
}
|
|
1896
2084
|
|
|
@@ -1899,7 +2087,7 @@ export class ContainerRuntime
|
|
|
1899
2087
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
1900
2088
|
}
|
|
1901
2089
|
|
|
1902
|
-
const dataStoreAliases = this.
|
|
2090
|
+
const dataStoreAliases = this.channelCollection.aliases;
|
|
1903
2091
|
if (dataStoreAliases.size > 0) {
|
|
1904
2092
|
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
1905
2093
|
}
|
|
@@ -1915,7 +2103,7 @@ export class ContainerRuntime
|
|
|
1915
2103
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
1916
2104
|
// and the blob manager can handle the tree not existing when loading
|
|
1917
2105
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
1918
|
-
|
|
2106
|
+
addSummarizeResultToSummary(summaryTree, blobsTreeName, blobManagerSummary);
|
|
1919
2107
|
}
|
|
1920
2108
|
|
|
1921
2109
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
@@ -2015,16 +2203,12 @@ export class ContainerRuntime
|
|
|
2015
2203
|
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
2016
2204
|
switch (opContents.type) {
|
|
2017
2205
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2018
|
-
return this.dataStores.applyStashedOp(opContents.contents);
|
|
2019
2206
|
case ContainerMessageType.Attach:
|
|
2020
|
-
|
|
2207
|
+
case ContainerMessageType.Alias:
|
|
2208
|
+
return this.channelCollection.applyStashedOp(opContents);
|
|
2021
2209
|
case ContainerMessageType.IdAllocation:
|
|
2022
|
-
assert(
|
|
2023
|
-
this.idCompressor !== undefined,
|
|
2024
|
-
0x67b /* IdCompressor should be defined if enabled */,
|
|
2025
|
-
);
|
|
2210
|
+
assert(this.idCompressorMode !== "off", 0x8f1 /* ID compressor should be in use */);
|
|
2026
2211
|
return;
|
|
2027
|
-
case ContainerMessageType.Alias:
|
|
2028
2212
|
case ContainerMessageType.BlobAttach:
|
|
2029
2213
|
return;
|
|
2030
2214
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -2054,11 +2238,27 @@ export class ContainerRuntime
|
|
|
2054
2238
|
this.closeFn(error);
|
|
2055
2239
|
throw error;
|
|
2056
2240
|
}
|
|
2241
|
+
// Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
|
|
2242
|
+
// All we can do is ignore it (similar to on process).
|
|
2057
2243
|
}
|
|
2058
2244
|
}
|
|
2059
2245
|
}
|
|
2060
2246
|
|
|
2061
2247
|
public setConnectionState(connected: boolean, clientId?: string) {
|
|
2248
|
+
if (connected && this.idCompressorMode === "delayed" && !this.compressorLoadInitiated) {
|
|
2249
|
+
this.compressorLoadInitiated = true;
|
|
2250
|
+
this.createIdCompressor()
|
|
2251
|
+
.then((compressor) => {
|
|
2252
|
+
this._idCompressor = compressor;
|
|
2253
|
+
for (const range of this.pendingIdCompressorOps) {
|
|
2254
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
2255
|
+
}
|
|
2256
|
+
this.pendingIdCompressorOps = [];
|
|
2257
|
+
})
|
|
2258
|
+
.catch((error) => {
|
|
2259
|
+
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2062
2262
|
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
2063
2263
|
this.delayConnectClientId = undefined;
|
|
2064
2264
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -2151,7 +2351,7 @@ export class ContainerRuntime
|
|
|
2151
2351
|
this.replayPendingStates();
|
|
2152
2352
|
}
|
|
2153
2353
|
|
|
2154
|
-
this.
|
|
2354
|
+
this.channelCollection.setConnectionState(connected, clientId);
|
|
2155
2355
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
2156
2356
|
|
|
2157
2357
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
@@ -2254,17 +2454,9 @@ export class ContainerRuntime
|
|
|
2254
2454
|
const { local } = messageWithContext;
|
|
2255
2455
|
switch (messageWithContext.message.type) {
|
|
2256
2456
|
case ContainerMessageType.Attach:
|
|
2257
|
-
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
2258
|
-
break;
|
|
2259
2457
|
case ContainerMessageType.Alias:
|
|
2260
|
-
this.dataStores.processAliasMessage(
|
|
2261
|
-
messageWithContext.message,
|
|
2262
|
-
localOpMetadata,
|
|
2263
|
-
local,
|
|
2264
|
-
);
|
|
2265
|
-
break;
|
|
2266
2458
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2267
|
-
this.
|
|
2459
|
+
this.channelCollection.process(
|
|
2268
2460
|
messageWithContext.message,
|
|
2269
2461
|
local,
|
|
2270
2462
|
localOpMetadata,
|
|
@@ -2275,17 +2467,23 @@ export class ContainerRuntime
|
|
|
2275
2467
|
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
2276
2468
|
break;
|
|
2277
2469
|
case ContainerMessageType.IdAllocation:
|
|
2278
|
-
assert(
|
|
2279
|
-
this.idCompressor !== undefined,
|
|
2280
|
-
0x67c /* IdCompressor should be defined if enabled */,
|
|
2281
|
-
);
|
|
2282
|
-
|
|
2283
2470
|
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
2284
2471
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
2472
|
+
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
2473
|
+
// thus we need to process all the ops.
|
|
2285
2474
|
if (
|
|
2286
|
-
(
|
|
2475
|
+
!(
|
|
2476
|
+
this.skipSavedCompressorOps &&
|
|
2477
|
+
(messageWithContext.message.metadata as IIdAllocationMetadata)?.savedOp ===
|
|
2478
|
+
true
|
|
2479
|
+
)
|
|
2287
2480
|
) {
|
|
2288
|
-
|
|
2481
|
+
const range = messageWithContext.message.contents;
|
|
2482
|
+
if (this._idCompressor === undefined) {
|
|
2483
|
+
this.pendingIdCompressorOps.push(range);
|
|
2484
|
+
} else {
|
|
2485
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
2486
|
+
}
|
|
2289
2487
|
}
|
|
2290
2488
|
break;
|
|
2291
2489
|
case ContainerMessageType.GC:
|
|
@@ -2391,7 +2589,16 @@ export class ContainerRuntime
|
|
|
2391
2589
|
return;
|
|
2392
2590
|
}
|
|
2393
2591
|
|
|
2394
|
-
|
|
2592
|
+
// Due to a mismatch between different layers in terms of
|
|
2593
|
+
// what is the interface of passing signals, we need to adjust
|
|
2594
|
+
// the signal envelope before sending it to the datastores to be processed
|
|
2595
|
+
const envelope2: IEnvelope = {
|
|
2596
|
+
address: envelope.address,
|
|
2597
|
+
contents: transformed.content,
|
|
2598
|
+
};
|
|
2599
|
+
transformed.content = envelope2;
|
|
2600
|
+
|
|
2601
|
+
this.channelCollection.processSignal(transformed, local);
|
|
2395
2602
|
}
|
|
2396
2603
|
|
|
2397
2604
|
/**
|
|
@@ -2478,9 +2685,17 @@ export class ContainerRuntime
|
|
|
2478
2685
|
public async getAliasedDataStoreEntryPoint(
|
|
2479
2686
|
alias: string,
|
|
2480
2687
|
): Promise<IFluidHandle<FluidObject> | undefined> {
|
|
2481
|
-
|
|
2688
|
+
// Back-comapatibility:
|
|
2689
|
+
// There are old files that were created without using data store aliasing feature, but
|
|
2690
|
+
// used createRoot*DataStore*() (already removed) API. Such data stores will have isRoot = true,
|
|
2691
|
+
// and internalID provided by user. The expectation is that such files behave as new files, where
|
|
2692
|
+
// same data store instances created using aliasing feature.
|
|
2693
|
+
// Please also see note on name collisions in DataStores.createDataStoreId()
|
|
2694
|
+
await this.channelCollection.waitIfPendingAlias(alias);
|
|
2482
2695
|
const internalId = this.internalId(alias);
|
|
2483
|
-
const context = await this.
|
|
2696
|
+
const context = await this.channelCollection.getDataStoreIfAvailable(internalId, {
|
|
2697
|
+
wait: false,
|
|
2698
|
+
});
|
|
2484
2699
|
// If the data store is not available or not an alias, return undefined.
|
|
2485
2700
|
if (context === undefined || !(await context.isRoot())) {
|
|
2486
2701
|
return undefined;
|
|
@@ -2501,29 +2716,26 @@ export class ContainerRuntime
|
|
|
2501
2716
|
return channel.entryPoint;
|
|
2502
2717
|
}
|
|
2503
2718
|
|
|
2504
|
-
public
|
|
2719
|
+
public createDetachedDataStore(
|
|
2505
2720
|
pkg: Readonly<string[]>,
|
|
2506
|
-
|
|
2721
|
+
loadingGroupId?: string,
|
|
2507
2722
|
): IFluidDataStoreContextDetached {
|
|
2508
|
-
|
|
2509
|
-
throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
2510
|
-
}
|
|
2511
|
-
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
2512
|
-
}
|
|
2513
|
-
|
|
2514
|
-
public createDetachedDataStore(pkg: Readonly<string[]>): IFluidDataStoreContextDetached {
|
|
2515
|
-
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
2723
|
+
return this.channelCollection.createDetachedDataStoreCore(pkg, loadingGroupId);
|
|
2516
2724
|
}
|
|
2517
2725
|
|
|
2518
|
-
public async createDataStore(
|
|
2519
|
-
|
|
2726
|
+
public async createDataStore(
|
|
2727
|
+
pkg: Readonly<string | string[]>,
|
|
2728
|
+
loadingGroupId?: string,
|
|
2729
|
+
): Promise<IDataStore> {
|
|
2730
|
+
const context = this.channelCollection._createFluidDataStoreContext(
|
|
2731
|
+
Array.isArray(pkg) ? pkg : [pkg],
|
|
2732
|
+
undefined, // props
|
|
2733
|
+
loadingGroupId,
|
|
2734
|
+
);
|
|
2520
2735
|
return channelToDataStore(
|
|
2521
|
-
await
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
id,
|
|
2525
|
-
this,
|
|
2526
|
-
this.dataStores,
|
|
2736
|
+
await context.realize(),
|
|
2737
|
+
context.id,
|
|
2738
|
+
this.channelCollection,
|
|
2527
2739
|
this.mc.logger,
|
|
2528
2740
|
);
|
|
2529
2741
|
}
|
|
@@ -2532,17 +2744,17 @@ export class ContainerRuntime
|
|
|
2532
2744
|
* @deprecated 0.16 Issue #1537, #3631
|
|
2533
2745
|
*/
|
|
2534
2746
|
public async _createDataStoreWithProps(
|
|
2535
|
-
pkg: string | string[]
|
|
2747
|
+
pkg: Readonly<string | string[]>,
|
|
2536
2748
|
props?: any,
|
|
2537
|
-
id = uuid(),
|
|
2538
2749
|
): Promise<IDataStore> {
|
|
2750
|
+
const context = this.channelCollection._createFluidDataStoreContext(
|
|
2751
|
+
Array.isArray(pkg) ? pkg : [pkg],
|
|
2752
|
+
props,
|
|
2753
|
+
);
|
|
2539
2754
|
return channelToDataStore(
|
|
2540
|
-
await
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
id,
|
|
2544
|
-
this,
|
|
2545
|
-
this.dataStores,
|
|
2755
|
+
await context.realize(),
|
|
2756
|
+
context.id,
|
|
2757
|
+
this.channelCollection,
|
|
2546
2758
|
this.mc.logger,
|
|
2547
2759
|
);
|
|
2548
2760
|
}
|
|
@@ -2643,22 +2855,6 @@ export class ContainerRuntime
|
|
|
2643
2855
|
return this.submitSignalFn(envelope, targetClientId);
|
|
2644
2856
|
}
|
|
2645
2857
|
|
|
2646
|
-
/**
|
|
2647
|
-
* Submits the signal to be sent to other clients.
|
|
2648
|
-
* @param type - Type of the signal.
|
|
2649
|
-
* @param content - Content of the signal.
|
|
2650
|
-
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
2651
|
-
*/
|
|
2652
|
-
public submitDataStoreSignal(
|
|
2653
|
-
address: string,
|
|
2654
|
-
type: string,
|
|
2655
|
-
content: any,
|
|
2656
|
-
targetClientId?: string,
|
|
2657
|
-
) {
|
|
2658
|
-
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
2659
|
-
return this.submitSignalFn(envelope, targetClientId);
|
|
2660
|
-
}
|
|
2661
|
-
|
|
2662
2858
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
2663
2859
|
if (attachState === AttachState.Attaching) {
|
|
2664
2860
|
assert(
|
|
@@ -2676,7 +2872,7 @@ export class ContainerRuntime
|
|
|
2676
2872
|
if (attachState === AttachState.Attached && !this.hasPendingMessages()) {
|
|
2677
2873
|
this.updateDocumentDirtyState(false);
|
|
2678
2874
|
}
|
|
2679
|
-
this.
|
|
2875
|
+
this.channelCollection.setAttachState(attachState);
|
|
2680
2876
|
}
|
|
2681
2877
|
|
|
2682
2878
|
/**
|
|
@@ -2696,12 +2892,12 @@ export class ContainerRuntime
|
|
|
2696
2892
|
}
|
|
2697
2893
|
|
|
2698
2894
|
// We can finalize any allocated IDs since we're the only client
|
|
2699
|
-
const idRange = this.
|
|
2895
|
+
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
2700
2896
|
if (idRange !== undefined) {
|
|
2701
|
-
this.
|
|
2897
|
+
this._idCompressor?.finalizeCreationRange(idRange);
|
|
2702
2898
|
}
|
|
2703
2899
|
|
|
2704
|
-
const summarizeResult = this.
|
|
2900
|
+
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
2705
2901
|
// Wrap data store summaries in .channels subtree.
|
|
2706
2902
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
2707
2903
|
|
|
@@ -2721,7 +2917,7 @@ export class ContainerRuntime
|
|
|
2721
2917
|
trackState: boolean,
|
|
2722
2918
|
telemetryContext?: ITelemetryContext,
|
|
2723
2919
|
): Promise<ISummarizeInternalResult> {
|
|
2724
|
-
const summarizeResult = await this.
|
|
2920
|
+
const summarizeResult = await this.channelCollection.summarize(
|
|
2725
2921
|
fullTree,
|
|
2726
2922
|
trackState,
|
|
2727
2923
|
telemetryContext,
|
|
@@ -2812,11 +3008,11 @@ export class ContainerRuntime
|
|
|
2812
3008
|
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
2813
3009
|
*/
|
|
2814
3010
|
public async updateStateBeforeGC() {
|
|
2815
|
-
return this.
|
|
3011
|
+
return this.channelCollection.updateStateBeforeGC();
|
|
2816
3012
|
}
|
|
2817
3013
|
|
|
2818
3014
|
private async getGCDataInternal(fullGC?: boolean): Promise<IGarbageCollectionData> {
|
|
2819
|
-
return this.
|
|
3015
|
+
return this.channelCollection.getGCData(fullGC);
|
|
2820
3016
|
}
|
|
2821
3017
|
|
|
2822
3018
|
/**
|
|
@@ -2846,7 +3042,7 @@ export class ContainerRuntime
|
|
|
2846
3042
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
2847
3043
|
|
|
2848
3044
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
2849
|
-
this.
|
|
3045
|
+
this.channelCollection.updateUsedRoutes(dataStoreRoutes);
|
|
2850
3046
|
}
|
|
2851
3047
|
|
|
2852
3048
|
/**
|
|
@@ -2857,7 +3053,7 @@ export class ContainerRuntime
|
|
|
2857
3053
|
const { blobManagerRoutes, dataStoreRoutes } =
|
|
2858
3054
|
this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
2859
3055
|
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
2860
|
-
this.
|
|
3056
|
+
this.channelCollection.updateUnusedRoutes(dataStoreRoutes);
|
|
2861
3057
|
}
|
|
2862
3058
|
|
|
2863
3059
|
/**
|
|
@@ -2876,7 +3072,7 @@ export class ContainerRuntime
|
|
|
2876
3072
|
const { dataStoreRoutes, blobManagerRoutes } =
|
|
2877
3073
|
this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
2878
3074
|
|
|
2879
|
-
const deletedRoutes = this.
|
|
3075
|
+
const deletedRoutes = this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes);
|
|
2880
3076
|
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
2881
3077
|
}
|
|
2882
3078
|
|
|
@@ -2892,7 +3088,7 @@ export class ContainerRuntime
|
|
|
2892
3088
|
const { blobManagerRoutes, dataStoreRoutes } =
|
|
2893
3089
|
this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
2894
3090
|
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
2895
|
-
this.
|
|
3091
|
+
this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
|
|
2896
3092
|
}
|
|
2897
3093
|
|
|
2898
3094
|
/**
|
|
@@ -2912,7 +3108,7 @@ export class ContainerRuntime
|
|
|
2912
3108
|
if (this.isBlobPath(nodePath)) {
|
|
2913
3109
|
return GCNodeType.Blob;
|
|
2914
3110
|
}
|
|
2915
|
-
return this.
|
|
3111
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
2916
3112
|
}
|
|
2917
3113
|
|
|
2918
3114
|
/**
|
|
@@ -2920,12 +3116,18 @@ export class ContainerRuntime
|
|
|
2920
3116
|
* data store or an attachment blob.
|
|
2921
3117
|
*/
|
|
2922
3118
|
public async getGCNodePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
3119
|
+
// GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
|
|
3120
|
+
// These have no package path so return a special value.
|
|
3121
|
+
if (nodePath === "/") {
|
|
3122
|
+
return ["_gcRoot"];
|
|
3123
|
+
}
|
|
3124
|
+
|
|
2923
3125
|
switch (this.getNodeType(nodePath)) {
|
|
2924
3126
|
case GCNodeType.Blob:
|
|
2925
3127
|
return [BlobManager.basePath];
|
|
2926
3128
|
case GCNodeType.DataStore:
|
|
2927
3129
|
case GCNodeType.SubDataStore:
|
|
2928
|
-
return this.
|
|
3130
|
+
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
2929
3131
|
default:
|
|
2930
3132
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
2931
3133
|
}
|
|
@@ -2985,7 +3187,10 @@ export class ContainerRuntime
|
|
|
2985
3187
|
* @param srcHandle - The handle of the node that added the reference.
|
|
2986
3188
|
* @param outboundHandle - The handle of the outbound node that is referenced.
|
|
2987
3189
|
*/
|
|
2988
|
-
public addedGCOutboundReference(
|
|
3190
|
+
public addedGCOutboundReference(
|
|
3191
|
+
srcHandle: { absolutePath: string },
|
|
3192
|
+
outboundHandle: { absolutePath: string },
|
|
3193
|
+
) {
|
|
2989
3194
|
this.garbageCollector.addedOutboundReference(
|
|
2990
3195
|
srcHandle.absolutePath,
|
|
2991
3196
|
outboundHandle.absolutePath,
|
|
@@ -3001,7 +3206,13 @@ export class ContainerRuntime
|
|
|
3001
3206
|
* @param options - options controlling how the summary is generated or submitted
|
|
3002
3207
|
*/
|
|
3003
3208
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
3004
|
-
const {
|
|
3209
|
+
const {
|
|
3210
|
+
fullTree = false,
|
|
3211
|
+
finalAttempt = false,
|
|
3212
|
+
refreshLatestAck,
|
|
3213
|
+
summaryLogger,
|
|
3214
|
+
latestSummaryRefSeqNum,
|
|
3215
|
+
} = options;
|
|
3005
3216
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
3006
3217
|
// use it for all events logged during this summary.
|
|
3007
3218
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -3015,7 +3226,6 @@ export class ContainerRuntime
|
|
|
3015
3226
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
3016
3227
|
|
|
3017
3228
|
// We close the summarizer and download a new snapshot and reload the container
|
|
3018
|
-
let latestSnapshotVersionId: string | undefined;
|
|
3019
3229
|
if (refreshLatestAck === true) {
|
|
3020
3230
|
return this.prefetchLatestSummaryThenClose(
|
|
3021
3231
|
createChildLogger({
|
|
@@ -3073,6 +3283,10 @@ export class ContainerRuntime
|
|
|
3073
3283
|
this.mc.config.getBoolean(
|
|
3074
3284
|
"Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
|
|
3075
3285
|
) !== true;
|
|
3286
|
+
const shouldValidatePreSummaryState =
|
|
3287
|
+
this.mc.config.getBoolean(
|
|
3288
|
+
"Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState",
|
|
3289
|
+
) === true;
|
|
3076
3290
|
|
|
3077
3291
|
let summaryRefSeqNum: number | undefined;
|
|
3078
3292
|
|
|
@@ -3087,7 +3301,33 @@ export class ContainerRuntime
|
|
|
3087
3301
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
3088
3302
|
const lastAck = this.summaryCollection.latestAck;
|
|
3089
3303
|
|
|
3090
|
-
this.summarizerNode.startSummary(
|
|
3304
|
+
const startSummaryResult = this.summarizerNode.startSummary(
|
|
3305
|
+
summaryRefSeqNum,
|
|
3306
|
+
summaryNumberLogger,
|
|
3307
|
+
latestSummaryRefSeqNum,
|
|
3308
|
+
);
|
|
3309
|
+
|
|
3310
|
+
if (
|
|
3311
|
+
startSummaryResult.invalidNodes > 0 ||
|
|
3312
|
+
startSummaryResult.mismatchNumbers.size > 0
|
|
3313
|
+
) {
|
|
3314
|
+
summaryLogger.sendErrorEvent({
|
|
3315
|
+
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
3316
|
+
details: {
|
|
3317
|
+
...startSummaryResult,
|
|
3318
|
+
mismatchNumbers: Array.from(startSummaryResult.mismatchNumbers),
|
|
3319
|
+
},
|
|
3320
|
+
});
|
|
3321
|
+
|
|
3322
|
+
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
3323
|
+
return {
|
|
3324
|
+
stage: "base",
|
|
3325
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3326
|
+
minimumSequenceNumber,
|
|
3327
|
+
error: `Summarizer node state inconsistent with summarizer state.`,
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3091
3331
|
|
|
3092
3332
|
// Helper function to check whether we should still continue between each async step.
|
|
3093
3333
|
const checkContinue = (): { continue: true } | { continue: false; error: string } => {
|
|
@@ -3209,8 +3449,8 @@ export class ContainerRuntime
|
|
|
3209
3449
|
: undefined;
|
|
3210
3450
|
|
|
3211
3451
|
const summaryStats: IGeneratedSummaryStats = {
|
|
3212
|
-
dataStoreCount: this.
|
|
3213
|
-
summarizedDataStoreCount: this.
|
|
3452
|
+
dataStoreCount: this.channelCollection.size,
|
|
3453
|
+
summarizedDataStoreCount: this.channelCollection.size - handleCount,
|
|
3214
3454
|
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
3215
3455
|
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
3216
3456
|
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
@@ -3231,34 +3471,18 @@ export class ContainerRuntime
|
|
|
3231
3471
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
3232
3472
|
}
|
|
3233
3473
|
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
ackHandle: latestSnapshotVersionId,
|
|
3247
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3248
|
-
};
|
|
3249
|
-
} else if (lastAck === undefined) {
|
|
3250
|
-
summaryContext = {
|
|
3251
|
-
proposalHandle: undefined,
|
|
3252
|
-
ackHandle: this.loadedFromVersionId,
|
|
3253
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3254
|
-
};
|
|
3255
|
-
} else {
|
|
3256
|
-
summaryContext = {
|
|
3257
|
-
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3258
|
-
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3259
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3260
|
-
};
|
|
3261
|
-
}
|
|
3474
|
+
const summaryContext =
|
|
3475
|
+
lastAck === undefined
|
|
3476
|
+
? {
|
|
3477
|
+
proposalHandle: undefined,
|
|
3478
|
+
ackHandle: this.loadedFromVersionId,
|
|
3479
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3480
|
+
}
|
|
3481
|
+
: {
|
|
3482
|
+
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3483
|
+
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3484
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3485
|
+
};
|
|
3262
3486
|
|
|
3263
3487
|
let handle: string;
|
|
3264
3488
|
try {
|
|
@@ -3423,28 +3647,15 @@ export class ContainerRuntime
|
|
|
3423
3647
|
}
|
|
3424
3648
|
}
|
|
3425
3649
|
|
|
3426
|
-
public
|
|
3427
|
-
|
|
3650
|
+
public submitMessage(
|
|
3651
|
+
type:
|
|
3652
|
+
| ContainerMessageType.FluidDataStoreOp
|
|
3653
|
+
| ContainerMessageType.Alias
|
|
3654
|
+
| ContainerMessageType.Attach,
|
|
3428
3655
|
contents: any,
|
|
3429
3656
|
localOpMetadata: unknown = undefined,
|
|
3430
3657
|
): void {
|
|
3431
|
-
|
|
3432
|
-
address: id,
|
|
3433
|
-
contents,
|
|
3434
|
-
};
|
|
3435
|
-
this.submit(
|
|
3436
|
-
{ type: ContainerMessageType.FluidDataStoreOp, contents: envelope },
|
|
3437
|
-
localOpMetadata,
|
|
3438
|
-
);
|
|
3439
|
-
}
|
|
3440
|
-
|
|
3441
|
-
public submitDataStoreAliasOp(contents: any, localOpMetadata: unknown): void {
|
|
3442
|
-
const aliasMessage = contents as IDataStoreAliasMessage;
|
|
3443
|
-
if (!isDataStoreAliasMessage(aliasMessage)) {
|
|
3444
|
-
throw new UsageError("malformedDataStoreAliasMessage");
|
|
3445
|
-
}
|
|
3446
|
-
|
|
3447
|
-
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
3658
|
+
this.submit({ type, contents }, localOpMetadata);
|
|
3448
3659
|
}
|
|
3449
3660
|
|
|
3450
3661
|
public async uploadBlob(
|
|
@@ -3455,35 +3666,22 @@ export class ContainerRuntime
|
|
|
3455
3666
|
return this.blobManager.createBlob(blob, signal);
|
|
3456
3667
|
}
|
|
3457
3668
|
|
|
3458
|
-
private
|
|
3459
|
-
if (
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
if (
|
|
3463
|
-
assert(
|
|
3464
|
-
this.idCompressor !== undefined,
|
|
3465
|
-
0x67d /* IdCompressor should be defined if enabled */,
|
|
3466
|
-
);
|
|
3467
|
-
idRange = this.idCompressor.takeNextCreationRange();
|
|
3468
|
-
// Don't include the idRange if there weren't any Ids allocated
|
|
3469
|
-
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
3470
|
-
}
|
|
3471
|
-
|
|
3472
|
-
if (idRange !== undefined) {
|
|
3669
|
+
private submitIdAllocationOpIfNeeded(): void {
|
|
3670
|
+
if (this._idCompressor) {
|
|
3671
|
+
const idRange = this._idCompressor.takeNextCreationRange();
|
|
3672
|
+
// Don't include the idRange if there weren't any Ids allocated
|
|
3673
|
+
if (idRange?.ids !== undefined) {
|
|
3473
3674
|
const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
|
|
3474
3675
|
type: ContainerMessageType.IdAllocation,
|
|
3475
3676
|
contents: idRange,
|
|
3476
3677
|
};
|
|
3477
|
-
idAllocationBatchMessage = {
|
|
3678
|
+
const idAllocationBatchMessage: BatchMessage = {
|
|
3478
3679
|
contents: JSON.stringify(idAllocationMessage),
|
|
3479
3680
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3480
3681
|
metadata: undefined,
|
|
3481
3682
|
localOpMetadata: undefined,
|
|
3482
3683
|
type: ContainerMessageType.IdAllocation,
|
|
3483
3684
|
};
|
|
3484
|
-
}
|
|
3485
|
-
|
|
3486
|
-
if (idAllocationBatchMessage !== undefined) {
|
|
3487
3685
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
3488
3686
|
}
|
|
3489
3687
|
}
|
|
@@ -3524,43 +3722,47 @@ export class ContainerRuntime
|
|
|
3524
3722
|
};
|
|
3525
3723
|
|
|
3526
3724
|
try {
|
|
3527
|
-
//
|
|
3528
|
-
// the
|
|
3529
|
-
// op
|
|
3530
|
-
//
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
3534
|
-
// Is it safe:
|
|
3535
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
3536
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
3537
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
3538
|
-
// Why:
|
|
3539
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
3540
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
3541
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
3542
|
-
// these issues.
|
|
3543
|
-
// Cons:
|
|
3544
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
3545
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
3546
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
3547
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
3548
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
3549
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
3550
|
-
// issue than sending.
|
|
3551
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
3552
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
3553
|
-
if (
|
|
3554
|
-
this.currentlyBatching() &&
|
|
3555
|
-
type === ContainerMessageType.Attach &&
|
|
3556
|
-
this.disableAttachReorder !== true
|
|
3557
|
-
) {
|
|
3558
|
-
this.outbox.submitAttach(message);
|
|
3559
|
-
} else if (type === ContainerMessageType.BlobAttach) {
|
|
3560
|
-
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
3561
|
-
this.outbox.submitBlobAttach(message);
|
|
3725
|
+
// If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
|
|
3726
|
+
// op into the correct batch to avoid ranges being finalized out of order.
|
|
3727
|
+
// Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
|
|
3728
|
+
// any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
|
|
3729
|
+
if (type === ContainerMessageType.IdAllocation) {
|
|
3730
|
+
this.outbox.submitIdAllocation(message);
|
|
3562
3731
|
} else {
|
|
3563
|
-
this.
|
|
3732
|
+
this.submitIdAllocationOpIfNeeded();
|
|
3733
|
+
|
|
3734
|
+
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
3735
|
+
// Is it safe:
|
|
3736
|
+
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
3737
|
+
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
3738
|
+
// is stored in some DDS, i.e. only after some other op.
|
|
3739
|
+
// Why:
|
|
3740
|
+
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
3741
|
+
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
3742
|
+
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
3743
|
+
// these issues.
|
|
3744
|
+
// Cons:
|
|
3745
|
+
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
3746
|
+
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
3747
|
+
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
3748
|
+
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
3749
|
+
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
3750
|
+
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
3751
|
+
// issue than sending.
|
|
3752
|
+
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
3753
|
+
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
3754
|
+
if (
|
|
3755
|
+
this.currentlyBatching() &&
|
|
3756
|
+
type === ContainerMessageType.Attach &&
|
|
3757
|
+
this.disableAttachReorder !== true
|
|
3758
|
+
) {
|
|
3759
|
+
this.outbox.submitAttach(message);
|
|
3760
|
+
} else if (type === ContainerMessageType.BlobAttach) {
|
|
3761
|
+
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
3762
|
+
this.outbox.submitBlobAttach(message);
|
|
3763
|
+
} else {
|
|
3764
|
+
this.outbox.submit(message);
|
|
3765
|
+
}
|
|
3564
3766
|
}
|
|
3565
3767
|
|
|
3566
3768
|
if (!this.currentlyBatching()) {
|
|
@@ -3702,14 +3904,18 @@ export class ContainerRuntime
|
|
|
3702
3904
|
localOpMetadata: unknown,
|
|
3703
3905
|
opMetadata: Record<string, unknown> | undefined,
|
|
3704
3906
|
) {
|
|
3907
|
+
assert(
|
|
3908
|
+
!this.isSummarizerClient,
|
|
3909
|
+
0x8f2 /* Summarizer never reconnects so should never resubmit */,
|
|
3910
|
+
);
|
|
3705
3911
|
switch (message.type) {
|
|
3706
3912
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3913
|
+
case ContainerMessageType.Attach:
|
|
3914
|
+
case ContainerMessageType.Alias:
|
|
3707
3915
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3708
3916
|
// and trigger resubmission on it.
|
|
3709
|
-
this.
|
|
3917
|
+
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
3710
3918
|
break;
|
|
3711
|
-
case ContainerMessageType.Attach:
|
|
3712
|
-
case ContainerMessageType.Alias:
|
|
3713
3919
|
case ContainerMessageType.IdAllocation: {
|
|
3714
3920
|
this.submit(message, localOpMetadata);
|
|
3715
3921
|
break;
|
|
@@ -3723,13 +3929,14 @@ export class ContainerRuntime
|
|
|
3723
3929
|
this.submit(message);
|
|
3724
3930
|
break;
|
|
3725
3931
|
case ContainerMessageType.GC:
|
|
3726
|
-
|
|
3727
|
-
|
|
3932
|
+
this.submit(message);
|
|
3933
|
+
break;
|
|
3728
3934
|
default: {
|
|
3729
3935
|
// This case should be very rare - it would imply an op was stashed from a
|
|
3730
|
-
// future version of runtime code and now is being applied on an older version
|
|
3936
|
+
// future version of runtime code and now is being applied on an older version.
|
|
3731
3937
|
const compatBehavior = message.compatDetails?.behavior;
|
|
3732
3938
|
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
3939
|
+
// We do not ultimately resubmit it, to be consistent with this version of the code.
|
|
3733
3940
|
this.logger.sendTelemetryEvent({
|
|
3734
3941
|
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
3735
3942
|
messageDetails: { type: message.type, compatBehavior },
|
|
@@ -3760,7 +3967,7 @@ export class ContainerRuntime
|
|
|
3760
3967
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3761
3968
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
3762
3969
|
// and trigger rollback on it.
|
|
3763
|
-
this.
|
|
3970
|
+
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
3764
3971
|
break;
|
|
3765
3972
|
default:
|
|
3766
3973
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -3786,7 +3993,7 @@ export class ContainerRuntime
|
|
|
3786
3993
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
3787
3994
|
*/
|
|
3788
3995
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
3789
|
-
|
|
3996
|
+
await this.fetchLatestSnapshotFromStorage(
|
|
3790
3997
|
summaryLogger,
|
|
3791
3998
|
{
|
|
3792
3999
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
@@ -3796,32 +4003,7 @@ export class ContainerRuntime
|
|
|
3796
4003
|
readAndParseBlob,
|
|
3797
4004
|
);
|
|
3798
4005
|
|
|
3799
|
-
|
|
3800
|
-
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
3801
|
-
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
3802
|
-
* However, there are couple of scenarios where it's possible:
|
|
3803
|
-
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
3804
|
-
* the document being unusable and we should not proceed.
|
|
3805
|
-
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
3806
|
-
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
3807
|
-
* state.
|
|
3808
|
-
*/
|
|
3809
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3810
|
-
const error = DataProcessingError.create(
|
|
3811
|
-
"Fetched snapshot is older than the received ack",
|
|
3812
|
-
"RefreshLatestSummaryAck",
|
|
3813
|
-
undefined /* sequencedMessage */,
|
|
3814
|
-
{
|
|
3815
|
-
ackHandle,
|
|
3816
|
-
summaryRefSeq,
|
|
3817
|
-
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3818
|
-
},
|
|
3819
|
-
);
|
|
3820
|
-
this.disposeFn(error);
|
|
3821
|
-
throw error;
|
|
3822
|
-
}
|
|
3823
|
-
|
|
3824
|
-
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
4006
|
+
await this.closeStaleSummarizer();
|
|
3825
4007
|
return;
|
|
3826
4008
|
}
|
|
3827
4009
|
|
|
@@ -3850,7 +4032,7 @@ export class ContainerRuntime
|
|
|
3850
4032
|
readAndParseBlob,
|
|
3851
4033
|
);
|
|
3852
4034
|
|
|
3853
|
-
await this.closeStaleSummarizer(
|
|
4035
|
+
await this.closeStaleSummarizer();
|
|
3854
4036
|
|
|
3855
4037
|
return {
|
|
3856
4038
|
stage: "base",
|
|
@@ -3860,7 +4042,7 @@ export class ContainerRuntime
|
|
|
3860
4042
|
};
|
|
3861
4043
|
}
|
|
3862
4044
|
|
|
3863
|
-
private async closeStaleSummarizer(
|
|
4045
|
+
private async closeStaleSummarizer(): Promise<void> {
|
|
3864
4046
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3865
4047
|
await delay(this.closeSummarizerDelayMs);
|
|
3866
4048
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
@@ -3874,7 +4056,7 @@ export class ContainerRuntime
|
|
|
3874
4056
|
*/
|
|
3875
4057
|
private async fetchLatestSnapshotFromStorage(
|
|
3876
4058
|
logger: ITelemetryLoggerExt,
|
|
3877
|
-
event:
|
|
4059
|
+
event: ITelemetryGenericEventExt,
|
|
3878
4060
|
readAndParseBlob: ReadAndParseBlob,
|
|
3879
4061
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3880
4062
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -3925,50 +4107,65 @@ export class ContainerRuntime
|
|
|
3925
4107
|
);
|
|
3926
4108
|
}
|
|
3927
4109
|
|
|
3928
|
-
public
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
3944
|
-
throw new UsageError("can't get state during orderSequentially");
|
|
3945
|
-
}
|
|
3946
|
-
// Flush pending batch.
|
|
3947
|
-
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3948
|
-
// to close current batch.
|
|
3949
|
-
this.flush();
|
|
3950
|
-
const pendingAttachmentBlobs = this.imminentClosure
|
|
3951
|
-
? await this.blobManager.attachAndGetPendingBlobs(stopBlobAttachingSignal)
|
|
3952
|
-
: undefined;
|
|
3953
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
3954
|
-
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3955
|
-
return; // no pending state to save
|
|
3956
|
-
}
|
|
4110
|
+
public getPendingLocalState(props?: IGetPendingLocalStateProps): unknown {
|
|
4111
|
+
this.verifyNotClosed();
|
|
4112
|
+
|
|
4113
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
4114
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
4115
|
+
}
|
|
4116
|
+
this.imminentClosure ||= props?.notifyImminentClosure ?? false;
|
|
4117
|
+
|
|
4118
|
+
const getSyncState = (
|
|
4119
|
+
pendingAttachmentBlobs?: IPendingBlobs,
|
|
4120
|
+
): IPendingRuntimeState | undefined => {
|
|
4121
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
4122
|
+
if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
|
|
4123
|
+
return; // no pending state to save
|
|
4124
|
+
}
|
|
3957
4125
|
|
|
3958
|
-
|
|
4126
|
+
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
3959
4127
|
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
4128
|
+
return {
|
|
4129
|
+
pending,
|
|
4130
|
+
pendingIdCompressorState,
|
|
4131
|
+
pendingAttachmentBlobs,
|
|
4132
|
+
sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
|
|
4133
|
+
};
|
|
4134
|
+
};
|
|
4135
|
+
const perfEvent = {
|
|
4136
|
+
eventName: "getPendingLocalState",
|
|
4137
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
4138
|
+
};
|
|
4139
|
+
const logAndReturnPendingState = (
|
|
4140
|
+
event: PerformanceEvent,
|
|
4141
|
+
pendingState?: IPendingRuntimeState,
|
|
4142
|
+
) => {
|
|
4143
|
+
event.end({
|
|
4144
|
+
attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
|
|
4145
|
+
pendingOpsSize: pendingState?.pending?.pendingStates.length,
|
|
4146
|
+
});
|
|
4147
|
+
return pendingState;
|
|
4148
|
+
};
|
|
4149
|
+
|
|
4150
|
+
// Flush pending batch.
|
|
4151
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
4152
|
+
// to close current batch.
|
|
4153
|
+
this.flush();
|
|
4154
|
+
|
|
4155
|
+
return props?.notifyImminentClosure === true
|
|
4156
|
+
? PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) =>
|
|
4157
|
+
logAndReturnPendingState(
|
|
4158
|
+
event,
|
|
4159
|
+
getSyncState(
|
|
4160
|
+
await this.blobManager.attachAndGetPendingBlobs(
|
|
4161
|
+
props?.stopBlobAttachingSignal,
|
|
4162
|
+
),
|
|
4163
|
+
),
|
|
4164
|
+
),
|
|
4165
|
+
)
|
|
4166
|
+
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) =>
|
|
4167
|
+
logAndReturnPendingState(event, getSyncState()),
|
|
4168
|
+
);
|
|
3972
4169
|
}
|
|
3973
4170
|
|
|
3974
4171
|
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|