mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-07 04:25:54 +00:00
docs(knowledge-base): prune stale content and add agent-facing index (#7035)
This commit is contained in:
@@ -1,353 +1,85 @@
|
||||
# ECStore Module Split Plan
|
||||
|
||||
This plan records the remaining ECStore split work after the final audit
|
||||
remediation pass. Runtime movement must still wait until each candidate
|
||||
boundary has explicit contracts, compatibility coverage, dependency evidence,
|
||||
and rollback steps.
|
||||
**Use this when:** you add lifecycle or replication logic and need to know which crate it belongs in, you plan to move an operation family out of `SetDisks`, or the guard fails on one of the split rules named below.
|
||||
**Source of truth:** `scripts/check_architecture_migration_rules.sh` (the rules), `crates/ecstore/src/bucket/lifecycle/README.md` and `crates/ecstore/src/bucket/replication/README.md` (module-level contract inventories, completion criteria, milestones), and [ecstore-api-facade-inventory.md](ecstore-api-facade-inventory.md) (facade groups and boundary files).
|
||||
|
||||
## Current Shape
|
||||
|
||||
| Area | Current owner | Size | Split status |
|
||||
|---|---|---:|---|
|
||||
| Bucket lifecycle | `crates/lifecycle/` + `crates/ecstore/src/bucket/lifecycle/` | core contracts + ECStore runtime | Core contract extracted |
|
||||
| Bucket replication | `crates/ecstore/src/bucket/replication/` | 15,619 lines | Contracts extracted; runtime move pending |
|
||||
| Set disks | `crates/ecstore/src/set_disk/` | state carrier plus operation modules | Keep in ECStore |
|
||||
| Public ECStore facade | `crates/ecstore/src/api/mod.rs` | broad compatibility surface | Shrink only through guarded PRs |
|
||||
| Embedded S3 client | `crates/s3-client/` (`rustfs-s3-client`) | ~8.4K lines | Extracted (rustfs/backlog#1842) |
|
||||
| Area | Owner | Split status |
|
||||
|---|---|---|
|
||||
| Bucket lifecycle | `crates/lifecycle/` (`rustfs-lifecycle`, pure contracts) + `crates/ecstore/src/bucket/lifecycle/` (runtime) | Core contracts extracted; runtime stays in ECStore |
|
||||
| Bucket replication | `crates/replication/` (`rustfs-replication`, contracts and wire formats) + `crates/ecstore/src/bucket/replication/` (worker runtime) | Contracts extracted; runtime move pending |
|
||||
| Set disks | `crates/ecstore/src/set_disk/` | Shared state carrier plus operation modules; stays in ECStore |
|
||||
| Public facade | `crates/ecstore/src/api/mod.rs` | Shrinks only through guarded changes |
|
||||
| S3 client | `crates/s3-client/` (`rustfs-s3-client`) | Extracted |
|
||||
|
||||
Measured 2026-08-12: the whole crate is 265 files / ~288K lines (roughly half
|
||||
is inline `#[cfg(test)]` code). The largest single files are `disk/local.rs`
|
||||
(21,063 lines), `bucket/lifecycle/bucket_lifecycle_ops.rs` (11,961 lines), and
|
||||
`set_disk/mod.rs` (11,151 lines). Reproduce with:
|
||||
Measure size instead of trusting numbers in a document:
|
||||
|
||||
```bash
|
||||
find crates/ecstore/src -name '*.rs' | xargs wc -l | sort -rn | head
|
||||
find crates/ecstore/src/bucket/replication -name '*.rs' | xargs wc -l | tail -1
|
||||
```
|
||||
|
||||
No split step has landed since the contract-extraction PRs of 2026-07-04,
|
||||
while the `bucket/replication` runtime grew from 8,730 to 15,619 lines (+79%)
|
||||
through feature work (e.g. SSE-C ciphertext passthrough replication #5898,
|
||||
delete-marker purge retry/replay #5864). To keep the gap from widening: in
|
||||
domains that already have a contract crate, new replication runtime logic that
|
||||
does not need ECStore runtime state must land in `rustfs-replication`, not in
|
||||
`crates/ecstore/src/bucket/replication/`.
|
||||
Rule for new code: in a domain that already has a contract crate, new logic that does not need ECStore runtime state lands in that crate (`rustfs-lifecycle`, `rustfs-replication`), not under `crates/ecstore/src/bucket/`.
|
||||
|
||||
The file split inside `set_disk/` is already operation-oriented: read, write,
|
||||
list, multipart, lock, heal, and replication code live in separate modules.
|
||||
The remaining large surface is the shared `SetDisks` state and cross-cutting
|
||||
contracts, not only file layout.
|
||||
|
||||
## Completed: S3 Client Extraction (rustfs/backlog#1842)
|
||||
|
||||
`crates/ecstore/src/client/` was a ~8.4K-line hand-written S3 HTTP client the engine uses to *consume* remote S3-compatible endpoints (ILM tier warm backends, transition targets). It was a legitimate engine capability misfiled inside the engine: it pulled `s3s`/`hyper` wire types into ecstore against ARCHITECTURE.md invariant 4, which distinguishes serving the S3 wire protocol (forbidden in ecstore) from consuming it (allowed, but in a dedicated crate).
|
||||
|
||||
The extraction landed as: pure move of the 21 client modules to `crates/s3-client` (`rustfs-s3-client`) with a temporary re-export shim, then direct `rustfs_s3_client::` imports and shim deletion. The two server-side modules historically misfiled under `client/` stayed in ecstore and moved to their real homes: `object_api_utils.rs` under `object_api/`, `object_handlers_common.rs` under `bucket/lifecycle/` (behind the `replication_sink` boundary). The remaining serving-side `s3s` references in ecstore are ratcheted shrink-only by the `S3S_ECSTORE_FILES_BASELINE` counter in `scripts/check_s3s_footprint.sh`; per-module conversions to storage-level types (first: `bucket/object_lock/`) lower the baseline in the same change.
|
||||
The S3 client extraction is complete: the former `client/` directory moved to `crates/s3-client`, its two server-side modules moved to `crates/ecstore/src/object_api/object_api_utils.rs` and `crates/ecstore/src/bucket/lifecycle/object_handlers_common.rs`, and the remaining serving-side `s3s` references in ECStore are ratcheted shrink-only by `S3S_ECSTORE_FILES_BASELINE` in `scripts/check_s3s_footprint.sh`.
|
||||
|
||||
## Non-Negotiable Rules
|
||||
|
||||
- Do not split crates in the same PR that moves runtime state or changes
|
||||
startup behavior.
|
||||
- Do not change object placement, quorum, reader semantics, lifecycle queues,
|
||||
replication queues, notification dispatch, audit events, or scanner repair
|
||||
behavior during inventory and contract PRs.
|
||||
- Do not expose new direct ECStore internals to outer crates; use the existing
|
||||
storage-api and owner-local facade boundaries.
|
||||
- Keep `rustfs_ecstore::api` compatibility visible until each consumer path has
|
||||
compile coverage and an explicit replacement.
|
||||
- Do not split crates in the same change that moves runtime state or changes startup behavior.
|
||||
- Do not change object placement, quorum, reader semantics, lifecycle queues, replication queues, notification dispatch, audit events, or scanner repair behavior during inventory and contract work.
|
||||
- Do not expose new direct ECStore internals to outer crates; use storage-api and owner-local facade boundaries.
|
||||
- Keep `rustfs_ecstore::api` compatibility visible until each consumer path has compile coverage and an explicit replacement.
|
||||
|
||||
## SetDisks Split Direction
|
||||
## Guarded Split Rules
|
||||
|
||||
Do not replace `SetDisks` with several runtime structs in one change. The safe
|
||||
path is:
|
||||
Each rule is enforced by `scripts/check_architecture_migration_rules.sh`; the name is the vocabulary used in reviews and guard failures.
|
||||
|
||||
1. Keep `SetDisks` as the shared state carrier while operation modules continue
|
||||
to own read/write/list/multipart/lock/heal/replication behavior.
|
||||
2. Extract pure contracts first: shard source, disk error, bitrot IO, namespace
|
||||
lock, metrics labels, and file metadata access.
|
||||
3. Move one operation family only after its contracts are covered by focused
|
||||
tests and the facade compatibility path is explicit.
|
||||
4. Preserve the old `rustfs_ecstore::api::set_disk` surface until downstream
|
||||
compatibility tests prove no caller depends on removed names.
|
||||
| Rule | What the guard checks |
|
||||
|---|---|
|
||||
| `LifecycleCrateCoreIndependence` | `crates/lifecycle` (rule validation, filtering, event evaluation, transition/expiration options, tag decoding, object-lock metadata checks, expiry-time rounding) imports no ECStore internals, `rustfs-filemeta`, or `rustfs-utils`; ECStore owns the `ObjectInfo` adapter in `crates/ecstore/src/bucket/lifecycle/core.rs`. |
|
||||
| `ReplicationCrateFileMetaIndependence` | Replication status, decision, MRF, resync, and target-reset wire contracts live in `crates/replication/src/filemeta.rs`; `rustfs-replication` neither imports nor depends on `rustfs-filemeta`. |
|
||||
| `ReplicationCrateStorageApiIndependence` | Delete work DTOs live in `crates/replication/src/storage_api.rs`; ECStore converts storage-api delete DTOs at its replication storage boundary; `rustfs-replication` does not depend on `rustfs-storage-api`. |
|
||||
| `ReplicationCrateUtilsIndependence` | HTTP metadata keys, S3 header labels, ETag trimming, and prefix matching used by replication wire contracts live in `crates/replication/src/http.rs`; `rustfs-replication` does not depend on `rustfs-utils`. |
|
||||
| `EcstoreReplicationBoundaryImports` | ECStore-side `rustfs_replication` imports are confined to the `*_boundary.rs` modules under `crates/ecstore/src/bucket/replication/`; grouped queue, stats, resync, and object-decision symbols each have one owning boundary file. |
|
||||
| `RuntimeReplicationFacadeConsumers` | Scanner, admin, storage-owner, and app code consume replication status/DTO/helper contracts through the `rustfs_ecstore` facade; the `rustfs` and `rustfs-scanner` crates do not depend on `rustfs-replication` directly. |
|
||||
| `StorageApiReplicationContracts` | Owner-facing storage-api delete DTO replication state/status helpers stay in `crates/storage-api/src/replication.rs`; replication worker DTOs stay in `rustfs-replication`. |
|
||||
|
||||
The first executable SetDisks follow-up should be an inventory or guardrail PR,
|
||||
not a runtime split PR.
|
||||
## Lifecycle
|
||||
|
||||
## Lifecycle Candidate
|
||||
`rustfs-lifecycle` owns the pure rule, event, evaluator, tag-filter, object-lock metadata check, and expiry-time contracts. ECStore keeps the object-store runtime, queues, tiering, audit/notification, metadata access (`crates/ecstore/src/bucket/lifecycle/metadata_boundary.rs`), and replication-delete scheduling adapters.
|
||||
|
||||
`rustfs-lifecycle` now owns the pure lifecycle rule, event, evaluator, tag
|
||||
filtering, object-lock metadata check, and expiry-time contracts. ECStore keeps
|
||||
the object-store runtime, queues, tiering, audit/notification, metadata, and
|
||||
replication scheduling adapters.
|
||||
Coupling that still blocks a runtime move: lifecycle workers read ECStore runtime sources (object store, expiry and transition state, tier config, deployment id, local node name); stale multipart cleanup depends on `SetDisks` internals and bucket metadata; expiry schedules replication deletes through the replication lifecycle bridge; the lifecycle runtime coordinates scanner metrics and notification/audit side effects. The contract list and the next step live in `crates/ecstore/src/bucket/lifecycle/README.md`.
|
||||
|
||||
Current coupling:
|
||||
## Replication
|
||||
|
||||
- lifecycle workers and transition state read ECStore runtime sources for
|
||||
object-store handles, expiry state, transition state, tier config, deployment
|
||||
IDs, and local node names;
|
||||
- stale multipart cleanup depends on `SetDisks` internals and bucket metadata
|
||||
through the lifecycle metadata boundary;
|
||||
- lifecycle expiry schedules bucket replication delete work through the
|
||||
replication lifecycle bridge contract;
|
||||
- lifecycle evaluation uses S3 DTOs and replication status contracts from the
|
||||
independent `rustfs-lifecycle`/`rustfs-replication` crates, while ECStore maps
|
||||
`ObjectInfo` into lifecycle object options at the compatibility boundary;
|
||||
- lifecycle runtime still coordinates scanner metrics, notification/audit side
|
||||
effects, metadata access, replication delete scheduling, and tier services.
|
||||
`rustfs-replication` owns resync status contracts, the persisted resync status wire format, filemeta-derived wire contracts, delete work DTOs, and HTTP helper contracts. ECStore keeps the worker runtime, error mapping, MRF persistence, and global pool/stat initialization.
|
||||
|
||||
Current extracted contracts:
|
||||
Boundary layout inside `crates/ecstore/src/bucket/replication/`: `*_boundary.rs` modules concentrate imports from `rustfs-replication`, storage-api, filemeta, config, target, error, lock, msgp, versioning, tagging, bandwidth, queue, stats, resync, and object-decision surfaces; `replication_*_bridge.rs` modules (lifecycle, scanner, object, migration, target-config) expose replication scheduling to other owners without leaking DTO construction; `replication_config_store.rs` exposes config persistence and storage-class labels. Modules inside the directory use relative self-imports, and the facade in `mod.rs` uses explicit symbol lists, never wildcard re-exports.
|
||||
|
||||
- `LifecycleCrateCoreIndependence`: lifecycle rule validation, filtering,
|
||||
event evaluation, transition/expiration options, tag decoding, object-lock
|
||||
metadata checks, and ILM expiry-time rounding live in `rustfs-lifecycle`.
|
||||
`rustfs-lifecycle` must not import ECStore internals, file metadata, or
|
||||
`rustfs-utils`; ECStore owns the `ObjectInfo` adapter in
|
||||
`crates/ecstore/src/bucket/lifecycle/core.rs`.
|
||||
Consumers outside ECStore: RustFS runtime code receives pool/stat handles through storage-owner wrapper types in `rustfs/src/storage/storage_api.rs`; scanner code receives scanner-local config/admission/heal DTOs from `crates/scanner/src/storage_api.rs`; observability reads replication metrics through obs-local snapshot DTOs in `crates/obs/src/metrics/storage_api.rs`; app object and multipart writes call object-replication bridge helpers instead of constructing replication work DTOs.
|
||||
|
||||
Required contracts before crate movement:
|
||||
Completion criteria, the milestone order, and the per-dependency contract inventory live in `crates/ecstore/src/bucket/replication/README.md` (sections "Completion Criteria" and "Milestones"). Remaining work starts from moving resyncer pure decision logic.
|
||||
|
||||
- `LifecycleObjectStore`: object stat, delete, transition, restore, multipart
|
||||
cleanup, and version-aware metadata operations needed by lifecycle workers.
|
||||
- `LifecycleMetadataStore`: lifecycle, object-lock, replication, bucket
|
||||
versioning, and stale multipart metadata lookups without importing ECStore
|
||||
implementation modules. Current lifecycle config reads are concentrated in
|
||||
`crates/ecstore/src/bucket/lifecycle/metadata_boundary.rs`.
|
||||
- `LifecycleRuntime`: expiry state, transition state, tier config, deployment
|
||||
ID, local node name, queue metrics, cancellation, and worker sizing.
|
||||
- `LifecycleReplicationSink`: schedule lifecycle-originated replication deletes
|
||||
without depending on the replication implementation module.
|
||||
- `LifecycleAuditSink`: lifecycle audit and notification emission boundary.
|
||||
## SetDisks
|
||||
|
||||
Next safe PR:
|
||||
Do not replace `SetDisks` with several runtime structs in one change:
|
||||
|
||||
- move one runtime-facing dependency behind a trait or adapter owned by
|
||||
`rustfs-lifecycle` without changing queue, transition, or delete behavior;
|
||||
- keep ECStore compatibility shims until scanner and RustFS app consumers stop
|
||||
depending on `rustfs_ecstore::api::bucket::lifecycle` paths;
|
||||
- add focused tests for the moved contract and keep architecture guard coverage.
|
||||
1. Keep `SetDisks` as the shared state carrier while operation modules own read/write/list/multipart/lock/heal/replication behavior.
|
||||
2. Extract pure contracts first: shard source, disk error, bitrot IO, namespace lock, metrics labels, and file metadata access.
|
||||
3. Move one operation family only after its contracts are covered by focused tests and the facade compatibility path is explicit.
|
||||
4. Preserve the `rustfs_ecstore::api::set_disk` surface until downstream compatibility tests prove no caller depends on removed names.
|
||||
|
||||
The module-level inventory lives in
|
||||
`crates/ecstore/src/bucket/lifecycle/README.md`.
|
||||
## Facade Shrink
|
||||
|
||||
Focused verification for the first code-bearing lifecycle PR:
|
||||
|
||||
- `cargo test -p rustfs-ecstore lifecycle --lib`
|
||||
- `cargo check -p rustfs-ecstore --tests`
|
||||
- `./scripts/check_architecture_migration_rules.sh`
|
||||
- `git diff --check`
|
||||
|
||||
## Replication Candidate
|
||||
|
||||
`rustfs-replication` now owns the resync status contracts and persisted resync
|
||||
status wire format. The remaining `bucket/replication` worker runtime is not
|
||||
ready for a full standalone crate yet.
|
||||
|
||||
The completion criteria and milestone sequence for this candidate (when the
|
||||
split counts as done, the target end state, and the order of the remaining
|
||||
moves) live in the module inventory:
|
||||
`crates/ecstore/src/bucket/replication/README.md`, sections "Completion
|
||||
Criteria" and "Milestones". The originally proposed first code-bearing step
|
||||
(event sink / runtime contracts) has landed; remaining work starts from moving
|
||||
resyncer pure decision logic.
|
||||
|
||||
Current coupling:
|
||||
|
||||
- replication workers depend on `ReplicationStorage`, ECStore object APIs and
|
||||
owner storage-api contracts through the replication storage boundary, bucket
|
||||
target clients, bucket metadata, file metadata replication state through the
|
||||
filemeta boundary, config-derived storage class labels through the config store, scanner repair
|
||||
classification, runtime replication pool/stat handles, bucket monitor and
|
||||
bandwidth reader access through local boundaries, local node names, and
|
||||
notification events;
|
||||
- resync and delete replication paths call metadata paths through the metadata
|
||||
boundary, while bucket target system access, target config types, and target
|
||||
operation types are concentrated behind the replication target boundary;
|
||||
- lifecycle delete paths schedule replication work through
|
||||
`ReplicationLifecycleBridge`, while scanner heal paths schedule replication
|
||||
work through `ReplicationScannerBridge`, and app/SetDisks object write/delete
|
||||
paths use `ReplicationObjectBridge`;
|
||||
- bucket metadata migration and bucket target removal checks use local
|
||||
replication bridges instead of importing resyncer codec or config helper
|
||||
internals;
|
||||
- resync options, bucket/target resync status DTOs, status display labels, and
|
||||
the persisted resync status wire format live in `crates/replication`, with
|
||||
ECStore retaining only error mapping and MRF persistence locally;
|
||||
- `ReplicationCrateFileMetaIndependence`: replication status, decision, MRF,
|
||||
resync, and target-reset wire contracts are owned inside `rustfs-replication`
|
||||
instead of importing `rustfs-filemeta`;
|
||||
- `ReplicationCrateStorageApiIndependence`: delete work DTOs are owned inside
|
||||
`rustfs-replication`; ECStore converts storage-api delete DTOs at the
|
||||
replication storage boundary instead of `rustfs-replication` importing
|
||||
`rustfs-storage-api`;
|
||||
- `ReplicationCrateUtilsIndependence`: HTTP metadata keys, S3 header labels,
|
||||
ETag trimming, and case-insensitive prefix matching used by replication wire
|
||||
contracts are owned inside `rustfs-replication` instead of importing
|
||||
`rustfs-utils`;
|
||||
- direct ECStore replication imports from `rustfs-replication` are limited to
|
||||
`*_boundary.rs` modules;
|
||||
- storage-api delete replication status/state helpers use the local
|
||||
`crates/storage-api/src/replication.rs` contract boundary; ECStore converts
|
||||
those owner DTOs at the replication storage boundary before queueing work;
|
||||
- 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, storage-owner, and app storage replication status/DTO/helper
|
||||
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;
|
||||
- RustFS runtime consumers receive replication pool/stat handles through
|
||||
storage-owner wrapper types instead of carrying ECStore replication handles
|
||||
through app, admin, startup, or workload-admission layers;
|
||||
- global replication pool/stat initialization still lives with ECStore runtime
|
||||
compatibility state;
|
||||
- modules inside `bucket/replication` use local relative paths rather than the
|
||||
ECStore owner path for replication self-imports;
|
||||
- replication runtime source access uses storage/bandwidth boundary aliases for
|
||||
ECStore object store and bucket monitor implementation types;
|
||||
- the ECStore replication facade in `mod.rs` uses explicit compatibility
|
||||
exports instead of wildcard re-exports from implementation modules.
|
||||
|
||||
Required contracts before crate movement:
|
||||
|
||||
- `ReplicationObjectIO`: object read/write primitives for config, MRF, resync
|
||||
status, and multipart replication paths. ECStore object API reader/writer
|
||||
types and storage-api object IO contracts are concentrated in
|
||||
`crates/ecstore/src/bucket/replication/replication_storage_boundary.rs`.
|
||||
- `ReplicationStorage`: keep the existing trait as the starting point, then
|
||||
split object read/write/delete, walk, and metadata update responsibilities
|
||||
only when call sites prove a narrower shape. ECStore object API,
|
||||
storage-api contracts, and read option types are concentrated in
|
||||
`crates/ecstore/src/bucket/replication/replication_storage_boundary.rs`.
|
||||
- `ReplicationMetadataStore`: replication config, target reset headers,
|
||||
MRF/resync state, and status persistence. Metadata sys access and replication
|
||||
metadata path constants are exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_metadata_boundary.rs`.
|
||||
- `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
|
||||
`crates/ecstore/src/bucket/replication/replication_config_store.rs`.
|
||||
- `ReplicationFileMeta`: replication status, decisions, MRF entries, resync
|
||||
decisions, and target reset helpers. ECStore concentrates filemeta-to-
|
||||
replication compatibility conversions in
|
||||
`crates/ecstore/src/bucket/replication/replication_filemeta_boundary.rs`,
|
||||
while `FileInfo` remains in the storage boundary for storage trait bindings
|
||||
and walk options.
|
||||
- `ReplicationCrateFileMetaIndependence`: filemeta wire contracts consumed by
|
||||
replication workers are owned in `crates/replication/src/filemeta.rs`, and
|
||||
`rustfs-replication` must not import or depend on `rustfs-filemeta`.
|
||||
- `ReplicationCrateStorageApiIndependence`: delete work DTOs consumed by
|
||||
replication delete/queue/operation helpers are owned in
|
||||
`crates/replication/src/storage_api.rs`, and `rustfs-replication` must not
|
||||
import or depend on `rustfs-storage-api`.
|
||||
- `ReplicationCrateUtilsIndependence`: replication-specific HTTP metadata,
|
||||
header, ETag, and prefix helper contracts are owned in
|
||||
`crates/replication/src/http.rs`, and `rustfs-replication` must not import or
|
||||
depend on `rustfs-utils`.
|
||||
- `EcstoreReplicationBoundaryImports`: ECStore-side imports from
|
||||
`rustfs-replication` are concentrated in replication `*_boundary.rs` modules.
|
||||
- `RuntimeReplicationFacadeConsumers`: scanner, admin, storage-owner, and app
|
||||
storage replication status/DTO/helper consumers import through
|
||||
`rustfs-ecstore`; runtime code under `rustfs/src` does not import
|
||||
`rustfs-replication` directly, and the RustFS runtime/scanner crates do not
|
||||
depend on it.
|
||||
- `StorageApiReplicationContracts`: owner-facing storage-api delete DTO
|
||||
replication state/status helpers remain concentrated in
|
||||
`crates/storage-api/src/replication.rs`, while replication worker DTOs live in
|
||||
`rustfs-replication`.
|
||||
- `ReplicationErrorBoundary`: ECStore error/result contracts and
|
||||
replication-specific error classifiers. `crate::error` imports are
|
||||
concentrated in
|
||||
`crates/ecstore/src/bucket/replication/replication_error_boundary.rs`.
|
||||
- `ReplicationTargetStore`: bucket target listing, target client lookup,
|
||||
target offline checks, target config types, and target operation option
|
||||
types. Bucket target sys access, `BucketTargets`, and target operation types
|
||||
are exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_target_boundary.rs`.
|
||||
- `ReplicationRuntime`: pool, stats, worker admission, bucket monitor, local
|
||||
node identity, cancellation, and queue sizing. Concrete ECStore object store
|
||||
and bucket monitor types stay behind local storage/bandwidth boundaries.
|
||||
- `ReplicationBandwidthLimiter`: target reader wrapping for replication
|
||||
bandwidth accounting and throttling.
|
||||
- `ReplicationVersioningStore`, `ReplicationLockTiming`, `ReplicationMsgpCodec`,
|
||||
and `ReplicationTagFilter`: smaller state/codec/filter contracts that keep
|
||||
bucket versioning, SetDisks lock timing, MessagePack helpers, and bucket
|
||||
tagging helper access behind local replication boundary types.
|
||||
- `ReplicationEventSink`: notification/audit events for skipped, failed, and
|
||||
completed replication operations, including local event host selection.
|
||||
- `ReplicationLifecycleBridge`: lifecycle-originated delete and version-purge
|
||||
scheduling is exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_lifecycle_bridge.rs`.
|
||||
- `ReplicationMigrationBridge`: persisted resync status decode/encode access
|
||||
for bucket metadata migration is exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_migration_bridge.rs`.
|
||||
- `ReplicationResyncContracts`: resync options, target/bucket resync status,
|
||||
status labels, and persisted status encoding live in `crates/replication`.
|
||||
- `ReplicationObjectBridge`: app and SetDisks object write/delete replication
|
||||
decisions and scheduling are exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_object_bridge.rs`.
|
||||
- `ObsReplicationStatsSnapshot`: observability reads replication bucket/site
|
||||
metrics through obs-local snapshot DTOs in
|
||||
`crates/obs/src/metrics/storage_api.rs` instead of carrying the ECStore
|
||||
replication stats handle through collectors.
|
||||
- `StorageReplicationPoolHandle` / `StorageReplicationStatsHandle`: RustFS app, admin,
|
||||
startup, and workload-admission code use storage-owner wrapper types from
|
||||
`rustfs/src/storage/storage_api.rs` for pool activity, resync, queue counts,
|
||||
proxy stats, and site metrics snapshots.
|
||||
- `ReplicationScannerBridge`: scanner-originated replication heal scheduling is
|
||||
exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_scanner_bridge.rs`.
|
||||
Scanner consumers receive scanner-local replication config/admission/heal
|
||||
object DTOs from `crates/scanner/src/storage_api.rs` instead of constructing
|
||||
or inspecting replication queue DTOs directly.
|
||||
- `ReplicationTargetConfigBridge`: bucket target removal checks against
|
||||
replication target rules are exposed through the contract type in
|
||||
`crates/ecstore/src/bucket/replication/replication_target_config_bridge.rs`.
|
||||
- `ReplicationFacade`: the current `rustfs_ecstore::api::bucket::replication`
|
||||
compatibility surface is an explicit symbol list guarded against wildcard
|
||||
re-exports while downstream owners migrate to narrower contracts.
|
||||
|
||||
First safe PR:
|
||||
|
||||
- add a replication extraction inventory section or module-level README;
|
||||
- list current ECStore/runtime dependencies and the target contract owner for
|
||||
each dependency;
|
||||
- keep global pool/stat initialization and queue behavior unchanged.
|
||||
|
||||
The module-level inventory lives in
|
||||
`crates/ecstore/src/bucket/replication/README.md`.
|
||||
|
||||
Focused verification for the first code-bearing replication PR:
|
||||
|
||||
- `cargo test -p rustfs-ecstore replication --lib`
|
||||
- `cargo check -p rustfs-ecstore --tests`
|
||||
- `./scripts/check_architecture_migration_rules.sh`
|
||||
- `git diff --check`
|
||||
|
||||
## Facade Shrink Plan
|
||||
|
||||
The broad `rustfs_ecstore::api` facade remains a compatibility boundary, not a
|
||||
new architecture target. The current facade groups and external consumers are
|
||||
recorded in
|
||||
[`ecstore-api-facade-inventory.md`](ecstore-api-facade-inventory.md).
|
||||
Shrinking it must be monotonic:
|
||||
|
||||
1. Inventory every public facade group and consumer.
|
||||
2. Add compile-time coverage before removing or narrowing a facade item.
|
||||
3. Move outer consumers to storage-api or owner-local compatibility boundaries.
|
||||
4. Remove one facade group per PR only after downstream compatibility tests pass.
|
||||
|
||||
Do not delete facade groups only because the underlying module moved. Keep the
|
||||
facade stable until the replacement path is visible and tested.
|
||||
Facade groups, boundary files, and shrink rules are in [ecstore-api-facade-inventory.md](ecstore-api-facade-inventory.md). Shrinking is monotonic: inventory, add compile-time coverage, move consumers to storage-api or owner-local boundaries, then remove one group per change. Do not delete facade groups only because the underlying module moved.
|
||||
|
||||
## Ready-To-Split Checklist
|
||||
|
||||
A candidate split is ready for code movement only when all items below are true:
|
||||
A candidate is ready for code movement only when all of these hold:
|
||||
|
||||
- dependency graph shows no cycle with ECStore, storage-api, runtime sources, or
|
||||
owner-local compatibility modules;
|
||||
- the dependency graph shows no cycle with ECStore, storage-api, runtime sources, or owner-local compatibility modules;
|
||||
- contract traits compile without importing ECStore implementation modules;
|
||||
- old facade names have compatibility tests or explicit deprecation coverage;
|
||||
- focused tests cover the changed owner path before any full gate is attempted;
|
||||
- rollback preserves object IO, quorum, lifecycle/replication queues, scanner
|
||||
repair, notification/audit events, and metadata compatibility.
|
||||
- rollback preserves object IO, quorum, lifecycle/replication queues, scanner repair, notification/audit events, and metadata compatibility.
|
||||
|
||||
Reference in New Issue
Block a user