mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 20:06:37 +00:00
refactor(storage-api): remove namespace lock from StorageAPI (#3365)
* refactor(storage-api): remove namespace lock from StorageAPI * test(scanner): wait for runtime budget cancellation --------- Co-authored-by: loverustfs <hello@rustfs.com>
This commit is contained in:
@@ -27,7 +27,7 @@ use crate::bucket::replication::replication_state::ReplicationStats;
|
||||
use crate::config::com::read_config;
|
||||
use crate::disk::BUCKET_META_PREFIX;
|
||||
use crate::error::Error as EcstoreError;
|
||||
use crate::store_api::{ObjectIO, ObjectInfo};
|
||||
use crate::store_api::{NamespaceLocking, ObjectIO, ObjectInfo};
|
||||
use lazy_static::lazy_static;
|
||||
use rustfs_filemeta::MrfReplicateEntry;
|
||||
use rustfs_filemeta::ReplicateDecision;
|
||||
@@ -205,7 +205,7 @@ impl Default for ReplicationPoolOpts {
|
||||
}
|
||||
/// Main replication pool structure
|
||||
#[derive(Debug)]
|
||||
pub struct ReplicationPool<S: StorageAPI> {
|
||||
pub struct ReplicationPool<S: StorageAPI + NamespaceLocking> {
|
||||
// Atomic counters for active workers
|
||||
active_workers: Arc<AtomicI32>,
|
||||
active_lrg_workers: Arc<AtomicI32>,
|
||||
@@ -245,7 +245,7 @@ pub struct ReplicationPool<S: StorageAPI> {
|
||||
resyncer: Arc<ReplicationResyncer>,
|
||||
}
|
||||
|
||||
impl<S: StorageAPI> ReplicationPool<S> {
|
||||
impl<S: StorageAPI + NamespaceLocking> ReplicationPool<S> {
|
||||
/// Creates a new replication pool with specified options
|
||||
pub async fn new(opts: ReplicationPoolOpts, stats: Arc<ReplicationStats>, storage: Arc<S>) -> Arc<Self> {
|
||||
let max_workers = opts.max_workers.unwrap_or(WORKER_MAX_LIMIT);
|
||||
@@ -1093,7 +1093,7 @@ pub trait ReplicationPoolTrait: std::fmt::Debug {
|
||||
|
||||
// Implement the trait for ReplicationPool
|
||||
#[async_trait::async_trait]
|
||||
impl<S: StorageAPI> ReplicationPoolTrait for ReplicationPool<S> {
|
||||
impl<S: StorageAPI + NamespaceLocking> ReplicationPoolTrait for ReplicationPool<S> {
|
||||
fn active_workers(&self) -> i32 {
|
||||
ReplicationPool::<S>::active_workers(self)
|
||||
}
|
||||
@@ -1145,7 +1145,7 @@ lazy_static! {
|
||||
}
|
||||
|
||||
/// Initializes background replication with the given options
|
||||
pub async fn init_background_replication<S: StorageAPI>(storage: Arc<S>) {
|
||||
pub async fn init_background_replication<S: StorageAPI + NamespaceLocking>(storage: Arc<S>) {
|
||||
let stats = GLOBAL_REPLICATION_STATS
|
||||
.get_or_init(|| async {
|
||||
let stats = Arc::new(ReplicationStats::new());
|
||||
@@ -1169,7 +1169,12 @@ pub fn get_global_replication_pool() -> Option<Arc<DynReplicationPool>> {
|
||||
GLOBAL_REPLICATION_POOL.get().cloned()
|
||||
}
|
||||
|
||||
pub async fn schedule_replication<S: StorageAPI>(oi: ObjectInfo, o: Arc<S>, dsc: ReplicateDecision, op_type: ReplicationType) {
|
||||
pub async fn schedule_replication<S: StorageAPI + NamespaceLocking>(
|
||||
oi: ObjectInfo,
|
||||
o: Arc<S>,
|
||||
dsc: ReplicateDecision,
|
||||
op_type: ReplicationType,
|
||||
) {
|
||||
let tgt_statuses = replication_statuses_map(&oi.replication_status_internal.clone().unwrap_or_default());
|
||||
let purge_statuses = version_purge_statuses_map(&oi.version_purge_status_internal.clone().unwrap_or_default());
|
||||
let tm = get_str(&oi.user_defined, SUFFIX_REPLICATION_TIMESTAMP)
|
||||
|
||||
@@ -32,7 +32,9 @@ use crate::event_notification::{EventArgs, send_event};
|
||||
use crate::global::GLOBAL_LocalNodeName;
|
||||
use crate::global::get_global_bucket_monitor;
|
||||
use crate::set_disk::get_lock_acquire_timeout;
|
||||
use crate::store_api::{DeletedObject, HTTPRangeSpec, ObjectIO, ObjectInfo, ObjectOptions, ObjectToDelete, WalkOptions};
|
||||
use crate::store_api::{
|
||||
DeletedObject, HTTPRangeSpec, NamespaceLocking, ObjectIO, ObjectInfo, ObjectOptions, ObjectToDelete, WalkOptions,
|
||||
};
|
||||
use crate::{StorageAPI, new_object_layer_fn};
|
||||
use aws_sdk_s3::error::{ProvideErrorMetadata, SdkError};
|
||||
use aws_sdk_s3::operation::head_object::{HeadObjectError, HeadObjectOutput};
|
||||
@@ -700,7 +702,7 @@ impl ReplicationResyncer {
|
||||
}
|
||||
|
||||
#[instrument(skip(cancellation_token, storage))]
|
||||
pub async fn resync_bucket<S: StorageAPI>(
|
||||
pub async fn resync_bucket<S: StorageAPI + NamespaceLocking>(
|
||||
self: Arc<Self>,
|
||||
cancellation_token: CancellationToken,
|
||||
storage: Arc<S>,
|
||||
@@ -1668,7 +1670,7 @@ pub async fn must_replicate(bucket: &str, object: &str, mopts: MustReplicateOpti
|
||||
dsc
|
||||
}
|
||||
|
||||
pub async fn replicate_delete<S: StorageAPI>(dobj: DeletedObjectReplicationInfo, storage: Arc<S>) {
|
||||
pub async fn replicate_delete<S: StorageAPI + NamespaceLocking>(dobj: DeletedObjectReplicationInfo, storage: Arc<S>) {
|
||||
if dobj.delete_object.force_delete {
|
||||
replicate_force_delete_to_targets(&dobj, storage).await;
|
||||
return;
|
||||
@@ -2170,7 +2172,10 @@ async fn replicate_delete_marker_purge_to_targets(bucket: &str, dobj: &DeletedOb
|
||||
}
|
||||
}
|
||||
|
||||
async fn replicate_force_delete_to_targets<S: StorageAPI>(dobj: &DeletedObjectReplicationInfo, storage: Arc<S>) {
|
||||
async fn replicate_force_delete_to_targets<S: StorageAPI + NamespaceLocking>(
|
||||
dobj: &DeletedObjectReplicationInfo,
|
||||
storage: Arc<S>,
|
||||
) {
|
||||
let bucket = &dobj.bucket;
|
||||
let object_name = &dobj.delete_object.object_name;
|
||||
|
||||
|
||||
@@ -1220,8 +1220,8 @@ mod tests {
|
||||
use crate::store_api::{
|
||||
BucketInfo, BucketOperations, BucketOptions, CompletePart, DeleteBucketOptions, DeletedObject, GetObjectReader,
|
||||
HTTPRangeSpec, HealOperations, ListMultipartsInfo, ListObjectVersionsInfo, ListObjectsV2Info, ListOperations,
|
||||
MakeBucketOptions, MultipartInfo, MultipartOperations, MultipartUploadResult, ObjectIO, ObjectInfo, ObjectOperations,
|
||||
ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI, WalkOptions,
|
||||
MakeBucketOptions, MultipartInfo, MultipartOperations, MultipartUploadResult, NamespaceLocking, ObjectIO, ObjectInfo,
|
||||
ObjectOperations, ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI, WalkOptions,
|
||||
};
|
||||
use http::HeaderMap;
|
||||
use rustfs_config::audit::{AUDIT_AMQP_SUB_SYS, AUDIT_KAFKA_SUB_SYS, AUDIT_MQTT_SUB_SYS, AUDIT_WEBHOOK_SUB_SYS};
|
||||
@@ -1726,7 +1726,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl StorageAPI for LockingConfigStorage {
|
||||
impl StorageAPI for LockingConfigStorage {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NamespaceLocking for LockingConfigStorage {
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<rustfs_lock::NamespaceLockWrapper> {
|
||||
self.set_disks.new_ns_lock(bucket, object).await
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::global::get_global_endpoints;
|
||||
use crate::pools::ListCallback;
|
||||
use crate::set_disk::{SetDisks, get_lock_acquire_timeout};
|
||||
use crate::store::ECStore;
|
||||
use crate::store_api::{GetObjectReader, HTTPRangeSpec, ObjectIO, ObjectInfo, ObjectOperations, ObjectOptions};
|
||||
use crate::store_api::{GetObjectReader, HTTPRangeSpec, NamespaceLocking, ObjectIO, ObjectInfo, ObjectOperations, ObjectOptions};
|
||||
use http::HeaderMap;
|
||||
use rand::RngExt as _;
|
||||
use rustfs_filemeta::{FileInfo, MetaCacheEntries, MetaCacheEntry, MetadataResolutionParams};
|
||||
@@ -651,7 +651,7 @@ impl RebalanceMeta {
|
||||
}
|
||||
|
||||
impl ECStore {
|
||||
async fn save_rebalance_meta_with_merge<S: StorageAPI>(
|
||||
async fn save_rebalance_meta_with_merge<S: StorageAPI + NamespaceLocking>(
|
||||
&self,
|
||||
pool: Arc<S>,
|
||||
local_snapshot: &RebalanceMeta,
|
||||
|
||||
@@ -54,7 +54,8 @@ use crate::{
|
||||
store_api::{
|
||||
BucketInfo, BucketOperations, BucketOptions, CompletePart, DeleteBucketOptions, DeletedObject, GetObjectReader,
|
||||
HTTPRangeSpec, HealOperations, ListMultipartsInfo, ListObjectsV2Info, ListOperations, MakeBucketOptions, MultipartInfo,
|
||||
MultipartOperations, MultipartUploadResult, ObjectIO, ObjectInfo, ObjectOperations, PartInfo, PutObjReader, StorageAPI,
|
||||
MultipartOperations, MultipartUploadResult, NamespaceLocking, ObjectIO, ObjectInfo, ObjectOperations, PartInfo,
|
||||
PutObjReader, StorageAPI,
|
||||
},
|
||||
store_init::load_format_erasure,
|
||||
};
|
||||
@@ -1586,7 +1587,10 @@ impl SetDisks {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl StorageAPI for SetDisks {
|
||||
impl StorageAPI for SetDisks {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NamespaceLocking for SetDisks {
|
||||
#[tracing::instrument(skip(self))]
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||
let set_lock = if is_dist_erasure().await {
|
||||
|
||||
@@ -30,8 +30,8 @@ use crate::{
|
||||
store_api::{
|
||||
BucketInfo, BucketOperations, BucketOptions, CompletePart, DeleteBucketOptions, DeletedObject, GetObjectReader,
|
||||
HTTPRangeSpec, HealOperations, ListMultipartsInfo, ListObjectVersionsInfo, ListObjectsV2Info, ListOperations,
|
||||
MakeBucketOptions, MultipartInfo, MultipartOperations, MultipartUploadResult, ObjectIO, ObjectInfo, ObjectOperations,
|
||||
ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI,
|
||||
MakeBucketOptions, MultipartInfo, MultipartOperations, MultipartUploadResult, NamespaceLocking, ObjectIO, ObjectInfo,
|
||||
ObjectOperations, ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI,
|
||||
},
|
||||
store_init::{check_format_erasure_values, get_format_erasure_in_quorum, load_format_erasure_all, save_format_file},
|
||||
};
|
||||
@@ -897,7 +897,10 @@ impl HealOperations for Sets {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl StorageAPI for Sets {
|
||||
impl StorageAPI for Sets {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NamespaceLocking for Sets {
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||
self.disk_set[0].new_ns_lock(bucket, object).await
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ use crate::{
|
||||
store_api::{
|
||||
BucketInfo, BucketOperations, BucketOptions, CompletePart, DeleteBucketOptions, DeletedObject, GetObjectReader,
|
||||
HTTPRangeSpec, HealOperations, ListObjectsV2Info, ListOperations, MakeBucketOptions, MultipartOperations,
|
||||
MultipartUploadResult, ObjectInfo, ObjectOperations, ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI,
|
||||
MultipartUploadResult, NamespaceLocking, ObjectInfo, ObjectOperations, ObjectOptions, ObjectToDelete, PartInfo,
|
||||
PutObjReader, StorageAPI,
|
||||
},
|
||||
store_init,
|
||||
};
|
||||
@@ -703,7 +704,10 @@ impl HealOperations for ECStore {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl StorageAPI for ECStore {
|
||||
impl StorageAPI for ECStore {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NamespaceLocking for ECStore {
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||
self.handle_new_ns_lock(bucket, object).await
|
||||
}
|
||||
|
||||
@@ -179,25 +179,12 @@ pub trait NamespaceLocking: Send + Sync + Debug + 'static {
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T> NamespaceLocking for T
|
||||
where
|
||||
T: StorageAPI + ?Sized + 'static,
|
||||
{
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||
StorageAPI::new_ns_lock(self, bucket, object).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Unified storage API combining all operation groups.
|
||||
///
|
||||
/// Consumers can depend on specific sub-traits (e.g., `BucketOperations`)
|
||||
/// when they don't need the full API surface.
|
||||
#[async_trait::async_trait]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub trait StorageAPI:
|
||||
ObjectIO + BucketOperations + ObjectOperations + ListOperations + MultipartOperations + HealOperations + Debug
|
||||
{
|
||||
// RUSTFS_COMPAT_TODO(API-012): keep old StorageAPI lock callers compiling while namespace-lock-only consumers migrate. Remove after namespace-lock-only consumers depend on NamespaceLocking and StorageAPI no longer owns namespace locking.
|
||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user