refactor(ecstore): migrate background replication pool/stats into InstanceContext (Phase 5 Slice 11) (#4495)

Phase 5 Slice 11 (backlog#939): move the background replication pool and stats —
the last service handles, and the only async ones — out of the process statics
into the per-instance InstanceContext.

- InstanceContext gains `replication_stats: OnceCell<Arc<ReplicationStats>>` and
  `replication_pool: OnceCell<Arc<DynReplicationPool>>` (tokio async OnceCell),
  with sync read accessors (`replication_stats`/`replication_pool`/
  `replication_initialized`) and pub(crate) cell accessors for the async init.
- `init_background_replication` initializes the current instance's cells via the
  same `get_or_init(async {…}).await` (workers still spawned once on first
  init). The lifecycle owner helpers and the runtime-source accessors keep their
  signatures and route through the current instance's context; the two statics
  (and the now-unused lazy_static import) are removed. The replication-boundary
  arch guard still passes.

Single-instance: init materializes one shared pool/stats via the bootstrap
context — byte-for-byte the same as the eager statics.

Tests: replication state is None until set and independent across instances.

Verification: cargo test -p rustfs-ecstore (22 instance-context tests green),
cargo clippy -p rustfs-ecstore --all-targets (clean), make pre-commit (pass).

Refs: backlog#939 (Phase 5, Slice 11). Stacked on Slice 10 (#4494).
This commit is contained in:
Zhengchao An
2026-07-08 23:15:01 +08:00
committed by GitHub
parent db8ba9e2e5
commit ca63a6cced
3 changed files with 80 additions and 17 deletions
@@ -45,7 +45,6 @@ use super::replication_storage_boundary::{
use super::replication_target_boundary::{ReplicationTargetStore, replication_object_is_ssec_encrypted};
use super::replication_versioning_boundary::ReplicationVersioningStore;
use super::runtime_boundary as runtime_sources;
use lazy_static::lazy_static;
use rustfs_utils::http::{SUFFIX_REPLICATION_TIMESTAMP, get_str};
use std::sync::Arc;
use std::sync::atomic::AtomicI32;
@@ -1293,14 +1292,16 @@ impl<S: ReplicationStorage> ReplicationPoolTrait for ReplicationPool<S> {
}
}
lazy_static! {
pub static ref GLOBAL_REPLICATION_POOL: tokio::sync::OnceCell<Arc<DynReplicationPool>> = tokio::sync::OnceCell::new();
pub static ref GLOBAL_REPLICATION_STATS: tokio::sync::OnceCell<Arc<ReplicationStats>> = tokio::sync::OnceCell::new();
}
/// Initializes background replication with the given options
/// Initializes background replication with the given options.
///
/// Phase 5 (backlog#939): the replication stats/pool moved into the per-instance
/// `InstanceContext`; this owner initializes the current instance's cells
/// (lazily, once — single-instance behavior is unchanged).
pub async fn init_background_replication<S: ReplicationStorage>(storage: Arc<S>) {
let stats = GLOBAL_REPLICATION_STATS
let ctx = crate::runtime::global::current_ctx();
let stats = ctx
.replication_stats_cell()
.get_or_init(|| async {
let stats = Arc::new(ReplicationStats::new());
stats.start_background_tasks().await;
@@ -1308,7 +1309,8 @@ pub async fn init_background_replication<S: ReplicationStorage>(storage: Arc<S>)
})
.await;
let _pool = GLOBAL_REPLICATION_POOL
let _pool = ctx
.replication_pool_cell()
.get_or_init(|| async {
let pool = ReplicationPool::new(ReplicationPoolOpts::default(), stats.clone(), storage).await;
pool as Arc<DynReplicationPool>