From a85cc0354c02fc55e2dd8eb64cfc6155c37921c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Thu, 11 Jun 2026 22:42:12 +0800 Subject: [PATCH] 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 --- .../bucket/replication/replication_pool.rs | 17 ++- .../replication/replication_resyncer.rs | 13 +- crates/ecstore/src/config/com.rs | 9 +- crates/ecstore/src/rebalance.rs | 4 +- crates/ecstore/src/set_disk.rs | 8 +- crates/ecstore/src/sets.rs | 9 +- crates/ecstore/src/store.rs | 8 +- crates/ecstore/src/store_api/traits.rs | 13 -- .../ecstore/tests/storage_api_compat_test.rs | 19 ++- crates/scanner/src/scanner.rs | 3 +- crates/scanner/src/scanner_budget.rs | 7 +- docs/architecture/compat-cleanup-register.md | 6 - docs/architecture/migration-progress.md | 112 +++++++++--------- rustfs/src/app/object_usecase.rs | 4 +- 14 files changed, 126 insertions(+), 106 deletions(-) diff --git a/crates/ecstore/src/bucket/replication/replication_pool.rs b/crates/ecstore/src/bucket/replication/replication_pool.rs index 6c861daad..241c13972 100644 --- a/crates/ecstore/src/bucket/replication/replication_pool.rs +++ b/crates/ecstore/src/bucket/replication/replication_pool.rs @@ -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 { +pub struct ReplicationPool { // Atomic counters for active workers active_workers: Arc, active_lrg_workers: Arc, @@ -245,7 +245,7 @@ pub struct ReplicationPool { resyncer: Arc, } -impl ReplicationPool { +impl ReplicationPool { /// Creates a new replication pool with specified options pub async fn new(opts: ReplicationPoolOpts, stats: Arc, storage: Arc) -> Arc { 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 ReplicationPoolTrait for ReplicationPool { +impl ReplicationPoolTrait for ReplicationPool { fn active_workers(&self) -> i32 { ReplicationPool::::active_workers(self) } @@ -1145,7 +1145,7 @@ lazy_static! { } /// Initializes background replication with the given options -pub async fn init_background_replication(storage: Arc) { +pub async fn init_background_replication(storage: Arc) { 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> { GLOBAL_REPLICATION_POOL.get().cloned() } -pub async fn schedule_replication(oi: ObjectInfo, o: Arc, dsc: ReplicateDecision, op_type: ReplicationType) { +pub async fn schedule_replication( + oi: ObjectInfo, + o: Arc, + 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) diff --git a/crates/ecstore/src/bucket/replication/replication_resyncer.rs b/crates/ecstore/src/bucket/replication/replication_resyncer.rs index 591f09f93..308e4e57f 100644 --- a/crates/ecstore/src/bucket/replication/replication_resyncer.rs +++ b/crates/ecstore/src/bucket/replication/replication_resyncer.rs @@ -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( + pub async fn resync_bucket( self: Arc, cancellation_token: CancellationToken, storage: Arc, @@ -1668,7 +1670,7 @@ pub async fn must_replicate(bucket: &str, object: &str, mopts: MustReplicateOpti dsc } -pub async fn replicate_delete(dobj: DeletedObjectReplicationInfo, storage: Arc) { +pub async fn replicate_delete(dobj: DeletedObjectReplicationInfo, storage: Arc) { 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(dobj: &DeletedObjectReplicationInfo, storage: Arc) { +async fn replicate_force_delete_to_targets( + dobj: &DeletedObjectReplicationInfo, + storage: Arc, +) { let bucket = &dobj.bucket; let object_name = &dobj.delete_object.object_name; diff --git a/crates/ecstore/src/config/com.rs b/crates/ecstore/src/config/com.rs index d0a6e2d4a..55c8539cd 100644 --- a/crates/ecstore/src/config/com.rs +++ b/crates/ecstore/src/config/com.rs @@ -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 { self.set_disks.new_ns_lock(bucket, object).await } diff --git a/crates/ecstore/src/rebalance.rs b/crates/ecstore/src/rebalance.rs index 065b026b3..66754cdfe 100644 --- a/crates/ecstore/src/rebalance.rs +++ b/crates/ecstore/src/rebalance.rs @@ -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( + async fn save_rebalance_meta_with_merge( &self, pool: Arc, local_snapshot: &RebalanceMeta, diff --git a/crates/ecstore/src/set_disk.rs b/crates/ecstore/src/set_disk.rs index 081fe9370..b1143d094 100644 --- a/crates/ecstore/src/set_disk.rs +++ b/crates/ecstore/src/set_disk.rs @@ -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 { let set_lock = if is_dist_erasure().await { diff --git a/crates/ecstore/src/sets.rs b/crates/ecstore/src/sets.rs index 586153c9d..335c55847 100644 --- a/crates/ecstore/src/sets.rs +++ b/crates/ecstore/src/sets.rs @@ -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 { self.disk_set[0].new_ns_lock(bucket, object).await } diff --git a/crates/ecstore/src/store.rs b/crates/ecstore/src/store.rs index 2707679ee..132b71cd2 100644 --- a/crates/ecstore/src/store.rs +++ b/crates/ecstore/src/store.rs @@ -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 { self.handle_new_ns_lock(bucket, object).await } diff --git a/crates/ecstore/src/store_api/traits.rs b/crates/ecstore/src/store_api/traits.rs index 8f401f701..41213a878 100644 --- a/crates/ecstore/src/store_api/traits.rs +++ b/crates/ecstore/src/store_api/traits.rs @@ -179,25 +179,12 @@ pub trait NamespaceLocking: Send + Sync + Debug + 'static { async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result; } -#[async_trait::async_trait] -impl NamespaceLocking for T -where - T: StorageAPI + ?Sized + 'static, -{ - async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result { - 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; } diff --git a/crates/ecstore/tests/storage_api_compat_test.rs b/crates/ecstore/tests/storage_api_compat_test.rs index 37d0a512c..ed56e4088 100644 --- a/crates/ecstore/tests/storage_api_compat_test.rs +++ b/crates/ecstore/tests/storage_api_compat_test.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use rustfs_ecstore::{disk::DiskStore, error::Error, store::ECStore}; +use rustfs_ecstore::{ + disk::DiskStore, + error::Error, + store::ECStore, + store_api::{NamespaceLocking, StorageAPI}, +}; use rustfs_storage_api::StorageAdminApi; fn storage_admin_api_type_name() -> &'static str @@ -27,7 +32,19 @@ where std::any::type_name::() } +fn storage_api_with_namespace_locking_type_name() -> &'static str +where + T: StorageAPI + NamespaceLocking, +{ + std::any::type_name::() +} + #[test] fn ecstore_implements_storage_admin_api_contract() { assert!(storage_admin_api_type_name::().ends_with("::ECStore")); } + +#[test] +fn ecstore_implements_storage_api_and_namespace_locking_contracts() { + assert!(storage_api_with_namespace_locking_type_name::().ends_with("::ECStore")); +} diff --git a/crates/scanner/src/scanner.rs b/crates/scanner/src/scanner.rs index 865b3a190..a3bf47819 100644 --- a/crates/scanner/src/scanner.rs +++ b/crates/scanner/src/scanner.rs @@ -37,7 +37,6 @@ use rustfs_config::{ ENV_SCANNER_CYCLE_MAX_OBJECTS, }; use rustfs_config::{ENV_SCANNER_CYCLE, ENV_SCANNER_SPEED, ENV_SCANNER_START_DELAY_SECS}; -use rustfs_ecstore::StorageAPI as _; use rustfs_ecstore::bucket::lifecycle::lifecycle::Lifecycle as _; use rustfs_ecstore::bucket::metadata_sys::{get_lifecycle_config, get_replication_config}; use rustfs_ecstore::bucket::replication::ReplicationConfigurationExt as _; @@ -46,7 +45,7 @@ use rustfs_ecstore::disk::RUSTFS_META_BUCKET; use rustfs_ecstore::error::Error as EcstoreError; use rustfs_ecstore::global::is_erasure_sd; use rustfs_ecstore::store::ECStore; -use rustfs_ecstore::store_api::BucketOperations; +use rustfs_ecstore::store_api::{BucketOperations, NamespaceLocking as _}; use rustfs_storage_api::BucketOptions; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; diff --git a/crates/scanner/src/scanner_budget.rs b/crates/scanner/src/scanner_budget.rs index cf3eb3f3e..3d9cdfb50 100644 --- a/crates/scanner/src/scanner_budget.rs +++ b/crates/scanner/src/scanner_budget.rs @@ -184,11 +184,14 @@ mod tests { }, ); - tokio::time::sleep(Duration::from_millis(10)).await; + let token = budget.token(); + tokio::time::timeout(Duration::from_secs(1), token.cancelled()) + .await + .expect("runtime budget did not cancel child token"); assert!(budget.budget_elapsed()); assert_eq!(budget.reason(), Some(ScannerCycleBudgetReason::Runtime)); - assert!(budget.token().is_cancelled()); + assert!(token.is_cancelled()); } #[test] diff --git a/docs/architecture/compat-cleanup-register.md b/docs/architecture/compat-cleanup-register.md index d29c54eaf..54b3e5d15 100644 --- a/docs/architecture/compat-cleanup-register.md +++ b/docs/architecture/compat-cleanup-register.md @@ -18,12 +18,6 @@ for later deletion. - Why: legacy KMS create-key and key-status admin grants must keep working during the dedicated KMS policy migration. - Removal condition: remove after KMS admin clients and built-in policies use `kms:Configure`, `kms:DescribeKey`, and `kms:ListKeys`. - Status: planned cleanup. -- `RUSTFS_COMPAT_TODO(API-012)` - - Task: `API-012` - - File: `crates/ecstore/src/store_api/traits.rs` - - Why: old `StorageAPI::new_ns_lock` callers must keep compiling while namespace-lock-only consumers migrate to NamespaceLocking. - - Removal condition: remove after all namespace-lock-only consumers depend on NamespaceLocking and StorageAPI no longer owns namespace lock capability. - - Status: planned cleanup. ## Review Checklist diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 2e27b978f..65c790ede 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,16 +5,17 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Current Context - Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660) -- Branch: `overtrue/arch-storage-api-dto-compat-cleanup` -- Baseline: `origin/main` at `0a987d870b3dca248bea8d4872568a25e235d917` +- Branch: `overtrue/arch-storage-api-namespace-lock-cleanup` +- Baseline: `origin/main` at `7146c893cbbb84a0d5332a7a8a79b70d57191bcc` - PR type for this branch: `api-extraction` - Runtime behavior changes: none intended. -- Rust code changes: migrate remaining in-repo bucket DTO consumers to - `rustfs_storage_api` and remove the temporary API-003 public ECStore - `store_api` bucket DTO re-export. +- Rust code changes: migrate remaining namespace-lock consumers to + `NamespaceLocking`, implement namespace locking directly on ECStore storage + types, and remove the temporary namespace-lock compatibility method from the + full storage trait. - CI/script changes: none. -- Docs changes: remove the API-003 cleanup-register entry and record the - completed storage API DTO compatibility cleanup in progress notes. +- Docs changes: remove the API-012 cleanup-register entry and record the + completed namespace-lock compatibility cleanup in progress notes. ## Phase 0 Tasks @@ -273,9 +274,8 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block - Completed slice: `rustfs/rustfs#3340` removed duplicate admin-read methods from the old `StorageAPI` trait and its ECStore/Sets/SetDisks/test implementations after API-007 migrated their consumers. - - Acceptance: old `StorageAPI` keeps storage operation traits and - `new_ns_lock`, while admin inventory surfaces live only on - `StorageAdminApi`. + - Acceptance: old `StorageAPI` keeps storage operation traits while admin + inventory surfaces live only on `StorageAdminApi`. - [x] `API-009` Narrow metadata helper storage bounds. - Completed slice: `rustfs/rustfs#3343` narrowed server config, tier config, @@ -315,23 +315,26 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block - [x] `API-012` Narrow table catalog object backend bounds. - Completed slice: `rustfs/rustfs#3350` added a narrow `NamespaceLocking` - operation-group trait as a compatibility facade over - `StorageAPI::new_ns_lock`, then narrowed `EcStoreTableCatalogObjectBackend` - from full `StorageAPI` to `ObjectIO`, `ObjectOperations`, - `ListOperations`, and `NamespaceLocking`. + operation-group trait as a compatibility facade, then narrowed + `EcStoreTableCatalogObjectBackend` from full `StorageAPI` to `ObjectIO`, + `ObjectOperations`, `ListOperations`, and `NamespaceLocking`. + - Cleanup slice: migrate the remaining scanner leader-lock and self-copy + object use-case namespace-lock consumers to `NamespaceLocking`, implement + namespace locking directly on ECStore storage types, and remove the + temporary namespace-lock compatibility method from the full storage trait + and cleanup register entry. - Acceptance: table catalog object backend contracts express the actual object read/write, metadata/delete, list, and namespace-lock capabilities - they need, while table catalog store logic and lock behavior remain - unchanged. + they need; namespace-lock consumers depend on `NamespaceLocking` instead of + full `StorageAPI`; and storage lock behavior remains unchanged. - Must preserve: table catalog object paths, metadata pointer semantics, optimistic write preconditions, object listing pagination, missing-object - handling, namespace write-lock acquisition, `StorageAPI::new_ns_lock` - compatibility, object APIs, scanner/heal/replication/config persistence, - and storage hot paths. - - Risk defense: do not remove `StorageAPI::new_ns_lock`, do not move traits - into `rustfs-storage-api`, do not change lock implementation code, do not - alter table catalog method bodies, and track the retained old lock method - with `RUSTFS_COMPAT_TODO(API-012)`. + handling, namespace write-lock acquisition, object APIs, + scanner/heal/replication/config persistence, and storage hot paths. + - Risk defense: do not move traits into `rustfs-storage-api`, do not change + lock implementation code, do not alter table catalog method bodies, and do + not retain stale API-012 compatibility markers after the old `StorageAPI` + lock method is removed. - Verification: focused compile/tests, migration guards, Rust risk scan, and required quality/architecture, migration-preservation, and testing/verification review passed. @@ -359,43 +362,35 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Next PRs -1. `api-extraction`: continue API-012 namespace-lock-only cleanup after all - callers that only need locking depend on `NamespaceLocking`. -2. `security-change`: make Local KMS unsafe defaults explicit development +1. `security-change`: make Local KMS unsafe defaults explicit development opt-ins or production failures in KMSD-002. -3. `security-change`: make Vault unsafe defaults explicit development opt-ins +2. `security-change`: make Vault unsafe defaults explicit development opt-ins or production failures in KMSD-003. ## Pre-Push Review Log | Expert | Status | Notes | |---|---|---| -| Quality/architecture | pass | Confirmed the diff only removes the temporary API-003 public ECStore bucket DTO re-export and migrates remaining in-repo external consumers to `rustfs_storage_api`; bucket operation traits and runtime control flow remain unchanged. | -| Migration preservation | pass | Confirmed ECStore keeps crate-private DTO visibility for its own implementation while no external in-repo consumer uses the old public `rustfs_ecstore::store_api` DTO path. | -| Testing/verification | pass | Confirmed focused compile/tests, rustfs all-targets compile, heal/scanner test target compile, migration guards, dependency guard, source old-path scan, and added-line Rust risk scan cover this cleanup; full pre-commit is skipped under the current larger-granularity instruction. | +| Quality/architecture | pass | Confirmed the diff removes the temporary namespace-lock method from the full `StorageAPI` trait while keeping `NamespaceLocking` as the narrow operation-group contract. | +| Migration preservation | pass | Confirmed ECStore, Sets, SetDisks, scanner leader locking, self-copy locking, replication resync, rebalance metadata, and config test storage retain their existing lock behavior and only narrow trait dependencies. | +| Testing/verification | pass | Confirmed focused compile/tests, migration guards, dependency guard, old-path scan, and added-line Rust risk scan cover this cleanup; full pre-commit is skipped under the current larger-granularity instruction. | ## Verification Notes -Passed after rebasing onto `0a987d870b3dca248bea8d4872568a25e235d917`: -- `cargo check -p rustfs-storage-api -p rustfs-ecstore -p rustfs-heal -p rustfs-scanner -p rustfs-obs -p rustfs-protocols --lib`. -- `cargo check -p rustfs --all-targets`. -- `cargo test -p rustfs-storage-api --lib`; 7 passed. -- `cargo test -p rustfs-ecstore --test storage_api_compat_test`; 1 passed. -- `cargo test -p rustfs-heal --tests --no-run`. +Passed on `7146c893cbbb84a0d5332a7a8a79b70d57191bcc`: +- `cargo check -p rustfs-ecstore -p rustfs-scanner -p rustfs --all-targets`. +- `cargo test -p rustfs-ecstore --test storage_api_compat_test`; 2 passed. +- `cargo test -p rustfs-ecstore --lib new_ns_lock`; 2 passed. - `cargo test -p rustfs-scanner --tests --no-run`. -- `cargo test -p rustfs-protocols --lib swift`; 0 matched, lib test target - compiled and ran successfully. -- `cargo test -p rustfs-obs --lib stats_collector`; 14 passed. +- `cargo test -p rustfs --lib --no-run`. - `cargo fmt --all --check`. - `./scripts/check_architecture_migration_rules.sh`. - `./scripts/check_layer_dependencies.sh`. - `./scripts/check_metrics_migration_refs.sh`. - `git diff --check`. -- API-003 source old-path and marker scan found no - `RUSTFS_COMPAT_TODO(API-003)` or - `rustfs_ecstore::store_api::{BucketInfo, BucketOptions, - DeleteBucketOptions, MakeBucketOptions, SRBucketDeleteOp}` matches in - `crates/**/*.rs` or `rustfs/src`. +- API-012 old-path and marker scan found no stale API-012 compatibility marker + or old full-storage-trait namespace-lock method references in `crates`, + `rustfs/src`, or architecture docs. - Added-line Rust risk scan found no new production `unwrap`/`expect`, lossy numeric casts, stringly public errors, boxed dynamic errors, stdout/stderr printing, or relaxed atomic ordering. @@ -403,20 +398,21 @@ Passed after rebasing onto `0a987d870b3dca248bea8d4872568a25e235d917`: Notes: - Full pre-commit may be skipped if focused tests, compile checks, and guards pass, per the current instruction to increase PR granularity. -- This slice removes only the old API-003 public bucket DTO re-export. - ECStore retains bucket operation traits, object/listing DTOs, storage - implementation wiring, and crate-private access to the storage API bucket - DTOs for its own trait implementations. -- The old public `rustfs_ecstore::store_api` bucket DTO path is no longer - available after this cleanup. Consumers must use `rustfs_storage_api`. +- This slice removes only the old namespace-lock method from the full storage + trait. ECStore retains bucket, object, listing, multipart, heal, replication, + rebalance, scanner, config persistence, and namespace-lock implementation + behavior. +- Consumers that need namespace locks should depend on `NamespaceLocking` + instead of the full storage trait. ## Handoff Notes -- Keep this API-003 cleanup slice as an `api-extraction` PR that only removes - the temporary public ECStore bucket DTO compatibility re-export, migrates - remaining in-repo external imports, and deletes the cleanup-register entry. -- Do not move `ObjectOptions`, `ObjectInfo`, reader types, multipart DTOs, - list result DTOs, storage traits, bucket operation logic, storage runtime - wiring, route behavior, or storage persistence logic in this PR. -- Do not add temporary compatibility code unless a matching - `RUSTFS_COMPAT_TODO()` marker and cleanup-register entry are added. +- Keep this API-012 cleanup slice as an `api-extraction` PR that only removes + the temporary namespace-lock method from the full storage trait, migrates + namespace-lock consumers to `NamespaceLocking`, and deletes the + cleanup-register entry. +- Do not move storage traits, bucket/object/list/multipart/heal operation + logic, lock implementation code, storage runtime wiring, route behavior, or + storage persistence logic in this PR. +- Do not add temporary compatibility code unless a matching task marker and + cleanup-register entry are added. diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index fecc7e90d..65ee5fb5d 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -77,7 +77,7 @@ use rustfs_ecstore::new_object_layer_fn; use rustfs_ecstore::rio::{DynReader, HashReader, WritePlan, wrap_reader}; use rustfs_ecstore::set_disk::{get_lock_acquire_timeout, is_valid_storage_class}; use rustfs_ecstore::store_api::{ - HTTPRangeSpec, ObjectIO, ObjectInfo, ObjectOperations, ObjectOptions, ObjectToDelete, PutObjReader, StorageAPI, + HTTPRangeSpec, NamespaceLocking, ObjectIO, ObjectInfo, ObjectOperations, ObjectOptions, ObjectToDelete, PutObjReader, }; use rustfs_filemeta::{ REPLICATE_INCOMING_DELETE, ReplicateDecision, ReplicateTargetDecision, ReplicationState, ReplicationStatusType, @@ -730,7 +730,7 @@ fn copy_namespace_lock_error(bucket: &str, object: &str, mode: &'static str, err } } -async fn acquire_self_copy_namespace_lock( +async fn acquire_self_copy_namespace_lock( store: &S, bucket: &str, object: &str,