// Copyright 2024 RustFS Team // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Main concurrency manager use crate::config::ConcurrencyConfig; use std::sync::Arc; /// Snapshot of disk permit queue usage for GetObject orchestration. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct GetObjectQueueSnapshot { /// Total permits configured for disk reads. pub total_permits: usize, /// Permits currently in use. pub permits_in_use: usize, } impl GetObjectQueueSnapshot { /// Create a queue snapshot from total and available permits. pub fn from_available_permits(total_permits: usize, available_permits: usize) -> Self { Self { total_permits, permits_in_use: total_permits.saturating_sub(available_permits), } } /// Return currently available permits. pub fn permits_available(&self) -> usize { self.total_permits.saturating_sub(self.permits_in_use) } /// Return queue utilization percentage in the 0-100 range. pub fn utilization_percent(&self) -> f64 { if self.total_permits == 0 { 0.0 } else { (self.permits_in_use as f64 / self.total_permits as f64) * 100.0 } } /// Return whether the queue is considered congested. pub fn is_congested(&self, threshold_percent: f64) -> bool { self.utilization_percent() > threshold_percent } } /// Main concurrency manager that provides access to all concurrency features pub struct ConcurrencyManager { config: ConcurrencyConfig, #[cfg(feature = "timeout")] timeout: Arc, #[cfg(feature = "lock")] lock: Arc, #[cfg(feature = "deadlock")] deadlock: Arc, #[cfg(feature = "backpressure")] backpressure: Arc, #[cfg(feature = "scheduler")] scheduler: Arc, } impl ConcurrencyManager { /// Create a new concurrency manager with the given configuration pub fn new(config: ConcurrencyConfig) -> Self { // Validate configuration if let Err(e) = config.validate() { panic!("Invalid concurrency configuration: {}", e); } Self { #[cfg(feature = "timeout")] timeout: Arc::new(crate::timeout::TimeoutManager::new( config.default_timeout, config.max_timeout, config.enable_dynamic_timeout, )), #[cfg(feature = "lock")] lock: Arc::new(crate::lock::LockManager::new( config.enable_lock_optimization, config.lock_acquire_timeout, )), #[cfg(feature = "deadlock")] deadlock: Arc::new(crate::deadlock::DeadlockManager::new( config.enable_deadlock_detection, config.deadlock_check_interval, config.hang_threshold, )), #[cfg(feature = "backpressure")] backpressure: Arc::new(crate::backpressure::BackpressureManager::new( config.backpressure_buffer_size, config.high_watermark, config.low_watermark, )), #[cfg(feature = "scheduler")] scheduler: Arc::new(crate::scheduler::SchedulerManager::new( config.io_buffer_size, config.max_buffer_size, config.high_priority_threshold, config.low_priority_threshold, )), config, } } /// Create with default configuration pub fn with_defaults() -> Self { Self::new(ConcurrencyConfig::default()) } /// Create from environment variables pub fn from_env() -> Self { Self::new(ConcurrencyConfig::from_env()) } /// Get the configuration pub fn config(&self) -> &ConcurrencyConfig { &self.config } // ============================================ // Feature enable checks // ============================================ /// Check if timeout feature is enabled pub fn is_timeout_enabled(&self) -> bool { #[cfg(feature = "timeout")] { self.config.features.timeout } #[cfg(not(feature = "timeout"))] { false } } /// Check if lock feature is enabled pub fn is_lock_enabled(&self) -> bool { #[cfg(feature = "lock")] { self.config.features.lock } #[cfg(not(feature = "lock"))] { false } } /// Check if deadlock feature is enabled pub fn is_deadlock_enabled(&self) -> bool { #[cfg(feature = "deadlock")] { self.config.features.deadlock } #[cfg(not(feature = "deadlock"))] { false } } /// Check if backpressure feature is enabled pub fn is_backpressure_enabled(&self) -> bool { #[cfg(feature = "backpressure")] { self.config.features.backpressure } #[cfg(not(feature = "backpressure"))] { false } } /// Check if scheduler feature is enabled pub fn is_scheduler_enabled(&self) -> bool { #[cfg(feature = "scheduler")] { self.config.features.scheduler } #[cfg(not(feature = "scheduler"))] { false } } // ============================================ // Feature accessors // ============================================ /// Get timeout manager #[cfg(feature = "timeout")] pub fn timeout(&self) -> Arc { self.timeout.clone() } /// Get lock manager #[cfg(feature = "lock")] pub fn lock(&self) -> Arc { self.lock.clone() } /// Get deadlock manager #[cfg(feature = "deadlock")] pub fn deadlock(&self) -> Arc { self.deadlock.clone() } /// Get backpressure manager #[cfg(feature = "backpressure")] pub fn backpressure(&self) -> Arc { self.backpressure.clone() } /// Get scheduler manager #[cfg(feature = "scheduler")] pub fn scheduler(&self) -> Arc { self.scheduler.clone() } // ============================================ // Lifecycle management // ============================================ /// Start all enabled services (e.g., deadlock detection background task) pub async fn start(&self) { #[cfg(feature = "deadlock")] { if self.config.enable_deadlock_detection { self.deadlock.start().await; } } tracing::info!( "Concurrency manager started (timeout={}, lock={}, deadlock={}, backpressure={}, scheduler={})", self.is_timeout_enabled(), self.is_lock_enabled(), self.is_deadlock_enabled(), self.is_backpressure_enabled(), self.is_scheduler_enabled() ); } /// Stop all services pub async fn stop(&self) { #[cfg(feature = "deadlock")] { self.deadlock.stop().await; } tracing::info!("Concurrency manager stopped"); } } impl Default for ConcurrencyManager { fn default() -> Self { Self::with_defaults() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_queue_snapshot() { let snapshot = GetObjectQueueSnapshot::from_available_permits(64, 16); assert_eq!(snapshot.permits_in_use, 48); assert_eq!(snapshot.permits_available(), 16); assert!(snapshot.is_congested(70.0)); } #[test] fn test_manager_creation() { let manager = ConcurrencyManager::with_defaults(); assert!(manager.config().validate().is_ok()); } #[tokio::test] async fn test_manager_lifecycle() { let manager = ConcurrencyManager::with_defaults(); manager.start().await; manager.stop().await; } #[test] fn test_feature_checks() { let manager = ConcurrencyManager::with_defaults(); // These should return the feature flag status let _ = manager.is_timeout_enabled(); let _ = manager.is_lock_enabled(); let _ = manager.is_deadlock_enabled(); let _ = manager.is_backpressure_enabled(); let _ = manager.is_scheduler_enabled(); } }