mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-31 10:32:24 +00:00
256 lines
8.8 KiB
Rust
256 lines
8.8 KiB
Rust
// 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.
|
|
|
|
// Example integration of FastObjectLockManager in set_disk.rs
|
|
// This shows how to replace the current slow lock system
|
|
|
|
use crate::fast_lock::{BatchLockRequest, FastObjectLockManager, ObjectLockRequest};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
|
|
/// Example integration into SetDisks structure
|
|
pub struct SetDisksWithFastLock {
|
|
/// Replace the old namespace_lock with fast lock manager
|
|
pub fast_lock_manager: Arc<FastObjectLockManager>,
|
|
pub locker_owner: String,
|
|
// ... other fields remain the same
|
|
}
|
|
|
|
impl SetDisksWithFastLock {
|
|
/// Example: Replace get_object_reader with fast locking
|
|
pub async fn get_object_reader_fast(
|
|
&self,
|
|
bucket: &str,
|
|
object: &str,
|
|
version: Option<&str>,
|
|
// ... other parameters
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Fast path: Try to acquire read lock immediately
|
|
let _read_guard = if let Some(v) = version {
|
|
// Version-specific lock
|
|
self.fast_lock_manager
|
|
.acquire_read_lock_versioned(bucket, object, v, self.locker_owner.as_str())
|
|
.await
|
|
.map_err(|_| "Lock acquisition failed")?
|
|
} else {
|
|
// Latest version lock
|
|
self.fast_lock_manager
|
|
.acquire_read_lock(bucket, object, self.locker_owner.as_str())
|
|
.await
|
|
.map_err(|_| "Lock acquisition failed")?
|
|
};
|
|
|
|
// Critical section: Read object
|
|
// The lock is automatically released when _read_guard goes out of scope
|
|
|
|
// ... actual read operation logic
|
|
Ok(())
|
|
}
|
|
|
|
/// Example: Replace put_object with fast locking
|
|
pub async fn put_object_fast(
|
|
&self,
|
|
bucket: &str,
|
|
object: &str,
|
|
version: Option<&str>,
|
|
// ... other parameters
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Acquire exclusive write lock with timeout
|
|
let request = ObjectLockRequest::new_write(bucket, object, self.locker_owner.as_str())
|
|
.with_acquire_timeout(Duration::from_secs(5))
|
|
.with_lock_timeout(Duration::from_secs(30));
|
|
|
|
let request = if let Some(v) = version {
|
|
request.with_version(v)
|
|
} else {
|
|
request
|
|
};
|
|
|
|
let _write_guard = self
|
|
.fast_lock_manager
|
|
.acquire_lock(request)
|
|
.await
|
|
.map_err(|_| "Lock acquisition failed")?;
|
|
|
|
// Critical section: Write object
|
|
// ... actual write operation logic
|
|
|
|
Ok(())
|
|
// Lock automatically released when _write_guard drops
|
|
}
|
|
|
|
/// Example: Replace delete_objects with batch fast locking
|
|
pub async fn delete_objects_fast(
|
|
&self,
|
|
bucket: &str,
|
|
objects: Vec<(&str, Option<&str>)>, // (object_name, version)
|
|
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
|
|
// Create batch request for atomic locking
|
|
let mut batch = BatchLockRequest::new(self.locker_owner.as_str()).with_all_or_nothing(true); // Either lock all or fail
|
|
|
|
// Add all objects to batch (sorted internally to prevent deadlocks)
|
|
for (object, version) in &objects {
|
|
let mut request = ObjectLockRequest::new_write(bucket, *object, self.locker_owner.as_str());
|
|
if let Some(v) = version {
|
|
request = request.with_version(*v);
|
|
}
|
|
batch.requests.push(request);
|
|
}
|
|
|
|
// Acquire all locks atomically
|
|
let batch_result = self.fast_lock_manager.acquire_locks_batch(batch).await;
|
|
|
|
if !batch_result.all_acquired {
|
|
return Err("Failed to acquire all locks for batch delete".into());
|
|
}
|
|
|
|
// Critical section: Delete all objects
|
|
let mut deleted = Vec::new();
|
|
for (object, _version) in objects {
|
|
// ... actual delete operation logic
|
|
deleted.push(object.to_string());
|
|
}
|
|
|
|
// All locks automatically released when guards go out of scope
|
|
Ok(deleted)
|
|
}
|
|
|
|
/// Example: Health check integration
|
|
pub fn get_lock_health(&self) -> crate::fast_lock::metrics::AggregatedMetrics {
|
|
self.fast_lock_manager.get_metrics()
|
|
}
|
|
|
|
/// Example: Cleanup integration
|
|
pub async fn cleanup_expired_locks(&self) -> usize {
|
|
self.fast_lock_manager.cleanup_expired().await
|
|
}
|
|
}
|
|
|
|
/// Performance comparison demonstration
|
|
pub mod performance_comparison {
|
|
use super::*;
|
|
use std::time::Instant;
|
|
|
|
pub async fn benchmark_fast_vs_old() {
|
|
let fast_manager = Arc::new(FastObjectLockManager::new());
|
|
let owner = "benchmark_owner";
|
|
|
|
// Benchmark fast lock acquisition
|
|
let start = Instant::now();
|
|
let mut guards = Vec::new();
|
|
|
|
for i in 0..1000 {
|
|
let guard = fast_manager
|
|
.acquire_write_lock("bucket", format!("object_{i}"), owner)
|
|
.await
|
|
.expect("Failed to acquire fast lock");
|
|
guards.push(guard);
|
|
}
|
|
|
|
let fast_duration = start.elapsed();
|
|
println!("Fast lock: 1000 acquisitions in {fast_duration:?}");
|
|
|
|
// Release all
|
|
drop(guards);
|
|
|
|
// Compare with metrics
|
|
let metrics = fast_manager.get_metrics();
|
|
println!("Fast path rate: {:.2}%", metrics.shard_metrics.fast_path_rate() * 100.0);
|
|
println!("Average wait time: {:?}", metrics.shard_metrics.avg_wait_time());
|
|
println!("Total operations/sec: {:.2}", metrics.ops_per_second());
|
|
}
|
|
}
|
|
|
|
/// Migration guide from old to new system
|
|
pub mod migration_guide {
|
|
/*
|
|
Step-by-step migration from old lock system:
|
|
|
|
1. Replace namespace_lock field:
|
|
OLD: pub namespace_lock: Arc<rustfs_lock::NamespaceLock>
|
|
NEW: pub fast_lock_manager: Arc<FastObjectLockManager>
|
|
|
|
2. Replace lock acquisition:
|
|
OLD: self.namespace_lock.lock_guard(object, &self.locker_owner, timeout, ttl).await?
|
|
NEW: self.fast_lock_manager.acquire_write_lock(bucket, object, &self.locker_owner).await?
|
|
|
|
3. Replace read lock acquisition:
|
|
OLD: self.namespace_lock.rlock_guard(object, &self.locker_owner, timeout, ttl).await?
|
|
NEW: self.fast_lock_manager.acquire_read_lock(bucket, object, &self.locker_owner).await?
|
|
|
|
4. Add version support where needed:
|
|
NEW: self.fast_lock_manager.acquire_write_lock_versioned(bucket, object, version, owner).await?
|
|
|
|
5. Replace batch operations:
|
|
OLD: Multiple individual lock_guard calls in loop
|
|
NEW: Single BatchLockRequest with all objects
|
|
|
|
6. Remove manual lock release (RAII handles it automatically)
|
|
OLD: guard.disarm() or explicit release
|
|
NEW: Just let guard go out of scope
|
|
|
|
Expected performance improvements:
|
|
- 10-50x faster lock acquisition
|
|
- 90%+ fast path success rate
|
|
- Sub-millisecond lock operations
|
|
- No deadlock issues with batch operations
|
|
- Automatic cleanup and monitoring
|
|
*/
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn test_integration_example() {
|
|
let fast_manager = Arc::new(FastObjectLockManager::new());
|
|
let set_disks = SetDisksWithFastLock {
|
|
fast_lock_manager: fast_manager,
|
|
locker_owner: "test_owner".to_string(),
|
|
};
|
|
|
|
// Test read operation
|
|
assert!(set_disks.get_object_reader_fast("bucket", "object", None).await.is_ok());
|
|
|
|
// Test write operation
|
|
assert!(set_disks.put_object_fast("bucket", "object", Some("v1")).await.is_ok());
|
|
|
|
// Test batch delete
|
|
let objects = vec![("obj1", None), ("obj2", Some("v1"))];
|
|
let result = set_disks.delete_objects_fast("bucket", objects).await;
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_version_locking() {
|
|
let fast_manager = Arc::new(FastObjectLockManager::new());
|
|
|
|
// Should be able to lock different versions simultaneously
|
|
let guard_v1 = fast_manager
|
|
.acquire_write_lock_versioned("bucket", "object", "v1", "owner1")
|
|
.await
|
|
.expect("Failed to lock v1");
|
|
|
|
let guard_v2 = fast_manager
|
|
.acquire_write_lock_versioned("bucket", "object", "v2", "owner2")
|
|
.await
|
|
.expect("Failed to lock v2");
|
|
|
|
// Both locks should coexist
|
|
assert!(!guard_v1.is_released());
|
|
assert!(!guard_v2.is_released());
|
|
}
|
|
}
|