From 205f964dc5007b18f416a5bad792b4319de22d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Thu, 18 Jun 2026 22:50:02 +0800 Subject: [PATCH] refactor: tighten storage compat store_api aliases (#3582) * refactor: collapse storage compat store_api modules * chore: guard storage compat store_api aliases --- crates/heal/src/heal/storage_compat.rs | 11 +--- crates/iam/src/store/storage_compat.rs | 10 +-- crates/notify/src/storage_compat.rs | 6 +- crates/protocols/src/swift/storage_compat.rs | 16 ++--- crates/s3select-api/src/storage_compat.rs | 14 +--- crates/scanner/src/storage_compat.rs | 16 ++--- docs/architecture/migration-progress.md | 65 ++++++++++++++++++- rustfs/src/storage/mod.rs | 8 +-- rustfs/src/storage/storage_compat.rs | 7 +- scripts/check_architecture_migration_rules.sh | 32 +++++++++ 10 files changed, 119 insertions(+), 66 deletions(-) diff --git a/crates/heal/src/heal/storage_compat.rs b/crates/heal/src/heal/storage_compat.rs index aae50e94c..4c2e71d76 100644 --- a/crates/heal/src/heal/storage_compat.rs +++ b/crates/heal/src/heal/storage_compat.rs @@ -14,10 +14,6 @@ pub(crate) mod ecstore { pub(crate) use rustfs_ecstore::{data_usage, disk, error, global, store}; - - pub(crate) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{ObjectInfo, ObjectOptions, PutObjReader}; - } } pub(crate) use self::ecstore::{ data_usage::DATA_USAGE_CACHE_NAME, @@ -25,12 +21,11 @@ pub(crate) use self::ecstore::{ error::{Error as EcstoreError, StorageError}, global::GLOBAL_LOCAL_DISK_MAP, store::ECStore, - store_api::{ObjectInfo as EcstoreObjectInfo, ObjectOptions as EcstoreObjectOptions, PutObjReader as EcstorePutObjReader}, }; #[cfg(test)] pub(crate) use self::ecstore::disk::{DiskOption, new_disk}; -pub type HealObjectInfo = EcstoreObjectInfo; -pub type HealObjectOptions = EcstoreObjectOptions; -pub type HealPutObjReader = EcstorePutObjReader; +pub type HealObjectInfo = rustfs_ecstore::store_api::ObjectInfo; +pub type HealObjectOptions = rustfs_ecstore::store_api::ObjectOptions; +pub type HealPutObjReader = rustfs_ecstore::store_api::PutObjReader; diff --git a/crates/iam/src/store/storage_compat.rs b/crates/iam/src/store/storage_compat.rs index 38df459a6..c5f1eaca8 100644 --- a/crates/iam/src/store/storage_compat.rs +++ b/crates/iam/src/store/storage_compat.rs @@ -12,11 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod ecstore { - pub(super) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{ObjectInfo, ObjectOptions}; - } -} - -pub(super) type IamObjectInfo = ecstore::store_api::ObjectInfo; -pub(super) type IamObjectOptions = ecstore::store_api::ObjectOptions; +pub(super) type IamObjectInfo = rustfs_ecstore::store_api::ObjectInfo; +pub(super) type IamObjectOptions = rustfs_ecstore::store_api::ObjectOptions; diff --git a/crates/notify/src/storage_compat.rs b/crates/notify/src/storage_compat.rs index d3147bafa..be6b0f4e2 100644 --- a/crates/notify/src/storage_compat.rs +++ b/crates/notify/src/storage_compat.rs @@ -14,10 +14,6 @@ pub(crate) mod ecstore { pub(crate) use rustfs_ecstore::{config, global}; - - pub(crate) mod store_api { - pub(crate) use rustfs_ecstore::store_api::ObjectInfo; - } } -pub type NotifyObjectInfo = ecstore::store_api::ObjectInfo; +pub type NotifyObjectInfo = rustfs_ecstore::store_api::ObjectInfo; diff --git a/crates/protocols/src/swift/storage_compat.rs b/crates/protocols/src/swift/storage_compat.rs index 34f5c7555..11be03dc1 100644 --- a/crates/protocols/src/swift/storage_compat.rs +++ b/crates/protocols/src/swift/storage_compat.rs @@ -14,26 +14,18 @@ mod ecstore { pub(super) use rustfs_ecstore::{bucket, error, resolve_object_store_handle, store}; - - pub(super) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{GetObjectReader, ObjectInfo, ObjectOptions, PutObjReader}; - } } use self::ecstore::{ bucket::{metadata::BucketMetadata, metadata_sys}, error::Result as EcstoreResult, store::ECStore, - store_api::{ - GetObjectReader as EcstoreGetObjectReader, ObjectInfo as EcstoreObjectInfo, ObjectOptions as EcstoreObjectOptions, - PutObjReader as EcstorePutObjReader, - }, }; use std::sync::Arc; -pub type SwiftGetObjectReader = EcstoreGetObjectReader; -pub type SwiftObjectInfo = EcstoreObjectInfo; -pub type SwiftObjectOptions = EcstoreObjectOptions; -pub type SwiftPutObjReader = EcstorePutObjReader; +pub type SwiftGetObjectReader = rustfs_ecstore::store_api::GetObjectReader; +pub type SwiftObjectInfo = rustfs_ecstore::store_api::ObjectInfo; +pub type SwiftObjectOptions = rustfs_ecstore::store_api::ObjectOptions; +pub type SwiftPutObjReader = rustfs_ecstore::store_api::PutObjReader; pub fn resolve_swift_object_store_handle() -> Option> { ecstore::resolve_object_store_handle() diff --git a/crates/s3select-api/src/storage_compat.rs b/crates/s3select-api/src/storage_compat.rs index 009e0fe41..b86ed950d 100644 --- a/crates/s3select-api/src/storage_compat.rs +++ b/crates/s3select-api/src/storage_compat.rs @@ -14,16 +14,8 @@ pub(crate) mod ecstore { pub(crate) use rustfs_ecstore::{error, resolve_object_store_handle, set_disk, store}; - - pub(crate) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{GetObjectReader, ObjectInfo, ObjectOptions}; - } } -use ecstore::store_api::{ - GetObjectReader as EcstoreGetObjectReader, ObjectInfo as EcstoreObjectInfo, ObjectOptions as EcstoreObjectOptions, -}; - -pub(crate) type SelectGetObjectReader = EcstoreGetObjectReader; -pub(crate) type SelectObjectInfo = EcstoreObjectInfo; -pub(crate) type SelectObjectOptions = EcstoreObjectOptions; +pub(crate) type SelectGetObjectReader = rustfs_ecstore::store_api::GetObjectReader; +pub(crate) type SelectObjectInfo = rustfs_ecstore::store_api::ObjectInfo; +pub(crate) type SelectObjectOptions = rustfs_ecstore::store_api::ObjectOptions; diff --git a/crates/scanner/src/storage_compat.rs b/crates/scanner/src/storage_compat.rs index 709e45ba2..ec09924a7 100644 --- a/crates/scanner/src/storage_compat.rs +++ b/crates/scanner/src/storage_compat.rs @@ -18,10 +18,6 @@ pub(crate) mod ecstore { bucket, cache_value, config, data_usage, disk, error, global, pools, resolve_object_store_handle, set_disk, store, store_utils, }; - - pub(crate) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{GetObjectReader, ObjectInfo, ObjectOptions, PutObjReader}; - } } pub(crate) use self::ecstore::{ bucket::{ @@ -51,10 +47,6 @@ pub(crate) use self::ecstore::{ pools::{path2_bucket_object, path2_bucket_object_with_base_path}, set_disk::SetDisks, store::ECStore, - store_api::{ - GetObjectReader as EcstoreGetObjectReader, ObjectInfo as EcstoreObjectInfo, ObjectOptions as EcstoreObjectOptions, - PutObjReader as EcstorePutObjReader, - }, store_utils::is_reserved_or_invalid_bucket, }; use rustfs_storage_api::{HTTPRangeSpec, ObjectIO, ObjectToDelete}; @@ -66,11 +58,11 @@ pub(crate) use self::ecstore::{ disk::{DiskOption, endpoint::Endpoint, new_disk}, }; -pub type ScannerGetObjectReader = EcstoreGetObjectReader; -pub type ScannerObjectInfo = EcstoreObjectInfo; -pub type ScannerObjectOptions = EcstoreObjectOptions; +pub type ScannerGetObjectReader = rustfs_ecstore::store_api::GetObjectReader; +pub type ScannerObjectInfo = rustfs_ecstore::store_api::ObjectInfo; +pub type ScannerObjectOptions = rustfs_ecstore::store_api::ObjectOptions; pub type ScannerObjectToDelete = ObjectToDelete; -pub type ScannerPutObjReader = EcstorePutObjReader; +pub type ScannerPutObjReader = rustfs_ecstore::store_api::PutObjReader; pub(crate) fn resolve_scanner_object_store_handle() -> Option> { ecstore::resolve_object_store_handle() diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index cf12266a5..ab1ff1547 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -1049,6 +1049,43 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block check, diff hygiene, risk scan, full pre-commit, and required three-expert review passed. +- [x] `API-039` Collapse nested `store_api` compatibility modules. + - Current branch: `overtrue/arch-compat-boundary-prune`. + - Current slice: replace nested `store_api` compatibility modules in RustFS + storage, scanner, heal, Swift, S3 Select, IAM, and notify boundaries with + direct local type aliases, and add a migration rule rejecting nested + `store_api` modules in storage compatibility files. + - Acceptance: storage compatibility boundaries no longer recreate + `store_api` module shapes; downstream aliases keep the same concrete + contract types; migration rules reject restoring nested `store_api` + compatibility modules outside ECStore and test-only boundaries. + - Must preserve: object info/options reader aliases, scanner/heal/Swift/S3 + Select/IAM/notify compile-time contracts, storage API compatibility names, + and ECStore-owned concrete type ownership. + - Risk defense: this is a local alias-shape cleanup only; it does not move + definitions, alter storage/runtime control flow, change object metadata + conversion, or mutate reader behavior. + - Verification: focused multi-crate compile, migration and layer guards, + formatting check, diff hygiene, risk scan, full pre-commit, and required + three-expert review passed. + +- [x] `API-040` Lock remaining `store_api` compatibility aliases. + - Current branch: `overtrue/arch-compat-boundary-prune`. + - Current slice: add a migration rule that allows the remaining + `rustfs_ecstore::store_api::*` references in production storage + compatibility files only when they are explicit local type aliases to the + four ECStore-owned contracts still intentionally kept in ECStore. + - Acceptance: production compatibility boundaries can keep only explicit + aliases to `GetObjectReader`, `ObjectInfo`, `ObjectOptions`, and + `PutObjReader`; any broader import, module recreation, or new raw + `store_api` compatibility dependency fails the architecture guard. + - Must preserve: existing local alias names and concrete ECStore-owned reader, + object info, and object option contract ownership. + - Risk defense: this is a guardrail-only slice; it does not change runtime + code, storage behavior, object metadata shape, or reader behavior. + - Verification: migration and layer guards, formatting check, diff hygiene, + risk scan, full pre-commit, and required three-expert review passed. + ## Phase 8 Background Controller Tasks - [x] `BGC-001` Inventory background services. @@ -1319,20 +1356,42 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block 1. `pure-move`/`consumer-migration`: continue larger cleanup slices with the loss-prevention guards active for remaining ECStore compatibility contracts - outside the source/test compatibility boundaries already cleaned. + outside the production compatibility boundaries already cleaned. ## Pre-Push Review Log | Expert | Status | Notes | |---|---|---| -| Quality/architecture | passed | Delete-object DTO ownership lives in storage-api; ECStore internal consumers use storage-api directly while public aliases remain, and store_api compatibility boundaries now expose explicit contract types only. | -| Migration preservation | passed | Field shape, helper semantics, delete behavior, replication scheduling, MRF delete replay, object info/options aliases, reader aliases, and old ECStore public import compatibility are preserved. | +| Quality/architecture | passed | Delete-object DTO ownership lives in storage-api; ECStore internal consumers use storage-api directly while public aliases remain, and store_api compatibility boundaries now expose only direct explicit contract aliases guarded by a whitelist. | +| Migration preservation | passed | Field shape, helper semantics, delete behavior, replication scheduling, MRF delete replay, object info/options aliases, reader aliases, and old ECStore concrete type compatibility are preserved. | | Testing/verification | passed | Multi-crate compile, guards, formatting, diff hygiene, risk scan, and full `make pre-commit` passed. | ## Verification Notes Passed before push: +- API-040 current slice: + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - Rust risk scan: passed; no new unwrap/expect, numeric casts, string error + public APIs, boxed public errors, production println/eprintln, or relaxed + ordering introduced in changed Rust files. + - `make pre-commit`: passed. + +- API-039 current slice: + - `cargo check --tests -p rustfs -p rustfs-scanner -p rustfs-heal -p rustfs-protocols -p rustfs-s3select-api -p rustfs-iam -p rustfs-notify`: + passed. + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - Rust risk scan: passed; no new unwrap/expect, numeric casts, string error + public APIs, boxed public errors, production println/eprintln, or relaxed + ordering introduced in changed Rust files. + - `make pre-commit`: passed. + - API-038 current slice: - `cargo check --tests -p rustfs -p rustfs-scanner -p rustfs-heal -p rustfs-protocols -p rustfs-s3select-api -p rustfs-iam -p rustfs-notify`: passed. diff --git a/rustfs/src/storage/mod.rs b/rustfs/src/storage/mod.rs index 81ce690e3..ad61ad0f9 100644 --- a/rustfs/src/storage/mod.rs +++ b/rustfs/src/storage/mod.rs @@ -29,11 +29,11 @@ pub mod timeout_wrapper; pub mod tonic_service; pub(crate) type StorageDeletedObject = rustfs_storage_api::DeletedObject; -pub(crate) type StorageGetObjectReader = crate::storage::storage_compat::ecstore::store_api::GetObjectReader; -pub(crate) type StorageObjectInfo = crate::storage::storage_compat::ecstore::store_api::ObjectInfo; -pub(crate) type StorageObjectOptions = crate::storage::storage_compat::ecstore::store_api::ObjectOptions; +pub(crate) type StorageGetObjectReader = crate::storage::storage_compat::ecstore::GetObjectReader; +pub(crate) type StorageObjectInfo = crate::storage::storage_compat::ecstore::ObjectInfo; +pub(crate) type StorageObjectOptions = crate::storage::storage_compat::ecstore::ObjectOptions; pub(crate) type StorageObjectToDelete = rustfs_storage_api::ObjectToDelete; -pub(crate) type StoragePutObjReader = crate::storage::storage_compat::ecstore::store_api::PutObjReader; +pub(crate) type StoragePutObjReader = crate::storage::storage_compat::ecstore::PutObjReader; #[cfg(test)] mod concurrent_fix_test; diff --git a/rustfs/src/storage/storage_compat.rs b/rustfs/src/storage/storage_compat.rs index 01cdec5a1..b91cbb37e 100644 --- a/rustfs/src/storage/storage_compat.rs +++ b/rustfs/src/storage/storage_compat.rs @@ -18,9 +18,10 @@ pub(crate) mod ecstore { resolve_object_store_handle, rio, rpc, set_disk, store, }; - pub(crate) mod store_api { - pub(crate) use rustfs_ecstore::store_api::{GetObjectReader, ObjectInfo, ObjectOptions, PutObjReader}; - } + pub(crate) type GetObjectReader = rustfs_ecstore::store_api::GetObjectReader; + pub(crate) type ObjectInfo = rustfs_ecstore::store_api::ObjectInfo; + pub(crate) type ObjectOptions = rustfs_ecstore::store_api::ObjectOptions; + pub(crate) type PutObjReader = rustfs_ecstore::store_api::PutObjReader; #[cfg(test)] pub(crate) use rustfs_ecstore::config; diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index e756de883..67e2859db 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -65,6 +65,8 @@ STORE_API_OBJECT_OPERATION_LOCAL_METHOD_HITS_FILE="${TMP_DIR}/store_api_object_o DIRECT_ECSTORE_IMPORT_HITS_FILE="${TMP_DIR}/direct_ecstore_import_hits.txt" PRODUCTION_UNUSED_COMPAT_ALLOW_HITS_FILE="${TMP_DIR}/production_unused_compat_allow_hits.txt" BROAD_STORE_API_COMPAT_REEXPORT_HITS_FILE="${TMP_DIR}/broad_store_api_compat_reexport_hits.txt" +NESTED_STORE_API_COMPAT_MODULE_HITS_FILE="${TMP_DIR}/nested_store_api_compat_module_hits.txt" +UNAPPROVED_STORE_API_COMPAT_ALIAS_HITS_FILE="${TMP_DIR}/unapproved_store_api_compat_alias_hits.txt" awk ' /^## PR Types$/ { @@ -388,6 +390,36 @@ if [[ -s "$BROAD_STORE_API_COMPAT_REEXPORT_HITS_FILE" ]]; then report_failure "storage compatibility boundaries must expose explicit store_api contracts only: $(paste -sd '; ' "$BROAD_STORE_API_COMPAT_REEXPORT_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --no-heading '\b(?:pub(?:\([^)]*\))?\s+)?mod\s+store_api\b' \ + rustfs/src crates/*/src fuzz/fuzz_targets \ + --glob '*storage_compat.rs' \ + --glob '!crates/ecstore/**' \ + --glob '!crates/e2e_test/**' || true +) >"$NESTED_STORE_API_COMPAT_MODULE_HITS_FILE" + +if [[ -s "$NESTED_STORE_API_COMPAT_MODULE_HITS_FILE" ]]; then + report_failure "storage compatibility boundaries must use direct type aliases instead of nested store_api modules: $(paste -sd '; ' "$NESTED_STORE_API_COMPAT_MODULE_HITS_FILE")" +fi + +( + cd "$ROOT_DIR" + rg -n --no-heading 'rustfs_ecstore::store_api::' \ + rustfs/src crates/*/src fuzz/fuzz_targets \ + --glob '*storage_compat.rs' \ + --glob '!crates/ecstore/**' \ + --glob '!crates/e2e_test/**' || true +) | awk ' + $0 !~ /^[^:]+:[0-9]+:[[:space:]]*(pub(\([^)]*\))?[[:space:]]+)?type[[:space:]]+[A-Za-z0-9_]+[[:space:]]*=[[:space:]]*rustfs_ecstore::store_api::(GetObjectReader|ObjectInfo|ObjectOptions|PutObjReader);$/ { + print + } +' >"$UNAPPROVED_STORE_API_COMPAT_ALIAS_HITS_FILE" + +if [[ -s "$UNAPPROVED_STORE_API_COMPAT_ALIAS_HITS_FILE" ]]; then + report_failure "storage compatibility boundaries may only keep explicit ECStore-owned store_api type aliases: $(paste -sd '; ' "$UNAPPROVED_STORE_API_COMPAT_ALIAS_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'async fn (get_object_reader|put_object|get_object_info|verify_object_integrity|copy_object|delete_object_version|delete_object|delete_objects|put_object_metadata|get_object_tags|put_object_tags|delete_object_tags|add_partial|transition_object|restore_transitioned_object|list_multipart_uploads|new_multipart_upload|copy_object_part|put_object_part|get_multipart_info|list_object_parts|abort_multipart_upload|complete_multipart_upload|heal_format|heal_bucket|heal_object|get_pool_and_set|check_abandoned_parts|new_ns_lock)\b' \