refactor(replication): route runtime facades through ecstore (#4248)

This commit is contained in:
Zhengchao An
2026-07-03 23:49:24 +08:00
committed by GitHub
parent 7cc470cb08
commit 4883d3eb50
8 changed files with 49 additions and 11 deletions
@@ -35,6 +35,7 @@ paths.
| `ReplicationStorage` | Object read/write/delete, object walk, metadata update, and target object IO. | ECStore object API, storage-api contracts, and read option types are concentrated in `replication_storage_boundary.rs`. |
| `ReplicationMetadataStore` | Replication config, MRF/resync state, target reset headers, and status persistence. | Metadata sys access and replication metadata path constants are exposed through the contract type in `replication_metadata_boundary.rs`; versioning sys and config storage imports remain separate contracts. |
| `EcstoreReplicationBoundaryImports` | ECStore-side imports from `rustfs-replication`. | Direct `rustfs-replication` imports under `crates/ecstore/src/bucket/replication` stay in `*_boundary.rs` modules, including config and resync facade re-exports. |
| `RuntimeReplicationFacadeConsumers` | Runtime owner consumers of replication DTOs and status types. | Scanner, admin, and storage owner facades import replication DTOs/status types through `rustfs-ecstore`; app storage keeps the remaining direct object/delete helper calls behind its local storage API boundary. |
| `ReplicationResyncContracts` | Resync options, target status, bucket status, status classifiers, and persisted resync/MRF status wire format. | Owned by `crates/replication`; ECStore imports them through `replication_resync_boundary.rs`, which maps crate errors to ECStore errors. |
| `ReplicationCrateFileMetaFacade` | Replication facade compatibility symbols that still originate in filemeta wire contracts. | `crates/replication/src/filemeta.rs` is the only direct `rustfs-filemeta` import boundary inside `rustfs-replication`. |
| `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`. |
@@ -96,6 +97,9 @@ paths.
concentrated in `crates/replication/src/storage_api.rs`.
14. Keep direct `rustfs-replication` imports inside ECStore replication
concentrated in `*_boundary.rs` modules.
15. Keep scanner, admin, and storage-owner replication status/DTO consumers
behind the ECStore replication facade; only `rustfs/src/app/storage_api.rs`
may retain direct object/delete replication helper calls.
## First Code-Bearing Step
+2 -2
View File
@@ -47,9 +47,9 @@ pub use replication_config_boundary::{ObjectOpts, ReplicationConfigurationExt};
#[cfg(test)]
pub(crate) use replication_filemeta_boundary::ReplicateTargetDecision;
pub(crate) use replication_filemeta_boundary::{
ReplicateDecision, ReplicationState, ReplicationStatusType, VersionPurgeStatusType, replication_statuses_map,
version_purge_statuses_map,
ReplicateDecision, ReplicationState, replication_statuses_map, version_purge_statuses_map,
};
pub use replication_filemeta_boundary::{ReplicateObjectInfo, ReplicationStatusType, ReplicationType, VersionPurgeStatusType};
pub(crate) use replication_lifecycle_bridge::{ReplicationLifecycleBridge, ReplicationLifecycleConfig};
pub(crate) use replication_migration_bridge::ReplicationMigrationBridge;
pub use replication_object_bridge::ReplicationObjectBridge;
@@ -15,7 +15,8 @@
pub(crate) use rustfs_replication::{MrfOpKind, MrfReplicateEntry};
pub(crate) use rustfs_replication::{
REPLICATE_EXISTING, REPLICATE_EXISTING_DELETE, REPLICATE_HEAL_DELETE, REPLICATE_INCOMING_DELETE, ReplicateDecision,
ReplicateObjectInfo, ReplicateTargetDecision, ReplicatedInfos, ReplicatedTargetInfo, ReplicationAction, ReplicationState,
ReplicationStatusType, ReplicationType, ReplicationWorkerOperation, ResyncDecision, VersionPurgeStatusType,
get_replication_state, parse_replicate_decision, replication_statuses_map, target_reset_header, version_purge_statuses_map,
ReplicateTargetDecision, ReplicatedInfos, ReplicatedTargetInfo, ReplicationAction, ReplicationState,
ReplicationWorkerOperation, ResyncDecision, get_replication_state, parse_replicate_decision, replication_statuses_map,
target_reset_header, version_purge_statuses_map,
};
pub use rustfs_replication::{ReplicateObjectInfo, ReplicationStatusType, ReplicationType, VersionPurgeStatusType};
+4 -3
View File
@@ -15,8 +15,6 @@
use std::collections::HashMap;
use std::sync::Arc;
use rustfs_replication::{ReplicateObjectInfo, ReplicationType};
pub(crate) use rustfs_replication::{ReplicationStatusType, VersionPurgeStatusType};
use serde::{Deserialize, Serialize};
pub(crate) use rustfs_ecstore::api::bucket::bucket_target_sys::BucketTargetSys as EcstoreBucketTargetSys;
@@ -34,10 +32,13 @@ pub(crate) use rustfs_ecstore::api::bucket::metadata_sys::{
get_replication_config as ecstore_get_replication_config,
};
pub(crate) use rustfs_ecstore::api::bucket::replication::{
ReplicationConfig as EcstoreReplicationConfig, ReplicationConfigurationExt as EcstoreReplicationConfigurationExt,
ReplicateObjectInfo, ReplicationConfig as EcstoreReplicationConfig,
ReplicationConfigurationExt as EcstoreReplicationConfigurationExt,
ReplicationHealQueueResult as EcstoreReplicationHealQueueResult,
ReplicationQueueAdmission as EcstoreReplicationQueueAdmission, ReplicationScannerBridge as EcstoreReplicationScannerBridge,
ReplicationType,
};
pub(crate) use rustfs_ecstore::api::bucket::replication::{ReplicationStatusType, VersionPurgeStatusType};
pub(crate) use rustfs_ecstore::api::bucket::target::BucketTargets as EcstoreBucketTargets;
pub(crate) use rustfs_ecstore::api::bucket::versioning::VersioningApi as EcstoreVersioningApi;
pub(crate) use rustfs_ecstore::api::bucket::versioning_sys::BucketVersioningSys as EcstoreBucketVersioningSys;
@@ -137,6 +137,8 @@ Current coupling:
- admin replication extension target filtering and resync request construction
stay behind the admin storage boundary instead of exposing replication work
DTO construction to handlers;
- scanner, admin, and storage-owner replication status/DTO consumers import
those contracts through the ECStore replication facade;
- app object and multipart writes call object-replication boundary helpers
instead of constructing replication work DTOs or choosing object replication
operation types at the use-case layer;
@@ -185,6 +187,10 @@ Required contracts before crate movement:
`crates/replication/src/storage_api.rs` inside `rustfs-replication`.
- `EcstoreReplicationBoundaryImports`: ECStore-side imports from
`rustfs-replication` are concentrated in replication `*_boundary.rs` modules.
- `RuntimeReplicationFacadeConsumers`: scanner, admin, and storage-owner
replication status/DTO consumers import through `rustfs-ecstore`, while app
storage keeps direct object/delete helper calls inside its storage API
boundary.
- `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
+2 -2
View File
@@ -150,7 +150,7 @@ pub(crate) trait AdminReplicationConfigExt {
impl AdminReplicationConfigExt for s3s::dto::ReplicationConfiguration {
fn filter_all_replication_target_arns(&self) -> Vec<String> {
let obj = ecstore_bucket::replication::ObjectOpts {
op_type: rustfs_replication::ReplicationType::All,
op_type: ecstore_bucket::replication::ReplicationType::All,
..Default::default()
};
<s3s::dto::ReplicationConfiguration as ecstore_bucket::replication::ReplicationConfigurationExt>::filter_target_arns(
@@ -309,7 +309,7 @@ pub(crate) mod quota {
pub(crate) mod replication {
pub(crate) type BucketReplicationResyncStatus = super::ecstore_bucket::replication::BucketReplicationResyncStatus;
pub(crate) type BucketStats = super::ecstore_bucket::replication::BucketStats;
pub(crate) type ReplicationStatusType = rustfs_replication::ReplicationStatusType;
pub(crate) type ReplicationStatusType = super::ecstore_bucket::replication::ReplicationStatusType;
pub(crate) type ResyncOpts = super::ecstore_bucket::replication::ResyncOpts;
#[cfg(test)]
pub(crate) type ResyncStatusType = super::ecstore_bucket::replication::ResyncStatusType;
+1 -1
View File
@@ -522,7 +522,7 @@ pub(crate) type ReadMultipleReq = ecstore_disk::ReadMultipleReq;
pub(crate) type ReadMultipleResp = ecstore_disk::ReadMultipleResp;
pub(crate) type ReadOptions = ecstore_disk::ReadOptions;
pub(crate) type RenameDataResp = ecstore_disk::RenameDataResp;
pub(crate) type ReplicationStatusType = rustfs_replication::ReplicationStatusType;
pub(crate) type ReplicationStatusType = ecstore_bucket::replication::ReplicationStatusType;
pub(crate) type ReplicationStats = StorageReplicationStatsHandle;
pub(crate) type SetupType = ecstore_layout::SetupType;
pub(crate) type StorageError = ecstore_error::StorageError;
@@ -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" "EcstoreReplicationBoundaryImports" "ECStore split plan replication boundary imports section"
require_source_contains "docs/architecture/ecstore-module-split-plan.md" "RuntimeReplicationFacadeConsumers" "ECStore split plan runtime replication facade consumer section"
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"
@@ -207,6 +208,8 @@ 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"
ECSTORE_REPLICATION_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/ecstore_replication_boundary_bypass_hits.txt"
SCANNER_REPLICATION_FACADE_BYPASS_HITS_FILE="${TMP_DIR}/scanner_replication_facade_bypass_hits.txt"
RUSTFS_REPLICATION_FACADE_BYPASS_HITS_FILE="${TMP_DIR}/rustfs_replication_facade_bypass_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"
@@ -2625,6 +2628,29 @@ if [[ -s "$ECSTORE_REPLICATION_BOUNDARY_BYPASS_HITS_FILE" ]]; then
report_failure "ECStore replication rustfs-replication imports must stay behind *_boundary.rs modules: $(paste -sd '; ' "$ECSTORE_REPLICATION_BOUNDARY_BYPASS_HITS_FILE")"
fi
(
cd "$ROOT_DIR"
rg -n --with-filename 'rustfs_replication::|use\s+rustfs_replication\b' \
crates/scanner/src \
--glob '*.rs' || true
) >"$SCANNER_REPLICATION_FACADE_BYPASS_HITS_FILE"
if [[ -s "$SCANNER_REPLICATION_FACADE_BYPASS_HITS_FILE" ]]; then
report_failure "scanner replication contracts must come through the ECStore replication facade: $(paste -sd '; ' "$SCANNER_REPLICATION_FACADE_BYPASS_HITS_FILE")"
fi
(
cd "$ROOT_DIR"
rg -n --with-filename 'rustfs_replication::|use\s+rustfs_replication\b' \
rustfs/src \
--glob '*.rs' |
rg -v '^rustfs/src/app/storage_api\.rs:' || true
) >"$RUSTFS_REPLICATION_FACADE_BYPASS_HITS_FILE"
if [[ -s "$RUSTFS_REPLICATION_FACADE_BYPASS_HITS_FILE" ]]; then
report_failure "RustFS runtime replication contracts must stay behind storage API facades: $(paste -sd '; ' "$RUSTFS_REPLICATION_FACADE_BYPASS_HITS_FILE")"
fi
(
cd "$ROOT_DIR"
rg -n --with-filename 'rustfs_filemeta::|use\s+rustfs_filemeta\b' \