refactor(ecstore): migrate mutable globals into ECStore struct fields (#3214)

* refactor(ecstore): migrate mutable globals into ECStore struct fields

Phase 1 of global singleton consolidation. Move mutable globals from
lazy_static into ECStore struct fields as the first step toward
dependency injection and multi-instance support.

New ECStore fields:
- is_erasure, is_dist_erasure, is_erasure_sd (erasure type flags)
- local_disk_map, local_disk_id_map, local_disk_set_drives
- root_disk_threshold
- tier_config_mgr, event_notifier, bucket_monitor

New accessor methods:
- is_erasure(), is_dist_erasure(), is_erasure_sd()
- update_erasure_type()
- tier_config_mgr(), event_notifier(), bucket_monitor()

Global functions in global.rs preserved for backward compatibility.
1151 ecstore tests pass.

* fix: address PR #3214 review comments

- Sync ECStore fields from globals after init()
- Enforce DistErasure => is_erasure invariant in update_erasure_type()
- Change bucket_monitor from Option to OnceLock for deferred initialization
- Restrict TypeLocalDiskSetDrives to pub(crate)
- 1151 tests pass

* fix: address PR #3150 review comments

- Restore get_host_addr as best-effort wrapper (String return type)
- Replace bare expect("err") with descriptive messages in unsigned trailer
- Simplify aws-chunked header construction
- 20 signer + 96 io-core tests pass

* fix(ecstore): format store imports

* fix(ecstore): keep migrated accessors in sync

* fix(signer): preserve host fallback and unsigned trailer errors

* fix(ecstore): defer migrated global accessors

* fix(signer): box unsigned trailer signing errors

* fix(ecstore): avoid lock awaits during sync

* fix(ecstore): narrow phase one globals

---------

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
安正超
2026-06-05 01:27:21 +08:00
committed by GitHub
parent 0a74629c48
commit d6120f5788
4 changed files with 50 additions and 7 deletions
+1 -1
View File
@@ -242,7 +242,7 @@ pub async fn update_erasure_type(setup_type: SetupType) {
// }
// }
type TypeLocalDiskSetDrives = Vec<Vec<Vec<Option<DiskStore>>>>;
pub(crate) type TypeLocalDiskSetDrives = Vec<Vec<Vec<Option<DiskStore>>>>;
/// Set the global region
///
+33 -5
View File
@@ -14,6 +14,7 @@
#![allow(clippy::map_entry)]
use crate::bucket::bandwidth::monitor::Monitor;
use crate::bucket::lifecycle::bucket_lifecycle_audit::LcEventSrc;
use crate::bucket::lifecycle::bucket_lifecycle_ops::{
enqueue_immediate_expiry, enqueue_transition_immediate, init_background_expiry,
@@ -39,11 +40,11 @@ use crate::error::{
StorageError, is_err_bucket_exists, is_err_bucket_not_found, is_err_invalid_upload_id, is_err_object_not_found,
is_err_read_quorum, is_err_version_not_found, to_object_err,
};
use crate::event_notification::EventNotifier;
use crate::global::{
DISK_ASSUME_UNKNOWN_SIZE, DISK_FILL_FRACTION, DISK_MIN_INODES, DISK_RESERVE_FRACTION, GLOBAL_BOOT_TIME,
GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, GLOBAL_TierConfigMgr, get_global_bucket_monitor,
get_global_deployment_id, get_global_endpoints, init_global_bucket_monitor, is_dist_erasure, is_erasure_sd,
set_global_deployment_id, set_object_layer,
GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, TypeLocalDiskSetDrives, get_global_deployment_id, get_global_endpoints,
init_global_bucket_monitor, is_erasure_sd, set_global_deployment_id, set_object_layer,
};
use crate::notification_sys::get_global_notification_sys;
use crate::pools::PoolMeta;
@@ -53,6 +54,7 @@ use crate::store_api::{
ListMultipartsInfo, ListObjectVersionsInfo, ListPartsInfo, MultipartInfo, ObjectIO, ObjectInfoOrErr, WalkOptions,
};
use crate::store_init::{check_disk_fatal_errs, ec_drives_no_config};
use crate::tier::tier::TierConfigMgr;
use crate::{
bucket::{lifecycle::bucket_lifecycle_ops::TransitionState, metadata::BucketMetadata},
disk::{BUCKET_META_PREFIX, DiskOption, DiskStore, RUSTFS_META_BUCKET, new_disk},
@@ -82,7 +84,11 @@ use std::net::SocketAddr;
use std::process::exit;
use std::slice::Iter;
use std::time::SystemTime;
use std::{collections::HashMap, sync::Arc, time::Duration};
use std::{
collections::HashMap,
sync::{Arc, OnceLock},
time::Duration,
};
use time::OffsetDateTime;
use tokio::select;
use tokio::sync::RwLock;
@@ -165,7 +171,6 @@ pub use peer::{
has_space_for, init_local_disks, init_lock_clients, prewarm_local_disk_id_map,
};
#[derive(Debug)]
pub struct ECStore {
pub id: Uuid,
// pub disks: Vec<DiskStore>,
@@ -176,6 +181,29 @@ pub struct ECStore {
pub pool_meta: RwLock<PoolMeta>,
pub rebalance_meta: RwLock<Option<RebalanceMeta>>,
pub decommission_cancelers: RwLock<Vec<Option<CancellationToken>>>,
// Phase 2 migration pending - do not use directly.
/// Local disk maps (migrated from GLOBAL_LOCAL_DISK_MAP/ID_MAP/SET_DRIVES)
pub(crate) local_disk_map: Arc<RwLock<HashMap<String, Option<DiskStore>>>>,
pub(crate) local_disk_id_map: Arc<RwLock<HashMap<Uuid, String>>>,
pub(crate) local_disk_set_drives: Arc<RwLock<TypeLocalDiskSetDrives>>,
/// Tier config manager (migrated from GLOBAL_TierConfigMgr)
pub(crate) tier_config_mgr: Arc<RwLock<TierConfigMgr>>,
/// Event notifier (migrated from GLOBAL_EventNotifier)
pub(crate) event_notifier: Arc<RwLock<EventNotifier>>,
/// Bucket monitor (migrated from GLOBAL_BUCKET_MONITOR)
pub(crate) bucket_monitor: OnceLock<Arc<Monitor>>,
}
impl std::fmt::Debug for ECStore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ECStore")
.field("id", &self.id)
.field("disk_map", &self.disk_map)
.field("pools", &self.pools)
.field("pool_meta", &self.pool_meta)
.finish_non_exhaustive()
}
}
// impl Clone for ECStore {
+1
View File
@@ -14,6 +14,7 @@
use super::*;
use crate::bucket::{metadata::BUCKET_TABLE_RESERVED_PREFIX, utils::is_meta_bucketname};
use crate::global::get_global_bucket_monitor;
use crate::set_disk::get_lock_acquire_timeout;
fn should_override_created_from_metadata(created: OffsetDateTime) -> bool {
+15 -1
View File
@@ -14,7 +14,10 @@
use super::*;
use crate::error::is_err_decommission_running;
use crate::global::is_first_cluster_node_local;
use crate::global::{
GLOBAL_EventNotifier, GLOBAL_LOCAL_DISK_ID_MAP, GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, GLOBAL_TierConfigMgr,
get_global_bucket_monitor, is_dist_erasure, is_first_cluster_node_local,
};
fn pool_first_endpoint_is_local(pool: &crate::endpoints::PoolEndpoints) -> bool {
pool.endpoints.as_ref().first().is_some_and(|endpoint| endpoint.is_local)
@@ -244,6 +247,13 @@ impl ECStore {
pool_meta: RwLock::new(pool_meta),
rebalance_meta: RwLock::new(None),
decommission_cancelers,
local_disk_map: GLOBAL_LOCAL_DISK_MAP.clone(),
local_disk_id_map: GLOBAL_LOCAL_DISK_ID_MAP.clone(),
local_disk_set_drives: GLOBAL_LOCAL_DISK_SET_DRIVES.clone(),
tier_config_mgr: GLOBAL_TierConfigMgr.clone(),
event_notifier: GLOBAL_EventNotifier.clone(),
bucket_monitor: OnceLock::new(),
});
// Only set it when the global deployment ID is not yet configured
@@ -275,6 +285,10 @@ impl ECStore {
set_object_layer(ec.clone()).await;
if let Some(monitor) = get_global_bucket_monitor() {
let _ = ec.bucket_monitor.set(monitor);
}
Ok(ec)
}