@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
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
2
|
-
import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
|
|
2
|
+
import { assert, Deferred, delay, LazyPromise, PromiseCache } from "@fluidframework/core-utils";
|
|
3
3
|
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
4
|
-
import { createChildLogger, createChildMonitoringContext, DataCorruptionError, DataProcessingError, GenericError, raiseConnectedEvent, PerformanceEvent,
|
|
5
|
-
// eslint-disable-next-line import/no-deprecated
|
|
6
|
-
TaggedLoggerAdapter, wrapError, UsageError, LoggingError, } from "@fluidframework/telemetry-utils";
|
|
4
|
+
import { createChildLogger, createChildMonitoringContext, DataCorruptionError, DataProcessingError, GenericError, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, wrapError, UsageError, LoggingError, createSampledLogger, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
|
|
7
5
|
import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
8
6
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
9
7
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
10
8
|
import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
11
|
-
import { addBlobToSummary, addSummarizeResultToSummary,
|
|
9
|
+
import { addBlobToSummary, addSummarizeResultToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, seqFromTree, calculateStats, TelemetryContext, responseToException, } from "@fluidframework/runtime-utils";
|
|
12
10
|
import { v4 as uuid } from "uuid";
|
|
13
|
-
import { ContainerFluidHandleContext } from "./containerHandleContext.
|
|
14
|
-
import { FluidDataStoreRegistry } from "./dataStoreRegistry.
|
|
15
|
-
import { ReportOpPerfTelemetry } from "./connectionTelemetry.
|
|
16
|
-
import { PendingStateManager, } from "./pendingStateManager.
|
|
17
|
-
import { pkgVersion } from "./packageVersion.
|
|
18
|
-
import { BlobManager } from "./blobManager.
|
|
19
|
-
import {
|
|
20
|
-
import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, idCompressorBlobName, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, RetriableSummaryError, } from "./summary/index.
|
|
21
|
-
import { formExponentialFn, Throttler } from "./throttler.
|
|
22
|
-
import { GarbageCollector, GCNodeType, gcGenerationOptionName,
|
|
23
|
-
import { channelToDataStore
|
|
24
|
-
import { BindBatchTracker } from "./batchTracker.
|
|
25
|
-
import { ScheduleManager } from "./scheduleManager.
|
|
26
|
-
import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, OpGroupingManager, getLongStack, } from "./opLifecycle/index.
|
|
27
|
-
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.
|
|
28
|
-
import { ContainerMessageType, } from "./messageTypes.
|
|
11
|
+
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
12
|
+
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
13
|
+
import { ReportOpPerfTelemetry } from "./connectionTelemetry.js";
|
|
14
|
+
import { PendingStateManager, } from "./pendingStateManager.js";
|
|
15
|
+
import { pkgVersion } from "./packageVersion.js";
|
|
16
|
+
import { BlobManager } from "./blobManager.js";
|
|
17
|
+
import { ChannelCollection, getSummaryForDatastores, wrapContext } from "./channelCollection.js";
|
|
18
|
+
import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, idCompressorBlobName, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, RetriableSummaryError, rootHasIsolatedChannels, } from "./summary/index.js";
|
|
19
|
+
import { formExponentialFn, Throttler } from "./throttler.js";
|
|
20
|
+
import { GarbageCollector, GCNodeType, gcGenerationOptionName, } from "./gc/index.js";
|
|
21
|
+
import { channelToDataStore } from "./dataStore.js";
|
|
22
|
+
import { BindBatchTracker } from "./batchTracker.js";
|
|
23
|
+
import { ScheduleManager } from "./scheduleManager.js";
|
|
24
|
+
import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, OpGroupingManager, getLongStack, } from "./opLifecycle/index.js";
|
|
25
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
|
|
26
|
+
import { ContainerMessageType, } from "./messageTypes.js";
|
|
29
27
|
/**
|
|
30
28
|
* Utility to implement compat behaviors given an unknown message type
|
|
31
29
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
@@ -55,26 +53,6 @@ export const DefaultSummaryConfiguration = {
|
|
|
55
53
|
runtimeOpWeight: 1.0,
|
|
56
54
|
nonRuntimeHeuristicThreshold: 20,
|
|
57
55
|
};
|
|
58
|
-
/**
|
|
59
|
-
* Accepted header keys for requests coming to the runtime.
|
|
60
|
-
* @internal
|
|
61
|
-
*/
|
|
62
|
-
export var RuntimeHeaders;
|
|
63
|
-
(function (RuntimeHeaders) {
|
|
64
|
-
/** True to wait for a data store to be created and loaded before returning it. */
|
|
65
|
-
RuntimeHeaders["wait"] = "wait";
|
|
66
|
-
/** True if the request is coming from an IFluidHandle. */
|
|
67
|
-
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
68
|
-
})(RuntimeHeaders || (RuntimeHeaders = {}));
|
|
69
|
-
/** True if a tombstoned object should be returned without erroring
|
|
70
|
-
* @alpha
|
|
71
|
-
*/
|
|
72
|
-
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
73
|
-
/**
|
|
74
|
-
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
75
|
-
* @internal
|
|
76
|
-
*/
|
|
77
|
-
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
78
56
|
/**
|
|
79
57
|
* Tombstone error responses will have this header set to true
|
|
80
58
|
* @alpha
|
|
@@ -243,7 +221,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
243
221
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
244
222
|
const backCompatContext = context;
|
|
245
223
|
const passLogger = backCompatContext.taggedLogger ??
|
|
246
|
-
// eslint-disable-next-line import/no-deprecated
|
|
247
224
|
new TaggedLoggerAdapter(backCompatContext.logger);
|
|
248
225
|
const logger = createChildLogger({
|
|
249
226
|
logger: passLogger,
|
|
@@ -253,7 +230,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
253
230
|
},
|
|
254
231
|
},
|
|
255
232
|
});
|
|
256
|
-
const
|
|
233
|
+
const mc = loggerToMonitoringContext(logger);
|
|
234
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = "off", chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
|
|
257
235
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
258
236
|
const tryFetchBlob = async (blobName) => {
|
|
259
237
|
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
@@ -298,21 +276,62 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
298
276
|
}
|
|
299
277
|
}
|
|
300
278
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
279
|
+
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
280
|
+
// allow new containers to turn it on
|
|
281
|
+
let idCompressorMode;
|
|
282
|
+
if (existing) {
|
|
283
|
+
// This setting has to be sticky for correctness:
|
|
284
|
+
// 1) if compressior is OFF, it can't be enabled, as already running clients (in given document session) do not know
|
|
285
|
+
// how to process compressor ops
|
|
286
|
+
// 2) if it's ON, then all sessions should load compressor right away
|
|
287
|
+
// 3) Same logic applies for "delayed" mode
|
|
288
|
+
// Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
|
|
289
|
+
// We could do "off" -> "on" transtition too, if all clients start loading compressor (but not using it initially) and do so for a while -
|
|
290
|
+
// this will allow clients to eventually to disregard "off" setting (when it's safe so) and start using compressor in future sessions.
|
|
291
|
+
// Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
|
|
292
|
+
idCompressorMode = metadata?.idCompressorMode ?? "off";
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// FG overwrite
|
|
296
|
+
const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
|
|
297
|
+
switch (enabled) {
|
|
298
|
+
case true:
|
|
299
|
+
idCompressorMode = "on";
|
|
300
|
+
break;
|
|
301
|
+
case false:
|
|
302
|
+
idCompressorMode = "off";
|
|
303
|
+
break;
|
|
304
|
+
default:
|
|
305
|
+
idCompressorMode = enableRuntimeIdCompressor;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const createIdCompressorFn = async () => {
|
|
304
310
|
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import("@fluidframework/id-compressor");
|
|
311
|
+
/**
|
|
312
|
+
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
313
|
+
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
314
|
+
*/
|
|
315
|
+
const idCompressorEventSampler = (() => {
|
|
316
|
+
const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
|
|
317
|
+
return {
|
|
318
|
+
sample: () => {
|
|
319
|
+
return isIdCompressorTelemetryEnabled;
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
})();
|
|
323
|
+
const compressorLogger = createSampledLogger(logger, idCompressorEventSampler);
|
|
305
324
|
const pendingLocalState = context.pendingLocalState;
|
|
306
325
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
307
|
-
|
|
326
|
+
return deserializeIdCompressor(pendingLocalState.pendingIdCompressorState, compressorLogger);
|
|
308
327
|
}
|
|
309
328
|
else if (serializedIdCompressor !== undefined) {
|
|
310
|
-
|
|
329
|
+
return deserializeIdCompressor(serializedIdCompressor, createSessionId(), compressorLogger);
|
|
311
330
|
}
|
|
312
331
|
else {
|
|
313
|
-
|
|
332
|
+
return createIdCompressor(compressorLogger);
|
|
314
333
|
}
|
|
315
|
-
}
|
|
334
|
+
};
|
|
316
335
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
317
336
|
summaryOptions,
|
|
318
337
|
gcOptions,
|
|
@@ -324,7 +343,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
324
343
|
enableRuntimeIdCompressor,
|
|
325
344
|
enableOpReentryCheck,
|
|
326
345
|
enableGroupedBatching,
|
|
327
|
-
}, containerScope, logger, existing, blobManagerSnapshot, context.storage,
|
|
346
|
+
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, idCompressorMode, provideEntryPoint, requestHandler, undefined);
|
|
328
347
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
329
348
|
// or zero. This must be done before Container replays saved ops.
|
|
330
349
|
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
@@ -338,6 +357,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
338
357
|
get storage() {
|
|
339
358
|
return this._storage;
|
|
340
359
|
}
|
|
360
|
+
get containerRuntime() {
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
341
363
|
get flushMode() {
|
|
342
364
|
return this._flushMode;
|
|
343
365
|
}
|
|
@@ -350,6 +372,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
350
372
|
get attachState() {
|
|
351
373
|
return this._getAttachState();
|
|
352
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* See IContainerRuntimeBase.idCompressor() for details.
|
|
377
|
+
*/
|
|
378
|
+
get idCompressor() {
|
|
379
|
+
// Expose ID Compressor only if it's On from the start.
|
|
380
|
+
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
381
|
+
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
382
|
+
// to reason over such things as session ID space.
|
|
383
|
+
if (this.idCompressorMode === "on") {
|
|
384
|
+
assert(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
385
|
+
return this._idCompressor;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* See IContainerRuntimeBase.generateDocumentUniqueId() for details.
|
|
390
|
+
*/
|
|
391
|
+
generateDocumentUniqueId() {
|
|
392
|
+
return this._idCompressor?.generateDocumentUniqueId() ?? uuid();
|
|
393
|
+
}
|
|
353
394
|
get IFluidHandleContext() {
|
|
354
395
|
return this.handleContext;
|
|
355
396
|
}
|
|
@@ -387,9 +428,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
387
428
|
isSummariesDisabled() {
|
|
388
429
|
return this.summaryConfiguration.state === "disabled";
|
|
389
430
|
}
|
|
390
|
-
isHeuristicsDisabled() {
|
|
391
|
-
return this.summaryConfiguration.state === "disableHeuristics";
|
|
392
|
-
}
|
|
393
431
|
getMaxOpsSinceLastSummary() {
|
|
394
432
|
return this.summaryConfiguration.state !== "disabled"
|
|
395
433
|
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
@@ -414,7 +452,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
414
452
|
return this.garbageCollector.throwOnTombstoneUsage;
|
|
415
453
|
}
|
|
416
454
|
/***/
|
|
417
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage,
|
|
455
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, createIdCompressor, idCompressorMode, provideEntryPoint, requestHandler, summaryConfiguration = {
|
|
418
456
|
// the defaults
|
|
419
457
|
...DefaultSummaryConfiguration,
|
|
420
458
|
// the runtime configuration overrides
|
|
@@ -422,13 +460,24 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
422
460
|
}) {
|
|
423
461
|
super();
|
|
424
462
|
this.registry = registry;
|
|
463
|
+
this.metadata = metadata;
|
|
425
464
|
this.runtimeOptions = runtimeOptions;
|
|
426
465
|
this.containerScope = containerScope;
|
|
427
466
|
this.logger = logger;
|
|
428
467
|
this._storage = _storage;
|
|
468
|
+
this.createIdCompressor = createIdCompressor;
|
|
469
|
+
this.idCompressorMode = idCompressorMode;
|
|
429
470
|
this.requestHandler = requestHandler;
|
|
430
471
|
this.summaryConfiguration = summaryConfiguration;
|
|
431
472
|
this.imminentClosure = false;
|
|
473
|
+
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
474
|
+
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
475
|
+
this.pendingIdCompressorOps = [];
|
|
476
|
+
/**
|
|
477
|
+
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
478
|
+
* this.idCompressorMode === "delayed" mode
|
|
479
|
+
*/
|
|
480
|
+
this.compressorLoadInitiated = false;
|
|
432
481
|
this.defaultMaxConsecutiveReconnects = 7;
|
|
433
482
|
this._orderSequentiallyCalls = 0;
|
|
434
483
|
this.flushTaskExists = false;
|
|
@@ -450,6 +499,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
450
499
|
signalTimestamp: 0,
|
|
451
500
|
trackingSignalSequenceNumber: undefined,
|
|
452
501
|
};
|
|
502
|
+
/**
|
|
503
|
+
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
504
|
+
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
505
|
+
*/
|
|
506
|
+
this.snapshotCacheForLoadingGroupIds = new PromiseCache({
|
|
507
|
+
expiry: { policy: "absolute", durationMs: 60000 },
|
|
508
|
+
});
|
|
453
509
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
454
510
|
this.innerDeltaManager = deltaManager;
|
|
455
511
|
this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
@@ -459,7 +515,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
459
515
|
this.submitBatchFn = submitBatchFn;
|
|
460
516
|
this.submitSummaryFn = submitSummaryFn;
|
|
461
517
|
this.submitSignalFn = submitSignalFn;
|
|
462
|
-
|
|
518
|
+
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
519
|
+
// Values are generally expected to be set from the runtime side.
|
|
520
|
+
this.options = options ?? {};
|
|
463
521
|
this.clientDetails = clientDetails;
|
|
464
522
|
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
465
523
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
@@ -497,9 +555,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
497
555
|
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
498
556
|
// the count is reset to 0.
|
|
499
557
|
loadSummaryNumber = metadata?.summaryNumber ?? 0;
|
|
500
|
-
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
501
|
-
// allow new containers to turn it on
|
|
502
|
-
this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
|
|
503
558
|
}
|
|
504
559
|
else {
|
|
505
560
|
this.createContainerMetadata = {
|
|
@@ -507,9 +562,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
507
562
|
createContainerTimestamp: Date.now(),
|
|
508
563
|
};
|
|
509
564
|
loadSummaryNumber = 0;
|
|
510
|
-
this.idCompressorEnabled =
|
|
511
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
|
|
512
|
-
idCompressor !== undefined;
|
|
513
565
|
}
|
|
514
566
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
515
567
|
this.messageAtLastSummary = metadata?.message;
|
|
@@ -544,12 +596,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
544
596
|
// Allow for a break-glass config to override the options
|
|
545
597
|
disableOpReentryCheck !== true;
|
|
546
598
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
547
|
-
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
548
599
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
549
600
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
550
|
-
if (this.idCompressorEnabled) {
|
|
551
|
-
this.idCompressor = idCompressor;
|
|
552
|
-
}
|
|
553
601
|
this.maxConsecutiveReconnects =
|
|
554
602
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
555
603
|
this.defaultMaxConsecutiveReconnects;
|
|
@@ -563,13 +611,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
563
611
|
this._flushMode = runtimeOptions.flushMode;
|
|
564
612
|
}
|
|
565
613
|
const pendingRuntimeState = pendingLocalState;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
maxSnapshotCacheDurationMs
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
614
|
+
if (context.attachState === AttachState.Attached) {
|
|
615
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
616
|
+
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
617
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
|
|
618
|
+
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
619
|
+
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
620
|
+
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
621
|
+
throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
622
|
+
}
|
|
573
623
|
}
|
|
574
624
|
this.garbageCollector = GarbageCollector.create({
|
|
575
625
|
runtime: this,
|
|
@@ -584,6 +634,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
584
634
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
585
635
|
readAndParseBlob: async (id) => readAndParse(this.storage, id),
|
|
586
636
|
submitMessage: (message) => this.submit(message),
|
|
637
|
+
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
587
638
|
});
|
|
588
639
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
589
640
|
this.summarizerNode = createRootSummarizerNodeWithGC(createChildLogger({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
@@ -596,9 +647,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
596
647
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
597
648
|
// a summary with an older protocol state.
|
|
598
649
|
canReuseHandle: false,
|
|
599
|
-
// Must set to true to throw on any data stores failure that was too severe to be handled.
|
|
600
|
-
// We also are not decoding the base summaries at the root.
|
|
601
|
-
throwOnFailure: true,
|
|
602
650
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
603
651
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
604
652
|
},
|
|
@@ -609,7 +657,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
609
657
|
if (baseSnapshot) {
|
|
610
658
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
611
659
|
}
|
|
612
|
-
|
|
660
|
+
const parentContext = wrapContext(this);
|
|
661
|
+
// Due to a mismatch between different layers in terms of
|
|
662
|
+
// what is the interface of passing signals, we need the
|
|
663
|
+
// downstream stores to wrap the signal.
|
|
664
|
+
parentContext.submitSignal = (type, content, targetClientId) => {
|
|
665
|
+
const envelope1 = content;
|
|
666
|
+
const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
|
|
667
|
+
return this.submitSignalFn(envelope2, targetClientId);
|
|
668
|
+
};
|
|
669
|
+
this.channelCollection = new ChannelCollection(getSummaryForDatastores(baseSnapshot, metadata), parentContext, this.mc.logger, (path, reason, timestampMs, packagePath, request, headerData) => this.garbageCollector.nodeUpdated(path, reason, timestampMs, packagePath, request, headerData), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
613
670
|
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
614
671
|
if (!this.disposed) {
|
|
615
672
|
this.submit({ type: ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
|
|
@@ -627,6 +684,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
627
684
|
reSubmit: this.reSubmit.bind(this),
|
|
628
685
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
629
686
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
687
|
+
isAttached: () => this.attachState !== AttachState.Detached,
|
|
630
688
|
}, pendingRuntimeState?.pending, this.logger);
|
|
631
689
|
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
632
690
|
const compressionOptions = disableCompression === true
|
|
@@ -718,7 +776,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
718
776
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
719
777
|
formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
|
|
720
778
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
721
|
-
}
|
|
779
|
+
});
|
|
722
780
|
this.summaryManager.on("summarize", (eventProps) => {
|
|
723
781
|
this.emit("summarize", eventProps);
|
|
724
782
|
});
|
|
@@ -733,25 +791,26 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
733
791
|
this.mc.logger.sendTelemetryEvent({
|
|
734
792
|
eventName: "ContainerLoadStats",
|
|
735
793
|
...this.createContainerMetadata,
|
|
736
|
-
...this.
|
|
794
|
+
...this.channelCollection.containerLoadStats,
|
|
737
795
|
summaryNumber: loadSummaryNumber,
|
|
738
796
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
739
797
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
740
798
|
gcVersion: metadata?.gcFeature,
|
|
741
799
|
options: JSON.stringify(runtimeOptions),
|
|
800
|
+
idCompressorModeMetadata: metadata?.idCompressorMode,
|
|
801
|
+
idCompressorMode: this.idCompressorMode,
|
|
742
802
|
featureGates: JSON.stringify({
|
|
743
803
|
disableCompression,
|
|
744
804
|
disableOpReentryCheck,
|
|
745
805
|
disableChunking,
|
|
746
806
|
disableAttachReorder: this.disableAttachReorder,
|
|
747
807
|
disablePartialFlush,
|
|
748
|
-
idCompressorEnabled: this.idCompressorEnabled,
|
|
749
808
|
closeSummarizerDelayOverride,
|
|
750
809
|
}),
|
|
751
810
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
752
811
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
753
812
|
});
|
|
754
|
-
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
813
|
+
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this, this.logger);
|
|
755
814
|
BindBatchTracker(this, this.logger);
|
|
756
815
|
this.entryPoint = new LazyPromise(async () => {
|
|
757
816
|
if (this.isSummarizerClient) {
|
|
@@ -760,11 +819,29 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
760
819
|
}
|
|
761
820
|
return provideEntryPoint(this);
|
|
762
821
|
});
|
|
822
|
+
// If we loaded from pending state, then we need to skip any ops that are already accounted in such
|
|
823
|
+
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
824
|
+
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
825
|
+
}
|
|
826
|
+
getCreateChildSummarizerNodeFn(id, createParam) {
|
|
827
|
+
return (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn);
|
|
828
|
+
}
|
|
829
|
+
deleteChildSummarizerNode(id) {
|
|
830
|
+
return this.summarizerNode.deleteChild(id);
|
|
831
|
+
}
|
|
832
|
+
makeLocallyVisible() {
|
|
833
|
+
assert(false, 0x8eb /* should not be called */);
|
|
763
834
|
}
|
|
764
835
|
/**
|
|
765
836
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
766
837
|
*/
|
|
767
838
|
async initializeBaseState() {
|
|
839
|
+
if (this.idCompressorMode === "on" ||
|
|
840
|
+
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
841
|
+
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
842
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
843
|
+
this._idCompressor = await this.createIdCompressor();
|
|
844
|
+
}
|
|
768
845
|
await this.garbageCollector.initializeBaseState();
|
|
769
846
|
}
|
|
770
847
|
dispose(error) {
|
|
@@ -783,11 +860,110 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
783
860
|
}
|
|
784
861
|
this.garbageCollector.dispose();
|
|
785
862
|
this._summarizer?.dispose();
|
|
786
|
-
this.
|
|
863
|
+
this.channelCollection.dispose();
|
|
787
864
|
this.pendingStateManager.dispose();
|
|
788
865
|
this.emit("dispose");
|
|
789
866
|
this.removeAllListeners();
|
|
790
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* Api to fetch the snapshot from the service for a loadingGroupIds.
|
|
870
|
+
* @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for.
|
|
871
|
+
* @param pathParts - Parts of the path, which we want to extract from the snapshot tree.
|
|
872
|
+
* @returns - snapshotTree and the sequence number of the snapshot.
|
|
873
|
+
*/
|
|
874
|
+
async getSnapshotForLoadingGroupId(loadingGroupIds, pathParts) {
|
|
875
|
+
const sortedLoadingGroupIds = loadingGroupIds.sort();
|
|
876
|
+
assert(this.storage.getSnapshot !== undefined, 0x8ed /* getSnapshot api should be defined if used */);
|
|
877
|
+
let loadedFromCache = true;
|
|
878
|
+
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
879
|
+
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
880
|
+
// any request, then cache that as same group could be requested in future too.
|
|
881
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(), async () => {
|
|
882
|
+
assert(this.storage.getSnapshot !== undefined, 0x8ee /* getSnapshot api should be defined if used */);
|
|
883
|
+
loadedFromCache = false;
|
|
884
|
+
return this.storage.getSnapshot({
|
|
885
|
+
cacheSnapshot: false,
|
|
886
|
+
scenarioName: "snapshotForLoadingGroupId",
|
|
887
|
+
loadingGroupIds: sortedLoadingGroupIds,
|
|
888
|
+
});
|
|
889
|
+
});
|
|
890
|
+
this.logger.sendTelemetryEvent({
|
|
891
|
+
eventName: "GroupIdSnapshotFetched",
|
|
892
|
+
details: JSON.stringify({
|
|
893
|
+
fromCache: loadedFromCache,
|
|
894
|
+
loadingGroupIds: loadingGroupIds.join(","),
|
|
895
|
+
}),
|
|
896
|
+
});
|
|
897
|
+
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
898
|
+
const hasIsolatedChannels = rootHasIsolatedChannels(this.metadata);
|
|
899
|
+
const snapshotTreeForPath = this.getSnapshotTreeForPath(snapshot.snapshotTree, pathParts, hasIsolatedChannels);
|
|
900
|
+
assert(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
901
|
+
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
902
|
+
assert(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
|
|
903
|
+
// This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
|
|
904
|
+
// Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
|
|
905
|
+
// the file has been overwritten or service lost data.
|
|
906
|
+
if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
|
|
907
|
+
throw DataProcessingError.create("Downloaded snapshot older than snapshot we loaded from", "getSnapshotForLoadingGroupId", undefined, {
|
|
908
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
909
|
+
snapshotSeqNumber,
|
|
910
|
+
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
// If the snapshot is ahead of the last seq number of the delta manager, then catch up before
|
|
914
|
+
// returning the snapshot.
|
|
915
|
+
if (snapshotSeqNumber > this.deltaManager.lastSequenceNumber) {
|
|
916
|
+
// If this is a summarizer client, which is trying to load a group and it finds that there is
|
|
917
|
+
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
918
|
+
// the summarizer state is not up to date.
|
|
919
|
+
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
920
|
+
if (this.isSummarizerClient) {
|
|
921
|
+
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
922
|
+
}
|
|
923
|
+
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
924
|
+
const props = {
|
|
925
|
+
eventName: "GroupIdSnapshotCatchup",
|
|
926
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
927
|
+
targetSequenceNumber: snapshotSeqNumber,
|
|
928
|
+
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
929
|
+
};
|
|
930
|
+
const event = PerformanceEvent.start(this.mc.logger, {
|
|
931
|
+
...props,
|
|
932
|
+
});
|
|
933
|
+
// If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
|
|
934
|
+
// as long as it's not a summarizer client.
|
|
935
|
+
if (this.deltaManager.inbound.paused) {
|
|
936
|
+
props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
|
|
937
|
+
}
|
|
938
|
+
const defP = new Deferred();
|
|
939
|
+
this.deltaManager.on("op", (message) => {
|
|
940
|
+
if (message.sequenceNumber >= snapshotSeqNumber) {
|
|
941
|
+
defP.resolve(true);
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
await defP.promise;
|
|
945
|
+
event.end(props);
|
|
946
|
+
}
|
|
947
|
+
return { snapshotTree: snapshotTreeForPath, sequenceNumber: snapshotSeqNumber };
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array.
|
|
951
|
+
* @param snapshotTree - snapshot tree to look into.
|
|
952
|
+
* @param pathParts - Part of the path, which we want to extract from the snapshot tree.
|
|
953
|
+
* @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older
|
|
954
|
+
* snapshots will not have trees inside ".channels", so check that.
|
|
955
|
+
* @returns - requested snapshot tree based on the path parts.
|
|
956
|
+
*/
|
|
957
|
+
getSnapshotTreeForPath(snapshotTree, pathParts, hasIsolatedChannels) {
|
|
958
|
+
let childTree = snapshotTree;
|
|
959
|
+
for (const part of pathParts) {
|
|
960
|
+
if (hasIsolatedChannels) {
|
|
961
|
+
childTree = childTree?.trees[channelsTreeName];
|
|
962
|
+
}
|
|
963
|
+
childTree = childTree?.trees[part];
|
|
964
|
+
}
|
|
965
|
+
return childTree;
|
|
966
|
+
}
|
|
791
967
|
/**
|
|
792
968
|
* Notifies this object about the request made to the container.
|
|
793
969
|
* @param request - Request made to the handler.
|
|
@@ -841,15 +1017,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
841
1017
|
: create404Response(request);
|
|
842
1018
|
}
|
|
843
1019
|
else if (requestParser.pathParts.length > 0) {
|
|
844
|
-
|
|
845
|
-
const requestForChild = !requestParser.isLeaf(1);
|
|
846
|
-
const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
|
|
847
|
-
const subRequest = requestParser.createSubRequest(1);
|
|
848
|
-
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
849
|
-
// unintentionally modifying the url if that changes.
|
|
850
|
-
assert(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
|
|
851
|
-
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
852
|
-
return dataStore.request(subRequest);
|
|
1020
|
+
return await this.channelCollection.request(request);
|
|
853
1021
|
}
|
|
854
1022
|
return create404Response(request);
|
|
855
1023
|
}
|
|
@@ -864,38 +1032,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
864
1032
|
return this.entryPoint;
|
|
865
1033
|
}
|
|
866
1034
|
internalId(maybeAlias) {
|
|
867
|
-
return this.
|
|
868
|
-
}
|
|
869
|
-
async getDataStoreFromRequest(id, request, requestForChild) {
|
|
870
|
-
const headerData = {};
|
|
871
|
-
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
872
|
-
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
873
|
-
}
|
|
874
|
-
if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
|
|
875
|
-
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
876
|
-
}
|
|
877
|
-
if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
|
|
878
|
-
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
879
|
-
}
|
|
880
|
-
if (typeof request.headers?.[AllowInactiveRequestHeaderKey] === "boolean") {
|
|
881
|
-
headerData.allowInactive = request.headers[AllowInactiveRequestHeaderKey];
|
|
882
|
-
}
|
|
883
|
-
// We allow Tombstone requests for sub-DataStore objects
|
|
884
|
-
if (requestForChild) {
|
|
885
|
-
headerData.allowTombstone = true;
|
|
886
|
-
}
|
|
887
|
-
await this.dataStores.waitIfPendingAlias(id);
|
|
888
|
-
const internalId = this.internalId(id);
|
|
889
|
-
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
890
|
-
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
891
|
-
// the same as GC nodes id.
|
|
892
|
-
const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
|
|
893
|
-
// Get the initial snapshot details which contain the data store package path.
|
|
894
|
-
const details = await dataStoreContext.getInitialSnapshotDetails();
|
|
895
|
-
// Note that this will throw if the data store is inactive or tombstoned and throwing on incorrect usage
|
|
896
|
-
// is configured.
|
|
897
|
-
this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, details.pkg, request, headerData);
|
|
898
|
-
return dataStoreContext.realize();
|
|
1035
|
+
return this.channelCollection.internalId(maybeAlias);
|
|
899
1036
|
}
|
|
900
1037
|
/** Adds the container's metadata to the given summary tree. */
|
|
901
1038
|
addMetadataToSummary(summaryTree) {
|
|
@@ -910,22 +1047,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
910
1047
|
message: extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
|
|
911
1048
|
this.messageAtLastSummary,
|
|
912
1049
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
913
|
-
|
|
1050
|
+
idCompressorMode: this.idCompressorMode,
|
|
914
1051
|
};
|
|
915
1052
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
916
1053
|
}
|
|
917
1054
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
918
1055
|
this.addMetadataToSummary(summaryTree);
|
|
919
|
-
if (this.
|
|
920
|
-
|
|
921
|
-
const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
|
|
1056
|
+
if (this._idCompressor) {
|
|
1057
|
+
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
922
1058
|
addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
|
|
923
1059
|
}
|
|
924
1060
|
if (this.remoteMessageProcessor.partialMessages.size > 0) {
|
|
925
1061
|
const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
|
|
926
1062
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
927
1063
|
}
|
|
928
|
-
const dataStoreAliases = this.
|
|
1064
|
+
const dataStoreAliases = this.channelCollection.aliases;
|
|
929
1065
|
if (dataStoreAliases.size > 0) {
|
|
930
1066
|
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
931
1067
|
}
|
|
@@ -937,7 +1073,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
937
1073
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
938
1074
|
// and the blob manager can handle the tree not existing when loading
|
|
939
1075
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
940
|
-
|
|
1076
|
+
addSummarizeResultToSummary(summaryTree, blobsTreeName, blobManagerSummary);
|
|
941
1077
|
}
|
|
942
1078
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
943
1079
|
if (gcSummary !== undefined) {
|
|
@@ -1024,13 +1160,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1024
1160
|
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
1025
1161
|
switch (opContents.type) {
|
|
1026
1162
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1027
|
-
return this.dataStores.applyStashedOp(opContents.contents);
|
|
1028
1163
|
case ContainerMessageType.Attach:
|
|
1029
|
-
|
|
1164
|
+
case ContainerMessageType.Alias:
|
|
1165
|
+
return this.channelCollection.applyStashedOp(opContents);
|
|
1030
1166
|
case ContainerMessageType.IdAllocation:
|
|
1031
|
-
assert(this.
|
|
1167
|
+
assert(this.idCompressorMode !== "off", 0x8f1 /* ID compressor should be in use */);
|
|
1032
1168
|
return;
|
|
1033
|
-
case ContainerMessageType.Alias:
|
|
1034
1169
|
case ContainerMessageType.BlobAttach:
|
|
1035
1170
|
return;
|
|
1036
1171
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -1055,10 +1190,26 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1055
1190
|
this.closeFn(error);
|
|
1056
1191
|
throw error;
|
|
1057
1192
|
}
|
|
1193
|
+
// Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
|
|
1194
|
+
// All we can do is ignore it (similar to on process).
|
|
1058
1195
|
}
|
|
1059
1196
|
}
|
|
1060
1197
|
}
|
|
1061
1198
|
setConnectionState(connected, clientId) {
|
|
1199
|
+
if (connected && this.idCompressorMode === "delayed" && !this.compressorLoadInitiated) {
|
|
1200
|
+
this.compressorLoadInitiated = true;
|
|
1201
|
+
this.createIdCompressor()
|
|
1202
|
+
.then((compressor) => {
|
|
1203
|
+
this._idCompressor = compressor;
|
|
1204
|
+
for (const range of this.pendingIdCompressorOps) {
|
|
1205
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
1206
|
+
}
|
|
1207
|
+
this.pendingIdCompressorOps = [];
|
|
1208
|
+
})
|
|
1209
|
+
.catch((error) => {
|
|
1210
|
+
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1062
1213
|
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
1063
1214
|
this.delayConnectClientId = undefined;
|
|
1064
1215
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -1122,7 +1273,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1122
1273
|
if (changeOfState) {
|
|
1123
1274
|
this.replayPendingStates();
|
|
1124
1275
|
}
|
|
1125
|
-
this.
|
|
1276
|
+
this.channelCollection.setConnectionState(connected, clientId);
|
|
1126
1277
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
1127
1278
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
1128
1279
|
}
|
|
@@ -1205,23 +1356,28 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1205
1356
|
const { local } = messageWithContext;
|
|
1206
1357
|
switch (messageWithContext.message.type) {
|
|
1207
1358
|
case ContainerMessageType.Attach:
|
|
1208
|
-
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
1209
|
-
break;
|
|
1210
1359
|
case ContainerMessageType.Alias:
|
|
1211
|
-
this.dataStores.processAliasMessage(messageWithContext.message, localOpMetadata, local);
|
|
1212
|
-
break;
|
|
1213
1360
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1214
|
-
this.
|
|
1361
|
+
this.channelCollection.process(messageWithContext.message, local, localOpMetadata, (from, to) => this.garbageCollector.addedOutboundReference(from, to));
|
|
1215
1362
|
break;
|
|
1216
1363
|
case ContainerMessageType.BlobAttach:
|
|
1217
1364
|
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
1218
1365
|
break;
|
|
1219
1366
|
case ContainerMessageType.IdAllocation:
|
|
1220
|
-
assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1221
1367
|
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
1222
1368
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1223
|
-
|
|
1224
|
-
|
|
1369
|
+
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1370
|
+
// thus we need to process all the ops.
|
|
1371
|
+
if (!(this.skipSavedCompressorOps &&
|
|
1372
|
+
messageWithContext.message.metadata?.savedOp ===
|
|
1373
|
+
true)) {
|
|
1374
|
+
const range = messageWithContext.message.contents;
|
|
1375
|
+
if (this._idCompressor === undefined) {
|
|
1376
|
+
this.pendingIdCompressorOps.push(range);
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
1380
|
+
}
|
|
1225
1381
|
}
|
|
1226
1382
|
break;
|
|
1227
1383
|
case ContainerMessageType.GC:
|
|
@@ -1308,7 +1464,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1308
1464
|
this.emit("signal", transformed, local);
|
|
1309
1465
|
return;
|
|
1310
1466
|
}
|
|
1311
|
-
|
|
1467
|
+
// Due to a mismatch between different layers in terms of
|
|
1468
|
+
// what is the interface of passing signals, we need to adjust
|
|
1469
|
+
// the signal envelope before sending it to the datastores to be processed
|
|
1470
|
+
const envelope2 = {
|
|
1471
|
+
address: envelope.address,
|
|
1472
|
+
contents: transformed.content,
|
|
1473
|
+
};
|
|
1474
|
+
transformed.content = envelope2;
|
|
1475
|
+
this.channelCollection.processSignal(transformed, local);
|
|
1312
1476
|
}
|
|
1313
1477
|
/**
|
|
1314
1478
|
* Flush the pending ops manually.
|
|
@@ -1372,9 +1536,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1372
1536
|
* Returns undefined if no data store has been assigned the given alias.
|
|
1373
1537
|
*/
|
|
1374
1538
|
async getAliasedDataStoreEntryPoint(alias) {
|
|
1375
|
-
|
|
1539
|
+
// Back-comapatibility:
|
|
1540
|
+
// There are old files that were created without using data store aliasing feature, but
|
|
1541
|
+
// used createRoot*DataStore*() (already removed) API. Such data stores will have isRoot = true,
|
|
1542
|
+
// and internalID provided by user. The expectation is that such files behave as new files, where
|
|
1543
|
+
// same data store instances created using aliasing feature.
|
|
1544
|
+
// Please also see note on name collisions in DataStores.createDataStoreId()
|
|
1545
|
+
await this.channelCollection.waitIfPendingAlias(alias);
|
|
1376
1546
|
const internalId = this.internalId(alias);
|
|
1377
|
-
const context = await this.
|
|
1547
|
+
const context = await this.channelCollection.getDataStoreIfAvailable(internalId, {
|
|
1548
|
+
wait: false,
|
|
1549
|
+
});
|
|
1378
1550
|
// If the data store is not available or not an alias, return undefined.
|
|
1379
1551
|
if (context === undefined || !(await context.isRoot())) {
|
|
1380
1552
|
return undefined;
|
|
@@ -1386,28 +1558,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1386
1558
|
this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
|
|
1387
1559
|
return channel.entryPoint;
|
|
1388
1560
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
1392
|
-
}
|
|
1393
|
-
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
1561
|
+
createDetachedDataStore(pkg, loadingGroupId) {
|
|
1562
|
+
return this.channelCollection.createDetachedDataStoreCore(pkg, loadingGroupId);
|
|
1394
1563
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
const id = uuid();
|
|
1400
|
-
return channelToDataStore(await this.dataStores
|
|
1401
|
-
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
|
|
1402
|
-
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1564
|
+
async createDataStore(pkg, loadingGroupId) {
|
|
1565
|
+
const context = this.channelCollection._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], undefined, // props
|
|
1566
|
+
loadingGroupId);
|
|
1567
|
+
return channelToDataStore(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1403
1568
|
}
|
|
1404
1569
|
/**
|
|
1405
1570
|
* @deprecated 0.16 Issue #1537, #3631
|
|
1406
1571
|
*/
|
|
1407
|
-
async _createDataStoreWithProps(pkg, props
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1572
|
+
async _createDataStoreWithProps(pkg, props) {
|
|
1573
|
+
const context = this.channelCollection._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], props);
|
|
1574
|
+
return channelToDataStore(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1411
1575
|
}
|
|
1412
1576
|
canSendOps() {
|
|
1413
1577
|
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
@@ -1485,16 +1649,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1485
1649
|
const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
|
|
1486
1650
|
return this.submitSignalFn(envelope, targetClientId);
|
|
1487
1651
|
}
|
|
1488
|
-
/**
|
|
1489
|
-
* Submits the signal to be sent to other clients.
|
|
1490
|
-
* @param type - Type of the signal.
|
|
1491
|
-
* @param content - Content of the signal.
|
|
1492
|
-
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
1493
|
-
*/
|
|
1494
|
-
submitDataStoreSignal(address, type, content, targetClientId) {
|
|
1495
|
-
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
1496
|
-
return this.submitSignalFn(envelope, targetClientId);
|
|
1497
|
-
}
|
|
1498
1652
|
setAttachState(attachState) {
|
|
1499
1653
|
if (attachState === AttachState.Attaching) {
|
|
1500
1654
|
assert(this.attachState === AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
|
|
@@ -1506,7 +1660,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1506
1660
|
if (attachState === AttachState.Attached && !this.hasPendingMessages()) {
|
|
1507
1661
|
this.updateDocumentDirtyState(false);
|
|
1508
1662
|
}
|
|
1509
|
-
this.
|
|
1663
|
+
this.channelCollection.setAttachState(attachState);
|
|
1510
1664
|
}
|
|
1511
1665
|
/**
|
|
1512
1666
|
* Create a summary. Used when attaching or serializing a detached container.
|
|
@@ -1521,18 +1675,18 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1521
1675
|
this.blobManager.setRedirectTable(blobRedirectTable);
|
|
1522
1676
|
}
|
|
1523
1677
|
// We can finalize any allocated IDs since we're the only client
|
|
1524
|
-
const idRange = this.
|
|
1678
|
+
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
1525
1679
|
if (idRange !== undefined) {
|
|
1526
|
-
this.
|
|
1680
|
+
this._idCompressor?.finalizeCreationRange(idRange);
|
|
1527
1681
|
}
|
|
1528
|
-
const summarizeResult = this.
|
|
1682
|
+
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
1529
1683
|
// Wrap data store summaries in .channels subtree.
|
|
1530
1684
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
1531
1685
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
1532
1686
|
return summarizeResult.summary;
|
|
1533
1687
|
}
|
|
1534
1688
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
1535
|
-
const summarizeResult = await this.
|
|
1689
|
+
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
1536
1690
|
// Wrap data store summaries in .channels subtree.
|
|
1537
1691
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
1538
1692
|
const pathPartsForChildren = [channelsTreeName];
|
|
@@ -1580,10 +1734,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1580
1734
|
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
1581
1735
|
*/
|
|
1582
1736
|
async updateStateBeforeGC() {
|
|
1583
|
-
return this.
|
|
1737
|
+
return this.channelCollection.updateStateBeforeGC();
|
|
1584
1738
|
}
|
|
1585
1739
|
async getGCDataInternal(fullGC) {
|
|
1586
|
-
return this.
|
|
1740
|
+
return this.channelCollection.getGCData(fullGC);
|
|
1587
1741
|
}
|
|
1588
1742
|
/**
|
|
1589
1743
|
* Generates and returns the GC data for this container.
|
|
@@ -1609,7 +1763,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1609
1763
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1610
1764
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1611
1765
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
1612
|
-
this.
|
|
1766
|
+
this.channelCollection.updateUsedRoutes(dataStoreRoutes);
|
|
1613
1767
|
}
|
|
1614
1768
|
/**
|
|
1615
1769
|
* This is called to update objects whose routes are unused.
|
|
@@ -1618,7 +1772,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1618
1772
|
updateUnusedRoutes(unusedRoutes) {
|
|
1619
1773
|
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
1620
1774
|
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1621
|
-
this.
|
|
1775
|
+
this.channelCollection.updateUnusedRoutes(dataStoreRoutes);
|
|
1622
1776
|
}
|
|
1623
1777
|
/**
|
|
1624
1778
|
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
@@ -1633,7 +1787,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1633
1787
|
*/
|
|
1634
1788
|
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
1635
1789
|
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
1636
|
-
const deletedRoutes = this.
|
|
1790
|
+
const deletedRoutes = this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes);
|
|
1637
1791
|
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
1638
1792
|
}
|
|
1639
1793
|
/**
|
|
@@ -1647,7 +1801,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1647
1801
|
updateTombstonedRoutes(tombstonedRoutes) {
|
|
1648
1802
|
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
1649
1803
|
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
1650
|
-
this.
|
|
1804
|
+
this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
|
|
1651
1805
|
}
|
|
1652
1806
|
/**
|
|
1653
1807
|
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
@@ -1665,19 +1819,24 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1665
1819
|
if (this.isBlobPath(nodePath)) {
|
|
1666
1820
|
return GCNodeType.Blob;
|
|
1667
1821
|
}
|
|
1668
|
-
return this.
|
|
1822
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
1669
1823
|
}
|
|
1670
1824
|
/**
|
|
1671
1825
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
1672
1826
|
* data store or an attachment blob.
|
|
1673
1827
|
*/
|
|
1674
1828
|
async getGCNodePackagePath(nodePath) {
|
|
1829
|
+
// GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
|
|
1830
|
+
// These have no package path so return a special value.
|
|
1831
|
+
if (nodePath === "/") {
|
|
1832
|
+
return ["_gcRoot"];
|
|
1833
|
+
}
|
|
1675
1834
|
switch (this.getNodeType(nodePath)) {
|
|
1676
1835
|
case GCNodeType.Blob:
|
|
1677
1836
|
return [BlobManager.basePath];
|
|
1678
1837
|
case GCNodeType.DataStore:
|
|
1679
1838
|
case GCNodeType.SubDataStore:
|
|
1680
|
-
return this.
|
|
1839
|
+
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
1681
1840
|
default:
|
|
1682
1841
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
1683
1842
|
}
|
|
@@ -1736,7 +1895,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1736
1895
|
* @param options - options controlling how the summary is generated or submitted
|
|
1737
1896
|
*/
|
|
1738
1897
|
async submitSummary(options) {
|
|
1739
|
-
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
|
|
1898
|
+
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
1740
1899
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1741
1900
|
// use it for all events logged during this summary.
|
|
1742
1901
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1748,7 +1907,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1748
1907
|
});
|
|
1749
1908
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
1750
1909
|
// We close the summarizer and download a new snapshot and reload the container
|
|
1751
|
-
let latestSnapshotVersionId;
|
|
1752
1910
|
if (refreshLatestAck === true) {
|
|
1753
1911
|
return this.prefetchLatestSummaryThenClose(createChildLogger({
|
|
1754
1912
|
logger: summaryNumberLogger,
|
|
@@ -1790,6 +1948,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1790
1948
|
}
|
|
1791
1949
|
}
|
|
1792
1950
|
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1951
|
+
const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
|
|
1793
1952
|
let summaryRefSeqNum;
|
|
1794
1953
|
try {
|
|
1795
1954
|
await this.deltaManager.inbound.pause();
|
|
@@ -1800,7 +1959,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1800
1959
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1801
1960
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
1802
1961
|
const lastAck = this.summaryCollection.latestAck;
|
|
1803
|
-
this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
|
|
1962
|
+
const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
|
|
1963
|
+
if (startSummaryResult.invalidNodes > 0 ||
|
|
1964
|
+
startSummaryResult.mismatchNumbers.size > 0) {
|
|
1965
|
+
summaryLogger.sendErrorEvent({
|
|
1966
|
+
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
1967
|
+
details: {
|
|
1968
|
+
...startSummaryResult,
|
|
1969
|
+
mismatchNumbers: Array.from(startSummaryResult.mismatchNumbers),
|
|
1970
|
+
},
|
|
1971
|
+
});
|
|
1972
|
+
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
1973
|
+
return {
|
|
1974
|
+
stage: "base",
|
|
1975
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1976
|
+
minimumSequenceNumber,
|
|
1977
|
+
error: `Summarizer node state inconsistent with summarizer state.`,
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1804
1981
|
// Helper function to check whether we should still continue between each async step.
|
|
1805
1982
|
const checkContinue = () => {
|
|
1806
1983
|
// Do not check for loss of connectivity directly! Instead leave it up to
|
|
@@ -1896,8 +2073,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1896
2073
|
? calculateStats(summaryTree.tree[gcTreeKey])
|
|
1897
2074
|
: undefined;
|
|
1898
2075
|
const summaryStats = {
|
|
1899
|
-
dataStoreCount: this.
|
|
1900
|
-
summarizedDataStoreCount: this.
|
|
2076
|
+
dataStoreCount: this.channelCollection.size,
|
|
2077
|
+
summarizedDataStoreCount: this.channelCollection.size - handleCount,
|
|
1901
2078
|
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
1902
2079
|
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
1903
2080
|
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
@@ -1916,34 +2093,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1916
2093
|
if (!continueResult.continue) {
|
|
1917
2094
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
1918
2095
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
// submitting the summaryOp then we can't rely on summaryAck. So in case we have
|
|
1922
|
-
// latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
|
|
1923
|
-
// the one fetched from storage as parent as that is the latest.
|
|
1924
|
-
let summaryContext;
|
|
1925
|
-
if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
|
|
1926
|
-
latestSnapshotVersionId !== undefined) {
|
|
1927
|
-
summaryContext = {
|
|
1928
|
-
proposalHandle: undefined,
|
|
1929
|
-
ackHandle: latestSnapshotVersionId,
|
|
1930
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
|
-
else if (lastAck === undefined) {
|
|
1934
|
-
summaryContext = {
|
|
2096
|
+
const summaryContext = lastAck === undefined
|
|
2097
|
+
? {
|
|
1935
2098
|
proposalHandle: undefined,
|
|
1936
2099
|
ackHandle: this.loadedFromVersionId,
|
|
1937
2100
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
else {
|
|
1941
|
-
summaryContext = {
|
|
2101
|
+
}
|
|
2102
|
+
: {
|
|
1942
2103
|
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
1943
2104
|
ackHandle: lastAck.summaryAck.contents.handle,
|
|
1944
2105
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1945
2106
|
};
|
|
1946
|
-
}
|
|
1947
2107
|
let handle;
|
|
1948
2108
|
try {
|
|
1949
2109
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
@@ -2068,48 +2228,29 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2068
2228
|
this.emit(dirty ? "dirty" : "saved");
|
|
2069
2229
|
}
|
|
2070
2230
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
address: id,
|
|
2074
|
-
contents,
|
|
2075
|
-
};
|
|
2076
|
-
this.submit({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
|
|
2077
|
-
}
|
|
2078
|
-
submitDataStoreAliasOp(contents, localOpMetadata) {
|
|
2079
|
-
const aliasMessage = contents;
|
|
2080
|
-
if (!isDataStoreAliasMessage(aliasMessage)) {
|
|
2081
|
-
throw new UsageError("malformedDataStoreAliasMessage");
|
|
2082
|
-
}
|
|
2083
|
-
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
2231
|
+
submitMessage(type, contents, localOpMetadata = undefined) {
|
|
2232
|
+
this.submit({ type, contents }, localOpMetadata);
|
|
2084
2233
|
}
|
|
2085
2234
|
async uploadBlob(blob, signal) {
|
|
2086
2235
|
this.verifyNotClosed();
|
|
2087
2236
|
return this.blobManager.createBlob(blob, signal);
|
|
2088
2237
|
}
|
|
2089
|
-
|
|
2090
|
-
if (
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
if (
|
|
2094
|
-
assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
|
|
2095
|
-
idRange = this.idCompressor.takeNextCreationRange();
|
|
2096
|
-
// Don't include the idRange if there weren't any Ids allocated
|
|
2097
|
-
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
2098
|
-
}
|
|
2099
|
-
if (idRange !== undefined) {
|
|
2238
|
+
submitIdAllocationOpIfNeeded() {
|
|
2239
|
+
if (this._idCompressor) {
|
|
2240
|
+
const idRange = this._idCompressor.takeNextCreationRange();
|
|
2241
|
+
// Don't include the idRange if there weren't any Ids allocated
|
|
2242
|
+
if (idRange?.ids !== undefined) {
|
|
2100
2243
|
const idAllocationMessage = {
|
|
2101
2244
|
type: ContainerMessageType.IdAllocation,
|
|
2102
2245
|
contents: idRange,
|
|
2103
2246
|
};
|
|
2104
|
-
idAllocationBatchMessage = {
|
|
2247
|
+
const idAllocationBatchMessage = {
|
|
2105
2248
|
contents: JSON.stringify(idAllocationMessage),
|
|
2106
2249
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2107
2250
|
metadata: undefined,
|
|
2108
2251
|
localOpMetadata: undefined,
|
|
2109
2252
|
type: ContainerMessageType.IdAllocation,
|
|
2110
2253
|
};
|
|
2111
|
-
}
|
|
2112
|
-
if (idAllocationBatchMessage !== undefined) {
|
|
2113
2254
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
2114
2255
|
}
|
|
2115
2256
|
}
|
|
@@ -2137,42 +2278,47 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2137
2278
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2138
2279
|
};
|
|
2139
2280
|
try {
|
|
2140
|
-
//
|
|
2141
|
-
// the
|
|
2142
|
-
// op
|
|
2143
|
-
//
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
// Is it safe:
|
|
2147
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2148
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2149
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
2150
|
-
// Why:
|
|
2151
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2152
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2153
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2154
|
-
// these issues.
|
|
2155
|
-
// Cons:
|
|
2156
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2157
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2158
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2159
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2160
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2161
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2162
|
-
// issue than sending.
|
|
2163
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2164
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2165
|
-
if (this.currentlyBatching() &&
|
|
2166
|
-
type === ContainerMessageType.Attach &&
|
|
2167
|
-
this.disableAttachReorder !== true) {
|
|
2168
|
-
this.outbox.submitAttach(message);
|
|
2169
|
-
}
|
|
2170
|
-
else if (type === ContainerMessageType.BlobAttach) {
|
|
2171
|
-
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2172
|
-
this.outbox.submitBlobAttach(message);
|
|
2281
|
+
// If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
|
|
2282
|
+
// op into the correct batch to avoid ranges being finalized out of order.
|
|
2283
|
+
// Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
|
|
2284
|
+
// any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
|
|
2285
|
+
if (type === ContainerMessageType.IdAllocation) {
|
|
2286
|
+
this.outbox.submitIdAllocation(message);
|
|
2173
2287
|
}
|
|
2174
2288
|
else {
|
|
2175
|
-
this.
|
|
2289
|
+
this.submitIdAllocationOpIfNeeded();
|
|
2290
|
+
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
2291
|
+
// Is it safe:
|
|
2292
|
+
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2293
|
+
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2294
|
+
// is stored in some DDS, i.e. only after some other op.
|
|
2295
|
+
// Why:
|
|
2296
|
+
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2297
|
+
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2298
|
+
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2299
|
+
// these issues.
|
|
2300
|
+
// Cons:
|
|
2301
|
+
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2302
|
+
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2303
|
+
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2304
|
+
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2305
|
+
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2306
|
+
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2307
|
+
// issue than sending.
|
|
2308
|
+
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2309
|
+
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2310
|
+
if (this.currentlyBatching() &&
|
|
2311
|
+
type === ContainerMessageType.Attach &&
|
|
2312
|
+
this.disableAttachReorder !== true) {
|
|
2313
|
+
this.outbox.submitAttach(message);
|
|
2314
|
+
}
|
|
2315
|
+
else if (type === ContainerMessageType.BlobAttach) {
|
|
2316
|
+
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2317
|
+
this.outbox.submitBlobAttach(message);
|
|
2318
|
+
}
|
|
2319
|
+
else {
|
|
2320
|
+
this.outbox.submit(message);
|
|
2321
|
+
}
|
|
2176
2322
|
}
|
|
2177
2323
|
if (!this.currentlyBatching()) {
|
|
2178
2324
|
this.flush();
|
|
@@ -2288,14 +2434,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2288
2434
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2289
2435
|
*/
|
|
2290
2436
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2437
|
+
assert(!this.isSummarizerClient, 0x8f2 /* Summarizer never reconnects so should never resubmit */);
|
|
2291
2438
|
switch (message.type) {
|
|
2292
2439
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2440
|
+
case ContainerMessageType.Attach:
|
|
2441
|
+
case ContainerMessageType.Alias:
|
|
2293
2442
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
2294
2443
|
// and trigger resubmission on it.
|
|
2295
|
-
this.
|
|
2444
|
+
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2296
2445
|
break;
|
|
2297
|
-
case ContainerMessageType.Attach:
|
|
2298
|
-
case ContainerMessageType.Alias:
|
|
2299
2446
|
case ContainerMessageType.IdAllocation: {
|
|
2300
2447
|
this.submit(message, localOpMetadata);
|
|
2301
2448
|
break;
|
|
@@ -2309,13 +2456,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2309
2456
|
this.submit(message);
|
|
2310
2457
|
break;
|
|
2311
2458
|
case ContainerMessageType.GC:
|
|
2312
|
-
|
|
2313
|
-
|
|
2459
|
+
this.submit(message);
|
|
2460
|
+
break;
|
|
2314
2461
|
default: {
|
|
2315
2462
|
// This case should be very rare - it would imply an op was stashed from a
|
|
2316
|
-
// future version of runtime code and now is being applied on an older version
|
|
2463
|
+
// future version of runtime code and now is being applied on an older version.
|
|
2317
2464
|
const compatBehavior = message.compatDetails?.behavior;
|
|
2318
2465
|
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
2466
|
+
// We do not ultimately resubmit it, to be consistent with this version of the code.
|
|
2319
2467
|
this.logger.sendTelemetryEvent({
|
|
2320
2468
|
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
2321
2469
|
messageDetails: { type: message.type, compatBehavior },
|
|
@@ -2341,7 +2489,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2341
2489
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2342
2490
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
2343
2491
|
// and trigger rollback on it.
|
|
2344
|
-
this.
|
|
2492
|
+
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
2345
2493
|
break;
|
|
2346
2494
|
default:
|
|
2347
2495
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -2362,31 +2510,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2362
2510
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
2363
2511
|
*/
|
|
2364
2512
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
2365
|
-
|
|
2513
|
+
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
2366
2514
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
2367
2515
|
ackHandle,
|
|
2368
2516
|
targetSequenceNumber: summaryRefSeq,
|
|
2369
2517
|
}, readAndParseBlob);
|
|
2370
|
-
|
|
2371
|
-
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
2372
|
-
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
2373
|
-
* However, there are couple of scenarios where it's possible:
|
|
2374
|
-
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
2375
|
-
* the document being unusable and we should not proceed.
|
|
2376
|
-
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
2377
|
-
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
2378
|
-
* state.
|
|
2379
|
-
*/
|
|
2380
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
2381
|
-
const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
2382
|
-
ackHandle,
|
|
2383
|
-
summaryRefSeq,
|
|
2384
|
-
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
2385
|
-
});
|
|
2386
|
-
this.disposeFn(error);
|
|
2387
|
-
throw error;
|
|
2388
|
-
}
|
|
2389
|
-
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
2518
|
+
await this.closeStaleSummarizer();
|
|
2390
2519
|
return;
|
|
2391
2520
|
}
|
|
2392
2521
|
// Notify the garbage collector so it can update its latest summary state.
|
|
@@ -2405,7 +2534,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2405
2534
|
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
2406
2535
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2407
2536
|
}, readAndParseBlob);
|
|
2408
|
-
await this.closeStaleSummarizer(
|
|
2537
|
+
await this.closeStaleSummarizer();
|
|
2409
2538
|
return {
|
|
2410
2539
|
stage: "base",
|
|
2411
2540
|
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
@@ -2413,7 +2542,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2413
2542
|
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
2414
2543
|
};
|
|
2415
2544
|
}
|
|
2416
|
-
async closeStaleSummarizer(
|
|
2545
|
+
async closeStaleSummarizer() {
|
|
2417
2546
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2418
2547
|
await delay(this.closeSummarizerDelayMs);
|
|
2419
2548
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
@@ -2445,44 +2574,43 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2445
2574
|
};
|
|
2446
2575
|
});
|
|
2447
2576
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
// try to change its value
|
|
2456
|
-
if (!this.imminentClosure) {
|
|
2457
|
-
this.imminentClosure = props?.notifyImminentClosure ?? this.imminentClosure;
|
|
2458
|
-
}
|
|
2459
|
-
const stopBlobAttachingSignal = props?.stopBlobAttachingSignal;
|
|
2460
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
2461
|
-
throw new UsageError("can't get state during orderSequentially");
|
|
2462
|
-
}
|
|
2463
|
-
// Flush pending batch.
|
|
2464
|
-
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2465
|
-
// to close current batch.
|
|
2466
|
-
this.flush();
|
|
2467
|
-
const pendingAttachmentBlobs = this.imminentClosure
|
|
2468
|
-
? await this.blobManager.attachAndGetPendingBlobs(stopBlobAttachingSignal)
|
|
2469
|
-
: undefined;
|
|
2577
|
+
getPendingLocalState(props) {
|
|
2578
|
+
this.verifyNotClosed();
|
|
2579
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
2580
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
2581
|
+
}
|
|
2582
|
+
this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
|
|
2583
|
+
const getSyncState = (pendingAttachmentBlobs) => {
|
|
2470
2584
|
const pending = this.pendingStateManager.getLocalState();
|
|
2471
|
-
if (
|
|
2585
|
+
if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
|
|
2472
2586
|
return; // no pending state to save
|
|
2473
2587
|
}
|
|
2474
|
-
const pendingIdCompressorState = this.
|
|
2475
|
-
|
|
2588
|
+
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
2589
|
+
return {
|
|
2476
2590
|
pending,
|
|
2477
|
-
pendingAttachmentBlobs,
|
|
2478
2591
|
pendingIdCompressorState,
|
|
2592
|
+
pendingAttachmentBlobs,
|
|
2593
|
+
sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
|
|
2479
2594
|
};
|
|
2595
|
+
};
|
|
2596
|
+
const perfEvent = {
|
|
2597
|
+
eventName: "getPendingLocalState",
|
|
2598
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
2599
|
+
};
|
|
2600
|
+
const logAndReturnPendingState = (event, pendingState) => {
|
|
2480
2601
|
event.end({
|
|
2481
|
-
attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
|
|
2482
|
-
pendingOpsSize: pending?.pendingStates.length,
|
|
2602
|
+
attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
|
|
2603
|
+
pendingOpsSize: pendingState?.pending?.pendingStates.length,
|
|
2483
2604
|
});
|
|
2484
2605
|
return pendingState;
|
|
2485
|
-
}
|
|
2606
|
+
};
|
|
2607
|
+
// Flush pending batch.
|
|
2608
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2609
|
+
// to close current batch.
|
|
2610
|
+
this.flush();
|
|
2611
|
+
return props?.notifyImminentClosure === true
|
|
2612
|
+
? PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) => logAndReturnPendingState(event, getSyncState(await this.blobManager.attachAndGetPendingBlobs(props?.stopBlobAttachingSignal))))
|
|
2613
|
+
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) => logAndReturnPendingState(event, getSyncState()));
|
|
2486
2614
|
}
|
|
2487
2615
|
summarizeOnDemand(options) {
|
|
2488
2616
|
if (this.isSummarizerClient) {
|
|
@@ -2536,4 +2664,4 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2536
2664
|
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
2537
2665
|
}
|
|
2538
2666
|
}
|
|
2539
|
-
//# sourceMappingURL=containerRuntime.
|
|
2667
|
+
//# sourceMappingURL=containerRuntime.js.map
|