From da08e411f1765030ada906afe98831d1bdf66371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Mon, 22 Jun 2026 13:22:48 +0800 Subject: [PATCH] refactor: use relative local compat consumers (#3723) --- docs/architecture/migration-progress.md | 45 +++++++++++---- rustfs/src/admin/router.rs | 56 +++++++++---------- rustfs/src/app/admin_usecase.rs | 14 ++--- rustfs/src/app/bucket_usecase.rs | 26 ++++----- rustfs/src/app/capacity_dirty_scope_test.rs | 4 +- .../src/app/lifecycle_transition_api_test.rs | 14 ++--- rustfs/src/app/multipart_usecase.rs | 48 +++++++--------- rustfs/src/app/object_usecase.rs | 48 ++++++++-------- rustfs/src/storage/ecfs_test.rs | 12 ++-- scripts/check_architecture_migration_rules.sh | 17 ++++++ 10 files changed, 159 insertions(+), 125 deletions(-) diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 830c8e2bf..940d0c7d6 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-root-compat-relative-consumers` -- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109`. -- Based on: API-108 slice. +- Branch: `overtrue/arch-rustfs-local-compat-consumers` +- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110`. +- Based on: API-109 slice. - PR type for this branch: `pure-move` - Runtime behavior changes: none. -- Rust code changes: collapse crate-qualified root compatibility and storage - owner compatibility consumer paths into relative `super::`/`self::` paths. -- CI/script changes: guard selected RustFS root and storage owner consumers +- Rust code changes: collapse crate-qualified RustFS app/admin/storage local + compatibility consumer paths into relative `super::`/`super::super::` paths. +- CI/script changes: guard selected RustFS app/admin/storage local consumers against crate-qualified compatibility paths. -- Docs changes: record the API-109 relative compatibility consumer cleanup. +- Docs changes: record the API-110 relative local compatibility consumer + cleanup. ## Phase 0 Tasks @@ -558,6 +559,18 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block compatibility consumer residual scans, migration and layer guards, formatting, diff hygiene, Rust risk scan, pre-commit quality gate, and three-expert review. +- [x] `API-110` Collapse RustFS local compatibility consumer paths. + - Completed slice: replace crate-qualified app usecase, admin router, and + storage ECFS test compatibility consumers with relative owner paths. + - Acceptance: selected RustFS app/admin/storage consumers no longer point back + to local compatibility facades through crate-qualified paths; migration + rules reject regressions. + - Must preserve: app object/bucket/multipart/admin usecase behavior, + lifecycle transition and capacity tests, admin replication/router helpers, + and storage ECFS test coverage. + - Verification: RustFS test-target compile coverage, local compatibility + consumer residual scan, migration and layer guards, formatting, diff + hygiene, Rust risk scan, pre-commit quality gate, and three-expert review. - [x] `G-012` Inventory placement and repair invariants. - Acceptance: [`placement-repair-invariants.md`](placement-repair-invariants.md) records @@ -3591,14 +3604,26 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block | Expert | Status | Notes | |---|---|---| -| Quality/architecture | pass | API-109 keeps selected root and storage owner compatibility consumers owner-relative by replacing crate-qualified compatibility paths with scoped `super::` or `self::` paths. | -| Migration preservation | pass | The new guards reject crate-qualified root compatibility and storage owner compatibility consumer paths while preserving the same local facade names and aliases. | -| Testing/verification | pass | Focused compile, root/storage owner residual scans, migration guard, layer guard, formatting, diff hygiene, risk scan, and full pre-commit passed. | +| Quality/architecture | pass | API-110 keeps selected app/admin/storage local compatibility consumers owner-relative by replacing crate-qualified compatibility paths with scoped `super::` or `super::super::` paths. | +| Migration preservation | pass | The new guard rejects crate-qualified app/admin/storage local compatibility consumer paths while preserving the same facade names and aliases. | +| Testing/verification | pass | Focused compile, local compatibility consumer residual scan, migration guard, layer guard, formatting, diff hygiene, risk scan, and full pre-commit passed. | ## Verification Notes Passed before push: +- Issue #660 API-110 current slice: + - `cargo check -p rustfs --tests`: passed. + - `cargo fmt --all`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - `bash -n scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - RustFS local compatibility consumer residual scan: passed. + - Rust risk scan on changed Rust files and guard script: passed. + - `make pre-commit`: passed. + - Issue #660 API-109 current slice: - `cargo check -p rustfs --tests`: passed. - `cargo fmt --all`: passed. diff --git a/rustfs/src/admin/router.rs b/rustfs/src/admin/router.rs index 348102398..815a0f3a3 100644 --- a/rustfs/src/admin/router.rs +++ b/rustfs/src/admin/router.rs @@ -12,25 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::admin::console::{is_console_path, make_console_server}; -use crate::admin::handlers::oidc::is_oidc_path; -use crate::admin::router_storage_compat::GLOBAL_BOOT_TIME; -use crate::admin::router_storage_compat::PeerRestClient; -use crate::admin::router_storage_compat::bandwidth::monitor::BandwidthDetails; -use crate::admin::router_storage_compat::bucket_target_sys::{ +use super::router_storage_compat::GLOBAL_BOOT_TIME; +use super::router_storage_compat::PeerRestClient; +use super::router_storage_compat::bandwidth::monitor::BandwidthDetails; +use super::router_storage_compat::bucket_target_sys::{ BucketTargetSys, PutObjectOptions, RemoveObjectOptions, S3ClientError, TargetClient, }; -use crate::admin::router_storage_compat::get_global_notification_sys; -use crate::admin::router_storage_compat::metadata::BUCKET_TARGETS_FILE; -use crate::admin::router_storage_compat::metadata_sys; -use crate::admin::router_storage_compat::read_admin_config_without_migrate; -use crate::admin::router_storage_compat::replication::{ +use super::router_storage_compat::get_global_notification_sys; +use super::router_storage_compat::metadata::BUCKET_TARGETS_FILE; +use super::router_storage_compat::metadata_sys; +use super::router_storage_compat::read_admin_config_without_migrate; +use super::router_storage_compat::replication::{ BucketReplicationResyncStatus, BucketStats, GLOBAL_REPLICATION_STATS, ObjectOpts, ResyncOpts, get_global_replication_pool, }; -use crate::admin::router_storage_compat::target::{BucketTarget, BucketTargetType, BucketTargets}; -use crate::admin::router_storage_compat::versioning_sys::BucketVersioningSys; -use crate::admin::router_storage_compat::{AdminReplicationConfigExt as _, AdminVersioningConfigExt as _}; -use crate::admin::router_storage_compat::{get_global_bucket_monitor, get_global_deployment_id, get_global_region}; +use super::router_storage_compat::target::{BucketTarget, BucketTargetType, BucketTargets}; +use super::router_storage_compat::versioning_sys::BucketVersioningSys; +use super::router_storage_compat::{AdminReplicationConfigExt as _, AdminVersioningConfigExt as _}; +use super::router_storage_compat::{get_global_bucket_monitor, get_global_deployment_id, get_global_region}; +use crate::admin::console::{is_console_path, make_console_server}; +use crate::admin::handlers::oidc::is_oidc_path; use crate::app::context::resolve_object_store_handle; use crate::app::object_usecase::DefaultObjectUsecase; use crate::auth::{check_key_valid, get_session_token}; @@ -1419,9 +1419,7 @@ async fn ensure_replication_bucket_exists(bucket: &str) -> S3Result<()> { async fn ensure_replication_config_exists(bucket: &str) -> S3Result<()> { match metadata_sys::get_replication_config(bucket).await { Ok(_) => Ok(()), - Err(crate::admin::router_storage_compat::StorageError::ConfigNotFound) => { - Err(s3_error!(ReplicationConfigurationNotFoundError)) - } + Err(super::router_storage_compat::StorageError::ConfigNotFound) => Err(s3_error!(ReplicationConfigurationNotFoundError)), Err(err) => Err(ApiError::from(err).into()), } } @@ -1946,7 +1944,7 @@ async fn resolve_replication_target_client(bucket: &str, target: &BucketTarget) fn build_replication_probe_put_options(now: OffsetDateTime) -> PutObjectOptions { PutObjectOptions { - internal: crate::admin::router_storage_compat::bucket_target_sys::AdvancedPutOptions { + internal: super::router_storage_compat::bucket_target_sys::AdvancedPutOptions { source_version_id: Uuid::new_v4().to_string(), replication_status: ReplicationStatusType::Replica, source_mtime: now, @@ -2061,7 +2059,7 @@ async fn source_bucket_requires_object_lock(bucket: &str) -> S3Result { .object_lock_enabled .as_ref() .is_some_and(|state| state.as_str() == s3s::dto::ObjectLockEnabled::ENABLED)), - Err(crate::admin::router_storage_compat::StorageError::ConfigNotFound) => Ok(false), + Err(super::router_storage_compat::StorageError::ConfigNotFound) => Ok(false), Err(err) => Err(ApiError::from(err).into()), } } @@ -2775,7 +2773,7 @@ mod tests { #[test] fn apply_replication_reset_to_targets_updates_matching_target() { let mut targets = BucketTargets { - targets: vec![crate::admin::router_storage_compat::target::BucketTarget { + targets: vec![super::super::router_storage_compat::target::BucketTarget { arn: "arn:target".to_string(), ..Default::default() }], @@ -2797,10 +2795,10 @@ mod tests { let mut status = BucketReplicationResyncStatus::new(); status.targets_map.insert( "arn:z".to_string(), - crate::admin::router_storage_compat::replication::TargetReplicationResyncStatus { + super::super::router_storage_compat::replication::TargetReplicationResyncStatus { resync_id: "rid-z".to_string(), last_update: Some(datetime!(2025-01-03 00:00 UTC)), - resync_status: crate::admin::router_storage_compat::replication::ResyncStatusType::ResyncFailed, + resync_status: super::super::router_storage_compat::replication::ResyncStatusType::ResyncFailed, failed_count: 2, failed_size: 4, bucket: "bucket-z".to_string(), @@ -2810,10 +2808,10 @@ mod tests { ); status.targets_map.insert( "arn:a".to_string(), - crate::admin::router_storage_compat::replication::TargetReplicationResyncStatus { + super::super::router_storage_compat::replication::TargetReplicationResyncStatus { resync_id: "rid-a".to_string(), last_update: Some(datetime!(2025-01-02 00:00 UTC)), - resync_status: crate::admin::router_storage_compat::replication::ResyncStatusType::ResyncCompleted, + resync_status: super::super::router_storage_compat::replication::ResyncStatusType::ResyncCompleted, replicated_count: 3, replicated_size: 9, bucket: "bucket-a".to_string(), @@ -2843,10 +2841,10 @@ mod tests { let mut status = BucketReplicationResyncStatus::new(); status.targets_map.insert( "arn:z".to_string(), - crate::admin::router_storage_compat::replication::TargetReplicationResyncStatus { + super::super::router_storage_compat::replication::TargetReplicationResyncStatus { resync_id: "rid-z".to_string(), last_update: Some(datetime!(2025-02-03 00:00 UTC)), - resync_status: crate::admin::router_storage_compat::replication::ResyncStatusType::ResyncFailed, + resync_status: super::super::router_storage_compat::replication::ResyncStatusType::ResyncFailed, failed_count: 2, failed_size: 4, bucket: "bucket-z".to_string(), @@ -2856,10 +2854,10 @@ mod tests { ); status.targets_map.insert( "arn:a".to_string(), - crate::admin::router_storage_compat::replication::TargetReplicationResyncStatus { + super::super::router_storage_compat::replication::TargetReplicationResyncStatus { resync_id: "rid-a".to_string(), last_update: Some(datetime!(2025-02-02 00:00 UTC)), - resync_status: crate::admin::router_storage_compat::replication::ResyncStatusType::ResyncCompleted, + resync_status: super::super::router_storage_compat::replication::ResyncStatusType::ResyncCompleted, replicated_count: 3, replicated_size: 9, bucket: "bucket-a".to_string(), diff --git a/rustfs/src/app/admin_usecase.rs b/rustfs/src/app/admin_usecase.rs index 730de0fa9..26bd8cb7c 100644 --- a/rustfs/src/app/admin_usecase.rs +++ b/rustfs/src/app/admin_usecase.rs @@ -14,14 +14,14 @@ //! Admin application use-case contracts. -use crate::app::context::{AppContext, get_global_app_context, resolve_object_store_handle_for_context}; -use crate::app::usecase_storage_compat::ECStore; -use crate::app::usecase_storage_compat::EndpointServerPools; -use crate::app::usecase_storage_compat::get_server_info; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::ECStore; +use super::usecase_storage_compat::EndpointServerPools; +use super::usecase_storage_compat::get_server_info; +use super::usecase_storage_compat::{ PoolDecommissionInfo, PoolStatus, get_total_usable_capacity, get_total_usable_capacity_free, }; -use crate::app::usecase_storage_compat::{apply_bucket_usage_memory_overlay, load_data_usage_from_backend}; +use super::usecase_storage_compat::{apply_bucket_usage_memory_overlay, load_data_usage_from_backend}; +use crate::app::context::{AppContext, get_global_app_context, resolve_object_store_handle_for_context}; use crate::capacity::resolve_admin_used_capacity; use crate::error::ApiError; use crate::server::{DependencyReadiness, collect_dependency_readiness as collect_runtime_dependency_readiness}; @@ -403,8 +403,8 @@ impl DefaultAdminUsecase { #[cfg(test)] mod tests { + use super::super::usecase_storage_compat::{PoolDecommissionInfo, PoolStatus}; use super::*; - use crate::app::usecase_storage_compat::{PoolDecommissionInfo, PoolStatus}; use time::OffsetDateTime; #[tokio::test] diff --git a/rustfs/src/app/bucket_usecase.rs b/rustfs/src/app/bucket_usecase.rs index dd7c91a7e..2e1141f1d 100644 --- a/rustfs/src/app/bucket_usecase.rs +++ b/rustfs/src/app/bucket_usecase.rs @@ -14,18 +14,12 @@ //! Bucket application use-case contracts. -use crate::admin::handlers::site_replication::{ - site_replication_bucket_meta_hook, site_replication_delete_bucket_hook, site_replication_make_bucket_hook, -}; -use crate::app::context::{ - AppContext, default_notify_interface, get_global_app_context, resolve_object_store_handle_for_context, -}; -use crate::app::usecase_storage_compat::ECStore; -use crate::app::usecase_storage_compat::StorageError; -use crate::app::usecase_storage_compat::get_global_notification_sys; -use crate::app::usecase_storage_compat::object_api_utils::to_s3s_etag; -use crate::app::usecase_storage_compat::{AppObjectLockConfigExt as _, AppVersioningConfigExt as _}; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::ECStore; +use super::usecase_storage_compat::StorageError; +use super::usecase_storage_compat::get_global_notification_sys; +use super::usecase_storage_compat::object_api_utils::to_s3s_etag; +use super::usecase_storage_compat::{AppObjectLockConfigExt as _, AppVersioningConfigExt as _}; +use super::usecase_storage_compat::{ bucket_target_sys::BucketTargetSys, lifecycle::bucket_lifecycle_ops::{ enqueue_expiry_for_existing_objects, enqueue_transition_for_existing_objects, validate_lifecycle_config, @@ -42,6 +36,12 @@ use crate::app::usecase_storage_compat::{ utils::serialize, versioning_sys::BucketVersioningSys, }; +use crate::admin::handlers::site_replication::{ + site_replication_bucket_meta_hook, site_replication_delete_bucket_hook, site_replication_make_bucket_hook, +}; +use crate::app::context::{ + AppContext, default_notify_interface, get_global_app_context, resolve_object_store_handle_for_context, +}; use crate::auth::get_condition_values_with_client_info; use crate::error::ApiError; use crate::server::RemoteAddr; @@ -2285,7 +2285,7 @@ mod tests { BucketTargets { targets: arns .iter() - .map(|arn| crate::app::usecase_storage_compat::target::BucketTarget { + .map(|arn| super::super::usecase_storage_compat::target::BucketTarget { arn: (*arn).to_string(), target_type: BucketTargetType::ReplicationService, ..Default::default() diff --git a/rustfs/src/app/capacity_dirty_scope_test.rs b/rustfs/src/app/capacity_dirty_scope_test.rs index 36275c496..a7d0a8bd9 100644 --- a/rustfs/src/app/capacity_dirty_scope_test.rs +++ b/rustfs/src/app/capacity_dirty_scope_test.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::app::usecase_storage_compat::{ECStore, Endpoint, EndpointServerPools, Endpoints, PoolEndpoints, metadata_sys}; +use super::usecase_storage_compat::{ECStore, Endpoint, EndpointServerPools, Endpoints, PoolEndpoints, metadata_sys}; use rustfs_common::heal_channel::{HealOpts, HealScanMode}; use rustfs_object_capacity::capacity_manager::{HybridStrategyConfig, create_isolated_manager}; use rustfs_storage_api::{BucketOperations, BucketOptions, HealOperations as _, MakeBucketOptions, ObjectIO as _}; @@ -77,7 +77,7 @@ async fn setup_capacity_dirty_scope_env() -> (Vec, Arc) { }; let endpoint_pools = EndpointServerPools(vec![pool_endpoints]); - crate::app::usecase_storage_compat::init_local_disks(endpoint_pools.clone()) + super::usecase_storage_compat::init_local_disks(endpoint_pools.clone()) .await .unwrap(); diff --git a/rustfs/src/app/lifecycle_transition_api_test.rs b/rustfs/src/app/lifecycle_transition_api_test.rs index 5b9c2f388..edbc9c3ad 100644 --- a/rustfs/src/app/lifecycle_transition_api_test.rs +++ b/rustfs/src/app/lifecycle_transition_api_test.rs @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{multipart_usecase::DefaultMultipartUsecase, object_usecase::DefaultObjectUsecase}; -use crate::app::bucket_usecase::DefaultBucketUsecase; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::{ AppWarmBackend, ECStore, Endpoint, EndpointServerPools, Endpoints, GLOBAL_TierConfigMgr, PoolEndpoints, TierConfig, TierType, WarmBackendGetOpts, metadata::{BUCKET_LIFECYCLE_CONFIG, OBJECT_LOCK_CONFIG}, @@ -22,6 +20,8 @@ use crate::app::usecase_storage_compat::{ object_api_utils::to_s3s_etag, transition_api::{ReadCloser, ReaderImpl}, }; +use super::{multipart_usecase::DefaultMultipartUsecase, object_usecase::DefaultObjectUsecase}; +use crate::app::bucket_usecase::DefaultBucketUsecase; use crate::storage::ecfs::FS; use crate::storage::{ StorageObjectInfo as ObjectInfo, StorageObjectOptions as ObjectOptions, StoragePutObjReader as PutObjReader, @@ -107,7 +107,7 @@ async fn setup_test_env() -> (Vec, Arc) { let endpoint_pools = EndpointServerPools(vec![pool_endpoints]); - crate::app::usecase_storage_compat::init_local_disks(endpoint_pools.clone()) + super::usecase_storage_compat::init_local_disks(endpoint_pools.clone()) .await .unwrap(); @@ -126,7 +126,7 @@ async fn setup_test_env() -> (Vec, Arc) { let buckets = buckets_list.into_iter().map(|v| v.name).collect(); metadata_sys::init_bucket_metadata_sys(ecstore.clone(), buckets).await; - crate::app::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::init_background_expiry(ecstore.clone()).await; + super::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::init_background_expiry(ecstore.clone()).await; let _ = GLOBAL_ENV.set((disk_paths.clone(), ecstore.clone())); @@ -926,7 +926,7 @@ async fn delete_transitioned_object_removes_remote_tier_copy_via_usecase() { .expect("Failed to set lifecycle configuration"); let _ = upload_test_object(&ecstore, bucket.as_str(), object, payload).await; - crate::app::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::enqueue_transition_for_existing_objects( + super::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::enqueue_transition_for_existing_objects( ecstore.clone(), bucket.as_str(), ) @@ -986,7 +986,7 @@ async fn lifecycle_transition_marks_dirty_disks_for_capacity_manager() { .expect("Failed to set lifecycle configuration"); let _ = upload_test_object(&ecstore, bucket.as_str(), object, payload).await; - crate::app::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::enqueue_transition_for_existing_objects( + super::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::enqueue_transition_for_existing_objects( ecstore.clone(), bucket.as_str(), ) diff --git a/rustfs/src/app/multipart_usecase.rs b/rustfs/src/app/multipart_usecase.rs index f261d346a..75799b550 100644 --- a/rustfs/src/app/multipart_usecase.rs +++ b/rustfs/src/app/multipart_usecase.rs @@ -14,24 +14,24 @@ //! Multipart application use-case contracts. -use crate::app::context::{AppContext, get_global_app_context, resolve_object_store_handle_for_context}; -use crate::app::object_usecase::{build_put_like_object_lock_metadata, validate_existing_object_lock_for_write}; -use crate::app::usecase_storage_compat::ECStore; -use crate::app::usecase_storage_compat::is_disk_compressible; -use crate::app::usecase_storage_compat::is_valid_storage_class; -use crate::app::usecase_storage_compat::object_api_utils::to_s3s_etag; -use crate::app::usecase_storage_compat::quota::checker::QuotaChecker; +use super::usecase_storage_compat::ECStore; +use super::usecase_storage_compat::is_disk_compressible; +use super::usecase_storage_compat::is_valid_storage_class; +use super::usecase_storage_compat::object_api_utils::to_s3s_etag; +use super::usecase_storage_compat::quota::checker::QuotaChecker; #[cfg(test)] -use crate::app::usecase_storage_compat::{DecryptReader, EncryptReader, HardLimitReader, boxed_reader, wrap_reader}; -use crate::app::usecase_storage_compat::{HashReader, WritePlan}; -use crate::app::usecase_storage_compat::{StorageError, is_err_object_not_found, is_err_version_not_found}; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::{DecryptReader, EncryptReader, HardLimitReader, boxed_reader, wrap_reader}; +use super::usecase_storage_compat::{HashReader, WritePlan}; +use super::usecase_storage_compat::{StorageError, is_err_object_not_found, is_err_version_not_found}; +use super::usecase_storage_compat::{ lifecycle::{bucket_lifecycle_audit::LcEventSrc, bucket_lifecycle_ops::enqueue_transition_immediate}, metadata_sys, quota::QuotaOperation, replication::{get_must_replicate_options, must_replicate, schedule_replication}, versioning_sys::BucketVersioningSys, }; +use crate::app::context::{AppContext, get_global_app_context, resolve_object_store_handle_for_context}; +use crate::app::object_usecase::{build_put_like_object_lock_metadata, validate_existing_object_lock_for_write}; use crate::capacity::record_capacity_write; use crate::error::ApiError; use crate::storage::access::has_bypass_governance_header; @@ -482,7 +482,7 @@ impl DefaultMultipartUsecase { )); } // Update quota tracking after successful multipart upload - crate::app::usecase_storage_compat::record_bucket_object_write_memory( + super::usecase_storage_compat::record_bucket_object_write_memory( &bucket, previous_current_size, obj_info.size.max(0) as u64, @@ -675,7 +675,7 @@ impl DefaultMultipartUsecase { rustfs_utils::http::insert_str( &mut metadata, rustfs_utils::http::SUFFIX_COMPRESSION, - crate::app::usecase_storage_compat::compression_metadata_value(CompressionAlgorithm::default()), + super::usecase_storage_compat::compression_metadata_value(CompressionAlgorithm::default()), ); } @@ -894,12 +894,9 @@ impl DefaultMultipartUsecase { .ok_or_else(|| ApiError::from(StorageError::other("Missing SSE-C session material")))?; let ssec_write = match ssec_material.key_kind { crate::storage::sse::EncryptionKeyKind::Object => { - crate::app::usecase_storage_compat::WriteEncryption::multipart_object_key( - ssec_material.key_bytes, - part_id as u32, - ) + super::usecase_storage_compat::WriteEncryption::multipart_object_key(ssec_material.key_bytes, part_id as u32) } - crate::storage::sse::EncryptionKeyKind::Direct => crate::app::usecase_storage_compat::WriteEncryption::multipart( + crate::storage::sse::EncryptionKeyKind::Direct => super::usecase_storage_compat::WriteEncryption::multipart( ssec_material.key_bytes, ssec_material.base_nonce, part_id, @@ -919,12 +916,12 @@ impl DefaultMultipartUsecase { .ok_or_else(|| ApiError::from(StorageError::other("Missing managed SSE session material")))?; let managed_write = match managed_material.key_kind { crate::storage::sse::EncryptionKeyKind::Object => { - crate::app::usecase_storage_compat::WriteEncryption::multipart_object_key( + super::usecase_storage_compat::WriteEncryption::multipart_object_key( managed_material.key_bytes, part_id as u32, ) } - crate::storage::sse::EncryptionKeyKind::Direct => crate::app::usecase_storage_compat::WriteEncryption::multipart( + crate::storage::sse::EncryptionKeyKind::Direct => super::usecase_storage_compat::WriteEncryption::multipart( managed_material.key_bytes, managed_material.base_nonce, part_id, @@ -1243,12 +1240,9 @@ impl DefaultMultipartUsecase { .ok_or_else(|| ApiError::from(StorageError::other("Missing SSE-C session material")))?; let ssec_write = match ssec_material.key_kind { crate::storage::sse::EncryptionKeyKind::Object => { - crate::app::usecase_storage_compat::WriteEncryption::multipart_object_key( - ssec_material.key_bytes, - part_id as u32, - ) + super::usecase_storage_compat::WriteEncryption::multipart_object_key(ssec_material.key_bytes, part_id as u32) } - crate::storage::sse::EncryptionKeyKind::Direct => crate::app::usecase_storage_compat::WriteEncryption::multipart( + crate::storage::sse::EncryptionKeyKind::Direct => super::usecase_storage_compat::WriteEncryption::multipart( ssec_material.key_bytes, ssec_material.base_nonce, part_id, @@ -1272,12 +1266,12 @@ impl DefaultMultipartUsecase { .ok_or_else(|| ApiError::from(StorageError::other("Missing managed SSE session material")))?; let managed_write = match managed_material.key_kind { crate::storage::sse::EncryptionKeyKind::Object => { - crate::app::usecase_storage_compat::WriteEncryption::multipart_object_key( + super::usecase_storage_compat::WriteEncryption::multipart_object_key( managed_material.key_bytes, part_id as u32, ) } - crate::storage::sse::EncryptionKeyKind::Direct => crate::app::usecase_storage_compat::WriteEncryption::multipart( + crate::storage::sse::EncryptionKeyKind::Direct => super::usecase_storage_compat::WriteEncryption::multipart( managed_material.key_bytes, managed_material.base_nonce, part_id, diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index ef92c3abc..34a6cb235 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -48,21 +48,21 @@ use metrics::{counter, histogram}; use pin_project_lite::pin_project; use rustfs_object_capacity::capacity_manager::get_capacity_manager; // Performance metrics recording (with zero-copy-metrics integration) -use crate::app::usecase_storage_compat::ECStore; -use crate::app::usecase_storage_compat::object_api_utils::to_s3s_etag; -use crate::app::usecase_storage_compat::quota::checker::QuotaChecker; -use crate::app::usecase_storage_compat::storageclass; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::ECStore; +use super::usecase_storage_compat::object_api_utils::to_s3s_etag; +use super::usecase_storage_compat::quota::checker::QuotaChecker; +use super::usecase_storage_compat::storageclass; +use super::usecase_storage_compat::{ AppReplicationConfigExt as _, AppVersioningConfigExt as _, predict_lifecycle_expiration, validate_restore_request, }; -use crate::app::usecase_storage_compat::{DiskError, is_all_buckets_not_found}; -use crate::app::usecase_storage_compat::{DynReader, HashReader, WritePlan, wrap_reader}; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::{DiskError, is_all_buckets_not_found}; +use super::usecase_storage_compat::{DynReader, HashReader, WritePlan, wrap_reader}; +use super::usecase_storage_compat::{ Error as EcstoreError, StorageError, is_err_bucket_not_found, is_err_object_not_found, is_err_version_not_found, }; -use crate::app::usecase_storage_compat::{MIN_DISK_COMPRESSIBLE_SIZE, is_disk_compressible}; -use crate::app::usecase_storage_compat::{get_lock_acquire_timeout, is_valid_storage_class}; -use crate::app::usecase_storage_compat::{ +use super::usecase_storage_compat::{MIN_DISK_COMPRESSIBLE_SIZE, is_disk_compressible}; +use super::usecase_storage_compat::{get_lock_acquire_timeout, is_valid_storage_class}; +use super::usecase_storage_compat::{ lifecycle::{ bucket_lifecycle_audit::LcEventSrc, bucket_lifecycle_ops::{enqueue_transition_immediate, post_restore_opts}, @@ -279,12 +279,12 @@ async fn enqueue_transitioned_delete_cleanup( let _activity_guard = DeleteTailActivityGuard::new(DeleteTailStage::Cleanup); let je = if opts.delete_prefix { - crate::app::usecase_storage_compat::lifecycle::tier_sweeper::transitioned_force_delete_journal_entry( + super::usecase_storage_compat::lifecycle::tier_sweeper::transitioned_force_delete_journal_entry( &existing.transitioned_object, ) } else { let version_id = opts.version_id.as_ref().and_then(|v| Uuid::parse_str(v).ok()); - crate::app::usecase_storage_compat::lifecycle::tier_sweeper::transitioned_delete_journal_entry( + super::usecase_storage_compat::lifecycle::tier_sweeper::transitioned_delete_journal_entry( version_id, opts.versioned, opts.version_suspended, @@ -295,9 +295,9 @@ async fn enqueue_transitioned_delete_cleanup( return Ok(()); }; - crate::app::usecase_storage_compat::lifecycle::tier_delete_journal::persist_tier_delete_journal_entry(store, &je).await?; + super::usecase_storage_compat::lifecycle::tier_delete_journal::persist_tier_delete_journal_entry(store, &je).await?; - let mut expiry_state = crate::app::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::GLOBAL_ExpiryState + let mut expiry_state = super::usecase_storage_compat::lifecycle::bucket_lifecycle_ops::GLOBAL_ExpiryState .write() .await; if let Err(err) = expiry_state.enqueue_tier_journal_entry(&je).await { @@ -1603,7 +1603,7 @@ impl DefaultObjectUsecase { #[allow(clippy::too_many_arguments)] async fn prepare_get_object_read( req: &S3Request, - store: &crate::app::usecase_storage_compat::ECStore, + store: &super::usecase_storage_compat::ECStore, manager: &ConcurrencyManager, bucket: &str, key: &str, @@ -2197,7 +2197,7 @@ impl DefaultObjectUsecase { insert_str( &mut metadata, SUFFIX_COMPRESSION, - crate::app::usecase_storage_compat::compression_metadata_value(algorithm), + super::usecase_storage_compat::compression_metadata_value(algorithm), ); insert_str(&mut metadata, SUFFIX_ACTUAL_SIZE, size.to_string()); @@ -2212,7 +2212,7 @@ impl DefaultObjectUsecase { insert_str( &mut opts.user_defined, SUFFIX_COMPRESSION, - crate::app::usecase_storage_compat::compression_metadata_value(algorithm), + super::usecase_storage_compat::compression_metadata_value(algorithm), ); insert_str(&mut opts.user_defined, SUFFIX_ACTUAL_SIZE, size.to_string()); @@ -2404,7 +2404,7 @@ impl DefaultObjectUsecase { maybe_enqueue_transition_immediate(&obj_info, LcEventSrc::S3PutObject).await; // Fast in-memory update for immediate quota and admin usage consistency - crate::app::usecase_storage_compat::record_bucket_object_write_memory( + super::usecase_storage_compat::record_bucket_object_write_memory( &bucket, previous_current_size, obj_info.size.max(0) as u64, @@ -3274,7 +3274,7 @@ impl DefaultObjectUsecase { insert_str( &mut compress_metadata, SUFFIX_COMPRESSION, - crate::app::usecase_storage_compat::compression_metadata_value(CompressionAlgorithm::default()), + super::usecase_storage_compat::compression_metadata_value(CompressionAlgorithm::default()), ); insert_str(&mut compress_metadata, SUFFIX_ACTUAL_SIZE, actual_size.to_string()); } else { @@ -3367,7 +3367,7 @@ impl DefaultObjectUsecase { // Update quota tracking after successful copy if has_bucket_metadata { - crate::app::usecase_storage_compat::record_bucket_object_write_memory( + super::usecase_storage_compat::record_bucket_object_write_memory( &bucket, previous_current_size, oi.size.max(0) as u64, @@ -3649,7 +3649,7 @@ impl DefaultObjectUsecase { ); } let size = object_sizes[i].max(0) as u64; - crate::app::usecase_storage_compat::record_bucket_object_delete_memory( + super::usecase_storage_compat::record_bucket_object_delete_memory( &bucket, size, existing_object_infos[i].is_some() && object_to_delete[i].version_id.is_none(), @@ -3887,7 +3887,7 @@ impl DefaultObjectUsecase { } // Fast in-memory update for immediate quota and admin usage consistency - crate::app::usecase_storage_compat::record_bucket_object_delete_memory( + super::usecase_storage_compat::record_bucket_object_delete_memory( &bucket, obj_info.size.max(0) as u64, opts.version_id.is_none(), @@ -4864,7 +4864,7 @@ impl DefaultObjectUsecase { insert_str( &mut metadata, SUFFIX_COMPRESSION, - crate::app::usecase_storage_compat::compression_metadata_value(algorithm), + super::usecase_storage_compat::compression_metadata_value(algorithm), ); insert_str(&mut metadata, SUFFIX_ACTUAL_SIZE, size.to_string()); diff --git a/rustfs/src/storage/ecfs_test.rs b/rustfs/src/storage/ecfs_test.rs index e33d19d5c..fa81933b9 100644 --- a/rustfs/src/storage/ecfs_test.rs +++ b/rustfs/src/storage/ecfs_test.rs @@ -14,11 +14,11 @@ #[cfg(test)] mod tests { - use crate::config::WorkloadProfile; - use crate::server::cors; - use crate::storage::core_storage_compat::{ + use super::super::core_storage_compat::{ BucketMetadata, DEFAULT_READ_BUFFER_SIZE, get_global_bucket_metadata_sys, set_bucket_metadata, }; + use crate::config::WorkloadProfile; + use crate::server::cors; use crate::storage::ecfs::{FS, validate_object_lock_configuration_input}; use crate::storage::s3_api::common::{rustfs_initiator, rustfs_owner}; use crate::storage::{ @@ -941,8 +941,8 @@ mod tests { #[tokio::test] async fn test_validate_bucket_object_lock_enabled() { - use crate::storage::core_storage_compat::bucket_metadata_sys_initialized; - use crate::storage::core_storage_compat::set_bucket_metadata; + use super::super::core_storage_compat::bucket_metadata_sys_initialized; + use super::super::core_storage_compat::set_bucket_metadata; use s3s::dto::{ObjectLockConfiguration, ObjectLockEnabled}; use time::OffsetDateTime; @@ -1781,7 +1781,7 @@ mod tests { /// with a single-element vec value, matching the format expected by policy evaluation. #[test] fn test_object_tag_condition_key_format() { - use crate::storage::core_storage_compat::decode_tags_to_map; + use super::super::core_storage_compat::decode_tags_to_map; use std::collections::HashMap; let tags_str = "security=public&project=webapp&env=prod"; diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index aff9ad060..b118ab190 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -101,6 +101,7 @@ ALL_STORAGE_COMPAT_SELF_FACADE_PATH_HITS_FILE="${TMP_DIR}/all_storage_compat_sel RUSTFS_LOCAL_COMPAT_OWNER_SELF_PATH_HITS_FILE="${TMP_DIR}/rustfs_local_compat_owner_self_path_hits.txt" RUSTFS_ROOT_COMPAT_RELATIVE_CONSUMER_HITS_FILE="${TMP_DIR}/rustfs_root_compat_relative_consumer_hits.txt" RUSTFS_STORAGE_CORE_COMPAT_RELATIVE_CONSUMER_HITS_FILE="${TMP_DIR}/rustfs_storage_core_compat_relative_consumer_hits.txt" +RUSTFS_LOCAL_COMPAT_RELATIVE_CONSUMER_HITS_FILE="${TMP_DIR}/rustfs_local_compat_relative_consumer_hits.txt" SCANNER_BUCKET_STORAGE_COMPAT_MODULE_HITS_FILE="${TMP_DIR}/scanner_bucket_storage_compat_module_hits.txt" NOTIFY_STORAGE_COMPAT_MODULE_HITS_FILE="${TMP_DIR}/notify_storage_compat_module_hits.txt" OBS_STORAGE_COMPAT_PASSTHROUGH_HITS_FILE="${TMP_DIR}/obs_storage_compat_passthrough_hits.txt" @@ -1082,6 +1083,22 @@ if [[ -s "$RUSTFS_STORAGE_CORE_COMPAT_RELATIVE_CONSUMER_HITS_FILE" ]]; then report_failure "RustFS storage owner consumers must use relative core_storage_compat paths instead of crate-qualified storage owner paths: $(paste -sd '; ' "$RUSTFS_STORAGE_CORE_COMPAT_RELATIVE_CONSUMER_HITS_FILE")" fi +( + cd "$ROOT_DIR" + { + rg -n --with-filename 'crate::app::usecase_storage_compat' \ + rustfs/src/app/*.rs || true + rg -n --with-filename 'crate::admin::router_storage_compat' \ + rustfs/src/admin/router.rs || true + rg -n --with-filename 'crate::storage::core_storage_compat' \ + rustfs/src/storage/ecfs_test.rs || true + } +) >"$RUSTFS_LOCAL_COMPAT_RELATIVE_CONSUMER_HITS_FILE" + +if [[ -s "$RUSTFS_LOCAL_COMPAT_RELATIVE_CONSUMER_HITS_FILE" ]]; then + report_failure "RustFS local compatibility consumers must use relative owner paths instead of crate-qualified local compatibility paths: $(paste -sd '; ' "$RUSTFS_LOCAL_COMPAT_RELATIVE_CONSUMER_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'pub\(crate\)\s+use rustfs_ecstore::api::bucket::\{[^}]*\b(?:bucket_target_sys|lifecycle|metadata_sys|replication|versioning|versioning_sys)\b[^}]*\}\s*;' \