@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/dist/containerRuntime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.
|
|
3
|
+
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
|
|
4
4
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
5
5
|
const core_utils_1 = require("@fluidframework/core-utils");
|
|
6
6
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
@@ -11,22 +11,22 @@ const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
|
11
11
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
12
12
|
const runtime_utils_1 = require("@fluidframework/runtime-utils");
|
|
13
13
|
const uuid_1 = require("uuid");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
14
|
+
const containerHandleContext_js_1 = require("./containerHandleContext.js");
|
|
15
|
+
const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
|
|
16
|
+
const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
|
|
17
|
+
const pendingStateManager_js_1 = require("./pendingStateManager.js");
|
|
18
|
+
const packageVersion_js_1 = require("./packageVersion.js");
|
|
19
|
+
const blobManager_js_1 = require("./blobManager.js");
|
|
20
|
+
const channelCollection_js_1 = require("./channelCollection.js");
|
|
21
|
+
const index_js_1 = require("./summary/index.js");
|
|
22
|
+
const throttler_js_1 = require("./throttler.js");
|
|
23
|
+
const index_js_2 = require("./gc/index.js");
|
|
24
|
+
const dataStore_js_1 = require("./dataStore.js");
|
|
25
|
+
const batchTracker_js_1 = require("./batchTracker.js");
|
|
26
|
+
const scheduleManager_js_1 = require("./scheduleManager.js");
|
|
27
|
+
const index_js_3 = require("./opLifecycle/index.js");
|
|
28
|
+
const deltaManagerSummarizerProxy_js_1 = require("./deltaManagerSummarizerProxy.js");
|
|
29
|
+
const messageTypes_js_1 = require("./messageTypes.js");
|
|
30
30
|
/**
|
|
31
31
|
* Utility to implement compat behaviors given an unknown message type
|
|
32
32
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
@@ -56,26 +56,6 @@ exports.DefaultSummaryConfiguration = {
|
|
|
56
56
|
runtimeOpWeight: 1.0,
|
|
57
57
|
nonRuntimeHeuristicThreshold: 20,
|
|
58
58
|
};
|
|
59
|
-
/**
|
|
60
|
-
* Accepted header keys for requests coming to the runtime.
|
|
61
|
-
* @internal
|
|
62
|
-
*/
|
|
63
|
-
var RuntimeHeaders;
|
|
64
|
-
(function (RuntimeHeaders) {
|
|
65
|
-
/** True to wait for a data store to be created and loaded before returning it. */
|
|
66
|
-
RuntimeHeaders["wait"] = "wait";
|
|
67
|
-
/** True if the request is coming from an IFluidHandle. */
|
|
68
|
-
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
69
|
-
})(RuntimeHeaders || (exports.RuntimeHeaders = RuntimeHeaders = {}));
|
|
70
|
-
/** True if a tombstoned object should be returned without erroring
|
|
71
|
-
* @alpha
|
|
72
|
-
*/
|
|
73
|
-
exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
74
|
-
/**
|
|
75
|
-
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
76
|
-
* @internal
|
|
77
|
-
*/
|
|
78
|
-
exports.AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
79
59
|
/**
|
|
80
60
|
* Tombstone error responses will have this header set to true
|
|
81
61
|
* @alpha
|
|
@@ -192,7 +172,7 @@ async function createSummarizer(loader, url) {
|
|
|
192
172
|
[container_definitions_1.LoaderHeader.cache]: false,
|
|
193
173
|
[container_definitions_1.LoaderHeader.clientDetails]: {
|
|
194
174
|
capabilities: { interactive: false },
|
|
195
|
-
type:
|
|
175
|
+
type: index_js_1.summarizerClientType,
|
|
196
176
|
},
|
|
197
177
|
[driver_definitions_1.DriverHeader.summarizingClient]: true,
|
|
198
178
|
[container_definitions_1.LoaderHeader.reconnect]: false,
|
|
@@ -247,18 +227,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
247
227
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
248
228
|
const backCompatContext = context;
|
|
249
229
|
const passLogger = backCompatContext.taggedLogger ??
|
|
250
|
-
// eslint-disable-next-line import/no-deprecated
|
|
251
230
|
new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
|
|
252
231
|
const logger = (0, telemetry_utils_1.createChildLogger)({
|
|
253
232
|
logger: passLogger,
|
|
254
233
|
properties: {
|
|
255
234
|
all: {
|
|
256
|
-
runtimeVersion:
|
|
235
|
+
runtimeVersion: packageVersion_js_1.pkgVersion,
|
|
257
236
|
},
|
|
258
237
|
},
|
|
259
238
|
});
|
|
260
|
-
const
|
|
261
|
-
const
|
|
239
|
+
const mc = (0, telemetry_utils_1.loggerToMonitoringContext)(logger);
|
|
240
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = "off", chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
|
|
241
|
+
const registry = new dataStoreRegistry_js_1.FluidDataStoreRegistry(registryEntries);
|
|
262
242
|
const tryFetchBlob = async (blobName) => {
|
|
263
243
|
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
264
244
|
if (context.baseSnapshot && blobId) {
|
|
@@ -269,14 +249,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
269
249
|
}
|
|
270
250
|
};
|
|
271
251
|
const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
|
|
272
|
-
tryFetchBlob(
|
|
273
|
-
tryFetchBlob(
|
|
274
|
-
tryFetchBlob(
|
|
275
|
-
tryFetchBlob(
|
|
276
|
-
tryFetchBlob(
|
|
252
|
+
tryFetchBlob(index_js_1.chunksBlobName),
|
|
253
|
+
tryFetchBlob(index_js_1.metadataBlobName),
|
|
254
|
+
tryFetchBlob(index_js_1.electedSummarizerBlobName),
|
|
255
|
+
tryFetchBlob(index_js_1.aliasBlobName),
|
|
256
|
+
tryFetchBlob(index_js_1.idCompressorBlobName),
|
|
277
257
|
]);
|
|
278
258
|
// read snapshot blobs needed for BlobManager to load
|
|
279
|
-
const blobManagerSnapshot = await
|
|
259
|
+
const blobManagerSnapshot = await blobManager_js_1.BlobManager.load(context.baseSnapshot?.trees[index_js_1.blobsTreeName], async (id) => {
|
|
280
260
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
281
261
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
282
262
|
(0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
@@ -293,7 +273,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
293
273
|
// "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
|
|
294
274
|
const error = new telemetry_utils_1.DataCorruptionError(
|
|
295
275
|
// pre-0.58 error message: SummaryMetadataMismatch
|
|
296
|
-
"Summary metadata mismatch", { runtimeVersion:
|
|
276
|
+
"Summary metadata mismatch", { runtimeVersion: packageVersion_js_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
|
|
297
277
|
if (loadSequenceNumberVerification === "log") {
|
|
298
278
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
299
279
|
}
|
|
@@ -302,21 +282,62 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
302
282
|
}
|
|
303
283
|
}
|
|
304
284
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
285
|
+
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
286
|
+
// allow new containers to turn it on
|
|
287
|
+
let idCompressorMode;
|
|
288
|
+
if (existing) {
|
|
289
|
+
// This setting has to be sticky for correctness:
|
|
290
|
+
// 1) if compressior is OFF, it can't be enabled, as already running clients (in given document session) do not know
|
|
291
|
+
// how to process compressor ops
|
|
292
|
+
// 2) if it's ON, then all sessions should load compressor right away
|
|
293
|
+
// 3) Same logic applies for "delayed" mode
|
|
294
|
+
// Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
|
|
295
|
+
// We could do "off" -> "on" transtition too, if all clients start loading compressor (but not using it initially) and do so for a while -
|
|
296
|
+
// this will allow clients to eventually to disregard "off" setting (when it's safe so) and start using compressor in future sessions.
|
|
297
|
+
// Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
|
|
298
|
+
idCompressorMode = metadata?.idCompressorMode ?? "off";
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// FG overwrite
|
|
302
|
+
const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
|
|
303
|
+
switch (enabled) {
|
|
304
|
+
case true:
|
|
305
|
+
idCompressorMode = "on";
|
|
306
|
+
break;
|
|
307
|
+
case false:
|
|
308
|
+
idCompressorMode = "off";
|
|
309
|
+
break;
|
|
310
|
+
default:
|
|
311
|
+
idCompressorMode = enableRuntimeIdCompressor;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const createIdCompressorFn = async () => {
|
|
308
316
|
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import("@fluidframework/id-compressor");
|
|
317
|
+
/**
|
|
318
|
+
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
319
|
+
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
320
|
+
*/
|
|
321
|
+
const idCompressorEventSampler = (() => {
|
|
322
|
+
const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
|
|
323
|
+
return {
|
|
324
|
+
sample: () => {
|
|
325
|
+
return isIdCompressorTelemetryEnabled;
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
})();
|
|
329
|
+
const compressorLogger = (0, telemetry_utils_1.createSampledLogger)(logger, idCompressorEventSampler);
|
|
309
330
|
const pendingLocalState = context.pendingLocalState;
|
|
310
331
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
311
|
-
|
|
332
|
+
return deserializeIdCompressor(pendingLocalState.pendingIdCompressorState, compressorLogger);
|
|
312
333
|
}
|
|
313
334
|
else if (serializedIdCompressor !== undefined) {
|
|
314
|
-
|
|
335
|
+
return deserializeIdCompressor(serializedIdCompressor, createSessionId(), compressorLogger);
|
|
315
336
|
}
|
|
316
337
|
else {
|
|
317
|
-
|
|
338
|
+
return createIdCompressor(compressorLogger);
|
|
318
339
|
}
|
|
319
|
-
}
|
|
340
|
+
};
|
|
320
341
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
321
342
|
summaryOptions,
|
|
322
343
|
gcOptions,
|
|
@@ -328,7 +349,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
328
349
|
enableRuntimeIdCompressor,
|
|
329
350
|
enableOpReentryCheck,
|
|
330
351
|
enableGroupedBatching,
|
|
331
|
-
}, containerScope, logger, existing, blobManagerSnapshot, context.storage,
|
|
352
|
+
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, idCompressorMode, provideEntryPoint, requestHandler, undefined);
|
|
332
353
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
333
354
|
// or zero. This must be done before Container replays saved ops.
|
|
334
355
|
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
@@ -342,6 +363,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
342
363
|
get storage() {
|
|
343
364
|
return this._storage;
|
|
344
365
|
}
|
|
366
|
+
get containerRuntime() {
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
345
369
|
get flushMode() {
|
|
346
370
|
return this._flushMode;
|
|
347
371
|
}
|
|
@@ -354,6 +378,25 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
354
378
|
get attachState() {
|
|
355
379
|
return this._getAttachState();
|
|
356
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* See IContainerRuntimeBase.idCompressor() for details.
|
|
383
|
+
*/
|
|
384
|
+
get idCompressor() {
|
|
385
|
+
// Expose ID Compressor only if it's On from the start.
|
|
386
|
+
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
387
|
+
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
388
|
+
// to reason over such things as session ID space.
|
|
389
|
+
if (this.idCompressorMode === "on") {
|
|
390
|
+
(0, core_utils_1.assert)(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
391
|
+
return this._idCompressor;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* See IContainerRuntimeBase.generateDocumentUniqueId() for details.
|
|
396
|
+
*/
|
|
397
|
+
generateDocumentUniqueId() {
|
|
398
|
+
return this._idCompressor?.generateDocumentUniqueId() ?? (0, uuid_1.v4)();
|
|
399
|
+
}
|
|
357
400
|
get IFluidHandleContext() {
|
|
358
401
|
return this.handleContext;
|
|
359
402
|
}
|
|
@@ -391,9 +434,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
391
434
|
isSummariesDisabled() {
|
|
392
435
|
return this.summaryConfiguration.state === "disabled";
|
|
393
436
|
}
|
|
394
|
-
isHeuristicsDisabled() {
|
|
395
|
-
return this.summaryConfiguration.state === "disableHeuristics";
|
|
396
|
-
}
|
|
397
437
|
getMaxOpsSinceLastSummary() {
|
|
398
438
|
return this.summaryConfiguration.state !== "disabled"
|
|
399
439
|
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
@@ -418,7 +458,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
418
458
|
return this.garbageCollector.throwOnTombstoneUsage;
|
|
419
459
|
}
|
|
420
460
|
/***/
|
|
421
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage,
|
|
461
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, createIdCompressor, idCompressorMode, provideEntryPoint, requestHandler, summaryConfiguration = {
|
|
422
462
|
// the defaults
|
|
423
463
|
...exports.DefaultSummaryConfiguration,
|
|
424
464
|
// the runtime configuration overrides
|
|
@@ -426,13 +466,24 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
426
466
|
}) {
|
|
427
467
|
super();
|
|
428
468
|
this.registry = registry;
|
|
469
|
+
this.metadata = metadata;
|
|
429
470
|
this.runtimeOptions = runtimeOptions;
|
|
430
471
|
this.containerScope = containerScope;
|
|
431
472
|
this.logger = logger;
|
|
432
473
|
this._storage = _storage;
|
|
474
|
+
this.createIdCompressor = createIdCompressor;
|
|
475
|
+
this.idCompressorMode = idCompressorMode;
|
|
433
476
|
this.requestHandler = requestHandler;
|
|
434
477
|
this.summaryConfiguration = summaryConfiguration;
|
|
435
478
|
this.imminentClosure = false;
|
|
479
|
+
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
480
|
+
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
481
|
+
this.pendingIdCompressorOps = [];
|
|
482
|
+
/**
|
|
483
|
+
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
484
|
+
* this.idCompressorMode === "delayed" mode
|
|
485
|
+
*/
|
|
486
|
+
this.compressorLoadInitiated = false;
|
|
436
487
|
this.defaultMaxConsecutiveReconnects = 7;
|
|
437
488
|
this._orderSequentiallyCalls = 0;
|
|
438
489
|
this.flushTaskExists = false;
|
|
@@ -454,18 +505,27 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
454
505
|
signalTimestamp: 0,
|
|
455
506
|
trackingSignalSequenceNumber: undefined,
|
|
456
507
|
};
|
|
508
|
+
/**
|
|
509
|
+
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
510
|
+
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
511
|
+
*/
|
|
512
|
+
this.snapshotCacheForLoadingGroupIds = new core_utils_1.PromiseCache({
|
|
513
|
+
expiry: { policy: "absolute", durationMs: 60000 },
|
|
514
|
+
});
|
|
457
515
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
458
516
|
this.innerDeltaManager = deltaManager;
|
|
459
|
-
this.deltaManager = new
|
|
517
|
+
this.deltaManager = new deltaManagerSummarizerProxy_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
460
518
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
461
519
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
462
520
|
this.submitFn = submitFn;
|
|
463
521
|
this.submitBatchFn = submitBatchFn;
|
|
464
522
|
this.submitSummaryFn = submitSummaryFn;
|
|
465
523
|
this.submitSignalFn = submitSignalFn;
|
|
466
|
-
|
|
524
|
+
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
525
|
+
// Values are generally expected to be set from the runtime side.
|
|
526
|
+
this.options = options ?? {};
|
|
467
527
|
this.clientDetails = clientDetails;
|
|
468
|
-
this.isSummarizerClient = this.clientDetails.type ===
|
|
528
|
+
this.isSummarizerClient = this.clientDetails.type === index_js_1.summarizerClientType;
|
|
469
529
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
470
530
|
this._getClientId = () => context.clientId;
|
|
471
531
|
this._getAttachState = () => context.attachState;
|
|
@@ -501,19 +561,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
501
561
|
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
502
562
|
// the count is reset to 0.
|
|
503
563
|
loadSummaryNumber = metadata?.summaryNumber ?? 0;
|
|
504
|
-
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
505
|
-
// allow new containers to turn it on
|
|
506
|
-
this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
|
|
507
564
|
}
|
|
508
565
|
else {
|
|
509
566
|
this.createContainerMetadata = {
|
|
510
|
-
createContainerRuntimeVersion:
|
|
567
|
+
createContainerRuntimeVersion: packageVersion_js_1.pkgVersion,
|
|
511
568
|
createContainerTimestamp: Date.now(),
|
|
512
569
|
};
|
|
513
570
|
loadSummaryNumber = 0;
|
|
514
|
-
this.idCompressorEnabled =
|
|
515
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
|
|
516
|
-
idCompressor !== undefined;
|
|
517
571
|
}
|
|
518
572
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
519
573
|
this.messageAtLastSummary = metadata?.message;
|
|
@@ -524,21 +578,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
524
578
|
eventName: "GCFeatureMatrix",
|
|
525
579
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
526
580
|
inputs: JSON.stringify({
|
|
527
|
-
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[
|
|
581
|
+
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[index_js_2.gcGenerationOptionName],
|
|
528
582
|
}),
|
|
529
583
|
});
|
|
530
584
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? (0, uuid_1.v4)();
|
|
531
585
|
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
532
586
|
const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
|
|
533
|
-
const opGroupingManager = new
|
|
587
|
+
const opGroupingManager = new index_js_3.OpGroupingManager({
|
|
534
588
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
535
589
|
opCountThreshold: this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
536
590
|
reentrantBatchGroupingEnabled: this.mc.config.getBoolean("Fluid.ContainerRuntime.GroupedBatchingReentrancy") ??
|
|
537
591
|
true,
|
|
538
592
|
}, this.mc.logger);
|
|
539
|
-
const opSplitter = new
|
|
540
|
-
this.remoteMessageProcessor = new
|
|
541
|
-
this.handleContext = new
|
|
593
|
+
const opSplitter = new index_js_3.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
594
|
+
this.remoteMessageProcessor = new index_js_3.RemoteMessageProcessor(opSplitter, new index_js_3.OpDecompressor(this.mc.logger), opGroupingManager);
|
|
595
|
+
this.handleContext = new containerHandleContext_js_1.ContainerFluidHandleContext("", this);
|
|
542
596
|
if (this.summaryConfiguration.state === "enabled") {
|
|
543
597
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
544
598
|
}
|
|
@@ -548,12 +602,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
548
602
|
// Allow for a break-glass config to override the options
|
|
549
603
|
disableOpReentryCheck !== true;
|
|
550
604
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
551
|
-
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
552
605
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
553
606
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
554
|
-
if (this.idCompressorEnabled) {
|
|
555
|
-
this.idCompressor = idCompressor;
|
|
556
|
-
}
|
|
557
607
|
this.maxConsecutiveReconnects =
|
|
558
608
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
559
609
|
this.defaultMaxConsecutiveReconnects;
|
|
@@ -567,15 +617,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
567
617
|
this._flushMode = runtimeOptions.flushMode;
|
|
568
618
|
}
|
|
569
619
|
const pendingRuntimeState = pendingLocalState;
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
maxSnapshotCacheDurationMs
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
620
|
+
if (context.attachState === container_definitions_1.AttachState.Attached) {
|
|
621
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
622
|
+
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
623
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
|
|
624
|
+
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
625
|
+
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
626
|
+
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
627
|
+
throw new telemetry_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
this.garbageCollector = index_js_2.GarbageCollector.create({
|
|
579
631
|
runtime: this,
|
|
580
632
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
581
633
|
baseSnapshot,
|
|
@@ -588,9 +640,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
588
640
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
589
641
|
readAndParseBlob: async (id) => (0, driver_utils_1.readAndParse)(this.storage, id),
|
|
590
642
|
submitMessage: (message) => this.submit(message),
|
|
643
|
+
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
591
644
|
});
|
|
592
645
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
593
|
-
this.summarizerNode = (0,
|
|
646
|
+
this.summarizerNode = (0, index_js_1.createRootSummarizerNodeWithGC)((0, telemetry_utils_1.createChildLogger)({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
594
647
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
595
648
|
async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
596
649
|
// Latest change sequence number, no changes since summary applied yet
|
|
@@ -600,9 +653,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
600
653
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
601
654
|
// a summary with an older protocol state.
|
|
602
655
|
canReuseHandle: false,
|
|
603
|
-
// Must set to true to throw on any data stores failure that was too severe to be handled.
|
|
604
|
-
// We also are not decoding the base summaries at the root.
|
|
605
|
-
throwOnFailure: true,
|
|
606
656
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
607
657
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
608
658
|
},
|
|
@@ -613,17 +663,26 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
613
663
|
if (baseSnapshot) {
|
|
614
664
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
615
665
|
}
|
|
616
|
-
|
|
617
|
-
|
|
666
|
+
const parentContext = (0, channelCollection_js_1.wrapContext)(this);
|
|
667
|
+
// Due to a mismatch between different layers in terms of
|
|
668
|
+
// what is the interface of passing signals, we need the
|
|
669
|
+
// downstream stores to wrap the signal.
|
|
670
|
+
parentContext.submitSignal = (type, content, targetClientId) => {
|
|
671
|
+
const envelope1 = content;
|
|
672
|
+
const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
|
|
673
|
+
return this.submitSignalFn(envelope2, targetClientId);
|
|
674
|
+
};
|
|
675
|
+
this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (path, reason, timestampMs, packagePath, request, headerData) => this.garbageCollector.nodeUpdated(path, reason, timestampMs, packagePath, request, headerData), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
676
|
+
this.blobManager = new blobManager_js_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
618
677
|
if (!this.disposed) {
|
|
619
|
-
this.submit({ type:
|
|
678
|
+
this.submit({ type: messageTypes_js_1.ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
|
|
620
679
|
localId,
|
|
621
680
|
blobId,
|
|
622
681
|
});
|
|
623
682
|
}
|
|
624
683
|
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState?.pendingAttachmentBlobs, (error) => this.closeFn(error));
|
|
625
|
-
this.scheduleManager = new
|
|
626
|
-
this.pendingStateManager = new
|
|
684
|
+
this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, telemetry_utils_1.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
685
|
+
this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
|
|
627
686
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
628
687
|
clientId: () => this.clientId,
|
|
629
688
|
close: this.closeFn,
|
|
@@ -631,6 +690,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
631
690
|
reSubmit: this.reSubmit.bind(this),
|
|
632
691
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
633
692
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
693
|
+
isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
|
|
634
694
|
}, pendingRuntimeState?.pending, this.logger);
|
|
635
695
|
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
636
696
|
const compressionOptions = disableCompression === true
|
|
@@ -641,12 +701,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
641
701
|
: runtimeOptions.compressionOptions;
|
|
642
702
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
643
703
|
const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
|
|
644
|
-
this.outbox = new
|
|
704
|
+
this.outbox = new index_js_3.Outbox({
|
|
645
705
|
shouldSend: () => this.canSendOps(),
|
|
646
706
|
pendingStateManager: this.pendingStateManager,
|
|
647
707
|
submitBatchFn: this.submitBatchFn,
|
|
648
708
|
legacySendBatchFn,
|
|
649
|
-
compressor: new
|
|
709
|
+
compressor: new index_js_3.OpCompressor(this.mc.logger),
|
|
650
710
|
splitter: opSplitter,
|
|
651
711
|
config: {
|
|
652
712
|
compressionOptions,
|
|
@@ -673,7 +733,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
673
733
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
674
734
|
this.validateSummaryBeforeUpload =
|
|
675
735
|
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
676
|
-
this.summaryCollection = new
|
|
736
|
+
this.summaryCollection = new index_js_1.SummaryCollection(this.deltaManager, this.logger);
|
|
677
737
|
this.dirtyContainer =
|
|
678
738
|
this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
|
|
679
739
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
@@ -685,16 +745,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
685
745
|
logger: this.logger,
|
|
686
746
|
namespace: "OrderedClientElection",
|
|
687
747
|
});
|
|
688
|
-
const orderedClientCollection = new
|
|
689
|
-
const orderedClientElectionForSummarizer = new
|
|
690
|
-
this.summarizerClientElection = new
|
|
748
|
+
const orderedClientCollection = new index_js_1.OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
749
|
+
const orderedClientElectionForSummarizer = new index_js_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, index_js_1.SummarizerClientElection.isClientEligible);
|
|
750
|
+
this.summarizerClientElection = new index_js_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
691
751
|
if (this.isSummarizerClient) {
|
|
692
|
-
this._summarizer = new
|
|
752
|
+
this._summarizer = new index_js_1.Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => index_js_1.RunWhileConnectedCoordinator.create(runtime,
|
|
693
753
|
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
694
754
|
// information. The proxy delta manager would always return false for summarizer client.
|
|
695
755
|
() => this.innerDeltaManager.active));
|
|
696
756
|
}
|
|
697
|
-
else if (
|
|
757
|
+
else if (index_js_1.SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
698
758
|
// Only create a SummaryManager and SummarizerClientElection
|
|
699
759
|
// if summaries are enabled and we are not the summarizer client.
|
|
700
760
|
const defaultAction = () => {
|
|
@@ -716,13 +776,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
716
776
|
};
|
|
717
777
|
this.summaryCollection.on("default", defaultAction);
|
|
718
778
|
// Create the SummaryManager and mark the initial state
|
|
719
|
-
this.summaryManager = new
|
|
720
|
-
this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new
|
|
779
|
+
this.summaryManager = new index_js_1.SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
780
|
+
this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new throttler_js_1.Throttler(60 * 1000, // 60 sec delay window
|
|
721
781
|
30 * 1000, // 30 sec max delay
|
|
722
782
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
723
|
-
(0,
|
|
783
|
+
(0, throttler_js_1.formExponentialFn)({ coefficient: 20, initialDelay: 0 })), {
|
|
724
784
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
725
|
-
}
|
|
785
|
+
});
|
|
726
786
|
this.summaryManager.on("summarize", (eventProps) => {
|
|
727
787
|
this.emit("summarize", eventProps);
|
|
728
788
|
});
|
|
@@ -737,26 +797,27 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
737
797
|
this.mc.logger.sendTelemetryEvent({
|
|
738
798
|
eventName: "ContainerLoadStats",
|
|
739
799
|
...this.createContainerMetadata,
|
|
740
|
-
...this.
|
|
800
|
+
...this.channelCollection.containerLoadStats,
|
|
741
801
|
summaryNumber: loadSummaryNumber,
|
|
742
802
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
743
803
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
744
804
|
gcVersion: metadata?.gcFeature,
|
|
745
805
|
options: JSON.stringify(runtimeOptions),
|
|
806
|
+
idCompressorModeMetadata: metadata?.idCompressorMode,
|
|
807
|
+
idCompressorMode: this.idCompressorMode,
|
|
746
808
|
featureGates: JSON.stringify({
|
|
747
809
|
disableCompression,
|
|
748
810
|
disableOpReentryCheck,
|
|
749
811
|
disableChunking,
|
|
750
812
|
disableAttachReorder: this.disableAttachReorder,
|
|
751
813
|
disablePartialFlush,
|
|
752
|
-
idCompressorEnabled: this.idCompressorEnabled,
|
|
753
814
|
closeSummarizerDelayOverride,
|
|
754
815
|
}),
|
|
755
816
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
756
817
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
757
818
|
});
|
|
758
|
-
(0,
|
|
759
|
-
(0,
|
|
819
|
+
(0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
|
|
820
|
+
(0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
|
|
760
821
|
this.entryPoint = new core_utils_1.LazyPromise(async () => {
|
|
761
822
|
if (this.isSummarizerClient) {
|
|
762
823
|
(0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
@@ -764,11 +825,33 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
764
825
|
}
|
|
765
826
|
return provideEntryPoint(this);
|
|
766
827
|
});
|
|
828
|
+
// If we loaded from pending state, then we need to skip any ops that are already accounted in such
|
|
829
|
+
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
830
|
+
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
831
|
+
}
|
|
832
|
+
getCreateChildSummarizerNodeFn(id, createParam) {
|
|
833
|
+
return (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn);
|
|
834
|
+
}
|
|
835
|
+
deleteChildSummarizerNode(id) {
|
|
836
|
+
return this.summarizerNode.deleteChild(id);
|
|
837
|
+
}
|
|
838
|
+
/* IFluidParentContext APIs that should not be called on Root */
|
|
839
|
+
makeLocallyVisible() {
|
|
840
|
+
(0, core_utils_1.assert)(false, 0x8eb /* should not be called */);
|
|
841
|
+
}
|
|
842
|
+
setChannelDirty(address) {
|
|
843
|
+
(0, core_utils_1.assert)(false, "should not be called");
|
|
767
844
|
}
|
|
768
845
|
/**
|
|
769
846
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
770
847
|
*/
|
|
771
848
|
async initializeBaseState() {
|
|
849
|
+
if (this.idCompressorMode === "on" ||
|
|
850
|
+
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
851
|
+
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
852
|
+
(0, core_utils_1.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
853
|
+
this._idCompressor = await this.createIdCompressor();
|
|
854
|
+
}
|
|
772
855
|
await this.garbageCollector.initializeBaseState();
|
|
773
856
|
}
|
|
774
857
|
dispose(error) {
|
|
@@ -787,11 +870,110 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
787
870
|
}
|
|
788
871
|
this.garbageCollector.dispose();
|
|
789
872
|
this._summarizer?.dispose();
|
|
790
|
-
this.
|
|
873
|
+
this.channelCollection.dispose();
|
|
791
874
|
this.pendingStateManager.dispose();
|
|
792
875
|
this.emit("dispose");
|
|
793
876
|
this.removeAllListeners();
|
|
794
877
|
}
|
|
878
|
+
/**
|
|
879
|
+
* Api to fetch the snapshot from the service for a loadingGroupIds.
|
|
880
|
+
* @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for.
|
|
881
|
+
* @param pathParts - Parts of the path, which we want to extract from the snapshot tree.
|
|
882
|
+
* @returns - snapshotTree and the sequence number of the snapshot.
|
|
883
|
+
*/
|
|
884
|
+
async getSnapshotForLoadingGroupId(loadingGroupIds, pathParts) {
|
|
885
|
+
const sortedLoadingGroupIds = loadingGroupIds.sort();
|
|
886
|
+
(0, core_utils_1.assert)(this.storage.getSnapshot !== undefined, 0x8ed /* getSnapshot api should be defined if used */);
|
|
887
|
+
let loadedFromCache = true;
|
|
888
|
+
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
889
|
+
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
890
|
+
// any request, then cache that as same group could be requested in future too.
|
|
891
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(), async () => {
|
|
892
|
+
(0, core_utils_1.assert)(this.storage.getSnapshot !== undefined, 0x8ee /* getSnapshot api should be defined if used */);
|
|
893
|
+
loadedFromCache = false;
|
|
894
|
+
return this.storage.getSnapshot({
|
|
895
|
+
cacheSnapshot: false,
|
|
896
|
+
scenarioName: "snapshotForLoadingGroupId",
|
|
897
|
+
loadingGroupIds: sortedLoadingGroupIds,
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
this.logger.sendTelemetryEvent({
|
|
901
|
+
eventName: "GroupIdSnapshotFetched",
|
|
902
|
+
details: JSON.stringify({
|
|
903
|
+
fromCache: loadedFromCache,
|
|
904
|
+
loadingGroupIds: loadingGroupIds.join(","),
|
|
905
|
+
}),
|
|
906
|
+
});
|
|
907
|
+
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
908
|
+
const hasIsolatedChannels = (0, index_js_1.rootHasIsolatedChannels)(this.metadata);
|
|
909
|
+
const snapshotTreeForPath = this.getSnapshotTreeForPath(snapshot.snapshotTree, pathParts, hasIsolatedChannels);
|
|
910
|
+
(0, core_utils_1.assert)(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
911
|
+
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
912
|
+
(0, core_utils_1.assert)(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
|
|
913
|
+
// This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
|
|
914
|
+
// Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
|
|
915
|
+
// the file has been overwritten or service lost data.
|
|
916
|
+
if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
|
|
917
|
+
throw telemetry_utils_1.DataProcessingError.create("Downloaded snapshot older than snapshot we loaded from", "getSnapshotForLoadingGroupId", undefined, {
|
|
918
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
919
|
+
snapshotSeqNumber,
|
|
920
|
+
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
// If the snapshot is ahead of the last seq number of the delta manager, then catch up before
|
|
924
|
+
// returning the snapshot.
|
|
925
|
+
if (snapshotSeqNumber > this.deltaManager.lastSequenceNumber) {
|
|
926
|
+
// If this is a summarizer client, which is trying to load a group and it finds that there is
|
|
927
|
+
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
928
|
+
// the summarizer state is not up to date.
|
|
929
|
+
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
930
|
+
if (this.isSummarizerClient) {
|
|
931
|
+
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
932
|
+
}
|
|
933
|
+
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
934
|
+
const props = {
|
|
935
|
+
eventName: "GroupIdSnapshotCatchup",
|
|
936
|
+
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
937
|
+
targetSequenceNumber: snapshotSeqNumber,
|
|
938
|
+
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
939
|
+
};
|
|
940
|
+
const event = telemetry_utils_1.PerformanceEvent.start(this.mc.logger, {
|
|
941
|
+
...props,
|
|
942
|
+
});
|
|
943
|
+
// If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
|
|
944
|
+
// as long as it's not a summarizer client.
|
|
945
|
+
if (this.deltaManager.inbound.paused) {
|
|
946
|
+
props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
|
|
947
|
+
}
|
|
948
|
+
const defP = new core_utils_1.Deferred();
|
|
949
|
+
this.deltaManager.on("op", (message) => {
|
|
950
|
+
if (message.sequenceNumber >= snapshotSeqNumber) {
|
|
951
|
+
defP.resolve(true);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
await defP.promise;
|
|
955
|
+
event.end(props);
|
|
956
|
+
}
|
|
957
|
+
return { snapshotTree: snapshotTreeForPath, sequenceNumber: snapshotSeqNumber };
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array.
|
|
961
|
+
* @param snapshotTree - snapshot tree to look into.
|
|
962
|
+
* @param pathParts - Part of the path, which we want to extract from the snapshot tree.
|
|
963
|
+
* @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older
|
|
964
|
+
* snapshots will not have trees inside ".channels", so check that.
|
|
965
|
+
* @returns - requested snapshot tree based on the path parts.
|
|
966
|
+
*/
|
|
967
|
+
getSnapshotTreeForPath(snapshotTree, pathParts, hasIsolatedChannels) {
|
|
968
|
+
let childTree = snapshotTree;
|
|
969
|
+
for (const part of pathParts) {
|
|
970
|
+
if (hasIsolatedChannels) {
|
|
971
|
+
childTree = childTree?.trees[runtime_definitions_1.channelsTreeName];
|
|
972
|
+
}
|
|
973
|
+
childTree = childTree?.trees[part];
|
|
974
|
+
}
|
|
975
|
+
return childTree;
|
|
976
|
+
}
|
|
795
977
|
/**
|
|
796
978
|
* Notifies this object about the request made to the container.
|
|
797
979
|
* @param request - Request made to the handler.
|
|
@@ -834,7 +1016,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
834
1016
|
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
835
1017
|
return this.resolveHandle(requestParser.createSubRequest(1));
|
|
836
1018
|
}
|
|
837
|
-
if (id ===
|
|
1019
|
+
if (id === blobManager_js_1.BlobManager.basePath && requestParser.isLeaf(2)) {
|
|
838
1020
|
const blob = await this.blobManager.getBlob(requestParser.pathParts[1]);
|
|
839
1021
|
return blob
|
|
840
1022
|
? {
|
|
@@ -845,15 +1027,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
845
1027
|
: (0, runtime_utils_1.create404Response)(request);
|
|
846
1028
|
}
|
|
847
1029
|
else if (requestParser.pathParts.length > 0) {
|
|
848
|
-
|
|
849
|
-
const requestForChild = !requestParser.isLeaf(1);
|
|
850
|
-
const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
|
|
851
|
-
const subRequest = requestParser.createSubRequest(1);
|
|
852
|
-
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
853
|
-
// unintentionally modifying the url if that changes.
|
|
854
|
-
(0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
|
|
855
|
-
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
856
|
-
return dataStore.request(subRequest);
|
|
1030
|
+
return await this.channelCollection.request(request);
|
|
857
1031
|
}
|
|
858
1032
|
return (0, runtime_utils_1.create404Response)(request);
|
|
859
1033
|
}
|
|
@@ -868,38 +1042,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
868
1042
|
return this.entryPoint;
|
|
869
1043
|
}
|
|
870
1044
|
internalId(maybeAlias) {
|
|
871
|
-
return this.
|
|
872
|
-
}
|
|
873
|
-
async getDataStoreFromRequest(id, request, requestForChild) {
|
|
874
|
-
const headerData = {};
|
|
875
|
-
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
876
|
-
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
877
|
-
}
|
|
878
|
-
if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
|
|
879
|
-
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
880
|
-
}
|
|
881
|
-
if (typeof request.headers?.[exports.AllowTombstoneRequestHeaderKey] === "boolean") {
|
|
882
|
-
headerData.allowTombstone = request.headers[exports.AllowTombstoneRequestHeaderKey];
|
|
883
|
-
}
|
|
884
|
-
if (typeof request.headers?.[exports.AllowInactiveRequestHeaderKey] === "boolean") {
|
|
885
|
-
headerData.allowInactive = request.headers[exports.AllowInactiveRequestHeaderKey];
|
|
886
|
-
}
|
|
887
|
-
// We allow Tombstone requests for sub-DataStore objects
|
|
888
|
-
if (requestForChild) {
|
|
889
|
-
headerData.allowTombstone = true;
|
|
890
|
-
}
|
|
891
|
-
await this.dataStores.waitIfPendingAlias(id);
|
|
892
|
-
const internalId = this.internalId(id);
|
|
893
|
-
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
894
|
-
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
895
|
-
// the same as GC nodes id.
|
|
896
|
-
const urlWithoutQuery = (0, gc_1.trimLeadingAndTrailingSlashes)(request.url.split("?")[0]);
|
|
897
|
-
// Get the initial snapshot details which contain the data store package path.
|
|
898
|
-
const details = await dataStoreContext.getInitialSnapshotDetails();
|
|
899
|
-
// Note that this will throw if the data store is inactive or tombstoned and throwing on incorrect usage
|
|
900
|
-
// is configured.
|
|
901
|
-
this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, details.pkg, request, headerData);
|
|
902
|
-
return dataStoreContext.realize();
|
|
1045
|
+
return this.channelCollection.internalId(maybeAlias);
|
|
903
1046
|
}
|
|
904
1047
|
/** Adds the container's metadata to the given summary tree. */
|
|
905
1048
|
addMetadataToSummary(summaryTree) {
|
|
@@ -911,37 +1054,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
911
1054
|
...this.garbageCollector.getMetadata(),
|
|
912
1055
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
913
1056
|
// last summary.
|
|
914
|
-
message: (0,
|
|
1057
|
+
message: (0, index_js_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage) ??
|
|
915
1058
|
this.messageAtLastSummary,
|
|
916
1059
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
917
|
-
|
|
1060
|
+
idCompressorMode: this.idCompressorMode,
|
|
918
1061
|
};
|
|
919
|
-
(0, runtime_utils_1.addBlobToSummary)(summaryTree,
|
|
1062
|
+
(0, runtime_utils_1.addBlobToSummary)(summaryTree, index_js_1.metadataBlobName, JSON.stringify(metadata));
|
|
920
1063
|
}
|
|
921
1064
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
922
1065
|
this.addMetadataToSummary(summaryTree);
|
|
923
|
-
if (this.
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
(0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.idCompressorBlobName, idCompressorState);
|
|
1066
|
+
if (this._idCompressor) {
|
|
1067
|
+
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
1068
|
+
(0, runtime_utils_1.addBlobToSummary)(summaryTree, index_js_1.idCompressorBlobName, idCompressorState);
|
|
927
1069
|
}
|
|
928
1070
|
if (this.remoteMessageProcessor.partialMessages.size > 0) {
|
|
929
1071
|
const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
|
|
930
|
-
(0, runtime_utils_1.addBlobToSummary)(summaryTree,
|
|
1072
|
+
(0, runtime_utils_1.addBlobToSummary)(summaryTree, index_js_1.chunksBlobName, content);
|
|
931
1073
|
}
|
|
932
|
-
const dataStoreAliases = this.
|
|
1074
|
+
const dataStoreAliases = this.channelCollection.aliases;
|
|
933
1075
|
if (dataStoreAliases.size > 0) {
|
|
934
|
-
(0, runtime_utils_1.addBlobToSummary)(summaryTree,
|
|
1076
|
+
(0, runtime_utils_1.addBlobToSummary)(summaryTree, index_js_1.aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
935
1077
|
}
|
|
936
1078
|
if (this.summarizerClientElection) {
|
|
937
1079
|
const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
|
|
938
|
-
(0, runtime_utils_1.addBlobToSummary)(summaryTree,
|
|
1080
|
+
(0, runtime_utils_1.addBlobToSummary)(summaryTree, index_js_1.electedSummarizerBlobName, electedSummarizerContent);
|
|
939
1081
|
}
|
|
940
1082
|
const blobManagerSummary = this.blobManager.summarize();
|
|
941
1083
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
942
1084
|
// and the blob manager can handle the tree not existing when loading
|
|
943
1085
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
944
|
-
(0, runtime_utils_1.
|
|
1086
|
+
(0, runtime_utils_1.addSummarizeResultToSummary)(summaryTree, index_js_1.blobsTreeName, blobManagerSummary);
|
|
945
1087
|
}
|
|
946
1088
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
947
1089
|
if (gcSummary !== undefined) {
|
|
@@ -981,7 +1123,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
981
1123
|
// in their own batches before the originating batch is sent.
|
|
982
1124
|
// Therefore, receiving them while attempting to send the originating batch
|
|
983
1125
|
// does not mean that the container is making any progress.
|
|
984
|
-
if (message?.type !==
|
|
1126
|
+
if (message?.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp) {
|
|
985
1127
|
this.consecutiveReconnects = 0;
|
|
986
1128
|
}
|
|
987
1129
|
}
|
|
@@ -1027,21 +1169,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1027
1169
|
// Need to parse from string for back-compat
|
|
1028
1170
|
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
1029
1171
|
switch (opContents.type) {
|
|
1030
|
-
case
|
|
1031
|
-
|
|
1032
|
-
case
|
|
1033
|
-
return this.
|
|
1034
|
-
case
|
|
1035
|
-
(0, core_utils_1.assert)(this.
|
|
1172
|
+
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp:
|
|
1173
|
+
case messageTypes_js_1.ContainerMessageType.Attach:
|
|
1174
|
+
case messageTypes_js_1.ContainerMessageType.Alias:
|
|
1175
|
+
return this.channelCollection.applyStashedOp(opContents);
|
|
1176
|
+
case messageTypes_js_1.ContainerMessageType.IdAllocation:
|
|
1177
|
+
(0, core_utils_1.assert)(this.idCompressorMode !== "off", 0x8f1 /* ID compressor should be in use */);
|
|
1036
1178
|
return;
|
|
1037
|
-
case
|
|
1038
|
-
case messageTypes_1.ContainerMessageType.BlobAttach:
|
|
1179
|
+
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
1039
1180
|
return;
|
|
1040
|
-
case
|
|
1181
|
+
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
1041
1182
|
throw new Error("chunkedOp not expected here");
|
|
1042
|
-
case
|
|
1183
|
+
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
1043
1184
|
throw new Error("rejoin not expected here");
|
|
1044
|
-
case
|
|
1185
|
+
case messageTypes_js_1.ContainerMessageType.GC:
|
|
1045
1186
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
1046
1187
|
throw new telemetry_utils_1.LoggingError("GC op not expected to be stashed in summarizer");
|
|
1047
1188
|
default: {
|
|
@@ -1059,10 +1200,26 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1059
1200
|
this.closeFn(error);
|
|
1060
1201
|
throw error;
|
|
1061
1202
|
}
|
|
1203
|
+
// Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
|
|
1204
|
+
// All we can do is ignore it (similar to on process).
|
|
1062
1205
|
}
|
|
1063
1206
|
}
|
|
1064
1207
|
}
|
|
1065
1208
|
setConnectionState(connected, clientId) {
|
|
1209
|
+
if (connected && this.idCompressorMode === "delayed" && !this.compressorLoadInitiated) {
|
|
1210
|
+
this.compressorLoadInitiated = true;
|
|
1211
|
+
this.createIdCompressor()
|
|
1212
|
+
.then((compressor) => {
|
|
1213
|
+
this._idCompressor = compressor;
|
|
1214
|
+
for (const range of this.pendingIdCompressorOps) {
|
|
1215
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
1216
|
+
}
|
|
1217
|
+
this.pendingIdCompressorOps = [];
|
|
1218
|
+
})
|
|
1219
|
+
.catch((error) => {
|
|
1220
|
+
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1066
1223
|
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
1067
1224
|
this.delayConnectClientId = undefined;
|
|
1068
1225
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -1126,7 +1283,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1126
1283
|
if (changeOfState) {
|
|
1127
1284
|
this.replayPendingStates();
|
|
1128
1285
|
}
|
|
1129
|
-
this.
|
|
1286
|
+
this.channelCollection.setConnectionState(connected, clientId);
|
|
1130
1287
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
1131
1288
|
(0, telemetry_utils_1.raiseConnectedEvent)(this.mc.logger, this, connected, clientId);
|
|
1132
1289
|
}
|
|
@@ -1176,7 +1333,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1176
1333
|
let localOpMetadata;
|
|
1177
1334
|
if (local &&
|
|
1178
1335
|
messageWithContext.modernRuntimeMessage &&
|
|
1179
|
-
message.type !==
|
|
1336
|
+
message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp) {
|
|
1180
1337
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
|
|
1181
1338
|
}
|
|
1182
1339
|
// If there are no more pending messages after processing a local message,
|
|
@@ -1208,31 +1365,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1208
1365
|
// TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
|
|
1209
1366
|
const { local } = messageWithContext;
|
|
1210
1367
|
switch (messageWithContext.message.type) {
|
|
1211
|
-
case
|
|
1212
|
-
|
|
1368
|
+
case messageTypes_js_1.ContainerMessageType.Attach:
|
|
1369
|
+
case messageTypes_js_1.ContainerMessageType.Alias:
|
|
1370
|
+
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp:
|
|
1371
|
+
this.channelCollection.process(messageWithContext.message, local, localOpMetadata, (from, to) => this.garbageCollector.addedOutboundReference(from, to));
|
|
1213
1372
|
break;
|
|
1214
|
-
case
|
|
1215
|
-
this.dataStores.processAliasMessage(messageWithContext.message, localOpMetadata, local);
|
|
1216
|
-
break;
|
|
1217
|
-
case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
|
|
1218
|
-
this.dataStores.processFluidDataStoreOp(messageWithContext.message, local, localOpMetadata, (from, to) => this.garbageCollector.addedOutboundReference(from, to));
|
|
1219
|
-
break;
|
|
1220
|
-
case messageTypes_1.ContainerMessageType.BlobAttach:
|
|
1373
|
+
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
1221
1374
|
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
1222
1375
|
break;
|
|
1223
|
-
case
|
|
1224
|
-
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1376
|
+
case messageTypes_js_1.ContainerMessageType.IdAllocation:
|
|
1225
1377
|
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
1226
1378
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1227
|
-
|
|
1228
|
-
|
|
1379
|
+
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1380
|
+
// thus we need to process all the ops.
|
|
1381
|
+
if (!(this.skipSavedCompressorOps &&
|
|
1382
|
+
messageWithContext.message.metadata?.savedOp ===
|
|
1383
|
+
true)) {
|
|
1384
|
+
const range = messageWithContext.message.contents;
|
|
1385
|
+
if (this._idCompressor === undefined) {
|
|
1386
|
+
this.pendingIdCompressorOps.push(range);
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
1390
|
+
}
|
|
1229
1391
|
}
|
|
1230
1392
|
break;
|
|
1231
|
-
case
|
|
1393
|
+
case messageTypes_js_1.ContainerMessageType.GC:
|
|
1232
1394
|
this.garbageCollector.processMessage(messageWithContext.message, local);
|
|
1233
1395
|
break;
|
|
1234
|
-
case
|
|
1235
|
-
case
|
|
1396
|
+
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
1397
|
+
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
1236
1398
|
break;
|
|
1237
1399
|
default: {
|
|
1238
1400
|
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
@@ -1312,7 +1474,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1312
1474
|
this.emit("signal", transformed, local);
|
|
1313
1475
|
return;
|
|
1314
1476
|
}
|
|
1315
|
-
|
|
1477
|
+
// Due to a mismatch between different layers in terms of
|
|
1478
|
+
// what is the interface of passing signals, we need to adjust
|
|
1479
|
+
// the signal envelope before sending it to the datastores to be processed
|
|
1480
|
+
const envelope2 = {
|
|
1481
|
+
address: envelope.address,
|
|
1482
|
+
contents: transformed.content,
|
|
1483
|
+
};
|
|
1484
|
+
transformed.content = envelope2;
|
|
1485
|
+
this.channelCollection.processSignal(transformed, local);
|
|
1316
1486
|
}
|
|
1317
1487
|
/**
|
|
1318
1488
|
* Flush the pending ops manually.
|
|
@@ -1323,6 +1493,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1323
1493
|
this.outbox.flush();
|
|
1324
1494
|
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
1325
1495
|
}
|
|
1496
|
+
/**
|
|
1497
|
+
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially}
|
|
1498
|
+
*/
|
|
1326
1499
|
orderSequentially(callback) {
|
|
1327
1500
|
let checkpoint;
|
|
1328
1501
|
let result;
|
|
@@ -1351,8 +1524,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1351
1524
|
}
|
|
1352
1525
|
}
|
|
1353
1526
|
else {
|
|
1354
|
-
|
|
1355
|
-
|
|
1527
|
+
this.closeFn((0, telemetry_utils_1.wrapError)(error, (errorMessage) => new telemetry_utils_1.GenericError(`orderSequentially callback exception: ${errorMessage}`, error, {
|
|
1528
|
+
orderSequentiallyCalls: this._orderSequentiallyCalls,
|
|
1529
|
+
})));
|
|
1356
1530
|
}
|
|
1357
1531
|
throw error; // throw the original error for the consumer of the runtime
|
|
1358
1532
|
}
|
|
@@ -1372,9 +1546,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1372
1546
|
* Returns undefined if no data store has been assigned the given alias.
|
|
1373
1547
|
*/
|
|
1374
1548
|
async getAliasedDataStoreEntryPoint(alias) {
|
|
1375
|
-
|
|
1549
|
+
// Back-comapatibility:
|
|
1550
|
+
// There are old files that were created without using data store aliasing feature, but
|
|
1551
|
+
// used createRoot*DataStore*() (already removed) API. Such data stores will have isRoot = true,
|
|
1552
|
+
// and internalID provided by user. The expectation is that such files behave as new files, where
|
|
1553
|
+
// same data store instances created using aliasing feature.
|
|
1554
|
+
// Please also see note on name collisions in DataStores.createDataStoreId()
|
|
1555
|
+
await this.channelCollection.waitIfPendingAlias(alias);
|
|
1376
1556
|
const internalId = this.internalId(alias);
|
|
1377
|
-
const context = await this.
|
|
1557
|
+
const context = await this.channelCollection.getDataStoreIfAvailable(internalId, {
|
|
1558
|
+
wait: false,
|
|
1559
|
+
});
|
|
1378
1560
|
// If the data store is not available or not an alias, return undefined.
|
|
1379
1561
|
if (context === undefined || !(await context.isRoot())) {
|
|
1380
1562
|
return undefined;
|
|
@@ -1386,28 +1568,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1386
1568
|
this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
|
|
1387
1569
|
return channel.entryPoint;
|
|
1388
1570
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
throw new telemetry_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
1392
|
-
}
|
|
1393
|
-
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
1571
|
+
createDetachedDataStore(pkg, loadingGroupId) {
|
|
1572
|
+
return this.channelCollection.createDetachedDataStore(pkg, loadingGroupId);
|
|
1394
1573
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
const id = (0, uuid_1.v4)();
|
|
1400
|
-
return (0, dataStore_1.channelToDataStore)(await this.dataStores
|
|
1401
|
-
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
|
|
1402
|
-
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1574
|
+
async createDataStore(pkg, loadingGroupId) {
|
|
1575
|
+
const context = this.channelCollection.createDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], undefined, // props
|
|
1576
|
+
loadingGroupId);
|
|
1577
|
+
return (0, dataStore_js_1.channelToDataStore)(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1403
1578
|
}
|
|
1404
1579
|
/**
|
|
1405
1580
|
* @deprecated 0.16 Issue #1537, #3631
|
|
1406
1581
|
*/
|
|
1407
|
-
async _createDataStoreWithProps(pkg, props
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1582
|
+
async _createDataStoreWithProps(pkg, props) {
|
|
1583
|
+
const context = this.channelCollection.createDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], props);
|
|
1584
|
+
return (0, dataStore_js_1.channelToDataStore)(await context.realize(), context.id, this.channelCollection, this.mc.logger);
|
|
1411
1585
|
}
|
|
1412
1586
|
canSendOps() {
|
|
1413
1587
|
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
@@ -1437,21 +1611,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1437
1611
|
// Certain container runtime messages should not mark the container dirty such as the old built-in
|
|
1438
1612
|
// AgentScheduler and Garbage collector messages.
|
|
1439
1613
|
switch (type) {
|
|
1440
|
-
case
|
|
1614
|
+
case messageTypes_js_1.ContainerMessageType.Attach: {
|
|
1441
1615
|
const attachMessage = contents;
|
|
1442
1616
|
if (attachMessage.id === exports.agentSchedulerId) {
|
|
1443
1617
|
return false;
|
|
1444
1618
|
}
|
|
1445
1619
|
break;
|
|
1446
1620
|
}
|
|
1447
|
-
case
|
|
1621
|
+
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp: {
|
|
1448
1622
|
const envelope = contents;
|
|
1449
1623
|
if (envelope.address === exports.agentSchedulerId) {
|
|
1450
1624
|
return false;
|
|
1451
1625
|
}
|
|
1452
1626
|
break;
|
|
1453
1627
|
}
|
|
1454
|
-
case
|
|
1628
|
+
case messageTypes_js_1.ContainerMessageType.GC: {
|
|
1455
1629
|
return false;
|
|
1456
1630
|
}
|
|
1457
1631
|
default:
|
|
@@ -1485,16 +1659,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1485
1659
|
const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
|
|
1486
1660
|
return this.submitSignalFn(envelope, targetClientId);
|
|
1487
1661
|
}
|
|
1488
|
-
/**
|
|
1489
|
-
* Submits the signal to be sent to other clients.
|
|
1490
|
-
* @param type - Type of the signal.
|
|
1491
|
-
* @param content - Content of the signal.
|
|
1492
|
-
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
1493
|
-
*/
|
|
1494
|
-
submitDataStoreSignal(address, type, content, targetClientId) {
|
|
1495
|
-
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
1496
|
-
return this.submitSignalFn(envelope, targetClientId);
|
|
1497
|
-
}
|
|
1498
1662
|
setAttachState(attachState) {
|
|
1499
1663
|
if (attachState === container_definitions_1.AttachState.Attaching) {
|
|
1500
1664
|
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
|
|
@@ -1506,7 +1670,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1506
1670
|
if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
|
|
1507
1671
|
this.updateDocumentDirtyState(false);
|
|
1508
1672
|
}
|
|
1509
|
-
this.
|
|
1673
|
+
this.channelCollection.setAttachState(attachState);
|
|
1510
1674
|
}
|
|
1511
1675
|
/**
|
|
1512
1676
|
* Create a summary. Used when attaching or serializing a detached container.
|
|
@@ -1521,20 +1685,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1521
1685
|
this.blobManager.setRedirectTable(blobRedirectTable);
|
|
1522
1686
|
}
|
|
1523
1687
|
// We can finalize any allocated IDs since we're the only client
|
|
1524
|
-
const idRange = this.
|
|
1688
|
+
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
1525
1689
|
if (idRange !== undefined) {
|
|
1526
|
-
this.
|
|
1690
|
+
this._idCompressor?.finalizeCreationRange(idRange);
|
|
1527
1691
|
}
|
|
1528
|
-
const summarizeResult = this.
|
|
1692
|
+
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
1529
1693
|
// Wrap data store summaries in .channels subtree.
|
|
1530
|
-
(0,
|
|
1694
|
+
(0, index_js_1.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1531
1695
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
1532
1696
|
return summarizeResult.summary;
|
|
1533
1697
|
}
|
|
1534
1698
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
1535
|
-
const summarizeResult = await this.
|
|
1699
|
+
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
1536
1700
|
// Wrap data store summaries in .channels subtree.
|
|
1537
|
-
(0,
|
|
1701
|
+
(0, index_js_1.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1538
1702
|
const pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
|
|
1539
1703
|
this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
|
|
1540
1704
|
return {
|
|
@@ -1580,10 +1744,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1580
1744
|
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
1581
1745
|
*/
|
|
1582
1746
|
async updateStateBeforeGC() {
|
|
1583
|
-
return this.
|
|
1747
|
+
return this.channelCollection.updateStateBeforeGC();
|
|
1584
1748
|
}
|
|
1585
1749
|
async getGCDataInternal(fullGC) {
|
|
1586
|
-
return this.
|
|
1750
|
+
return this.channelCollection.getGCData(fullGC);
|
|
1587
1751
|
}
|
|
1588
1752
|
/**
|
|
1589
1753
|
* Generates and returns the GC data for this container.
|
|
@@ -1609,22 +1773,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1609
1773
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1610
1774
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1611
1775
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
1612
|
-
this.
|
|
1613
|
-
}
|
|
1614
|
-
/**
|
|
1615
|
-
* This is called to update objects whose routes are unused.
|
|
1616
|
-
* @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
|
|
1617
|
-
*/
|
|
1618
|
-
updateUnusedRoutes(unusedRoutes) {
|
|
1619
|
-
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
1620
|
-
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1621
|
-
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
1622
|
-
}
|
|
1623
|
-
/**
|
|
1624
|
-
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
1625
|
-
*/
|
|
1626
|
-
deleteUnusedNodes(unusedRoutes) {
|
|
1627
|
-
throw new Error("deleteUnusedRoutes should not be called");
|
|
1776
|
+
this.channelCollection.updateUsedRoutes(dataStoreRoutes);
|
|
1628
1777
|
}
|
|
1629
1778
|
/**
|
|
1630
1779
|
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
@@ -1633,7 +1782,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1633
1782
|
*/
|
|
1634
1783
|
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
1635
1784
|
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
1636
|
-
const deletedRoutes = this.
|
|
1785
|
+
const deletedRoutes = this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes);
|
|
1637
1786
|
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
1638
1787
|
}
|
|
1639
1788
|
/**
|
|
@@ -1647,7 +1796,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1647
1796
|
updateTombstonedRoutes(tombstonedRoutes) {
|
|
1648
1797
|
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
1649
1798
|
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
1650
|
-
this.
|
|
1799
|
+
this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
|
|
1651
1800
|
}
|
|
1652
1801
|
/**
|
|
1653
1802
|
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
@@ -1663,21 +1812,26 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1663
1812
|
*/
|
|
1664
1813
|
getNodeType(nodePath) {
|
|
1665
1814
|
if (this.isBlobPath(nodePath)) {
|
|
1666
|
-
return
|
|
1815
|
+
return index_js_2.GCNodeType.Blob;
|
|
1667
1816
|
}
|
|
1668
|
-
return this.
|
|
1817
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? index_js_2.GCNodeType.Other;
|
|
1669
1818
|
}
|
|
1670
1819
|
/**
|
|
1671
1820
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
1672
1821
|
* data store or an attachment blob.
|
|
1673
1822
|
*/
|
|
1674
1823
|
async getGCNodePackagePath(nodePath) {
|
|
1824
|
+
// GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
|
|
1825
|
+
// These have no package path so return a special value.
|
|
1826
|
+
if (nodePath === "/") {
|
|
1827
|
+
return ["_gcRoot"];
|
|
1828
|
+
}
|
|
1675
1829
|
switch (this.getNodeType(nodePath)) {
|
|
1676
|
-
case
|
|
1677
|
-
return [
|
|
1678
|
-
case
|
|
1679
|
-
case
|
|
1680
|
-
return this.
|
|
1830
|
+
case index_js_2.GCNodeType.Blob:
|
|
1831
|
+
return [blobManager_js_1.BlobManager.basePath];
|
|
1832
|
+
case index_js_2.GCNodeType.DataStore:
|
|
1833
|
+
case index_js_2.GCNodeType.SubDataStore:
|
|
1834
|
+
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
1681
1835
|
default:
|
|
1682
1836
|
(0, core_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
1683
1837
|
}
|
|
@@ -1687,7 +1841,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1687
1841
|
*/
|
|
1688
1842
|
isBlobPath(path) {
|
|
1689
1843
|
const pathParts = path.split("/");
|
|
1690
|
-
if (pathParts.length < 2 || pathParts[1] !==
|
|
1844
|
+
if (pathParts.length < 2 || pathParts[1] !== blobManager_js_1.BlobManager.basePath) {
|
|
1691
1845
|
return false;
|
|
1692
1846
|
}
|
|
1693
1847
|
return true;
|
|
@@ -1736,7 +1890,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1736
1890
|
* @param options - options controlling how the summary is generated or submitted
|
|
1737
1891
|
*/
|
|
1738
1892
|
async submitSummary(options) {
|
|
1739
|
-
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
|
|
1893
|
+
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
1740
1894
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1741
1895
|
// use it for all events logged during this summary.
|
|
1742
1896
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1748,7 +1902,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1748
1902
|
});
|
|
1749
1903
|
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
1750
1904
|
// We close the summarizer and download a new snapshot and reload the container
|
|
1751
|
-
let latestSnapshotVersionId;
|
|
1752
1905
|
if (refreshLatestAck === true) {
|
|
1753
1906
|
return this.prefetchLatestSummaryThenClose((0, telemetry_utils_1.createChildLogger)({
|
|
1754
1907
|
logger: summaryNumberLogger,
|
|
@@ -1790,6 +1943,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1790
1943
|
}
|
|
1791
1944
|
}
|
|
1792
1945
|
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1946
|
+
const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
|
|
1793
1947
|
let summaryRefSeqNum;
|
|
1794
1948
|
try {
|
|
1795
1949
|
await this.deltaManager.inbound.pause();
|
|
@@ -1800,7 +1954,25 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1800
1954
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1801
1955
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
1802
1956
|
const lastAck = this.summaryCollection.latestAck;
|
|
1803
|
-
this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
|
|
1957
|
+
const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
|
|
1958
|
+
if (startSummaryResult.invalidNodes > 0 ||
|
|
1959
|
+
startSummaryResult.mismatchNumbers.size > 0) {
|
|
1960
|
+
summaryLogger.sendErrorEvent({
|
|
1961
|
+
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
1962
|
+
details: {
|
|
1963
|
+
...startSummaryResult,
|
|
1964
|
+
mismatchNumbers: Array.from(startSummaryResult.mismatchNumbers),
|
|
1965
|
+
},
|
|
1966
|
+
});
|
|
1967
|
+
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
1968
|
+
return {
|
|
1969
|
+
stage: "base",
|
|
1970
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1971
|
+
minimumSequenceNumber,
|
|
1972
|
+
error: `Summarizer node state inconsistent with summarizer state.`,
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1804
1976
|
// Helper function to check whether we should still continue between each async step.
|
|
1805
1977
|
const checkContinue = () => {
|
|
1806
1978
|
// Do not check for loss of connectivity directly! Instead leave it up to
|
|
@@ -1870,7 +2042,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1870
2042
|
const validateResult = this.summarizerNode.validateSummary();
|
|
1871
2043
|
if (!validateResult.success) {
|
|
1872
2044
|
const { success, ...loggingProps } = validateResult;
|
|
1873
|
-
const error = new
|
|
2045
|
+
const error = new index_js_1.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
1874
2046
|
return {
|
|
1875
2047
|
stage: "base",
|
|
1876
2048
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
@@ -1896,8 +2068,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1896
2068
|
? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
|
|
1897
2069
|
: undefined;
|
|
1898
2070
|
const summaryStats = {
|
|
1899
|
-
dataStoreCount: this.
|
|
1900
|
-
summarizedDataStoreCount: this.
|
|
2071
|
+
dataStoreCount: this.channelCollection.size,
|
|
2072
|
+
summarizedDataStoreCount: this.channelCollection.size - handleCount,
|
|
1901
2073
|
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
1902
2074
|
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
1903
2075
|
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
@@ -1916,34 +2088,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1916
2088
|
if (!continueResult.continue) {
|
|
1917
2089
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
1918
2090
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
// submitting the summaryOp then we can't rely on summaryAck. So in case we have
|
|
1922
|
-
// latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
|
|
1923
|
-
// the one fetched from storage as parent as that is the latest.
|
|
1924
|
-
let summaryContext;
|
|
1925
|
-
if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
|
|
1926
|
-
latestSnapshotVersionId !== undefined) {
|
|
1927
|
-
summaryContext = {
|
|
1928
|
-
proposalHandle: undefined,
|
|
1929
|
-
ackHandle: latestSnapshotVersionId,
|
|
1930
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
|
-
else if (lastAck === undefined) {
|
|
1934
|
-
summaryContext = {
|
|
2091
|
+
const summaryContext = lastAck === undefined
|
|
2092
|
+
? {
|
|
1935
2093
|
proposalHandle: undefined,
|
|
1936
2094
|
ackHandle: this.loadedFromVersionId,
|
|
1937
2095
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
else {
|
|
1941
|
-
summaryContext = {
|
|
2096
|
+
}
|
|
2097
|
+
: {
|
|
1942
2098
|
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
1943
2099
|
ackHandle: lastAck.summaryAck.contents.handle,
|
|
1944
2100
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1945
2101
|
};
|
|
1946
|
-
}
|
|
1947
2102
|
let handle;
|
|
1948
2103
|
try {
|
|
1949
2104
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
@@ -2034,7 +2189,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2034
2189
|
// based on telemetry while we decide on a stable number.
|
|
2035
2190
|
const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
2036
2191
|
exports.defaultPendingOpsRetryDelayMs;
|
|
2037
|
-
const error = new
|
|
2192
|
+
const error = new index_js_1.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
|
|
2038
2193
|
count: this.pendingMessagesCount,
|
|
2039
2194
|
beforeGenerate: beforeSummaryGeneration,
|
|
2040
2195
|
});
|
|
@@ -2068,48 +2223,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2068
2223
|
this.emit(dirty ? "dirty" : "saved");
|
|
2069
2224
|
}
|
|
2070
2225
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
address: id,
|
|
2074
|
-
contents,
|
|
2075
|
-
};
|
|
2076
|
-
this.submit({ type: messageTypes_1.ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
|
|
2077
|
-
}
|
|
2078
|
-
submitDataStoreAliasOp(contents, localOpMetadata) {
|
|
2079
|
-
const aliasMessage = contents;
|
|
2080
|
-
if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
|
|
2081
|
-
throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
|
|
2082
|
-
}
|
|
2083
|
-
this.submit({ type: messageTypes_1.ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
2226
|
+
submitMessage(type, contents, localOpMetadata = undefined) {
|
|
2227
|
+
this.submit({ type, contents }, localOpMetadata);
|
|
2084
2228
|
}
|
|
2085
2229
|
async uploadBlob(blob, signal) {
|
|
2086
2230
|
this.verifyNotClosed();
|
|
2087
2231
|
return this.blobManager.createBlob(blob, signal);
|
|
2088
2232
|
}
|
|
2089
|
-
|
|
2090
|
-
if (
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
if (
|
|
2094
|
-
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
|
|
2095
|
-
idRange = this.idCompressor.takeNextCreationRange();
|
|
2096
|
-
// Don't include the idRange if there weren't any Ids allocated
|
|
2097
|
-
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
2098
|
-
}
|
|
2099
|
-
if (idRange !== undefined) {
|
|
2233
|
+
submitIdAllocationOpIfNeeded() {
|
|
2234
|
+
if (this._idCompressor) {
|
|
2235
|
+
const idRange = this._idCompressor.takeNextCreationRange();
|
|
2236
|
+
// Don't include the idRange if there weren't any Ids allocated
|
|
2237
|
+
if (idRange?.ids !== undefined) {
|
|
2100
2238
|
const idAllocationMessage = {
|
|
2101
|
-
type:
|
|
2239
|
+
type: messageTypes_js_1.ContainerMessageType.IdAllocation,
|
|
2102
2240
|
contents: idRange,
|
|
2103
2241
|
};
|
|
2104
|
-
idAllocationBatchMessage = {
|
|
2242
|
+
const idAllocationBatchMessage = {
|
|
2105
2243
|
contents: JSON.stringify(idAllocationMessage),
|
|
2106
2244
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2107
2245
|
metadata: undefined,
|
|
2108
2246
|
localOpMetadata: undefined,
|
|
2109
|
-
type:
|
|
2247
|
+
type: messageTypes_js_1.ContainerMessageType.IdAllocation,
|
|
2110
2248
|
};
|
|
2111
|
-
}
|
|
2112
|
-
if (idAllocationBatchMessage !== undefined) {
|
|
2113
2249
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
2114
2250
|
}
|
|
2115
2251
|
}
|
|
@@ -2137,42 +2273,47 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2137
2273
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2138
2274
|
};
|
|
2139
2275
|
try {
|
|
2140
|
-
//
|
|
2141
|
-
// the
|
|
2142
|
-
// op
|
|
2143
|
-
//
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
// Is it safe:
|
|
2147
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2148
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2149
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
2150
|
-
// Why:
|
|
2151
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2152
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2153
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2154
|
-
// these issues.
|
|
2155
|
-
// Cons:
|
|
2156
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2157
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2158
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2159
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2160
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2161
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2162
|
-
// issue than sending.
|
|
2163
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2164
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2165
|
-
if (this.currentlyBatching() &&
|
|
2166
|
-
type === messageTypes_1.ContainerMessageType.Attach &&
|
|
2167
|
-
this.disableAttachReorder !== true) {
|
|
2168
|
-
this.outbox.submitAttach(message);
|
|
2169
|
-
}
|
|
2170
|
-
else if (type === messageTypes_1.ContainerMessageType.BlobAttach) {
|
|
2171
|
-
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2172
|
-
this.outbox.submitBlobAttach(message);
|
|
2276
|
+
// If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
|
|
2277
|
+
// op into the correct batch to avoid ranges being finalized out of order.
|
|
2278
|
+
// Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
|
|
2279
|
+
// any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
|
|
2280
|
+
if (type === messageTypes_js_1.ContainerMessageType.IdAllocation) {
|
|
2281
|
+
this.outbox.submitIdAllocation(message);
|
|
2173
2282
|
}
|
|
2174
2283
|
else {
|
|
2175
|
-
this.
|
|
2284
|
+
this.submitIdAllocationOpIfNeeded();
|
|
2285
|
+
// If this is attach message for new data store, and we are in a batch, send this op out of order
|
|
2286
|
+
// Is it safe:
|
|
2287
|
+
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2288
|
+
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2289
|
+
// is stored in some DDS, i.e. only after some other op.
|
|
2290
|
+
// Why:
|
|
2291
|
+
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2292
|
+
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2293
|
+
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2294
|
+
// these issues.
|
|
2295
|
+
// Cons:
|
|
2296
|
+
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2297
|
+
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2298
|
+
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2299
|
+
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2300
|
+
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2301
|
+
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2302
|
+
// issue than sending.
|
|
2303
|
+
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2304
|
+
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2305
|
+
if (this.currentlyBatching() &&
|
|
2306
|
+
type === messageTypes_js_1.ContainerMessageType.Attach &&
|
|
2307
|
+
this.disableAttachReorder !== true) {
|
|
2308
|
+
this.outbox.submitAttach(message);
|
|
2309
|
+
}
|
|
2310
|
+
else if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
|
|
2311
|
+
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2312
|
+
this.outbox.submitBlobAttach(message);
|
|
2313
|
+
}
|
|
2314
|
+
else {
|
|
2315
|
+
this.outbox.submit(message);
|
|
2316
|
+
}
|
|
2176
2317
|
}
|
|
2177
2318
|
if (!this.currentlyBatching()) {
|
|
2178
2319
|
this.flush();
|
|
@@ -2247,7 +2388,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2247
2388
|
if (this.opReentryCallsToReport > 0) {
|
|
2248
2389
|
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
2249
2390
|
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
2250
|
-
(0,
|
|
2391
|
+
(0, index_js_3.getLongStack)(() => new telemetry_utils_1.UsageError(errorMessage)));
|
|
2251
2392
|
this.opReentryCallsToReport--;
|
|
2252
2393
|
}
|
|
2253
2394
|
// Creating ops while processing ops can lead
|
|
@@ -2288,34 +2429,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2288
2429
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2289
2430
|
*/
|
|
2290
2431
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2432
|
+
(0, core_utils_1.assert)(!this.isSummarizerClient, 0x8f2 /* Summarizer never reconnects so should never resubmit */);
|
|
2291
2433
|
switch (message.type) {
|
|
2292
|
-
case
|
|
2434
|
+
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp:
|
|
2435
|
+
case messageTypes_js_1.ContainerMessageType.Attach:
|
|
2436
|
+
case messageTypes_js_1.ContainerMessageType.Alias:
|
|
2293
2437
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
2294
2438
|
// and trigger resubmission on it.
|
|
2295
|
-
this.
|
|
2439
|
+
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2296
2440
|
break;
|
|
2297
|
-
case
|
|
2298
|
-
case messageTypes_1.ContainerMessageType.Alias:
|
|
2299
|
-
case messageTypes_1.ContainerMessageType.IdAllocation: {
|
|
2441
|
+
case messageTypes_js_1.ContainerMessageType.IdAllocation: {
|
|
2300
2442
|
this.submit(message, localOpMetadata);
|
|
2301
2443
|
break;
|
|
2302
2444
|
}
|
|
2303
|
-
case
|
|
2445
|
+
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
2304
2446
|
throw new Error(`chunkedOp not expected here`);
|
|
2305
|
-
case
|
|
2447
|
+
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
2306
2448
|
this.blobManager.reSubmit(opMetadata);
|
|
2307
2449
|
break;
|
|
2308
|
-
case
|
|
2450
|
+
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
2451
|
+
this.submit(message);
|
|
2452
|
+
break;
|
|
2453
|
+
case messageTypes_js_1.ContainerMessageType.GC:
|
|
2309
2454
|
this.submit(message);
|
|
2310
2455
|
break;
|
|
2311
|
-
case messageTypes_1.ContainerMessageType.GC:
|
|
2312
|
-
// GC op is only sent in summarizer which should never reconnect.
|
|
2313
|
-
throw new telemetry_utils_1.LoggingError("GC op not expected to be resubmitted in summarizer");
|
|
2314
2456
|
default: {
|
|
2315
2457
|
// This case should be very rare - it would imply an op was stashed from a
|
|
2316
|
-
// future version of runtime code and now is being applied on an older version
|
|
2458
|
+
// future version of runtime code and now is being applied on an older version.
|
|
2317
2459
|
const compatBehavior = message.compatDetails?.behavior;
|
|
2318
2460
|
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
2461
|
+
// We do not ultimately resubmit it, to be consistent with this version of the code.
|
|
2319
2462
|
this.logger.sendTelemetryEvent({
|
|
2320
2463
|
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
2321
2464
|
messageDetails: { type: message.type, compatBehavior },
|
|
@@ -2338,10 +2481,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2338
2481
|
// Need to parse from string for back-compat
|
|
2339
2482
|
const { type, contents } = this.parseLocalOpContent(content);
|
|
2340
2483
|
switch (type) {
|
|
2341
|
-
case
|
|
2484
|
+
case messageTypes_js_1.ContainerMessageType.FluidDataStoreOp:
|
|
2342
2485
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
2343
2486
|
// and trigger rollback on it.
|
|
2344
|
-
this.
|
|
2487
|
+
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
2345
2488
|
break;
|
|
2346
2489
|
default:
|
|
2347
2490
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -2362,31 +2505,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2362
2505
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
2363
2506
|
*/
|
|
2364
2507
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
2365
|
-
|
|
2508
|
+
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
2366
2509
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
2367
2510
|
ackHandle,
|
|
2368
2511
|
targetSequenceNumber: summaryRefSeq,
|
|
2369
2512
|
}, readAndParseBlob);
|
|
2370
|
-
|
|
2371
|
-
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
2372
|
-
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
2373
|
-
* However, there are couple of scenarios where it's possible:
|
|
2374
|
-
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
2375
|
-
* the document being unusable and we should not proceed.
|
|
2376
|
-
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
2377
|
-
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
2378
|
-
* state.
|
|
2379
|
-
*/
|
|
2380
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
2381
|
-
const error = telemetry_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
2382
|
-
ackHandle,
|
|
2383
|
-
summaryRefSeq,
|
|
2384
|
-
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
2385
|
-
});
|
|
2386
|
-
this.disposeFn(error);
|
|
2387
|
-
throw error;
|
|
2388
|
-
}
|
|
2389
|
-
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
2513
|
+
await this.closeStaleSummarizer();
|
|
2390
2514
|
return;
|
|
2391
2515
|
}
|
|
2392
2516
|
// Notify the garbage collector so it can update its latest summary state.
|
|
@@ -2405,7 +2529,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2405
2529
|
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
2406
2530
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2407
2531
|
}, readAndParseBlob);
|
|
2408
|
-
await this.closeStaleSummarizer(
|
|
2532
|
+
await this.closeStaleSummarizer();
|
|
2409
2533
|
return {
|
|
2410
2534
|
stage: "base",
|
|
2411
2535
|
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
@@ -2413,7 +2537,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2413
2537
|
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
2414
2538
|
};
|
|
2415
2539
|
}
|
|
2416
|
-
async closeStaleSummarizer(
|
|
2540
|
+
async closeStaleSummarizer() {
|
|
2417
2541
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2418
2542
|
await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
|
|
2419
2543
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
@@ -2445,44 +2569,43 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2445
2569
|
};
|
|
2446
2570
|
});
|
|
2447
2571
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
// try to change its value
|
|
2456
|
-
if (!this.imminentClosure) {
|
|
2457
|
-
this.imminentClosure = props?.notifyImminentClosure ?? this.imminentClosure;
|
|
2458
|
-
}
|
|
2459
|
-
const stopBlobAttachingSignal = props?.stopBlobAttachingSignal;
|
|
2460
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
2461
|
-
throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
|
|
2462
|
-
}
|
|
2463
|
-
// Flush pending batch.
|
|
2464
|
-
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2465
|
-
// to close current batch.
|
|
2466
|
-
this.flush();
|
|
2467
|
-
const pendingAttachmentBlobs = this.imminentClosure
|
|
2468
|
-
? await this.blobManager.attachAndGetPendingBlobs(stopBlobAttachingSignal)
|
|
2469
|
-
: undefined;
|
|
2572
|
+
getPendingLocalState(props) {
|
|
2573
|
+
this.verifyNotClosed();
|
|
2574
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
2575
|
+
throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
|
|
2576
|
+
}
|
|
2577
|
+
this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
|
|
2578
|
+
const getSyncState = (pendingAttachmentBlobs) => {
|
|
2470
2579
|
const pending = this.pendingStateManager.getLocalState();
|
|
2471
|
-
if (
|
|
2580
|
+
if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
|
|
2472
2581
|
return; // no pending state to save
|
|
2473
2582
|
}
|
|
2474
|
-
const pendingIdCompressorState = this.
|
|
2475
|
-
|
|
2583
|
+
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
2584
|
+
return {
|
|
2476
2585
|
pending,
|
|
2477
|
-
pendingAttachmentBlobs,
|
|
2478
2586
|
pendingIdCompressorState,
|
|
2587
|
+
pendingAttachmentBlobs,
|
|
2588
|
+
sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
|
|
2479
2589
|
};
|
|
2590
|
+
};
|
|
2591
|
+
const perfEvent = {
|
|
2592
|
+
eventName: "getPendingLocalState",
|
|
2593
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
2594
|
+
};
|
|
2595
|
+
const logAndReturnPendingState = (event, pendingState) => {
|
|
2480
2596
|
event.end({
|
|
2481
|
-
attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
|
|
2482
|
-
pendingOpsSize: pending?.pendingStates.length,
|
|
2597
|
+
attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
|
|
2598
|
+
pendingOpsSize: pendingState?.pending?.pendingStates.length,
|
|
2483
2599
|
});
|
|
2484
2600
|
return pendingState;
|
|
2485
|
-
}
|
|
2601
|
+
};
|
|
2602
|
+
// Flush pending batch.
|
|
2603
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2604
|
+
// to close current batch.
|
|
2605
|
+
this.flush();
|
|
2606
|
+
return props?.notifyImminentClosure === true
|
|
2607
|
+
? telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) => logAndReturnPendingState(event, getSyncState(await this.blobManager.attachAndGetPendingBlobs(props?.stopBlobAttachingSignal))))
|
|
2608
|
+
: telemetry_utils_1.PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) => logAndReturnPendingState(event, getSyncState()));
|
|
2486
2609
|
}
|
|
2487
2610
|
summarizeOnDemand(options) {
|
|
2488
2611
|
if (this.isSummarizerClient) {
|