refactor(replication): isolate storage api contracts (#4244)

This commit is contained in:
Zhengchao An
2026-07-03 22:48:21 +08:00
committed by GitHub
parent 24e88a2cf4
commit d19ee6c51c
8 changed files with 44 additions and 8 deletions
@@ -39,6 +39,7 @@ paths.
| `ReplicationConfigStore` | Replication config persistence and config-derived labels used by target options. | Config read/save helpers and storage class labels are exposed through the contract type in `replication_config_store.rs`. |
| `ReplicationFileMeta` | Replication status, decisions, MRF entries, resync decisions, and target reset helpers. | `rustfs_filemeta` replication contracts are concentrated in `replication_filemeta_boundary.rs`; `FileInfo` remains in the storage boundary for storage trait bindings and walk options. |
| `StorageApiReplicationContracts` | Storage-api delete DTO replication state/status helpers. | The temporary `rustfs-filemeta` dependency is isolated in `crates/storage-api/src/replication.rs` until the wire contracts can move without creating a `rustfs-replication` / `rustfs-storage-api` cycle. |
| `ReplicationCrateStorageApiBoundary` | Storage API delete DTOs consumed by `rustfs-replication`. | `crates/replication/src/storage_api.rs` is the only direct `rustfs-storage-api` import boundary inside `rustfs-replication`. |
| `ReplicationObjectDecisionContracts` | Object replication options, delete replication decisions, resync target projection, multipart planning, and delete-marker retry classifiers. | Owned by `crates/replication`; ECStore imports them through `replication_object_decision_boundary.rs`. |
| `ReplicationQueueContracts` | Queue admission, heal queue results/actions, worker operations, worker sizing, and backpressure decisions. | Owned by `crates/replication`; ECStore imports them through `replication_queue_boundary.rs`. |
| `ReplicationStatsContracts` | Bucket stats, replication target stats, queue/proxy metrics, and worker metric snapshots. | Owned by `crates/replication`; ECStore imports them through `replication_stats_boundary.rs`. |
@@ -90,6 +91,8 @@ paths.
cycle.
12. Keep direct `rustfs-filemeta` imports inside `rustfs-replication`
concentrated in `crates/replication/src/filemeta.rs`.
13. Keep direct `rustfs-storage-api` imports inside `rustfs-replication`
concentrated in `crates/replication/src/storage_api.rs`.
## First Code-Bearing Step
+2 -3
View File
@@ -14,8 +14,7 @@
use std::any::Any;
use rustfs_storage_api::DeletedObject;
use crate::storage_api::DeletedObject;
use crate::{MrfOpKind, MrfReplicateEntry, ReplicationType, ReplicationWorkerOperation};
#[derive(Debug, Clone, Default)]
@@ -85,8 +84,8 @@ mod tests {
DeletedObjectReplicationInfo, is_retryable_delete_replication_head_error, is_version_delete_replication,
should_retry_delete_marker_purge,
};
use crate::storage_api::DeletedObject;
use crate::{MrfOpKind, ReplicationType, ReplicationWorkerOperation};
use rustfs_storage_api::DeletedObject;
use uuid::Uuid;
#[test]
+1
View File
@@ -24,6 +24,7 @@ pub mod resync;
pub mod rule;
pub mod runtime;
pub mod stats;
mod storage_api;
pub mod tagging;
pub use config::{
+2 -2
View File
@@ -14,7 +14,6 @@
use std::collections::HashMap;
use rustfs_storage_api::ObjectToDelete;
use rustfs_utils::http::{
AMZ_BUCKET_REPLICATION_STATUS, AMZ_OBJECT_TAGGING, SSEC_ALGORITHM_HEADER, SSEC_KEY_HEADER, SSEC_KEY_MD5_HEADER,
SUFFIX_REPLICATION_RESET_STATUS, get_header_map,
@@ -23,6 +22,7 @@ use s3s::dto::ReplicationConfiguration;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::storage_api::ObjectToDelete;
use crate::{
ObjectOpts, ReplicateDecision, ReplicateTargetDecision, ReplicationConfigurationExt as _, ReplicationState,
ReplicationStatusType, ReplicationType, ResyncTargetDecision, VersionPurgeStatusType, replication_statuses_map,
@@ -318,8 +318,8 @@ mod tests {
is_ssec_encrypted, resync_target_for_object, should_schedule_delete_replication,
should_use_existing_delete_replication_info, should_use_existing_delete_replication_source,
};
use crate::storage_api::ObjectToDelete;
use crate::{ReplicationStatusType, ReplicationType, VersionPurgeStatusType, target_reset_header};
use rustfs_storage_api::ObjectToDelete;
use rustfs_utils::http::{AMZ_BUCKET_REPLICATION_STATUS, SSEC_ALGORITHM_HEADER};
use s3s::dto::{
DeleteMarkerReplication, DeleteMarkerReplicationStatus, Destination, ExistingObjectReplication,
+2 -3
View File
@@ -14,8 +14,7 @@
use std::any::Any;
use rustfs_storage_api::DeletedObject;
use crate::storage_api::DeletedObject;
use crate::{
DeletedObjectReplicationInfo, MrfReplicateEntry, REPLICATE_EXISTING, REPLICATE_HEAL, REPLICATE_HEAL_DELETE,
ReplicateObjectInfo, ReplicationStatusType, ReplicationType, ReplicationWorkerOperation, ResyncDecision,
@@ -265,12 +264,12 @@ impl ReplicationWorkerOperation for ReplicationOperation {
mod tests {
use std::str::FromStr;
use rustfs_storage_api::DeletedObject;
use uuid::Uuid;
use super::{
ReplicationHealQueueAction, ReplicationOperation, ReplicationPriority, ReplicationQueueAdmission, ReplicationWorkerQueue,
};
use crate::storage_api::DeletedObject;
use crate::{
DeletedObjectReplicationInfo, REPLICATE_EXISTING, REPLICATE_HEAL, REPLICATE_HEAL_DELETE, ReplicateDecision,
ReplicateObjectInfo, ReplicateTargetDecision, ReplicationStatusType, ReplicationType, ReplicationWorkerOperation,
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub(crate) use rustfs_storage_api::{DeletedObject, ObjectToDelete};
@@ -127,6 +127,8 @@ Current coupling:
ECStore retaining only error mapping and MRF persistence locally;
- `crates/replication/src/filemeta.rs` is the only direct filemeta wire-contract
import boundary inside `rustfs-replication`;
- `crates/replication/src/storage_api.rs` is the only direct storage-api delete
DTO import boundary inside `rustfs-replication`;
- storage-api delete replication status/state helpers use the local
`crates/storage-api/src/replication.rs` contract boundary while the
underlying wire types remain in `rustfs-filemeta`;
@@ -176,6 +178,9 @@ Required contracts before crate movement:
- `ReplicationCrateFileMetaFacade`: replication facade compatibility symbols
that still originate in filemeta wire contracts are concentrated in
`crates/replication/src/filemeta.rs` inside `rustfs-replication`.
- `ReplicationCrateStorageApiBoundary`: storage API delete DTOs consumed by
replication delete/queue/operation helpers are concentrated in
`crates/replication/src/storage_api.rs` inside `rustfs-replication`.
- `StorageApiReplicationContracts`: storage-api delete DTO replication
state/status helpers are concentrated in `crates/storage-api/src/replication.rs`
until the underlying wire contracts can move without a
@@ -85,6 +85,7 @@ require_source_contains "docs/architecture/obs-ecstore-dependency-inventory.md"
require_source_contains "docs/architecture/overview.md" "ecstore-api-facade-inventory.md" "architecture overview ECStore facade inventory link"
require_source_contains "docs/architecture/ecstore-module-split-plan.md" "ecstore-api-facade-inventory.md" "ECStore split plan facade inventory link"
require_source_contains "docs/architecture/ecstore-module-split-plan.md" "ReplicationCrateFileMetaFacade" "ECStore split plan replication crate filemeta facade section"
require_source_contains "docs/architecture/ecstore-module-split-plan.md" "ReplicationCrateStorageApiBoundary" "ECStore split plan replication crate storage-api boundary section"
require_source_contains "docs/architecture/ecstore-module-split-plan.md" "StorageApiReplicationContracts" "ECStore split plan storage-api replication contract section"
require_source_contains "docs/architecture/ecstore-api-facade-inventory.md" "## Facade Group Inventory" "ECStore facade inventory group section"
require_source_contains "docs/architecture/ecstore-api-facade-inventory.md" "## External Consumer Boundaries" "ECStore facade inventory consumer boundary section"
@@ -205,6 +206,7 @@ EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE="${TMP_DIR}/external_ecstore_api_boundar
REPLICATION_FACADE_BYPASS_HITS_FILE="${TMP_DIR}/replication_facade_bypass_hits.txt"
REPLICATION_FACADE_WILDCARD_EXPORT_HITS_FILE="${TMP_DIR}/replication_facade_wildcard_export_hits.txt"
REPLICATION_CRATE_FILEMETA_BYPASS_HITS_FILE="${TMP_DIR}/replication_crate_filemeta_bypass_hits.txt"
REPLICATION_CRATE_STORAGE_API_BYPASS_HITS_FILE="${TMP_DIR}/replication_crate_storage_api_bypass_hits.txt"
REPLICATION_CONFIG_RULE_CONTRACT_BACKSLIDE_HITS_FILE="${TMP_DIR}/replication_config_rule_contract_backslide_hits.txt"
REPLICATION_DELETE_WORKER_CONTRACT_BACKSLIDE_HITS_FILE="${TMP_DIR}/replication_delete_worker_contract_backslide_hits.txt"
REPLICATION_OPERATION_CONTRACT_BACKSLIDE_HITS_FILE="${TMP_DIR}/replication_operation_contract_backslide_hits.txt"
@@ -2621,6 +2623,18 @@ if [[ -s "$REPLICATION_CRATE_FILEMETA_BYPASS_HITS_FILE" ]]; then
report_failure "replication crate filemeta contracts must stay behind crates/replication/src/filemeta.rs: $(paste -sd '; ' "$REPLICATION_CRATE_FILEMETA_BYPASS_HITS_FILE")"
fi
(
cd "$ROOT_DIR"
rg -n --with-filename 'rustfs_storage_api::|use\s+rustfs_storage_api\b' \
crates/replication/src \
--glob '*.rs' |
rg -v '^crates/replication/src/storage_api\.rs:' || true
) >"$REPLICATION_CRATE_STORAGE_API_BYPASS_HITS_FILE"
if [[ -s "$REPLICATION_CRATE_STORAGE_API_BYPASS_HITS_FILE" ]]; then
report_failure "replication crate storage-api contracts must stay behind crates/replication/src/storage_api.rs: $(paste -sd '; ' "$REPLICATION_CRATE_STORAGE_API_BYPASS_HITS_FILE")"
fi
(
cd "$ROOT_DIR"
replication_config_rule_status=0