mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 17:28:12 +00:00
refactor(concurrency): remove zero-caller facade modules, fix feature build (#4530)
refactor(concurrency): remove zero-caller facade modules and fix no-default-features build (backlog#1025) The audit in rustfs/backlog#1010 (consistent with #805) established that most of crates/concurrency was a decorative facade with zero production callers; the real runtime concurrency control lives in rustfs/src/storage/*. This deletes the dead facades and keeps only what the workspace actually consumes. Deleted (zero callers verified by workspace-wide grep): - manager.rs: ConcurrencyManager, lifecycle start/stop, misleading 'started' lifecycle logs - config.rs: ConcurrencyConfig, ConcurrencyFeatures, from_env - timeout.rs: TimeoutManager, TimeoutGuard, TimeoutManagerPolicy - lock.rs: LockManager, LockScopeGuard, OptimizedLockGuard - scheduler.rs: SchedulerManager, SchedulerPolicy, IoStrategy - deadlock.rs facade: DeadlockManager, RequestTracker - backpressure.rs facade: BackpressureManager, BackpressurePipe - the prelude module, unused io-core re-exports, and all feature flags Kept (real callers in ecstore/heal/rustfs): - workload.rs admission contract types (unchanged) - workers.rs Workers pool (unchanged, retained per #4498) - GetObjectQueueSnapshot (moved from manager.rs to new queue.rs) - PipeBackpressurePolicy (used by rustfs/src/storage/backpressure.rs) - DeadlockMonitorPolicy (used by rustfs/src/storage/deadlock_detector.rs) - OperationProgress re-export (used by rustfs/src/storage/timeout_wrapper.rs) Removing the feature flags fixes the previously broken cargo check -p rustfs-concurrency --no-default-features (E0432). Docs and the logging guardrail file list are updated to match. Ref: rustfs/backlog#1025
This commit is contained in:
@@ -12,15 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Deadlock detection management
|
||||
//! Shared deadlock-monitor policy type.
|
||||
//!
|
||||
//! The runtime request-hang / deadlock detection loop lives in
|
||||
//! `rustfs/src/storage/deadlock_detector.rs`; this module only carries the
|
||||
//! monitor policy type that implementation shares.
|
||||
|
||||
use rustfs_io_core::{DeadlockDetector as CoreDeadlockDetector, DeadlockDetectorConfig as CoreDeadlockConfig, LockType};
|
||||
use rustfs_io_metrics::deadlock_metrics;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use rustfs_io_core::DeadlockDetectorConfig as CoreDeadlockConfig;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Facade policy for the concurrency-layer deadlock monitor.
|
||||
/// Policy for the request-hang deadlock monitor.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DeadlockMonitorPolicy {
|
||||
/// Enable deadlock detection
|
||||
@@ -42,7 +43,7 @@ impl Default for DeadlockMonitorPolicy {
|
||||
}
|
||||
|
||||
impl DeadlockMonitorPolicy {
|
||||
/// Convert the facade policy into the reusable io-core deadlock config.
|
||||
/// Convert the policy into the reusable io-core deadlock config.
|
||||
pub fn to_core_config(&self) -> CoreDeadlockConfig {
|
||||
CoreDeadlockConfig {
|
||||
enabled: self.enabled,
|
||||
@@ -52,182 +53,14 @@ impl DeadlockMonitorPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deadlock manager
|
||||
pub struct DeadlockManager {
|
||||
config: DeadlockMonitorPolicy,
|
||||
detector: Arc<CoreDeadlockDetector>,
|
||||
running: Arc<tokio::sync::Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl DeadlockManager {
|
||||
/// Create a new deadlock manager
|
||||
pub fn new(enabled: bool, check_interval: Duration, hang_threshold: Duration) -> Self {
|
||||
Self::from_policy(DeadlockMonitorPolicy {
|
||||
enabled,
|
||||
check_interval,
|
||||
hang_threshold,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new deadlock manager from the facade policy type.
|
||||
pub fn from_policy(config: DeadlockMonitorPolicy) -> Self {
|
||||
let core_config = config.to_core_config();
|
||||
Self {
|
||||
config,
|
||||
detector: Arc::new(CoreDeadlockDetector::new(core_config)),
|
||||
running: Arc::new(tokio::sync::Mutex::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the configuration
|
||||
pub fn config(&self) -> &DeadlockMonitorPolicy {
|
||||
&self.config
|
||||
}
|
||||
|
||||
/// Get the core detector
|
||||
pub fn detector(&self) -> Arc<CoreDeadlockDetector> {
|
||||
self.detector.clone()
|
||||
}
|
||||
|
||||
/// Start the deadlock detection background task
|
||||
pub async fn start(&self) {
|
||||
if !self.config.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut running = self.running.lock().await;
|
||||
if *running {
|
||||
return;
|
||||
}
|
||||
*running = true;
|
||||
drop(running);
|
||||
|
||||
tracing::info!(
|
||||
event = "deadlock_monitor.lifecycle",
|
||||
component = "concurrency",
|
||||
subsystem = "deadlock",
|
||||
state = "started",
|
||||
check_interval_ms = self.config.check_interval.as_millis(),
|
||||
hang_threshold_ms = self.config.hang_threshold.as_millis(),
|
||||
"deadlock monitor state changed"
|
||||
);
|
||||
}
|
||||
|
||||
/// Stop the deadlock detection
|
||||
pub async fn stop(&self) {
|
||||
let mut running = self.running.lock().await;
|
||||
*running = false;
|
||||
|
||||
tracing::info!(
|
||||
event = "deadlock_monitor.lifecycle",
|
||||
component = "concurrency",
|
||||
subsystem = "deadlock",
|
||||
state = "stopped",
|
||||
check_interval_ms = self.config.check_interval.as_millis(),
|
||||
hang_threshold_ms = self.config.hang_threshold.as_millis(),
|
||||
"deadlock monitor state changed"
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a request tracker
|
||||
pub fn track_request(&self, request_id: String, description: String) -> RequestTracker {
|
||||
RequestTracker::new(request_id, description, self.detector.clone())
|
||||
}
|
||||
|
||||
/// Register a lock
|
||||
pub fn register_lock(&self, lock_type: LockType) -> u64 {
|
||||
self.detector.register_lock(lock_type)
|
||||
}
|
||||
|
||||
/// Unregister a lock
|
||||
pub fn unregister_lock(&self, lock_id: u64) {
|
||||
self.detector.unregister_lock(lock_id);
|
||||
}
|
||||
|
||||
/// Detect deadlock
|
||||
pub fn detect_deadlock(&self) -> Option<Vec<u64>> {
|
||||
let result = self.detector.detect_deadlock();
|
||||
if let Some(ref cycle) = result {
|
||||
deadlock_metrics::record_deadlock_detected(cycle.len());
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Lightweight compatibility wrapper for request-scoped deadlock bookkeeping.
|
||||
///
|
||||
/// This type intentionally stays minimal in the concurrency layer. Rich
|
||||
/// request-level lock/resource diagnostics belong to
|
||||
/// `rustfs::storage::deadlock_detector::RequestResourceTracker`.
|
||||
pub struct RequestTracker {
|
||||
request_id: String,
|
||||
description: String,
|
||||
start_time: Instant,
|
||||
resources: HashMap<String, Vec<String>>,
|
||||
detector: Arc<CoreDeadlockDetector>,
|
||||
}
|
||||
|
||||
impl RequestTracker {
|
||||
fn new(request_id: String, description: String, detector: Arc<CoreDeadlockDetector>) -> Self {
|
||||
let start_time = Instant::now();
|
||||
detector.register_request(&request_id, 1); // Use placeholder thread ID
|
||||
|
||||
Self {
|
||||
request_id,
|
||||
description,
|
||||
start_time,
|
||||
resources: HashMap::new(),
|
||||
detector,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the request ID
|
||||
pub fn request_id(&self) -> &str {
|
||||
&self.request_id
|
||||
}
|
||||
|
||||
/// Get the description
|
||||
pub fn description(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
||||
/// Get the elapsed time
|
||||
pub fn elapsed(&self) -> Duration {
|
||||
self.start_time.elapsed()
|
||||
}
|
||||
|
||||
/// Record a lock acquisition
|
||||
pub fn record_lock_acquire(&mut self, lock_id: u64, resource: String) {
|
||||
self.resources.entry("locks".to_string()).or_default().push(resource);
|
||||
self.detector.record_acquire(lock_id, 1); // Use placeholder thread ID
|
||||
deadlock_metrics::record_lock_acquisition("read");
|
||||
}
|
||||
|
||||
/// Return a read-only view of tracked resource names.
|
||||
pub fn resources(&self) -> &HashMap<String, Vec<String>> {
|
||||
&self.resources
|
||||
}
|
||||
|
||||
/// Record a lock release
|
||||
pub fn record_lock_release(&mut self, lock_id: u64) {
|
||||
self.detector.record_release(lock_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RequestTracker {
|
||||
fn drop(&mut self) {
|
||||
self.detector.unregister_request(&self.request_id);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_deadlock_manager_creation() {
|
||||
let manager = DeadlockManager::new(false, Duration::from_secs(10), Duration::from_secs(60));
|
||||
assert!(!manager.config().enabled);
|
||||
fn test_deadlock_policy_defaults_disabled() {
|
||||
let policy = DeadlockMonitorPolicy::default();
|
||||
assert!(!policy.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -238,16 +71,4 @@ mod tests {
|
||||
assert_eq!(core.detection_interval, policy.check_interval);
|
||||
assert_eq!(core.max_hold_time, policy.hang_threshold);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_request_tracker() {
|
||||
let manager = DeadlockManager::new(true, Duration::from_secs(10), Duration::from_secs(60));
|
||||
let mut tracker = manager.track_request("req-1".to_string(), "test request".to_string());
|
||||
let lock_id = manager.register_lock(LockType::Mutex);
|
||||
tracker.record_lock_acquire(lock_id, "bucket/key".to_string());
|
||||
|
||||
assert_eq!(tracker.request_id(), "req-1");
|
||||
assert_eq!(tracker.description(), "test request");
|
||||
assert_eq!(tracker.resources().get("locks").map(Vec::len), Some(1));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user