mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 15:37:02 +00:00
refactor(ecstore): add per-instance InstanceContext, migrate erasure setup type (#4413)
* refactor(ecstore): add per-instance InstanceContext, migrate erasure setup type Phase 5 of the global-singleton consolidation (backlog#939): begin moving runtime identity state out of process globals so multiple ECStore instances can coexist in one process. Isolation is carried by the object graph (ECStore -> Sets -> SetDisks holding an Arc<InstanceContext>), not a task-local, which does not propagate across the many internal tokio::spawn boundaries in the data/background paths. This first slice migrates the erasure setup type -- previously three independent process-global bools -- into a single per-instance RwLock<SetupType> that derives is_erasure / is_dist_erasure / is_erasure_sd, removing a triple source of truth that could drift out of sync. - New runtime::instance module: InstanceContext + process bootstrap context. - The legacy free-function facade (is_erasure/update_erasure_type/...) keeps its signatures and forwards to the current instance's context, falling back to the bootstrap context before a store is published. - ECStore gains a pub(crate) ctx field and setup_is_* accessors; its constructors adopt the bootstrap context (never mint a fresh one) so startup writes and post-construction reads share one cell -- single-instance behavior is byte-for-byte unchanged. Tests: erasure predicate derivation vs the legacy behavior, object-graph carrier isolation across two ECStore instances, and bootstrap adoption. Refs: backlog#939 (Phase 5, Slice 1), backlog#653 (item 8) * refactor(ecstore): thread InstanceContext down the object graph (Phase 5 Slice 2) (#4415) * refactor(ecstore): source the namespace lock manager per-instance (#4417) refactor(ecstore): source the namespace lock manager per-instance (Phase 5 Slice 3) Phase 5 Slice 3 (backlog#939): give each instance its own lock namespace by sourcing SetDisks' lock manager from the instance context instead of the process singleton. This removes the false cross-instance mutual exclusion (and attendant ABBA risk) that a shared GlobalLockManager would cause once multiple instances coexist. - InstanceContext gains a `lock_manager: Arc<GlobalLockManager>`. `new()` mints a fresh manager (independent per-instance); `bootstrap_ctx()` aliases the process singleton via get_global_lock_manager(), so a single-instance deployment keeps exactly one shared namespace. - SetDisks::new sources `local_lock_manager` from `ctx.lock_manager()` (the ctx it already adopts), not `runtime_sources::global_lock_manager()`. Single instance: same Arc as before, so behavior is unchanged. - Remove the now-unused `runtime_sources::global_lock_manager()` wrapper. Tests: bootstrap lock manager aliases the process singleton; two fresh contexts own distinct managers; a SetDisks' lock manager is the one from its context and aliases the global singleton in a single-instance build. Verification: cargo test -p rustfs-ecstore (10 Phase 5 + set_disk locking regressions green), cargo clippy -p rustfs-ecstore --all-targets (clean), make pre-commit (pass). Refs: backlog#939 (Phase 5, Slice 3). Stacked on #4415 (Slice 2).
This commit is contained in:
@@ -81,6 +81,7 @@ use crate::error::{GenericError, ObjectApiError, is_err_object_not_found};
|
||||
use crate::io_support::bitrot::{create_bitrot_reader, create_bitrot_reader_from_bytes, create_bitrot_writer};
|
||||
use crate::object_api::ObjectOptions;
|
||||
use crate::object_api::get_object_body_cache_hook;
|
||||
use crate::runtime::instance::{InstanceContext, bootstrap_ctx};
|
||||
use crate::runtime::sources as runtime_sources;
|
||||
use crate::services::batch_processor::AsyncBatchProcessor;
|
||||
use crate::storage_api_contracts::{
|
||||
@@ -1571,6 +1572,12 @@ pub struct SetDisks {
|
||||
get_object_metadata_cache: moka::future::Cache<GetObjectMetadataCacheKey, Arc<GetObjectMetadataCacheEntry>>,
|
||||
pub lockers: Vec<Arc<dyn LockClient>>,
|
||||
local_lock_manager: Arc<rustfs_lock::GlobalLockManager>,
|
||||
/// Per-instance runtime context (Phase 5, backlog#939).
|
||||
///
|
||||
/// The leaf of the object-graph ctx plumbing (ECStore → Sets → SetDisks).
|
||||
/// Slice 3 sources `local_lock_manager` from this context to give each
|
||||
/// instance its own lock namespace.
|
||||
ctx: Arc<InstanceContext>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
@@ -1716,6 +1723,10 @@ impl SetDisks {
|
||||
format: FormatV3,
|
||||
lockers: Vec<Arc<dyn LockClient>>,
|
||||
) -> Arc<Self> {
|
||||
// Single-instance sources the process bootstrap context (the one the
|
||||
// owning ECStore adopts). Slice 8 threads a per-instance context in for
|
||||
// true multi-instance.
|
||||
let ctx = bootstrap_ctx();
|
||||
Arc::new(SetDisks {
|
||||
locker_owner,
|
||||
disks,
|
||||
@@ -1731,10 +1742,26 @@ impl SetDisks {
|
||||
.time_to_live(GET_OBJECT_METADATA_CACHE_TTL)
|
||||
.build(),
|
||||
lockers,
|
||||
local_lock_manager: runtime_sources::global_lock_manager(),
|
||||
// Sourced from the instance context so each instance owns its lock
|
||||
// namespace (Phase 5 Slice 3). Single-instance: ctx aliases the
|
||||
// process lock-manager singleton, so this is unchanged.
|
||||
local_lock_manager: ctx.lock_manager(),
|
||||
ctx,
|
||||
})
|
||||
}
|
||||
|
||||
/// This set's per-instance runtime context (Phase 5, backlog#939).
|
||||
#[allow(dead_code)] // Read by tests; consumed by later slices.
|
||||
pub(crate) fn instance_ctx(&self) -> &Arc<InstanceContext> {
|
||||
&self.ctx
|
||||
}
|
||||
|
||||
/// The lock manager this set actually uses (test-only; Phase 5 Slice 3).
|
||||
#[cfg(test)]
|
||||
pub(crate) fn local_lock_manager_for_test(&self) -> &Arc<rustfs_lock::GlobalLockManager> {
|
||||
&self.local_lock_manager
|
||||
}
|
||||
|
||||
// async fn cached_disk_health(&self, index: usize) -> Option<bool> {
|
||||
// let cache = self.disk_health_cache.read().await;
|
||||
// cache
|
||||
|
||||
Reference in New Issue
Block a user