10 KiB
Global State And Crate Split Plan
This document records the late global-state cleanup plan after the AppContext foundation, storage API contracts, ECStore layout, runtime lifecycle, and cluster control-plane boundaries are stable.
As of the Phase 7 closeout, runtime resolver fallbacks have been pushed out of the root facade and into explicit owner-local boundaries. Future work should therefore treat broad fallback removal as complete and use this document for the remaining ECStore-owned bootstrap state and crate-split decisions.
The issue #730 global-state baseline and runtime migration target inventory are
recorded in global-state-inventory.md.
Remaining Global Owners
| Owner | Current role | Migration stance |
|---|---|---|
rustfs/src/app/context.rs |
AppContext-first resolver facade. | Resolver helpers stay context-first and do not construct concrete no-AppContext defaults. |
rustfs/src/app/context/runtime_sources.rs |
Default adapters for KMS, IAM, object store, endpoints, config, metrics, and notification state used by AppContext construction. | This is an allowed adapter boundary, not a business logic owner. |
rustfs/src/*/runtime_sources.rs |
Root, admin, app, server, startup, and storage owner-local runtime-source boundaries. | Business modules use these boundaries instead of calling global state directly; owner facades own any remaining no-AppContext compatibility defaults. |
rustfs/src/*/storage_api.rs |
Root, admin, app, and storage owner-local storage contract/facade boundaries. | Storage helper and ECStore facade access remains visible at local owner boundaries. |
crates/*/storage_api.rs |
External crate-local storage facade boundaries for IAM, scanner, heal, notify, observability, Swift, and S3 Select. | External runtime crates consume ECStore runtime state through rustfs_ecstore::api::runtime instead of the direct global facade. |
crates/ecstore/src/runtime/global.rs |
ECStore bootstrap/runtime state owner. | Keep internal until ECStore has explicit owner handles for all remaining bootstrap state. |
crates/ecstore/src/runtime/sources.rs |
ECStore runtime-source adapter over global state. | Preferred ECStore-internal access path while shrinking direct runtime::global reads. |
Runtime Source Boundaries
Runtime-source modules are the allowed compatibility layer between migrated consumers and process-global state. They must keep these properties:
- context-first lookup when an
AppContexthandle exists; - explicit fallback to the existing global only where compatibility still requires it;
- no hidden service construction in business logic;
- no startup, readiness, IAM, KMS, lock, notification, or storage behavior change in inventory or guardrail PRs.
Guarded Boundary List
The architecture guard snapshots the files currently allowed to reference
rustfs_ecstore::api::global directly:
rustfs/src/storage/storage_api.rs
That boundary now keeps only bootstrap writes and lifecycle controls in the
global facade. Read-only runtime getters must be exported through
rustfs_ecstore::api::runtime and consumed through the local storage facade.
New direct uses must either move behind an existing owner-local boundary or
update this plan and the guard in the same reviewed migration PR.
Fallback Removal Plan
- Keep AppContext-first lookup as the stable resolver contract.
- Keep concrete no-AppContext compatibility defaults only at owner-local runtime-source facades that consume them.
- Do not let business logic call
AppContextor ECStore globals directly when an owner-local runtime-source boundary exists. - Keep embedded startup and tests working before deleting any remaining owner fallback.
- Do not remove ECStore bootstrap globals until ownership handles exist for local disks, endpoint pools, lock clients, notification state, tier config, lifecycle state, and object-store publication.
GLOB-007 Closeout Boundary
GLOB-007 is complete when these invariants hold:
- root
rustfs/src/runtime_sources.rsis an AppContext/root facade entrypoint and no longer composes concrete fallback defaults withunwrap_or,unwrap_or_else, directinit_global, or directnew_globalcalls; - private AppContext resolver helpers are context-first and do not hide fallback closure parameters;
- admin, app, storage, server, startup, and config owner facades decide when to apply no-AppContext compatibility defaults;
- production callers outside runtime-source and storage-api boundary modules do not import ECStore global state directly;
- the architecture guard keeps the direct
rustfs_ecstore::api::globalboundary list explicit.
Allowed remaining fallbacks are owner compatibility decisions, not resolver fallback families. They are kept so embedded startup, tests, and no-context callers preserve the previous behavior while higher layers continue migrating to explicit AppContext ownership.
Crate Split Evaluation
ecstore-erasure and storage-cluster remain proposal-only until dependency
cycles and hot-path risks are proven safe. The Phase 7 evaluation is complete
for now: neither split is ready for code movement in this migration round.
The follow-up ECStore module split plan is recorded in
ecstore-module-split-plan.md, including the
remaining SetDisks, lifecycle, replication, and facade-shrink boundaries.
CRATE-001: ecstore-erasure
Current coupling:
- erasure decoding depends on disk errors, disk read timeouts, and set-disk shard sources;
- set-disk read/write/heal paths construct erasure codecs in hot object I/O paths;
- bitrot readers/writers live in ECStore IO support and are used by both erasure and set-disk code;
- public compatibility still exposes erasure symbols through
rustfs_ecstore::api::erasure.
Decision: do not split in code yet. The erasure boundary is a candidate only after the shard-source, disk-error, bitrot, and metrics contracts are explicit enough to avoid a dependency cycle back into ECStore.
Required evidence before proposing the split:
cargo tree -p rustfs-ecstore -e normal --depth 2snapshot for dependency impact;- focused benchmarks for encode/decode, read reconstruction, bitrot verification, and large-object streaming;
- contract sketch for shard sources, disk errors, bitrot IO, metrics, and file metadata without importing ECStore implementation modules;
- compatibility plan for
rustfs_ecstore::api::erasureand test harnesses; - rollback plan that keeps object read/write quorum and old-version file decode behavior unchanged.
CRATE-002: storage-cluster
Current coupling:
- cluster RPC remote disk code depends on disk stores, disk health tracking, set-disk buffer sizing, local disk scan guards, internode metrics, and runtime credential/signature sources;
- peer S3 and peer REST clients share bucket metadata, disk quorum reduction, endpoint layout, local disk initialization, and store helpers;
- control-plane snapshots are separated from data-plane RPC, but remote disk and peer clients still own data movement side effects inside ECStore.
Decision: do not split in code yet. The storage-cluster boundary is a candidate only after remote disk, peer health, lock/quorum, runtime metrics, and endpoint layout contracts are explicit enough to stand below ECStore without circular dependencies.
Required evidence before proposing the split:
- dependency graph showing no cycle with ECStore,
rustfs-storage-api, runtime source owners, or cluster control-plane owners; - RPC contract sketch for remote disk, peer S3, peer REST, auth/signature, internode metrics, and cancellation;
- compatibility plan for
rustfs_ecstore::api::cluster,api::rpc, and test fixtures that build local disks or endpoint pools; - focused tests for remote disk error classification, peer health recovery, per-pool quorum reduction, lock behavior, and data-stream request paths;
- rollback plan that preserves quorum, remote disk IO, lock, peer health, and data movement behavior.
CRATE-003: bucket-lifecycle
Decision: do not split in code yet. Lifecycle remains coupled to ECStore object
operations, bucket metadata, SetDisks stale multipart cleanup, tier config,
runtime lifecycle state, scanner metrics, notification/audit side effects, and
replication delete scheduling.
Required evidence before proposing the split:
- contract sketch for lifecycle object operations, metadata access, runtime state, replication delete scheduling, and audit/notification sinks;
- dependency graph showing the candidate crate can avoid importing ECStore implementation modules;
- focused tests for lifecycle evaluation, expiry, transition, stale multipart cleanup, tier journal recovery, and lifecycle-originated replication deletes;
- compatibility plan for
rustfs_ecstore::api::bucket::lifecycleconsumers; - rollback plan that preserves lifecycle queues, scanner repair accounting, tier transitions, object deletion behavior, and notification/audit events.
CRATE-004: bucket-replication
Decision: do not split in code yet. Replication remains coupled to ECStore object APIs, bucket target clients, metadata systems, file metadata replication state, ECStore-owned runtime replication pool/stat handles, bucket monitor state, scanner repair classification, lifecycle-originated deletes, and notification events. RustFS-facing runtime consumers should use storage-owner wrapper handles while that state remains in ECStore.
Required evidence before proposing the split:
- contract sketch for replication storage operations, metadata/target access, runtime pool and stats, event sinks, and lifecycle/heal bridges;
- dependency graph showing the candidate crate can avoid importing ECStore implementation modules;
- focused tests for object replication, delete replication, resync state, heal repair queueing, target error handling, and queue admission;
- compatibility plan for
rustfs_ecstore::api::bucket::replicationconsumers; - rollback plan that preserves replication queues, MRF/resync state, target client behavior, scanner repair, and event emission.
Preservation Rules
- Do not reintroduce AppContext resolver fallback families in broad cleanup PRs.
- Do not introduce direct global reads in admin, app, server, storage, scanner, heal, IAM, notify, observability, Swift, or S3 Select business logic.
- Do not split crates in the same PR that moves runtime state.
- Do not change startup order, readiness, KMS fatal boundaries, IAM recovery, lock quorum, object placement, reader behavior, or notification/audit lifecycle while shrinking global state.