@fluidframework/container-runtime 2.0.0-dev-rc.1.0.0.228517 → 2.0.0-dev-rc.2.0.0.245554
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 +46 -1
- 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 +435 -33
- 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.d.ts +0 -5
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +0 -12
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +225 -0
- package/dist/channelCollection.d.ts.map +1 -0
- package/dist/{dataStores.js → channelCollection.js} +449 -143
- 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 +138 -49
- package/dist/container-runtime-beta.d.ts +75 -9
- package/dist/container-runtime-public.d.ts +75 -9
- package/dist/container-runtime-untrimmed.d.ts +717 -49
- 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 +84 -64
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +550 -427
- 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 +118 -38
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +249 -161
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +2 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +1 -0
- 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 +29 -7
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +179 -98
- 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 +30 -23
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +40 -15
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +11 -4
- 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 +11 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -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 -6
- package/lib/blobManager.d.ts.map +1 -0
- package/lib/{blobManager.mjs → blobManager.js} +1 -13
- package/lib/blobManager.js.map +1 -0
- package/lib/channelCollection.d.ts +225 -0
- package/lib/channelCollection.d.ts.map +1 -0
- package/lib/{dataStores.mjs → channelCollection.js} +436 -133
- 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} +138 -49
- package/lib/{container-runtime-beta.d.mts → container-runtime-beta.d.ts} +75 -9
- package/lib/{container-runtime-public.d.mts → container-runtime-public.d.ts} +75 -9
- package/lib/{container-runtime-untrimmed.d.mts → container-runtime-untrimmed.d.ts} +717 -49
- 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} +89 -65
- package/lib/containerRuntime.d.ts.map +1 -0
- package/lib/{containerRuntime.mjs → containerRuntime.js} +469 -348
- 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} +119 -39
- package/lib/dataStoreContext.d.ts.map +1 -0
- package/lib/{dataStoreContext.mjs → dataStoreContext.js} +241 -153
- package/lib/dataStoreContext.js.map +1 -0
- package/lib/{dataStoreContexts.d.mts → dataStoreContexts.d.ts} +3 -2
- package/lib/dataStoreContexts.d.ts.map +1 -0
- package/lib/{dataStoreContexts.mjs → dataStoreContexts.js} +2 -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} +30 -8
- package/lib/gc/garbageCollection.d.ts.map +1 -0
- package/lib/gc/{garbageCollection.mjs → garbageCollection.js} +149 -68
- 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} +14 -7
- package/lib/gc/gcConfigs.js.map +1 -0
- package/lib/gc/{gcDefinitions.d.mts → gcDefinitions.d.ts} +41 -16
- package/lib/gc/gcDefinitions.d.ts.map +1 -0
- package/lib/gc/{gcDefinitions.mjs → gcDefinitions.js} +11 -4
- 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.ts +13 -0
- 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} +12 -21
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +15 -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 +138 -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 +771 -0
- package/lib/test/dataStoreContext.spec.js.map +1 -0
- package/lib/test/dataStoreCreation.spec.js +303 -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 +1464 -0
- package/lib/test/gc/garbageCollection.spec.js.map +1 -0
- package/lib/test/gc/gcConfigs.spec.js +689 -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 +390 -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 +106 -87
- package/src/batchTracker.ts +1 -1
- package/src/blobManager.ts +1 -15
- package/src/{dataStores.ts → channelCollection.ts} +622 -170
- package/src/connectionTelemetry.ts +42 -3
- package/src/containerHandleContext.ts +1 -1
- package/src/containerRuntime.ts +683 -483
- package/src/dataStore.ts +16 -15
- package/src/dataStoreContext.ts +378 -216
- package/src/dataStoreContexts.ts +2 -1
- package/src/deltaManagerSummarizerProxy.ts +132 -7
- package/src/gc/garbageCollection.ts +167 -71
- package/src/gc/gcConfigs.ts +17 -7
- package/src/gc/gcDefinitions.ts +42 -16
- 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 +11 -9
- package/src/index.ts +29 -26
- 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 +0 -13
- package/lib/gc/index.d.mts.map +0 -1
- package/lib/gc/index.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -24
- package/lib/index.mjs.map +0 -1
- package/lib/messageTypes.d.mts.map +0 -1
- package/lib/messageTypes.mjs.map +0 -1
- package/lib/metadata.d.mts.map +0 -1
- package/lib/metadata.mjs.map +0 -1
- package/lib/opLifecycle/batchManager.d.mts.map +0 -1
- package/lib/opLifecycle/batchManager.mjs.map +0 -1
- package/lib/opLifecycle/definitions.d.mts.map +0 -1
- package/lib/opLifecycle/definitions.mjs.map +0 -1
- package/lib/opLifecycle/index.d.mts +0 -13
- package/lib/opLifecycle/index.d.mts.map +0 -1
- package/lib/opLifecycle/index.mjs +0 -12
- package/lib/opLifecycle/index.mjs.map +0 -1
- package/lib/opLifecycle/opCompressor.d.mts.map +0 -1
- package/lib/opLifecycle/opCompressor.mjs.map +0 -1
- package/lib/opLifecycle/opDecompressor.d.mts.map +0 -1
- package/lib/opLifecycle/opDecompressor.mjs.map +0 -1
- package/lib/opLifecycle/opGroupingManager.d.mts.map +0 -1
- package/lib/opLifecycle/opGroupingManager.mjs.map +0 -1
- package/lib/opLifecycle/opSplitter.d.mts.map +0 -1
- package/lib/opLifecycle/opSplitter.mjs.map +0 -1
- package/lib/opLifecycle/outbox.d.mts.map +0 -1
- package/lib/opLifecycle/outbox.mjs.map +0 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +0 -1
- package/lib/opLifecycle/remoteMessageProcessor.mjs.map +0 -1
- package/lib/opProperties.d.mts.map +0 -1
- package/lib/opProperties.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/pendingStateManager.d.mts.map +0 -1
- package/lib/pendingStateManager.mjs.map +0 -1
- package/lib/scheduleManager.d.mts.map +0 -1
- package/lib/scheduleManager.mjs.map +0 -1
- package/lib/storageServiceWithAttachBlobs.d.mts.map +0 -1
- package/lib/storageServiceWithAttachBlobs.mjs.map +0 -1
- package/lib/summary/index.d.mts.map +0 -1
- package/lib/summary/index.mjs.map +0 -1
- package/lib/summary/orderedClientElection.d.mts.map +0 -1
- package/lib/summary/orderedClientElection.mjs.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.d.mts.map +0 -1
- package/lib/summary/runWhileConnectedCoordinator.mjs.map +0 -1
- package/lib/summary/runningSummarizer.d.mts.map +0 -1
- package/lib/summary/runningSummarizer.mjs.map +0 -1
- package/lib/summary/summarizer.d.mts.map +0 -1
- package/lib/summary/summarizer.mjs.map +0 -1
- package/lib/summary/summarizerClientElection.d.mts.map +0 -1
- package/lib/summary/summarizerClientElection.mjs.map +0 -1
- package/lib/summary/summarizerHeuristics.d.mts.map +0 -1
- package/lib/summary/summarizerHeuristics.mjs.map +0 -1
- package/lib/summary/summarizerNode/index.d.mts.map +0 -1
- package/lib/summary/summarizerNode/index.mjs +0 -7
- package/lib/summary/summarizerNode/index.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNode.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNode.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +0 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +0 -1
- package/lib/summary/summarizerTypes.d.mts.map +0 -1
- package/lib/summary/summarizerTypes.mjs.map +0 -1
- package/lib/summary/summaryCollection.d.mts.map +0 -1
- package/lib/summary/summaryCollection.mjs.map +0 -1
- package/lib/summary/summaryFormat.d.mts.map +0 -1
- package/lib/summary/summaryFormat.mjs.map +0 -1
- package/lib/summary/summaryGenerator.d.mts.map +0 -1
- package/lib/summary/summaryGenerator.mjs.map +0 -1
- package/lib/summary/summaryManager.d.mts.map +0 -1
- package/lib/summary/summaryManager.mjs.map +0 -1
- package/lib/throttler.d.mts.map +0 -1
- package/lib/throttler.mjs.map +0 -1
- package/src/deltaManagerProxyBase.ts +0 -111
package/src/containerRuntime.ts
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
6
|
ITelemetryBaseLogger,
|
|
7
|
-
ITelemetryGenericEvent,
|
|
8
7
|
FluidObject,
|
|
9
8
|
IFluidHandle,
|
|
10
9
|
IFluidHandleContext,
|
|
11
10
|
IRequest,
|
|
12
11
|
IResponse,
|
|
13
12
|
IProvideFluidHandleContext,
|
|
13
|
+
ISignalEnvelope,
|
|
14
14
|
} from "@fluidframework/core-interfaces";
|
|
15
15
|
import {
|
|
16
16
|
IAudience,
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
IRuntime,
|
|
21
21
|
ICriticalContainerError,
|
|
22
22
|
AttachState,
|
|
23
|
-
ILoaderOptions,
|
|
24
23
|
ILoader,
|
|
25
24
|
LoaderHeader,
|
|
26
25
|
IGetPendingLocalStateProps,
|
|
@@ -29,7 +28,7 @@ import {
|
|
|
29
28
|
IContainerRuntime,
|
|
30
29
|
IContainerRuntimeEvents,
|
|
31
30
|
} from "@fluidframework/container-runtime-definitions";
|
|
32
|
-
import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
|
|
31
|
+
import { assert, Deferred, delay, LazyPromise, PromiseCache } from "@fluidframework/core-utils";
|
|
33
32
|
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
34
33
|
import {
|
|
35
34
|
createChildLogger,
|
|
@@ -39,19 +38,22 @@ import {
|
|
|
39
38
|
GenericError,
|
|
40
39
|
raiseConnectedEvent,
|
|
41
40
|
PerformanceEvent,
|
|
42
|
-
// eslint-disable-next-line import/no-deprecated
|
|
43
41
|
TaggedLoggerAdapter,
|
|
44
42
|
MonitoringContext,
|
|
45
43
|
wrapError,
|
|
46
44
|
ITelemetryLoggerExt,
|
|
47
45
|
UsageError,
|
|
48
46
|
LoggingError,
|
|
47
|
+
createSampledLogger,
|
|
48
|
+
IEventSampler,
|
|
49
|
+
type ITelemetryGenericEventExt,
|
|
50
|
+
loggerToMonitoringContext,
|
|
49
51
|
} from "@fluidframework/telemetry-utils";
|
|
50
52
|
import {
|
|
51
53
|
DriverHeader,
|
|
52
54
|
FetchSource,
|
|
53
55
|
IDocumentStorageService,
|
|
54
|
-
|
|
56
|
+
type ISnapshot,
|
|
55
57
|
} from "@fluidframework/driver-definitions";
|
|
56
58
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
57
59
|
import {
|
|
@@ -73,11 +75,8 @@ import {
|
|
|
73
75
|
InboundAttachMessage,
|
|
74
76
|
IFluidDataStoreContextDetached,
|
|
75
77
|
IFluidDataStoreRegistry,
|
|
76
|
-
IFluidDataStoreChannel,
|
|
77
78
|
IGarbageCollectionData,
|
|
78
|
-
IEnvelope,
|
|
79
79
|
IInboundSignalMessage,
|
|
80
|
-
ISignalEnvelope,
|
|
81
80
|
NamedFluidDataStoreRegistryEntries,
|
|
82
81
|
ISummaryTreeWithStats,
|
|
83
82
|
ISummarizeInternalResult,
|
|
@@ -86,18 +85,18 @@ import {
|
|
|
86
85
|
channelsTreeName,
|
|
87
86
|
IDataStore,
|
|
88
87
|
ITelemetryContext,
|
|
88
|
+
IEnvelope,
|
|
89
89
|
} from "@fluidframework/runtime-definitions";
|
|
90
90
|
import type {
|
|
91
91
|
SerializedIdCompressorWithNoSession,
|
|
92
92
|
IIdCompressor,
|
|
93
93
|
IIdCompressorCore,
|
|
94
|
-
IdCreationRange,
|
|
95
94
|
SerializedIdCompressorWithOngoingSession,
|
|
95
|
+
IdCreationRange,
|
|
96
96
|
} from "@fluidframework/id-compressor";
|
|
97
97
|
import {
|
|
98
98
|
addBlobToSummary,
|
|
99
99
|
addSummarizeResultToSummary,
|
|
100
|
-
addTreeToSummary,
|
|
101
100
|
RequestParser,
|
|
102
101
|
create404Response,
|
|
103
102
|
exceptionToResponse,
|
|
@@ -109,17 +108,17 @@ import {
|
|
|
109
108
|
responseToException,
|
|
110
109
|
} from "@fluidframework/runtime-utils";
|
|
111
110
|
import { v4 as uuid } from "uuid";
|
|
112
|
-
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
113
|
-
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
114
|
-
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
|
|
111
|
+
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
112
|
+
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
113
|
+
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry.js";
|
|
115
114
|
import {
|
|
116
115
|
IPendingBatchMessage,
|
|
117
116
|
IPendingLocalState,
|
|
118
117
|
PendingStateManager,
|
|
119
|
-
} from "./pendingStateManager";
|
|
120
|
-
import { pkgVersion } from "./packageVersion";
|
|
121
|
-
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager";
|
|
122
|
-
import {
|
|
118
|
+
} from "./pendingStateManager.js";
|
|
119
|
+
import { pkgVersion } from "./packageVersion.js";
|
|
120
|
+
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager.js";
|
|
121
|
+
import { ChannelCollection, getSummaryForDatastores, wrapContext } from "./channelCollection.js";
|
|
123
122
|
import {
|
|
124
123
|
aliasBlobName,
|
|
125
124
|
blobsTreeName,
|
|
@@ -159,8 +158,10 @@ import {
|
|
|
159
158
|
ISummarizerEvents,
|
|
160
159
|
IBaseSummarizeResult,
|
|
161
160
|
ISummarizer,
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
rootHasIsolatedChannels,
|
|
162
|
+
IdCompressorMode,
|
|
163
|
+
} from "./summary/index.js";
|
|
164
|
+
import { formExponentialFn, Throttler } from "./throttler.js";
|
|
164
165
|
import {
|
|
165
166
|
GarbageCollector,
|
|
166
167
|
GCNodeType,
|
|
@@ -168,11 +169,10 @@ import {
|
|
|
168
169
|
IGarbageCollector,
|
|
169
170
|
IGCRuntimeOptions,
|
|
170
171
|
IGCStats,
|
|
171
|
-
|
|
172
|
-
} from "./
|
|
173
|
-
import {
|
|
174
|
-
import {
|
|
175
|
-
import { ScheduleManager } from "./scheduleManager";
|
|
172
|
+
} from "./gc/index.js";
|
|
173
|
+
import { channelToDataStore } from "./dataStore.js";
|
|
174
|
+
import { BindBatchTracker } from "./batchTracker.js";
|
|
175
|
+
import { ScheduleManager } from "./scheduleManager.js";
|
|
176
176
|
import {
|
|
177
177
|
BatchMessage,
|
|
178
178
|
IBatch,
|
|
@@ -184,9 +184,9 @@ import {
|
|
|
184
184
|
RemoteMessageProcessor,
|
|
185
185
|
OpGroupingManager,
|
|
186
186
|
getLongStack,
|
|
187
|
-
} from "./opLifecycle";
|
|
188
|
-
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
189
|
-
import { IBatchMetadata, IIdAllocationMetadata } from "./metadata";
|
|
187
|
+
} from "./opLifecycle/index.js";
|
|
188
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
|
|
189
|
+
import { IBatchMetadata, IIdAllocationMetadata } from "./metadata.js";
|
|
190
190
|
import {
|
|
191
191
|
ContainerMessageType,
|
|
192
192
|
type InboundSequencedContainerRuntimeMessage,
|
|
@@ -196,7 +196,7 @@ import {
|
|
|
196
196
|
type OutboundContainerRuntimeMessage,
|
|
197
197
|
type UnknownContainerRuntimeMessage,
|
|
198
198
|
ContainerRuntimeGCMessage,
|
|
199
|
-
} from "./messageTypes";
|
|
199
|
+
} from "./messageTypes.js";
|
|
200
200
|
|
|
201
201
|
/**
|
|
202
202
|
* Utility to implement compat behaviors given an unknown message type
|
|
@@ -441,7 +441,7 @@ export interface IContainerRuntimeOptions {
|
|
|
441
441
|
* Enable the IdCompressor in the runtime.
|
|
442
442
|
* @experimental Not ready for use.
|
|
443
443
|
*/
|
|
444
|
-
readonly enableRuntimeIdCompressor?:
|
|
444
|
+
readonly enableRuntimeIdCompressor?: IdCompressorMode;
|
|
445
445
|
|
|
446
446
|
/**
|
|
447
447
|
* If enabled, the runtime will block all attempts to send an op inside the
|
|
@@ -466,27 +466,6 @@ export interface IContainerRuntimeOptions {
|
|
|
466
466
|
readonly enableGroupedBatching?: boolean;
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
-
/**
|
|
470
|
-
* Accepted header keys for requests coming to the runtime.
|
|
471
|
-
* @internal
|
|
472
|
-
*/
|
|
473
|
-
export enum RuntimeHeaders {
|
|
474
|
-
/** True to wait for a data store to be created and loaded before returning it. */
|
|
475
|
-
wait = "wait",
|
|
476
|
-
/** True if the request is coming from an IFluidHandle. */
|
|
477
|
-
viaHandle = "viaHandle",
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/** True if a tombstoned object should be returned without erroring
|
|
481
|
-
* @alpha
|
|
482
|
-
*/
|
|
483
|
-
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
484
|
-
/**
|
|
485
|
-
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
486
|
-
* @internal
|
|
487
|
-
*/
|
|
488
|
-
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
489
|
-
|
|
490
469
|
/**
|
|
491
470
|
* Tombstone error responses will have this header set to true
|
|
492
471
|
* @alpha
|
|
@@ -500,6 +479,7 @@ export const InactiveResponseHeaderKey = "isInactive";
|
|
|
500
479
|
|
|
501
480
|
/**
|
|
502
481
|
* The full set of parsed header data that may be found on Runtime requests
|
|
482
|
+
* @internal
|
|
503
483
|
*/
|
|
504
484
|
export interface RuntimeHeaderData {
|
|
505
485
|
wait?: boolean;
|
|
@@ -553,6 +533,11 @@ export interface IPendingRuntimeState {
|
|
|
553
533
|
* Pending idCompressor state
|
|
554
534
|
*/
|
|
555
535
|
pendingIdCompressorState?: SerializedIdCompressorWithOngoingSession;
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Time at which session expiry timer started.
|
|
539
|
+
*/
|
|
540
|
+
sessionExpiryTimerStarted?: number | undefined;
|
|
556
541
|
}
|
|
557
542
|
|
|
558
543
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
@@ -767,7 +752,6 @@ export class ContainerRuntime
|
|
|
767
752
|
const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
|
|
768
753
|
const passLogger =
|
|
769
754
|
backCompatContext.taggedLogger ??
|
|
770
|
-
// eslint-disable-next-line import/no-deprecated
|
|
771
755
|
new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
|
|
772
756
|
const logger = createChildLogger({
|
|
773
757
|
logger: passLogger,
|
|
@@ -778,6 +762,8 @@ export class ContainerRuntime
|
|
|
778
762
|
},
|
|
779
763
|
});
|
|
780
764
|
|
|
765
|
+
const mc = loggerToMonitoringContext(logger);
|
|
766
|
+
|
|
781
767
|
const {
|
|
782
768
|
summaryOptions = {},
|
|
783
769
|
gcOptions = {},
|
|
@@ -785,7 +771,7 @@ export class ContainerRuntime
|
|
|
785
771
|
flushMode = defaultFlushMode,
|
|
786
772
|
compressionOptions = defaultCompressionConfig,
|
|
787
773
|
maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
|
|
788
|
-
enableRuntimeIdCompressor =
|
|
774
|
+
enableRuntimeIdCompressor = "off",
|
|
789
775
|
chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
790
776
|
enableOpReentryCheck = false,
|
|
791
777
|
enableGroupedBatching = false,
|
|
@@ -854,24 +840,72 @@ export class ContainerRuntime
|
|
|
854
840
|
}
|
|
855
841
|
}
|
|
856
842
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
let
|
|
860
|
-
if (
|
|
843
|
+
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
844
|
+
// allow new containers to turn it on
|
|
845
|
+
let idCompressorMode: IdCompressorMode;
|
|
846
|
+
if (existing) {
|
|
847
|
+
// This setting has to be sticky for correctness:
|
|
848
|
+
// 1) if compressior is OFF, it can't be enabled, as already running clients (in given document session) do not know
|
|
849
|
+
// how to process compressor ops
|
|
850
|
+
// 2) if it's ON, then all sessions should load compressor right away
|
|
851
|
+
// 3) Same logic applies for "delayed" mode
|
|
852
|
+
// Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
|
|
853
|
+
// We could do "off" -> "on" transtition too, if all clients start loading compressor (but not using it initially) and do so for a while -
|
|
854
|
+
// this will allow clients to eventually to disregard "off" setting (when it's safe so) and start using compressor in future sessions.
|
|
855
|
+
// Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
|
|
856
|
+
idCompressorMode = metadata?.idCompressorMode ?? "off";
|
|
857
|
+
} else {
|
|
858
|
+
// FG overwrite
|
|
859
|
+
const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
|
|
860
|
+
switch (enabled) {
|
|
861
|
+
case true:
|
|
862
|
+
idCompressorMode = "on";
|
|
863
|
+
break;
|
|
864
|
+
case false:
|
|
865
|
+
idCompressorMode = "off";
|
|
866
|
+
break;
|
|
867
|
+
default:
|
|
868
|
+
idCompressorMode = enableRuntimeIdCompressor;
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const createIdCompressorFn = async () => {
|
|
861
874
|
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import(
|
|
862
875
|
"@fluidframework/id-compressor"
|
|
863
876
|
);
|
|
864
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
880
|
+
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
881
|
+
*/
|
|
882
|
+
const idCompressorEventSampler: IEventSampler = (() => {
|
|
883
|
+
const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
|
|
884
|
+
return {
|
|
885
|
+
sample: () => {
|
|
886
|
+
return isIdCompressorTelemetryEnabled;
|
|
887
|
+
},
|
|
888
|
+
};
|
|
889
|
+
})();
|
|
890
|
+
|
|
891
|
+
const compressorLogger = createSampledLogger(logger, idCompressorEventSampler);
|
|
865
892
|
const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
|
|
866
893
|
|
|
867
894
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
868
|
-
|
|
895
|
+
return deserializeIdCompressor(
|
|
896
|
+
pendingLocalState.pendingIdCompressorState,
|
|
897
|
+
compressorLogger,
|
|
898
|
+
);
|
|
869
899
|
} else if (serializedIdCompressor !== undefined) {
|
|
870
|
-
|
|
900
|
+
return deserializeIdCompressor(
|
|
901
|
+
serializedIdCompressor,
|
|
902
|
+
createSessionId(),
|
|
903
|
+
compressorLogger,
|
|
904
|
+
);
|
|
871
905
|
} else {
|
|
872
|
-
|
|
906
|
+
return createIdCompressor(compressorLogger);
|
|
873
907
|
}
|
|
874
|
-
}
|
|
908
|
+
};
|
|
875
909
|
|
|
876
910
|
const runtime = new containerRuntimeCtor(
|
|
877
911
|
context,
|
|
@@ -897,7 +931,8 @@ export class ContainerRuntime
|
|
|
897
931
|
existing,
|
|
898
932
|
blobManagerSnapshot,
|
|
899
933
|
context.storage,
|
|
900
|
-
|
|
934
|
+
createIdCompressorFn,
|
|
935
|
+
idCompressorMode,
|
|
901
936
|
provideEntryPoint,
|
|
902
937
|
requestHandler,
|
|
903
938
|
undefined, // summaryConfiguration
|
|
@@ -913,7 +948,7 @@ export class ContainerRuntime
|
|
|
913
948
|
return runtime;
|
|
914
949
|
}
|
|
915
950
|
|
|
916
|
-
public readonly options:
|
|
951
|
+
public readonly options: Record<string | number, any>;
|
|
917
952
|
private imminentClosure: boolean = false;
|
|
918
953
|
|
|
919
954
|
private readonly _getClientId: () => string | undefined;
|
|
@@ -927,6 +962,10 @@ export class ContainerRuntime
|
|
|
927
962
|
return this._storage;
|
|
928
963
|
}
|
|
929
964
|
|
|
965
|
+
public get containerRuntime() {
|
|
966
|
+
return this;
|
|
967
|
+
}
|
|
968
|
+
|
|
930
969
|
private readonly submitFn: (
|
|
931
970
|
type: MessageType,
|
|
932
971
|
contents: any,
|
|
@@ -964,7 +1003,47 @@ export class ContainerRuntime
|
|
|
964
1003
|
return this._getAttachState();
|
|
965
1004
|
}
|
|
966
1005
|
|
|
967
|
-
|
|
1006
|
+
private _idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
|
|
1007
|
+
|
|
1008
|
+
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
1009
|
+
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
1010
|
+
private pendingIdCompressorOps: IdCreationRange[] = [];
|
|
1011
|
+
|
|
1012
|
+
// Id Compressor serializes final state (see getPendingLocalState()). As result, it needs to skip all ops that preceeded that state
|
|
1013
|
+
// (such ops will be marked by Loader layer as savedOp === true)
|
|
1014
|
+
// That said, in "delayed" mode it's possible that Id Compressor was never initialized before getPendingLocalState() is called.
|
|
1015
|
+
// In such case we have to process all ops, including those marked with saveOp === true.
|
|
1016
|
+
private readonly skipSavedCompressorOps: boolean;
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* See IContainerRuntimeBase.idCompressor() for details.
|
|
1020
|
+
*/
|
|
1021
|
+
public get idCompressor() {
|
|
1022
|
+
// Expose ID Compressor only if it's On from the start.
|
|
1023
|
+
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
1024
|
+
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
1025
|
+
// to reason over such things as session ID space.
|
|
1026
|
+
if (this.idCompressorMode === "on") {
|
|
1027
|
+
assert(
|
|
1028
|
+
this._idCompressor !== undefined,
|
|
1029
|
+
0x8ea /* compressor should have been loaded */,
|
|
1030
|
+
);
|
|
1031
|
+
return this._idCompressor;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
1037
|
+
* this.idCompressorMode === "delayed" mode
|
|
1038
|
+
*/
|
|
1039
|
+
protected compressorLoadInitiated = false;
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* See IContainerRuntimeBase.generateDocumentUniqueId() for details.
|
|
1043
|
+
*/
|
|
1044
|
+
public generateDocumentUniqueId() {
|
|
1045
|
+
return this._idCompressor?.generateDocumentUniqueId() ?? uuid();
|
|
1046
|
+
}
|
|
968
1047
|
|
|
969
1048
|
public get IFluidHandleContext(): IFluidHandleContext {
|
|
970
1049
|
return this.handleContext;
|
|
@@ -1088,7 +1167,7 @@ export class ContainerRuntime
|
|
|
1088
1167
|
private readonly outbox: Outbox;
|
|
1089
1168
|
private readonly garbageCollector: IGarbageCollector;
|
|
1090
1169
|
|
|
1091
|
-
private readonly
|
|
1170
|
+
private readonly channelCollection: ChannelCollection;
|
|
1092
1171
|
private readonly remoteMessageProcessor: RemoteMessageProcessor;
|
|
1093
1172
|
|
|
1094
1173
|
/** The last message processed at the time of the last summary. */
|
|
@@ -1104,11 +1183,6 @@ export class ContainerRuntime
|
|
|
1104
1183
|
return this.summaryConfiguration.state === "disabled";
|
|
1105
1184
|
}
|
|
1106
1185
|
|
|
1107
|
-
private readonly heuristicsDisabled: boolean;
|
|
1108
|
-
private isHeuristicsDisabled(): boolean {
|
|
1109
|
-
return this.summaryConfiguration.state === "disableHeuristics";
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
1186
|
private readonly maxOpsSinceLastSummary: number;
|
|
1113
1187
|
private getMaxOpsSinceLastSummary(): number {
|
|
1114
1188
|
return this.summaryConfiguration.state !== "disabled"
|
|
@@ -1151,11 +1225,6 @@ export class ContainerRuntime
|
|
|
1151
1225
|
*/
|
|
1152
1226
|
private readonly telemetryDocumentId: string;
|
|
1153
1227
|
|
|
1154
|
-
/**
|
|
1155
|
-
* If true, the runtime has access to an IdCompressor
|
|
1156
|
-
*/
|
|
1157
|
-
private readonly idCompressorEnabled: boolean;
|
|
1158
|
-
|
|
1159
1228
|
/**
|
|
1160
1229
|
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1161
1230
|
*/
|
|
@@ -1166,11 +1235,19 @@ export class ContainerRuntime
|
|
|
1166
1235
|
*/
|
|
1167
1236
|
private readonly loadedFromVersionId: string | undefined;
|
|
1168
1237
|
|
|
1238
|
+
/**
|
|
1239
|
+
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
1240
|
+
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
1241
|
+
*/
|
|
1242
|
+
private readonly snapshotCacheForLoadingGroupIds = new PromiseCache<string, ISnapshot>({
|
|
1243
|
+
expiry: { policy: "absolute", durationMs: 60000 },
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1169
1246
|
/***/
|
|
1170
1247
|
protected constructor(
|
|
1171
1248
|
context: IContainerContext,
|
|
1172
1249
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1173
|
-
metadata: IContainerRuntimeMetadata | undefined,
|
|
1250
|
+
private readonly metadata: IContainerRuntimeMetadata | undefined,
|
|
1174
1251
|
electedSummarizerData: ISerializedElection | undefined,
|
|
1175
1252
|
chunks: [string, string[]][],
|
|
1176
1253
|
dataStoreAliasMap: [string, string][],
|
|
@@ -1180,7 +1257,8 @@ export class ContainerRuntime
|
|
|
1180
1257
|
existing: boolean,
|
|
1181
1258
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1182
1259
|
private readonly _storage: IDocumentStorageService,
|
|
1183
|
-
|
|
1260
|
+
private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
|
|
1261
|
+
private readonly idCompressorMode: IdCompressorMode,
|
|
1184
1262
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1185
1263
|
private readonly requestHandler?: (
|
|
1186
1264
|
request: IRequest,
|
|
@@ -1224,7 +1302,9 @@ export class ContainerRuntime
|
|
|
1224
1302
|
this.submitSummaryFn = submitSummaryFn;
|
|
1225
1303
|
this.submitSignalFn = submitSignalFn;
|
|
1226
1304
|
|
|
1227
|
-
|
|
1305
|
+
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
1306
|
+
// Values are generally expected to be set from the runtime side.
|
|
1307
|
+
this.options = options ?? {};
|
|
1228
1308
|
this.clientDetails = clientDetails;
|
|
1229
1309
|
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1230
1310
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
@@ -1265,20 +1345,12 @@ export class ContainerRuntime
|
|
|
1265
1345
|
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
1266
1346
|
// the count is reset to 0.
|
|
1267
1347
|
loadSummaryNumber = metadata?.summaryNumber ?? 0;
|
|
1268
|
-
|
|
1269
|
-
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
1270
|
-
// allow new containers to turn it on
|
|
1271
|
-
this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
|
|
1272
1348
|
} else {
|
|
1273
1349
|
this.createContainerMetadata = {
|
|
1274
1350
|
createContainerRuntimeVersion: pkgVersion,
|
|
1275
1351
|
createContainerTimestamp: Date.now(),
|
|
1276
1352
|
};
|
|
1277
1353
|
loadSummaryNumber = 0;
|
|
1278
|
-
|
|
1279
|
-
this.idCompressorEnabled =
|
|
1280
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
|
|
1281
|
-
idCompressor !== undefined;
|
|
1282
1354
|
}
|
|
1283
1355
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
1284
1356
|
|
|
@@ -1346,14 +1418,9 @@ export class ContainerRuntime
|
|
|
1346
1418
|
disableOpReentryCheck !== true;
|
|
1347
1419
|
|
|
1348
1420
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
1349
|
-
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
1350
1421
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
1351
1422
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
1352
1423
|
|
|
1353
|
-
if (this.idCompressorEnabled) {
|
|
1354
|
-
this.idCompressor = idCompressor;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
1424
|
this.maxConsecutiveReconnects =
|
|
1358
1425
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
1359
1426
|
this.defaultMaxConsecutiveReconnects;
|
|
@@ -1371,15 +1438,17 @@ export class ContainerRuntime
|
|
|
1371
1438
|
|
|
1372
1439
|
const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
|
|
1373
1440
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1441
|
+
if (context.attachState === AttachState.Attached) {
|
|
1442
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1443
|
+
if (
|
|
1444
|
+
maxSnapshotCacheDurationMs !== undefined &&
|
|
1445
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000
|
|
1446
|
+
) {
|
|
1447
|
+
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
1448
|
+
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
1449
|
+
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
1450
|
+
throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
1451
|
+
}
|
|
1383
1452
|
}
|
|
1384
1453
|
|
|
1385
1454
|
this.garbageCollector = GarbageCollector.create({
|
|
@@ -1395,6 +1464,7 @@ export class ContainerRuntime
|
|
|
1395
1464
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1396
1465
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1397
1466
|
submitMessage: (message: ContainerRuntimeGCMessage) => this.submit(message),
|
|
1467
|
+
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
1398
1468
|
});
|
|
1399
1469
|
|
|
1400
1470
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
@@ -1411,9 +1481,6 @@ export class ContainerRuntime
|
|
|
1411
1481
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1412
1482
|
// a summary with an older protocol state.
|
|
1413
1483
|
canReuseHandle: false,
|
|
1414
|
-
// Must set to true to throw on any data stores failure that was too severe to be handled.
|
|
1415
|
-
// We also are not decoding the base summaries at the root.
|
|
1416
|
-
throwOnFailure: true,
|
|
1417
1484
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
1418
1485
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
1419
1486
|
},
|
|
@@ -1427,28 +1494,44 @@ export class ContainerRuntime
|
|
|
1427
1494
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1428
1495
|
}
|
|
1429
1496
|
|
|
1430
|
-
|
|
1497
|
+
const parentContext = wrapContext(this);
|
|
1498
|
+
|
|
1499
|
+
// Due to a mismatch between different layers in terms of
|
|
1500
|
+
// what is the interface of passing signals, we need the
|
|
1501
|
+
// downstream stores to wrap the signal.
|
|
1502
|
+
parentContext.submitSignal = (type: string, content: any, targetClientId?: string) => {
|
|
1503
|
+
const envelope1 = content as IEnvelope;
|
|
1504
|
+
const envelope2 = this.createNewSignalEnvelope(
|
|
1505
|
+
envelope1.address,
|
|
1506
|
+
type,
|
|
1507
|
+
envelope1.contents,
|
|
1508
|
+
);
|
|
1509
|
+
return this.submitSignalFn(envelope2, targetClientId);
|
|
1510
|
+
};
|
|
1511
|
+
|
|
1512
|
+
this.channelCollection = new ChannelCollection(
|
|
1431
1513
|
getSummaryForDatastores(baseSnapshot, metadata),
|
|
1432
|
-
|
|
1433
|
-
(attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }),
|
|
1434
|
-
(id: string, createParam: CreateChildSummarizerNodeParam) =>
|
|
1435
|
-
(
|
|
1436
|
-
summarizeInternal: SummarizeInternalFn,
|
|
1437
|
-
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1438
|
-
) =>
|
|
1439
|
-
this.summarizerNode.createChild(
|
|
1440
|
-
summarizeInternal,
|
|
1441
|
-
id,
|
|
1442
|
-
createParam,
|
|
1443
|
-
undefined,
|
|
1444
|
-
getGCDataFn,
|
|
1445
|
-
),
|
|
1446
|
-
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1514
|
+
parentContext,
|
|
1447
1515
|
this.mc.logger,
|
|
1448
|
-
(
|
|
1449
|
-
|
|
1516
|
+
(
|
|
1517
|
+
path: string,
|
|
1518
|
+
reason: "Loaded" | "Changed",
|
|
1519
|
+
timestampMs?: number,
|
|
1520
|
+
packagePath?: readonly string[],
|
|
1521
|
+
request?: IRequest,
|
|
1522
|
+
headerData?: RuntimeHeaderData,
|
|
1523
|
+
) =>
|
|
1524
|
+
this.garbageCollector.nodeUpdated(
|
|
1525
|
+
path,
|
|
1526
|
+
reason,
|
|
1527
|
+
timestampMs,
|
|
1528
|
+
packagePath,
|
|
1529
|
+
request,
|
|
1530
|
+
headerData,
|
|
1531
|
+
),
|
|
1450
1532
|
(path: string) => this.garbageCollector.isNodeDeleted(path),
|
|
1451
1533
|
new Map<string, string>(dataStoreAliasMap),
|
|
1534
|
+
async (runtime: ChannelCollection) => provideEntryPoint,
|
|
1452
1535
|
);
|
|
1453
1536
|
|
|
1454
1537
|
this.blobManager = new BlobManager(
|
|
@@ -1490,6 +1573,7 @@ export class ContainerRuntime
|
|
|
1490
1573
|
reSubmit: this.reSubmit.bind(this),
|
|
1491
1574
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1492
1575
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
1576
|
+
isAttached: () => this.attachState !== AttachState.Detached,
|
|
1493
1577
|
},
|
|
1494
1578
|
pendingRuntimeState?.pending,
|
|
1495
1579
|
this.logger,
|
|
@@ -1636,7 +1720,6 @@ export class ContainerRuntime
|
|
|
1636
1720
|
{
|
|
1637
1721
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
1638
1722
|
},
|
|
1639
|
-
this.heuristicsDisabled,
|
|
1640
1723
|
);
|
|
1641
1724
|
this.summaryManager.on("summarize", (eventProps) => {
|
|
1642
1725
|
this.emit("summarize", eventProps);
|
|
@@ -1654,26 +1737,27 @@ export class ContainerRuntime
|
|
|
1654
1737
|
this.mc.logger.sendTelemetryEvent({
|
|
1655
1738
|
eventName: "ContainerLoadStats",
|
|
1656
1739
|
...this.createContainerMetadata,
|
|
1657
|
-
...this.
|
|
1740
|
+
...this.channelCollection.containerLoadStats,
|
|
1658
1741
|
summaryNumber: loadSummaryNumber,
|
|
1659
1742
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1660
1743
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1661
1744
|
gcVersion: metadata?.gcFeature,
|
|
1662
1745
|
options: JSON.stringify(runtimeOptions),
|
|
1746
|
+
idCompressorModeMetadata: metadata?.idCompressorMode,
|
|
1747
|
+
idCompressorMode: this.idCompressorMode,
|
|
1663
1748
|
featureGates: JSON.stringify({
|
|
1664
1749
|
disableCompression,
|
|
1665
1750
|
disableOpReentryCheck,
|
|
1666
1751
|
disableChunking,
|
|
1667
1752
|
disableAttachReorder: this.disableAttachReorder,
|
|
1668
1753
|
disablePartialFlush,
|
|
1669
|
-
idCompressorEnabled: this.idCompressorEnabled,
|
|
1670
1754
|
closeSummarizerDelayOverride,
|
|
1671
1755
|
}),
|
|
1672
1756
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1673
1757
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1674
1758
|
});
|
|
1675
1759
|
|
|
1676
|
-
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
1760
|
+
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this, this.logger);
|
|
1677
1761
|
BindBatchTracker(this, this.logger);
|
|
1678
1762
|
|
|
1679
1763
|
this.entryPoint = new LazyPromise(async () => {
|
|
@@ -1686,12 +1770,52 @@ export class ContainerRuntime
|
|
|
1686
1770
|
}
|
|
1687
1771
|
return provideEntryPoint(this);
|
|
1688
1772
|
});
|
|
1773
|
+
|
|
1774
|
+
// If we loaded from pending state, then we need to skip any ops that are already accounted in such
|
|
1775
|
+
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
1776
|
+
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
public getCreateChildSummarizerNodeFn(id: string, createParam: CreateChildSummarizerNodeParam) {
|
|
1780
|
+
return (
|
|
1781
|
+
summarizeInternal: SummarizeInternalFn,
|
|
1782
|
+
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1783
|
+
) =>
|
|
1784
|
+
this.summarizerNode.createChild(
|
|
1785
|
+
summarizeInternal,
|
|
1786
|
+
id,
|
|
1787
|
+
createParam,
|
|
1788
|
+
undefined,
|
|
1789
|
+
getGCDataFn,
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
public deleteChildSummarizerNode(id: string) {
|
|
1794
|
+
return this.summarizerNode.deleteChild(id);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
/* IFluidParentContext APIs that should not be called on Root */
|
|
1798
|
+
public makeLocallyVisible() {
|
|
1799
|
+
assert(false, 0x8eb /* should not be called */);
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
public setChannelDirty(address: string) {
|
|
1803
|
+
assert(false, "should not be called");
|
|
1689
1804
|
}
|
|
1690
1805
|
|
|
1691
1806
|
/**
|
|
1692
1807
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
1693
1808
|
*/
|
|
1694
1809
|
private async initializeBaseState(): Promise<void> {
|
|
1810
|
+
if (
|
|
1811
|
+
this.idCompressorMode === "on" ||
|
|
1812
|
+
(this.idCompressorMode === "delayed" && this.connected)
|
|
1813
|
+
) {
|
|
1814
|
+
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
1815
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
1816
|
+
this._idCompressor = await this.createIdCompressor();
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1695
1819
|
await this.garbageCollector.initializeBaseState();
|
|
1696
1820
|
}
|
|
1697
1821
|
|
|
@@ -1716,12 +1840,145 @@ export class ContainerRuntime
|
|
|
1716
1840
|
}
|
|
1717
1841
|
this.garbageCollector.dispose();
|
|
1718
1842
|
this._summarizer?.dispose();
|
|
1719
|
-
this.
|
|
1843
|
+
this.channelCollection.dispose();
|
|
1720
1844
|
this.pendingStateManager.dispose();
|
|
1721
1845
|
this.emit("dispose");
|
|
1722
1846
|
this.removeAllListeners();
|
|
1723
1847
|
}
|
|
1724
1848
|
|
|
1849
|
+
/**
|
|
1850
|
+
* Api to fetch the snapshot from the service for a loadingGroupIds.
|
|
1851
|
+
* @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for.
|
|
1852
|
+
* @param pathParts - Parts of the path, which we want to extract from the snapshot tree.
|
|
1853
|
+
* @returns - snapshotTree and the sequence number of the snapshot.
|
|
1854
|
+
*/
|
|
1855
|
+
public async getSnapshotForLoadingGroupId(
|
|
1856
|
+
loadingGroupIds: string[],
|
|
1857
|
+
pathParts: string[],
|
|
1858
|
+
): Promise<{ snapshotTree: ISnapshotTree; sequenceNumber: number }> {
|
|
1859
|
+
const sortedLoadingGroupIds = loadingGroupIds.sort();
|
|
1860
|
+
assert(
|
|
1861
|
+
this.storage.getSnapshot !== undefined,
|
|
1862
|
+
0x8ed /* getSnapshot api should be defined if used */,
|
|
1863
|
+
);
|
|
1864
|
+
let loadedFromCache = true;
|
|
1865
|
+
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
1866
|
+
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
1867
|
+
// any request, then cache that as same group could be requested in future too.
|
|
1868
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(
|
|
1869
|
+
sortedLoadingGroupIds.join(),
|
|
1870
|
+
async () => {
|
|
1871
|
+
assert(
|
|
1872
|
+
this.storage.getSnapshot !== undefined,
|
|
1873
|
+
0x8ee /* getSnapshot api should be defined if used */,
|
|
1874
|
+
);
|
|
1875
|
+
loadedFromCache = false;
|
|
1876
|
+
return this.storage.getSnapshot({
|
|
1877
|
+
cacheSnapshot: false,
|
|
1878
|
+
scenarioName: "snapshotForLoadingGroupId",
|
|
1879
|
+
loadingGroupIds: sortedLoadingGroupIds,
|
|
1880
|
+
});
|
|
1881
|
+
},
|
|
1882
|
+
);
|
|
1883
|
+
|
|
1884
|
+
this.logger.sendTelemetryEvent({
|
|
1885
|
+
eventName: "GroupIdSnapshotFetched",
|
|
1886
|
+
details: JSON.stringify({
|
|
1887
|
+
fromCache: loadedFromCache,
|
|
1888
|
+
loadingGroupIds: loadingGroupIds.join(","),
|
|
1889
|
+
}),
|
|
1890
|
+
});
|
|
1891
|
+
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
1892
|
+
const hasIsolatedChannels = rootHasIsolatedChannels(this.metadata);
|
|
1893
|
+
const snapshotTreeForPath = this.getSnapshotTreeForPath(
|
|
1894
|
+
snapshot.snapshotTree,
|
|
1895
|
+
pathParts,
|
|
1896
|
+
hasIsolatedChannels,
|
|
1897
|
+
);
|
|
1898
|
+
assert(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
1899
|
+
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
1900
|
+
assert(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
|
|
1901
|
+
|
|
1902
|
+
// This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
|
|
1903
|
+
// Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
|
|
1904
|
+
// the file has been overwritten or service lost data.
|
|
1905
|
+
if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
|
|
1906
|
+
throw DataProcessingError.create(
|
|
1907
|
+
"Downloaded snapshot older than snapshot we loaded from",
|
|
1908
|
+
"getSnapshotForLoadingGroupId",
|
|
1909
|
+
undefined,
|
|
1910
|
+
{
|
|
1911
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
1912
|
+
snapshotSeqNumber,
|
|
1913
|
+
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
1914
|
+
},
|
|
1915
|
+
);
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
// If the snapshot is ahead of the last seq number of the delta manager, then catch up before
|
|
1919
|
+
// returning the snapshot.
|
|
1920
|
+
if (snapshotSeqNumber > this.deltaManager.lastSequenceNumber) {
|
|
1921
|
+
// If this is a summarizer client, which is trying to load a group and it finds that there is
|
|
1922
|
+
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
1923
|
+
// the summarizer state is not up to date.
|
|
1924
|
+
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
1925
|
+
if (this.isSummarizerClient) {
|
|
1926
|
+
throw new Error(
|
|
1927
|
+
"Summarizer client behind, loaded newer snapshot with loadingGroupId",
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
1932
|
+
const props: ITelemetryGenericEventExt = {
|
|
1933
|
+
eventName: "GroupIdSnapshotCatchup",
|
|
1934
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
1935
|
+
targetSequenceNumber: snapshotSeqNumber, // This is so we reuse some columns in telemetry
|
|
1936
|
+
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
1937
|
+
};
|
|
1938
|
+
|
|
1939
|
+
const event = PerformanceEvent.start(this.mc.logger, {
|
|
1940
|
+
...props,
|
|
1941
|
+
});
|
|
1942
|
+
// If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
|
|
1943
|
+
// as long as it's not a summarizer client.
|
|
1944
|
+
if (this.deltaManager.inbound.paused) {
|
|
1945
|
+
props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
|
|
1946
|
+
}
|
|
1947
|
+
const defP = new Deferred<boolean>();
|
|
1948
|
+
this.deltaManager.on("op", (message: ISequencedDocumentMessage) => {
|
|
1949
|
+
if (message.sequenceNumber >= snapshotSeqNumber) {
|
|
1950
|
+
defP.resolve(true);
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
await defP.promise;
|
|
1954
|
+
event.end(props);
|
|
1955
|
+
}
|
|
1956
|
+
return { snapshotTree: snapshotTreeForPath, sequenceNumber: snapshotSeqNumber };
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
/**
|
|
1960
|
+
* Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array.
|
|
1961
|
+
* @param snapshotTree - snapshot tree to look into.
|
|
1962
|
+
* @param pathParts - Part of the path, which we want to extract from the snapshot tree.
|
|
1963
|
+
* @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older
|
|
1964
|
+
* snapshots will not have trees inside ".channels", so check that.
|
|
1965
|
+
* @returns - requested snapshot tree based on the path parts.
|
|
1966
|
+
*/
|
|
1967
|
+
private getSnapshotTreeForPath(
|
|
1968
|
+
snapshotTree: ISnapshotTree,
|
|
1969
|
+
pathParts: string[],
|
|
1970
|
+
hasIsolatedChannels: boolean,
|
|
1971
|
+
): ISnapshotTree | undefined {
|
|
1972
|
+
let childTree = snapshotTree;
|
|
1973
|
+
for (const part of pathParts) {
|
|
1974
|
+
if (hasIsolatedChannels) {
|
|
1975
|
+
childTree = childTree?.trees[channelsTreeName];
|
|
1976
|
+
}
|
|
1977
|
+
childTree = childTree?.trees[part];
|
|
1978
|
+
}
|
|
1979
|
+
return childTree;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1725
1982
|
/**
|
|
1726
1983
|
* Notifies this object about the request made to the container.
|
|
1727
1984
|
* @param request - Request made to the handler.
|
|
@@ -1778,19 +2035,7 @@ export class ContainerRuntime
|
|
|
1778
2035
|
}
|
|
1779
2036
|
: create404Response(request);
|
|
1780
2037
|
} else if (requestParser.pathParts.length > 0) {
|
|
1781
|
-
|
|
1782
|
-
const requestForChild = !requestParser.isLeaf(1);
|
|
1783
|
-
const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
|
|
1784
|
-
|
|
1785
|
-
const subRequest = requestParser.createSubRequest(1);
|
|
1786
|
-
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
1787
|
-
// unintentionally modifying the url if that changes.
|
|
1788
|
-
assert(
|
|
1789
|
-
subRequest.url.startsWith("/"),
|
|
1790
|
-
0x126 /* "Expected createSubRequest url to include a leading slash" */,
|
|
1791
|
-
);
|
|
1792
|
-
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1793
|
-
return dataStore.request(subRequest);
|
|
2038
|
+
return await this.channelCollection.request(request);
|
|
1794
2039
|
}
|
|
1795
2040
|
|
|
1796
2041
|
return create404Response(request);
|
|
@@ -1808,54 +2053,7 @@ export class ContainerRuntime
|
|
|
1808
2053
|
private readonly entryPoint: LazyPromise<FluidObject>;
|
|
1809
2054
|
|
|
1810
2055
|
private internalId(maybeAlias: string): string {
|
|
1811
|
-
return this.
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
private async getDataStoreFromRequest(
|
|
1815
|
-
id: string,
|
|
1816
|
-
request: IRequest,
|
|
1817
|
-
requestForChild: boolean,
|
|
1818
|
-
): Promise<IFluidDataStoreChannel> {
|
|
1819
|
-
const headerData: RuntimeHeaderData = {};
|
|
1820
|
-
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
1821
|
-
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
1822
|
-
}
|
|
1823
|
-
if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
|
|
1824
|
-
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
1825
|
-
}
|
|
1826
|
-
if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
|
|
1827
|
-
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
1828
|
-
}
|
|
1829
|
-
if (typeof request.headers?.[AllowInactiveRequestHeaderKey] === "boolean") {
|
|
1830
|
-
headerData.allowInactive = request.headers[AllowInactiveRequestHeaderKey];
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
// We allow Tombstone requests for sub-DataStore objects
|
|
1834
|
-
if (requestForChild) {
|
|
1835
|
-
headerData.allowTombstone = true;
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
await this.dataStores.waitIfPendingAlias(id);
|
|
1839
|
-
const internalId = this.internalId(id);
|
|
1840
|
-
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
1841
|
-
|
|
1842
|
-
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
1843
|
-
// the same as GC nodes id.
|
|
1844
|
-
const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
|
|
1845
|
-
// Get the initial snapshot details which contain the data store package path.
|
|
1846
|
-
const details = await dataStoreContext.getInitialSnapshotDetails();
|
|
1847
|
-
|
|
1848
|
-
// Note that this will throw if the data store is inactive or tombstoned and throwing on incorrect usage
|
|
1849
|
-
// is configured.
|
|
1850
|
-
this.garbageCollector.nodeUpdated(
|
|
1851
|
-
`/${urlWithoutQuery}`,
|
|
1852
|
-
"Loaded",
|
|
1853
|
-
undefined /* timestampMs */,
|
|
1854
|
-
details.pkg,
|
|
1855
|
-
request,
|
|
1856
|
-
headerData,
|
|
1857
|
-
);
|
|
1858
|
-
return dataStoreContext.realize();
|
|
2056
|
+
return this.channelCollection.internalId(maybeAlias);
|
|
1859
2057
|
}
|
|
1860
2058
|
|
|
1861
2059
|
/** Adds the container's metadata to the given summary tree. */
|
|
@@ -1872,7 +2070,7 @@ export class ContainerRuntime
|
|
|
1872
2070
|
extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
|
|
1873
2071
|
this.messageAtLastSummary,
|
|
1874
2072
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1875
|
-
|
|
2073
|
+
idCompressorMode: this.idCompressorMode,
|
|
1876
2074
|
};
|
|
1877
2075
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
1878
2076
|
}
|
|
@@ -1885,12 +2083,8 @@ export class ContainerRuntime
|
|
|
1885
2083
|
) {
|
|
1886
2084
|
this.addMetadataToSummary(summaryTree);
|
|
1887
2085
|
|
|
1888
|
-
if (this.
|
|
1889
|
-
|
|
1890
|
-
this.idCompressor !== undefined,
|
|
1891
|
-
0x67a /* IdCompressor should be defined if enabled */,
|
|
1892
|
-
);
|
|
1893
|
-
const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
|
|
2086
|
+
if (this._idCompressor) {
|
|
2087
|
+
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
1894
2088
|
addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
|
|
1895
2089
|
}
|
|
1896
2090
|
|
|
@@ -1899,7 +2093,7 @@ export class ContainerRuntime
|
|
|
1899
2093
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
1900
2094
|
}
|
|
1901
2095
|
|
|
1902
|
-
const dataStoreAliases = this.
|
|
2096
|
+
const dataStoreAliases = this.channelCollection.aliases;
|
|
1903
2097
|
if (dataStoreAliases.size > 0) {
|
|
1904
2098
|
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
1905
2099
|
}
|
|
@@ -1915,7 +2109,7 @@ export class ContainerRuntime
|
|
|
1915
2109
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
1916
2110
|
// and the blob manager can handle the tree not existing when loading
|
|
1917
2111
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
1918
|
-
|
|
2112
|
+
addSummarizeResultToSummary(summaryTree, blobsTreeName, blobManagerSummary);
|
|
1919
2113
|
}
|
|
1920
2114
|
|
|
1921
2115
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
@@ -2015,16 +2209,12 @@ export class ContainerRuntime
|
|
|
2015
2209
|
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
2016
2210
|
switch (opContents.type) {
|
|
2017
2211
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2018
|
-
return this.dataStores.applyStashedOp(opContents.contents);
|
|
2019
2212
|
case ContainerMessageType.Attach:
|
|
2020
|
-
|
|
2213
|
+
case ContainerMessageType.Alias:
|
|
2214
|
+
return this.channelCollection.applyStashedOp(opContents);
|
|
2021
2215
|
case ContainerMessageType.IdAllocation:
|
|
2022
|
-
assert(
|
|
2023
|
-
this.idCompressor !== undefined,
|
|
2024
|
-
0x67b /* IdCompressor should be defined if enabled */,
|
|
2025
|
-
);
|
|
2216
|
+
assert(this.idCompressorMode !== "off", 0x8f1 /* ID compressor should be in use */);
|
|
2026
2217
|
return;
|
|
2027
|
-
case ContainerMessageType.Alias:
|
|
2028
2218
|
case ContainerMessageType.BlobAttach:
|
|
2029
2219
|
return;
|
|
2030
2220
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -2054,11 +2244,27 @@ export class ContainerRuntime
|
|
|
2054
2244
|
this.closeFn(error);
|
|
2055
2245
|
throw error;
|
|
2056
2246
|
}
|
|
2247
|
+
// Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
|
|
2248
|
+
// All we can do is ignore it (similar to on process).
|
|
2057
2249
|
}
|
|
2058
2250
|
}
|
|
2059
2251
|
}
|
|
2060
2252
|
|
|
2061
2253
|
public setConnectionState(connected: boolean, clientId?: string) {
|
|
2254
|
+
if (connected && this.idCompressorMode === "delayed" && !this.compressorLoadInitiated) {
|
|
2255
|
+
this.compressorLoadInitiated = true;
|
|
2256
|
+
this.createIdCompressor()
|
|
2257
|
+
.then((compressor) => {
|
|
2258
|
+
this._idCompressor = compressor;
|
|
2259
|
+
for (const range of this.pendingIdCompressorOps) {
|
|
2260
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
2261
|
+
}
|
|
2262
|
+
this.pendingIdCompressorOps = [];
|
|
2263
|
+
})
|
|
2264
|
+
.catch((error) => {
|
|
2265
|
+
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2062
2268
|
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
2063
2269
|
this.delayConnectClientId = undefined;
|
|
2064
2270
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -2151,7 +2357,7 @@ export class ContainerRuntime
|
|
|
2151
2357
|
this.replayPendingStates();
|
|
2152
2358
|
}
|
|
2153
2359
|
|
|
2154
|
-
this.
|
|
2360
|
+
this.channelCollection.setConnectionState(connected, clientId);
|
|
2155
2361
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
2156
2362
|
|
|
2157
2363
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
@@ -2254,17 +2460,9 @@ export class ContainerRuntime
|
|
|
2254
2460
|
const { local } = messageWithContext;
|
|
2255
2461
|
switch (messageWithContext.message.type) {
|
|
2256
2462
|
case ContainerMessageType.Attach:
|
|
2257
|
-
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
2258
|
-
break;
|
|
2259
2463
|
case ContainerMessageType.Alias:
|
|
2260
|
-
this.dataStores.processAliasMessage(
|
|
2261
|
-
messageWithContext.message,
|
|
2262
|
-
localOpMetadata,
|
|
2263
|
-
local,
|
|
2264
|
-
);
|
|
2265
|
-
break;
|
|
2266
2464
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2267
|
-
this.
|
|
2465
|
+
this.channelCollection.process(
|
|
2268
2466
|
messageWithContext.message,
|
|
2269
2467
|
local,
|
|
2270
2468
|
localOpMetadata,
|
|
@@ -2275,17 +2473,23 @@ export class ContainerRuntime
|
|
|
2275
2473
|
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
2276
2474
|
break;
|
|
2277
2475
|
case ContainerMessageType.IdAllocation:
|
|
2278
|
-
assert(
|
|
2279
|
-
this.idCompressor !== undefined,
|
|
2280
|
-
0x67c /* IdCompressor should be defined if enabled */,
|
|
2281
|
-
);
|
|
2282
|
-
|
|
2283
2476
|
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
2284
2477
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
2478
|
+
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
2479
|
+
// thus we need to process all the ops.
|
|
2285
2480
|
if (
|
|
2286
|
-
(
|
|
2481
|
+
!(
|
|
2482
|
+
this.skipSavedCompressorOps &&
|
|
2483
|
+
(messageWithContext.message.metadata as IIdAllocationMetadata)?.savedOp ===
|
|
2484
|
+
true
|
|
2485
|
+
)
|
|
2287
2486
|
) {
|
|
2288
|
-
|
|
2487
|
+
const range = messageWithContext.message.contents;
|
|
2488
|
+
if (this._idCompressor === undefined) {
|
|
2489
|
+
this.pendingIdCompressorOps.push(range);
|
|
2490
|
+
} else {
|
|
2491
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
2492
|
+
}
|
|
2289
2493
|
}
|
|
2290
2494
|
break;
|
|
2291
2495
|
case ContainerMessageType.GC:
|
|
@@ -2391,7 +2595,16 @@ export class ContainerRuntime
|
|
|
2391
2595
|
return;
|
|
2392
2596
|
}
|
|
2393
2597
|
|
|
2394
|
-
|
|
2598
|
+
// Due to a mismatch between different layers in terms of
|
|
2599
|
+
// what is the interface of passing signals, we need to adjust
|
|
2600
|
+
// the signal envelope before sending it to the datastores to be processed
|
|
2601
|
+
const envelope2: IEnvelope = {
|
|
2602
|
+
address: envelope.address,
|
|
2603
|
+
contents: transformed.content,
|
|
2604
|
+
};
|
|
2605
|
+
transformed.content = envelope2;
|
|
2606
|
+
|
|
2607
|
+
this.channelCollection.processSignal(transformed, local);
|
|
2395
2608
|
}
|
|
2396
2609
|
|
|
2397
2610
|
/**
|
|
@@ -2408,6 +2621,9 @@ export class ContainerRuntime
|
|
|
2408
2621
|
assert(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
2409
2622
|
}
|
|
2410
2623
|
|
|
2624
|
+
/**
|
|
2625
|
+
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially}
|
|
2626
|
+
*/
|
|
2411
2627
|
public orderSequentially<T>(callback: () => T): T {
|
|
2412
2628
|
let checkpoint: IBatchCheckpoint | undefined;
|
|
2413
2629
|
let result: T;
|
|
@@ -2439,9 +2655,21 @@ export class ContainerRuntime
|
|
|
2439
2655
|
throw error2;
|
|
2440
2656
|
}
|
|
2441
2657
|
} else {
|
|
2442
|
-
|
|
2443
|
-
|
|
2658
|
+
this.closeFn(
|
|
2659
|
+
wrapError(
|
|
2660
|
+
error,
|
|
2661
|
+
(errorMessage) =>
|
|
2662
|
+
new GenericError(
|
|
2663
|
+
`orderSequentially callback exception: ${errorMessage}`,
|
|
2664
|
+
error,
|
|
2665
|
+
{
|
|
2666
|
+
orderSequentiallyCalls: this._orderSequentiallyCalls,
|
|
2667
|
+
},
|
|
2668
|
+
),
|
|
2669
|
+
),
|
|
2670
|
+
);
|
|
2444
2671
|
}
|
|
2672
|
+
|
|
2445
2673
|
throw error; // throw the original error for the consumer of the runtime
|
|
2446
2674
|
} finally {
|
|
2447
2675
|
this._orderSequentiallyCalls--;
|
|
@@ -2463,9 +2691,17 @@ export class ContainerRuntime
|
|
|
2463
2691
|
public async getAliasedDataStoreEntryPoint(
|
|
2464
2692
|
alias: string,
|
|
2465
2693
|
): Promise<IFluidHandle<FluidObject> | undefined> {
|
|
2466
|
-
|
|
2694
|
+
// Back-comapatibility:
|
|
2695
|
+
// There are old files that were created without using data store aliasing feature, but
|
|
2696
|
+
// used createRoot*DataStore*() (already removed) API. Such data stores will have isRoot = true,
|
|
2697
|
+
// and internalID provided by user. The expectation is that such files behave as new files, where
|
|
2698
|
+
// same data store instances created using aliasing feature.
|
|
2699
|
+
// Please also see note on name collisions in DataStores.createDataStoreId()
|
|
2700
|
+
await this.channelCollection.waitIfPendingAlias(alias);
|
|
2467
2701
|
const internalId = this.internalId(alias);
|
|
2468
|
-
const context = await this.
|
|
2702
|
+
const context = await this.channelCollection.getDataStoreIfAvailable(internalId, {
|
|
2703
|
+
wait: false,
|
|
2704
|
+
});
|
|
2469
2705
|
// If the data store is not available or not an alias, return undefined.
|
|
2470
2706
|
if (context === undefined || !(await context.isRoot())) {
|
|
2471
2707
|
return undefined;
|
|
@@ -2486,29 +2722,26 @@ export class ContainerRuntime
|
|
|
2486
2722
|
return channel.entryPoint;
|
|
2487
2723
|
}
|
|
2488
2724
|
|
|
2489
|
-
public
|
|
2725
|
+
public createDetachedDataStore(
|
|
2490
2726
|
pkg: Readonly<string[]>,
|
|
2491
|
-
|
|
2727
|
+
loadingGroupId?: string,
|
|
2492
2728
|
): IFluidDataStoreContextDetached {
|
|
2493
|
-
|
|
2494
|
-
throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
2495
|
-
}
|
|
2496
|
-
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
2729
|
+
return this.channelCollection.createDetachedDataStore(pkg, loadingGroupId);
|
|
2497
2730
|
}
|
|
2498
2731
|
|
|
2499
|
-
public
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2732
|
+
public async createDataStore(
|
|
2733
|
+
pkg: Readonly<string | string[]>,
|
|
2734
|
+
loadingGroupId?: string,
|
|
2735
|
+
): Promise<IDataStore> {
|
|
2736
|
+
const context = this.channelCollection.createDataStoreContext(
|
|
2737
|
+
Array.isArray(pkg) ? pkg : [pkg],
|
|
2738
|
+
undefined, // props
|
|
2739
|
+
loadingGroupId,
|
|
2740
|
+
);
|
|
2505
2741
|
return channelToDataStore(
|
|
2506
|
-
await
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
id,
|
|
2510
|
-
this,
|
|
2511
|
-
this.dataStores,
|
|
2742
|
+
await context.realize(),
|
|
2743
|
+
context.id,
|
|
2744
|
+
this.channelCollection,
|
|
2512
2745
|
this.mc.logger,
|
|
2513
2746
|
);
|
|
2514
2747
|
}
|
|
@@ -2517,17 +2750,17 @@ export class ContainerRuntime
|
|
|
2517
2750
|
* @deprecated 0.16 Issue #1537, #3631
|
|
2518
2751
|
*/
|
|
2519
2752
|
public async _createDataStoreWithProps(
|
|
2520
|
-
pkg: string | string[]
|
|
2753
|
+
pkg: Readonly<string | string[]>,
|
|
2521
2754
|
props?: any,
|
|
2522
|
-
id = uuid(),
|
|
2523
2755
|
): Promise<IDataStore> {
|
|
2756
|
+
const context = this.channelCollection.createDataStoreContext(
|
|
2757
|
+
Array.isArray(pkg) ? pkg : [pkg],
|
|
2758
|
+
props,
|
|
2759
|
+
);
|
|
2524
2760
|
return channelToDataStore(
|
|
2525
|
-
await
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
id,
|
|
2529
|
-
this,
|
|
2530
|
-
this.dataStores,
|
|
2761
|
+
await context.realize(),
|
|
2762
|
+
context.id,
|
|
2763
|
+
this.channelCollection,
|
|
2531
2764
|
this.mc.logger,
|
|
2532
2765
|
);
|
|
2533
2766
|
}
|
|
@@ -2628,22 +2861,6 @@ export class ContainerRuntime
|
|
|
2628
2861
|
return this.submitSignalFn(envelope, targetClientId);
|
|
2629
2862
|
}
|
|
2630
2863
|
|
|
2631
|
-
/**
|
|
2632
|
-
* Submits the signal to be sent to other clients.
|
|
2633
|
-
* @param type - Type of the signal.
|
|
2634
|
-
* @param content - Content of the signal.
|
|
2635
|
-
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
2636
|
-
*/
|
|
2637
|
-
public submitDataStoreSignal(
|
|
2638
|
-
address: string,
|
|
2639
|
-
type: string,
|
|
2640
|
-
content: any,
|
|
2641
|
-
targetClientId?: string,
|
|
2642
|
-
) {
|
|
2643
|
-
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
2644
|
-
return this.submitSignalFn(envelope, targetClientId);
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
2864
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
2648
2865
|
if (attachState === AttachState.Attaching) {
|
|
2649
2866
|
assert(
|
|
@@ -2661,7 +2878,7 @@ export class ContainerRuntime
|
|
|
2661
2878
|
if (attachState === AttachState.Attached && !this.hasPendingMessages()) {
|
|
2662
2879
|
this.updateDocumentDirtyState(false);
|
|
2663
2880
|
}
|
|
2664
|
-
this.
|
|
2881
|
+
this.channelCollection.setAttachState(attachState);
|
|
2665
2882
|
}
|
|
2666
2883
|
|
|
2667
2884
|
/**
|
|
@@ -2681,12 +2898,12 @@ export class ContainerRuntime
|
|
|
2681
2898
|
}
|
|
2682
2899
|
|
|
2683
2900
|
// We can finalize any allocated IDs since we're the only client
|
|
2684
|
-
const idRange = this.
|
|
2901
|
+
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
2685
2902
|
if (idRange !== undefined) {
|
|
2686
|
-
this.
|
|
2903
|
+
this._idCompressor?.finalizeCreationRange(idRange);
|
|
2687
2904
|
}
|
|
2688
2905
|
|
|
2689
|
-
const summarizeResult = this.
|
|
2906
|
+
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
2690
2907
|
// Wrap data store summaries in .channels subtree.
|
|
2691
2908
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
2692
2909
|
|
|
@@ -2706,7 +2923,7 @@ export class ContainerRuntime
|
|
|
2706
2923
|
trackState: boolean,
|
|
2707
2924
|
telemetryContext?: ITelemetryContext,
|
|
2708
2925
|
): Promise<ISummarizeInternalResult> {
|
|
2709
|
-
const summarizeResult = await this.
|
|
2926
|
+
const summarizeResult = await this.channelCollection.summarize(
|
|
2710
2927
|
fullTree,
|
|
2711
2928
|
trackState,
|
|
2712
2929
|
telemetryContext,
|
|
@@ -2797,11 +3014,11 @@ export class ContainerRuntime
|
|
|
2797
3014
|
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
2798
3015
|
*/
|
|
2799
3016
|
public async updateStateBeforeGC() {
|
|
2800
|
-
return this.
|
|
3017
|
+
return this.channelCollection.updateStateBeforeGC();
|
|
2801
3018
|
}
|
|
2802
3019
|
|
|
2803
3020
|
private async getGCDataInternal(fullGC?: boolean): Promise<IGarbageCollectionData> {
|
|
2804
|
-
return this.
|
|
3021
|
+
return this.channelCollection.getGCData(fullGC);
|
|
2805
3022
|
}
|
|
2806
3023
|
|
|
2807
3024
|
/**
|
|
@@ -2831,25 +3048,7 @@ export class ContainerRuntime
|
|
|
2831
3048
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
2832
3049
|
|
|
2833
3050
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
2834
|
-
this.
|
|
2835
|
-
}
|
|
2836
|
-
|
|
2837
|
-
/**
|
|
2838
|
-
* This is called to update objects whose routes are unused.
|
|
2839
|
-
* @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
|
|
2840
|
-
*/
|
|
2841
|
-
public updateUnusedRoutes(unusedRoutes: readonly string[]) {
|
|
2842
|
-
const { blobManagerRoutes, dataStoreRoutes } =
|
|
2843
|
-
this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
2844
|
-
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
2845
|
-
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
2846
|
-
}
|
|
2847
|
-
|
|
2848
|
-
/**
|
|
2849
|
-
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
2850
|
-
*/
|
|
2851
|
-
public deleteUnusedNodes(unusedRoutes: readonly string[]): string[] {
|
|
2852
|
-
throw new Error("deleteUnusedRoutes should not be called");
|
|
3051
|
+
this.channelCollection.updateUsedRoutes(dataStoreRoutes);
|
|
2853
3052
|
}
|
|
2854
3053
|
|
|
2855
3054
|
/**
|
|
@@ -2861,7 +3060,7 @@ export class ContainerRuntime
|
|
|
2861
3060
|
const { dataStoreRoutes, blobManagerRoutes } =
|
|
2862
3061
|
this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
2863
3062
|
|
|
2864
|
-
const deletedRoutes = this.
|
|
3063
|
+
const deletedRoutes = this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes);
|
|
2865
3064
|
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
2866
3065
|
}
|
|
2867
3066
|
|
|
@@ -2877,7 +3076,7 @@ export class ContainerRuntime
|
|
|
2877
3076
|
const { blobManagerRoutes, dataStoreRoutes } =
|
|
2878
3077
|
this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
2879
3078
|
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
2880
|
-
this.
|
|
3079
|
+
this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
|
|
2881
3080
|
}
|
|
2882
3081
|
|
|
2883
3082
|
/**
|
|
@@ -2897,7 +3096,7 @@ export class ContainerRuntime
|
|
|
2897
3096
|
if (this.isBlobPath(nodePath)) {
|
|
2898
3097
|
return GCNodeType.Blob;
|
|
2899
3098
|
}
|
|
2900
|
-
return this.
|
|
3099
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
2901
3100
|
}
|
|
2902
3101
|
|
|
2903
3102
|
/**
|
|
@@ -2905,12 +3104,18 @@ export class ContainerRuntime
|
|
|
2905
3104
|
* data store or an attachment blob.
|
|
2906
3105
|
*/
|
|
2907
3106
|
public async getGCNodePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
3107
|
+
// GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
|
|
3108
|
+
// These have no package path so return a special value.
|
|
3109
|
+
if (nodePath === "/") {
|
|
3110
|
+
return ["_gcRoot"];
|
|
3111
|
+
}
|
|
3112
|
+
|
|
2908
3113
|
switch (this.getNodeType(nodePath)) {
|
|
2909
3114
|
case GCNodeType.Blob:
|
|
2910
3115
|
return [BlobManager.basePath];
|
|
2911
3116
|
case GCNodeType.DataStore:
|
|
2912
3117
|
case GCNodeType.SubDataStore:
|
|
2913
|
-
return this.
|
|
3118
|
+
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
2914
3119
|
default:
|
|
2915
3120
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
2916
3121
|
}
|
|
@@ -2970,7 +3175,10 @@ export class ContainerRuntime
|
|
|
2970
3175
|
* @param srcHandle - The handle of the node that added the reference.
|
|
2971
3176
|
* @param outboundHandle - The handle of the outbound node that is referenced.
|
|
2972
3177
|
*/
|
|
2973
|
-
public addedGCOutboundReference(
|
|
3178
|
+
public addedGCOutboundReference(
|
|
3179
|
+
srcHandle: { absolutePath: string },
|
|
3180
|
+
outboundHandle: { absolutePath: string },
|
|
3181
|
+
) {
|
|
2974
3182
|
this.garbageCollector.addedOutboundReference(
|
|
2975
3183
|
srcHandle.absolutePath,
|
|
2976
3184
|
outboundHandle.absolutePath,
|
|
@@ -2986,7 +3194,13 @@ export class ContainerRuntime
|
|
|
2986
3194
|
* @param options - options controlling how the summary is generated or submitted
|
|
2987
3195
|
*/
|
|
2988
3196
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
2989
|
-
const {
|
|
3197
|
+
const {
|
|
3198
|
+
fullTree = false,
|
|
3199
|
+
finalAttempt = false,
|
|
3200
|
+
refreshLatestAck,
|
|
3201
|
+
summaryLogger,
|
|
3202
|
+
latestSummaryRefSeqNum,
|
|
3203
|
+
} = options;
|
|
2990
3204
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2991
3205
|
// use it for all events logged during this summary.
|
|
2992
3206
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -3000,7 +3214,6 @@ export class ContainerRuntime
|
|
|
3000
3214
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
3001
3215
|
|
|
3002
3216
|
// We close the summarizer and download a new snapshot and reload the container
|
|
3003
|
-
let latestSnapshotVersionId: string | undefined;
|
|
3004
3217
|
if (refreshLatestAck === true) {
|
|
3005
3218
|
return this.prefetchLatestSummaryThenClose(
|
|
3006
3219
|
createChildLogger({
|
|
@@ -3058,6 +3271,10 @@ export class ContainerRuntime
|
|
|
3058
3271
|
this.mc.config.getBoolean(
|
|
3059
3272
|
"Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
|
|
3060
3273
|
) !== true;
|
|
3274
|
+
const shouldValidatePreSummaryState =
|
|
3275
|
+
this.mc.config.getBoolean(
|
|
3276
|
+
"Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState",
|
|
3277
|
+
) === true;
|
|
3061
3278
|
|
|
3062
3279
|
let summaryRefSeqNum: number | undefined;
|
|
3063
3280
|
|
|
@@ -3072,7 +3289,33 @@ export class ContainerRuntime
|
|
|
3072
3289
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
3073
3290
|
const lastAck = this.summaryCollection.latestAck;
|
|
3074
3291
|
|
|
3075
|
-
this.summarizerNode.startSummary(
|
|
3292
|
+
const startSummaryResult = this.summarizerNode.startSummary(
|
|
3293
|
+
summaryRefSeqNum,
|
|
3294
|
+
summaryNumberLogger,
|
|
3295
|
+
latestSummaryRefSeqNum,
|
|
3296
|
+
);
|
|
3297
|
+
|
|
3298
|
+
if (
|
|
3299
|
+
startSummaryResult.invalidNodes > 0 ||
|
|
3300
|
+
startSummaryResult.mismatchNumbers.size > 0
|
|
3301
|
+
) {
|
|
3302
|
+
summaryLogger.sendErrorEvent({
|
|
3303
|
+
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
3304
|
+
details: {
|
|
3305
|
+
...startSummaryResult,
|
|
3306
|
+
mismatchNumbers: Array.from(startSummaryResult.mismatchNumbers),
|
|
3307
|
+
},
|
|
3308
|
+
});
|
|
3309
|
+
|
|
3310
|
+
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
3311
|
+
return {
|
|
3312
|
+
stage: "base",
|
|
3313
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3314
|
+
minimumSequenceNumber,
|
|
3315
|
+
error: `Summarizer node state inconsistent with summarizer state.`,
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3076
3319
|
|
|
3077
3320
|
// Helper function to check whether we should still continue between each async step.
|
|
3078
3321
|
const checkContinue = (): { continue: true } | { continue: false; error: string } => {
|
|
@@ -3194,8 +3437,8 @@ export class ContainerRuntime
|
|
|
3194
3437
|
: undefined;
|
|
3195
3438
|
|
|
3196
3439
|
const summaryStats: IGeneratedSummaryStats = {
|
|
3197
|
-
dataStoreCount: this.
|
|
3198
|
-
summarizedDataStoreCount: this.
|
|
3440
|
+
dataStoreCount: this.channelCollection.size,
|
|
3441
|
+
summarizedDataStoreCount: this.channelCollection.size - handleCount,
|
|
3199
3442
|
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
3200
3443
|
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
3201
3444
|
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
@@ -3216,34 +3459,18 @@ export class ContainerRuntime
|
|
|
3216
3459
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
3217
3460
|
}
|
|
3218
3461
|
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
ackHandle: latestSnapshotVersionId,
|
|
3232
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3233
|
-
};
|
|
3234
|
-
} else if (lastAck === undefined) {
|
|
3235
|
-
summaryContext = {
|
|
3236
|
-
proposalHandle: undefined,
|
|
3237
|
-
ackHandle: this.loadedFromVersionId,
|
|
3238
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3239
|
-
};
|
|
3240
|
-
} else {
|
|
3241
|
-
summaryContext = {
|
|
3242
|
-
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3243
|
-
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3244
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3245
|
-
};
|
|
3246
|
-
}
|
|
3462
|
+
const summaryContext =
|
|
3463
|
+
lastAck === undefined
|
|
3464
|
+
? {
|
|
3465
|
+
proposalHandle: undefined,
|
|
3466
|
+
ackHandle: this.loadedFromVersionId,
|
|
3467
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3468
|
+
}
|
|
3469
|
+
: {
|
|
3470
|
+
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3471
|
+
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3472
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3473
|
+
};
|
|
3247
3474
|
|
|
3248
3475
|
let handle: string;
|
|
3249
3476
|
try {
|
|
@@ -3408,28 +3635,15 @@ export class ContainerRuntime
|
|
|
3408
3635
|
}
|
|
3409
3636
|
}
|
|
3410
3637
|
|
|
3411
|
-
public
|
|
3412
|
-
|
|
3638
|
+
public submitMessage(
|
|
3639
|
+
type:
|
|
3640
|
+
| ContainerMessageType.FluidDataStoreOp
|
|
3641
|
+
| ContainerMessageType.Alias
|
|
3642
|
+
| ContainerMessageType.Attach,
|
|
3413
3643
|
contents: any,
|
|
3414
3644
|
localOpMetadata: unknown = undefined,
|
|
3415
3645
|
): void {
|
|
3416
|
-
|
|
3417
|
-
address: id,
|
|
3418
|
-
contents,
|
|
3419
|
-
};
|
|
3420
|
-
this.submit(
|
|
3421
|
-
{ type: ContainerMessageType.FluidDataStoreOp, contents: envelope },
|
|
3422
|
-
localOpMetadata,
|
|
3423
|
-
);
|
|
3424
|
-
}
|
|
3425
|
-
|
|
3426
|
-
public submitDataStoreAliasOp(contents: any, localOpMetadata: unknown): void {
|
|
3427
|
-
const aliasMessage = contents as IDataStoreAliasMessage;
|
|
3428
|
-
if (!isDataStoreAliasMessage(aliasMessage)) {
|
|
3429
|
-
throw new UsageError("malformedDataStoreAliasMessage");
|
|
3430
|
-
}
|
|
3431
|
-
|
|
3432
|
-
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
3646
|
+
this.submit({ type, contents }, localOpMetadata);
|
|
3433
3647
|
}
|
|
3434
3648
|
|
|
3435
3649
|
public async uploadBlob(
|
|
@@ -3440,35 +3654,22 @@ export class ContainerRuntime
|
|
|
3440
3654
|
return this.blobManager.createBlob(blob, signal);
|
|
3441
3655
|
}
|
|
3442
3656
|
|
|
3443
|
-
private
|
|
3444
|
-
if (
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
if (
|
|
3448
|
-
assert(
|
|
3449
|
-
this.idCompressor !== undefined,
|
|
3450
|
-
0x67d /* IdCompressor should be defined if enabled */,
|
|
3451
|
-
);
|
|
3452
|
-
idRange = this.idCompressor.takeNextCreationRange();
|
|
3453
|
-
// Don't include the idRange if there weren't any Ids allocated
|
|
3454
|
-
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
3455
|
-
}
|
|
3456
|
-
|
|
3457
|
-
if (idRange !== undefined) {
|
|
3657
|
+
private submitIdAllocationOpIfNeeded(): void {
|
|
3658
|
+
if (this._idCompressor) {
|
|
3659
|
+
const idRange = this._idCompressor.takeNextCreationRange();
|
|
3660
|
+
// Don't include the idRange if there weren't any Ids allocated
|
|
3661
|
+
if (idRange?.ids !== undefined) {
|
|
3458
3662
|
const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
|
|
3459
3663
|
type: ContainerMessageType.IdAllocation,
|
|
3460
3664
|
contents: idRange,
|
|
3461
3665
|
};
|
|
3462
|
-
idAllocationBatchMessage = {
|
|
3666
|
+
const idAllocationBatchMessage: BatchMessage = {
|
|
3463
3667
|
contents: JSON.stringify(idAllocationMessage),
|
|
3464
3668
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3465
3669
|
metadata: undefined,
|
|
3466
3670
|
localOpMetadata: undefined,
|
|
3467
3671
|
type: ContainerMessageType.IdAllocation,
|
|
3468
3672
|
};
|
|
3469
|
-
}
|
|
3470
|
-
|
|
3471
|
-
if (idAllocationBatchMessage !== undefined) {
|
|
3472
3673
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
3473
3674
|
}
|
|
3474
3675
|
}
|
|
@@ -3509,43 +3710,47 @@ export class ContainerRuntime
|
|
|
3509
3710
|
};
|
|
3510
3711
|
|
|
3511
3712
|
try {
|
|
3512
|
-
//
|
|
3513
|
-
// the
|
|
3514
|
-
// op
|
|
3515
|
-
//
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
3519
|
-
// Is it safe:
|
|
3520
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
3521
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
3522
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
3523
|
-
// Why:
|
|
3524
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
3525
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
3526
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
3527
|
-
// these issues.
|
|
3528
|
-
// Cons:
|
|
3529
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
3530
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
3531
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
3532
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
3533
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
3534
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
3535
|
-
// issue than sending.
|
|
3536
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
3537
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
3538
|
-
if (
|
|
3539
|
-
this.currentlyBatching() &&
|
|
3540
|
-
type === ContainerMessageType.Attach &&
|
|
3541
|
-
this.disableAttachReorder !== true
|
|
3542
|
-
) {
|
|
3543
|
-
this.outbox.submitAttach(message);
|
|
3544
|
-
} else if (type === ContainerMessageType.BlobAttach) {
|
|
3545
|
-
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
3546
|
-
this.outbox.submitBlobAttach(message);
|
|
3713
|
+
// If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
|
|
3714
|
+
// op into the correct batch to avoid ranges being finalized out of order.
|
|
3715
|
+
// Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
|
|
3716
|
+
// any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
|
|
3717
|
+
if (type === ContainerMessageType.IdAllocation) {
|
|
3718
|
+
this.outbox.submitIdAllocation(message);
|
|
3547
3719
|
} else {
|
|
3548
|
-
this.
|
|
3720
|
+
this.submitIdAllocationOpIfNeeded();
|
|
3721
|
+
|
|
3722
|
+
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
3723
|
+
// Is it safe:
|
|
3724
|
+
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
3725
|
+
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
3726
|
+
// is stored in some DDS, i.e. only after some other op.
|
|
3727
|
+
// Why:
|
|
3728
|
+
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
3729
|
+
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
3730
|
+
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
3731
|
+
// these issues.
|
|
3732
|
+
// Cons:
|
|
3733
|
+
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
3734
|
+
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
3735
|
+
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
3736
|
+
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
3737
|
+
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
3738
|
+
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
3739
|
+
// issue than sending.
|
|
3740
|
+
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
3741
|
+
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
3742
|
+
if (
|
|
3743
|
+
this.currentlyBatching() &&
|
|
3744
|
+
type === ContainerMessageType.Attach &&
|
|
3745
|
+
this.disableAttachReorder !== true
|
|
3746
|
+
) {
|
|
3747
|
+
this.outbox.submitAttach(message);
|
|
3748
|
+
} else if (type === ContainerMessageType.BlobAttach) {
|
|
3749
|
+
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
3750
|
+
this.outbox.submitBlobAttach(message);
|
|
3751
|
+
} else {
|
|
3752
|
+
this.outbox.submit(message);
|
|
3753
|
+
}
|
|
3549
3754
|
}
|
|
3550
3755
|
|
|
3551
3756
|
if (!this.currentlyBatching()) {
|
|
@@ -3687,14 +3892,18 @@ export class ContainerRuntime
|
|
|
3687
3892
|
localOpMetadata: unknown,
|
|
3688
3893
|
opMetadata: Record<string, unknown> | undefined,
|
|
3689
3894
|
) {
|
|
3895
|
+
assert(
|
|
3896
|
+
!this.isSummarizerClient,
|
|
3897
|
+
0x8f2 /* Summarizer never reconnects so should never resubmit */,
|
|
3898
|
+
);
|
|
3690
3899
|
switch (message.type) {
|
|
3691
3900
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3901
|
+
case ContainerMessageType.Attach:
|
|
3902
|
+
case ContainerMessageType.Alias:
|
|
3692
3903
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3693
3904
|
// and trigger resubmission on it.
|
|
3694
|
-
this.
|
|
3905
|
+
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
3695
3906
|
break;
|
|
3696
|
-
case ContainerMessageType.Attach:
|
|
3697
|
-
case ContainerMessageType.Alias:
|
|
3698
3907
|
case ContainerMessageType.IdAllocation: {
|
|
3699
3908
|
this.submit(message, localOpMetadata);
|
|
3700
3909
|
break;
|
|
@@ -3708,13 +3917,14 @@ export class ContainerRuntime
|
|
|
3708
3917
|
this.submit(message);
|
|
3709
3918
|
break;
|
|
3710
3919
|
case ContainerMessageType.GC:
|
|
3711
|
-
|
|
3712
|
-
|
|
3920
|
+
this.submit(message);
|
|
3921
|
+
break;
|
|
3713
3922
|
default: {
|
|
3714
3923
|
// This case should be very rare - it would imply an op was stashed from a
|
|
3715
|
-
// future version of runtime code and now is being applied on an older version
|
|
3924
|
+
// future version of runtime code and now is being applied on an older version.
|
|
3716
3925
|
const compatBehavior = message.compatDetails?.behavior;
|
|
3717
3926
|
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
3927
|
+
// We do not ultimately resubmit it, to be consistent with this version of the code.
|
|
3718
3928
|
this.logger.sendTelemetryEvent({
|
|
3719
3929
|
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
3720
3930
|
messageDetails: { type: message.type, compatBehavior },
|
|
@@ -3745,7 +3955,7 @@ export class ContainerRuntime
|
|
|
3745
3955
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3746
3956
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
3747
3957
|
// and trigger rollback on it.
|
|
3748
|
-
this.
|
|
3958
|
+
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
3749
3959
|
break;
|
|
3750
3960
|
default:
|
|
3751
3961
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -3771,7 +3981,7 @@ export class ContainerRuntime
|
|
|
3771
3981
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
3772
3982
|
*/
|
|
3773
3983
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
3774
|
-
|
|
3984
|
+
await this.fetchLatestSnapshotFromStorage(
|
|
3775
3985
|
summaryLogger,
|
|
3776
3986
|
{
|
|
3777
3987
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
@@ -3781,32 +3991,7 @@ export class ContainerRuntime
|
|
|
3781
3991
|
readAndParseBlob,
|
|
3782
3992
|
);
|
|
3783
3993
|
|
|
3784
|
-
|
|
3785
|
-
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
3786
|
-
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
3787
|
-
* However, there are couple of scenarios where it's possible:
|
|
3788
|
-
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
3789
|
-
* the document being unusable and we should not proceed.
|
|
3790
|
-
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
3791
|
-
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
3792
|
-
* state.
|
|
3793
|
-
*/
|
|
3794
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3795
|
-
const error = DataProcessingError.create(
|
|
3796
|
-
"Fetched snapshot is older than the received ack",
|
|
3797
|
-
"RefreshLatestSummaryAck",
|
|
3798
|
-
undefined /* sequencedMessage */,
|
|
3799
|
-
{
|
|
3800
|
-
ackHandle,
|
|
3801
|
-
summaryRefSeq,
|
|
3802
|
-
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3803
|
-
},
|
|
3804
|
-
);
|
|
3805
|
-
this.disposeFn(error);
|
|
3806
|
-
throw error;
|
|
3807
|
-
}
|
|
3808
|
-
|
|
3809
|
-
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
3994
|
+
await this.closeStaleSummarizer();
|
|
3810
3995
|
return;
|
|
3811
3996
|
}
|
|
3812
3997
|
|
|
@@ -3835,7 +4020,7 @@ export class ContainerRuntime
|
|
|
3835
4020
|
readAndParseBlob,
|
|
3836
4021
|
);
|
|
3837
4022
|
|
|
3838
|
-
await this.closeStaleSummarizer(
|
|
4023
|
+
await this.closeStaleSummarizer();
|
|
3839
4024
|
|
|
3840
4025
|
return {
|
|
3841
4026
|
stage: "base",
|
|
@@ -3845,7 +4030,7 @@ export class ContainerRuntime
|
|
|
3845
4030
|
};
|
|
3846
4031
|
}
|
|
3847
4032
|
|
|
3848
|
-
private async closeStaleSummarizer(
|
|
4033
|
+
private async closeStaleSummarizer(): Promise<void> {
|
|
3849
4034
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3850
4035
|
await delay(this.closeSummarizerDelayMs);
|
|
3851
4036
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
@@ -3859,7 +4044,7 @@ export class ContainerRuntime
|
|
|
3859
4044
|
*/
|
|
3860
4045
|
private async fetchLatestSnapshotFromStorage(
|
|
3861
4046
|
logger: ITelemetryLoggerExt,
|
|
3862
|
-
event:
|
|
4047
|
+
event: ITelemetryGenericEventExt,
|
|
3863
4048
|
readAndParseBlob: ReadAndParseBlob,
|
|
3864
4049
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3865
4050
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -3910,50 +4095,65 @@ export class ContainerRuntime
|
|
|
3910
4095
|
);
|
|
3911
4096
|
}
|
|
3912
4097
|
|
|
3913
|
-
public
|
|
3914
|
-
|
|
3915
|
-
this.mc.logger,
|
|
3916
|
-
{
|
|
3917
|
-
eventName: "getPendingLocalState",
|
|
3918
|
-
notifyImminentClosure: props?.notifyImminentClosure,
|
|
3919
|
-
},
|
|
3920
|
-
async (event) => {
|
|
3921
|
-
this.verifyNotClosed();
|
|
3922
|
-
// in case imminentClosure is set to true by future code, we don't
|
|
3923
|
-
// try to change its value
|
|
3924
|
-
if (!this.imminentClosure) {
|
|
3925
|
-
this.imminentClosure = props?.notifyImminentClosure ?? this.imminentClosure;
|
|
3926
|
-
}
|
|
3927
|
-
const stopBlobAttachingSignal = props?.stopBlobAttachingSignal;
|
|
3928
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
3929
|
-
throw new UsageError("can't get state during orderSequentially");
|
|
3930
|
-
}
|
|
3931
|
-
// Flush pending batch.
|
|
3932
|
-
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3933
|
-
// to close current batch.
|
|
3934
|
-
this.flush();
|
|
3935
|
-
const pendingAttachmentBlobs = this.imminentClosure
|
|
3936
|
-
? await this.blobManager.attachAndGetPendingBlobs(stopBlobAttachingSignal)
|
|
3937
|
-
: undefined;
|
|
3938
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
3939
|
-
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3940
|
-
return; // no pending state to save
|
|
3941
|
-
}
|
|
4098
|
+
public getPendingLocalState(props?: IGetPendingLocalStateProps): unknown {
|
|
4099
|
+
this.verifyNotClosed();
|
|
3942
4100
|
|
|
3943
|
-
|
|
4101
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
4102
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
4103
|
+
}
|
|
4104
|
+
this.imminentClosure ||= props?.notifyImminentClosure ?? false;
|
|
4105
|
+
|
|
4106
|
+
const getSyncState = (
|
|
4107
|
+
pendingAttachmentBlobs?: IPendingBlobs,
|
|
4108
|
+
): IPendingRuntimeState | undefined => {
|
|
4109
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
4110
|
+
if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
|
|
4111
|
+
return; // no pending state to save
|
|
4112
|
+
}
|
|
3944
4113
|
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
4114
|
+
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
4115
|
+
|
|
4116
|
+
return {
|
|
4117
|
+
pending,
|
|
4118
|
+
pendingIdCompressorState,
|
|
4119
|
+
pendingAttachmentBlobs,
|
|
4120
|
+
sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
|
|
4121
|
+
};
|
|
4122
|
+
};
|
|
4123
|
+
const perfEvent = {
|
|
4124
|
+
eventName: "getPendingLocalState",
|
|
4125
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
4126
|
+
};
|
|
4127
|
+
const logAndReturnPendingState = (
|
|
4128
|
+
event: PerformanceEvent,
|
|
4129
|
+
pendingState?: IPendingRuntimeState,
|
|
4130
|
+
) => {
|
|
4131
|
+
event.end({
|
|
4132
|
+
attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
|
|
4133
|
+
pendingOpsSize: pendingState?.pending?.pendingStates.length,
|
|
4134
|
+
});
|
|
4135
|
+
return pendingState;
|
|
4136
|
+
};
|
|
4137
|
+
|
|
4138
|
+
// Flush pending batch.
|
|
4139
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
4140
|
+
// to close current batch.
|
|
4141
|
+
this.flush();
|
|
4142
|
+
|
|
4143
|
+
return props?.notifyImminentClosure === true
|
|
4144
|
+
? PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) =>
|
|
4145
|
+
logAndReturnPendingState(
|
|
4146
|
+
event,
|
|
4147
|
+
getSyncState(
|
|
4148
|
+
await this.blobManager.attachAndGetPendingBlobs(
|
|
4149
|
+
props?.stopBlobAttachingSignal,
|
|
4150
|
+
),
|
|
4151
|
+
),
|
|
4152
|
+
),
|
|
4153
|
+
)
|
|
4154
|
+
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) =>
|
|
4155
|
+
logAndReturnPendingState(event, getSyncState()),
|
|
4156
|
+
);
|
|
3957
4157
|
}
|
|
3958
4158
|
|
|
3959
4159
|
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|