refactor: align storage runtime facade helpers (#3946)

This commit is contained in:
Zhengchao An
2026-06-27 14:55:37 +08:00
committed by GitHub
parent 261e16a446
commit 7979ecb545
20 changed files with 140 additions and 126 deletions
+28 -9
View File
@@ -5,7 +5,7 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
## Current Context
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
- Branch: `overtrue/arch-global-runtime-owner-consumer-batch`
- Branch: `overtrue/arch-global-storage-runtime-consumer-batch`
- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181/API-182/API-183/API-184/API-185/API-186/API-187/API-188/API-189/API-190/API-191/API-192/API-193/API-194/API-195/API-196/API-197/API-198/API-199/API-200/API-201/API-202/API-203/API-204/API-205/API-206/API-207/API-208/API-209/API-210/API-211/API-212/API-213/API-214/API-215/API-216/API-217/API-218/API-219/API-220/API-221/API-222/API-223/API-224/API-225/API-226/API-227/API-228/API-229/API-230/API-231/API-232/API-233/API-234/API-235/API-236/API-237/API-238/API-239/API-240/API-241/API-242/API-243/API-244/API-245/API-246/API-247/API-248/API-249/API-250/API-251/API-252/API-253/API-254/CTX-002`.
- Current baseline also includes API-255 from PR #3923, API-256 from PR
#3925, CFG-009 from PR #3927, C-007/C-009 from PR #3935, C-008/C-010
@@ -15,17 +15,17 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
the first GLOB-007 admin runtime context handoff from PR #3942, and the
GLOB-007 admin object-store/notification/server-config consumer batch from
PR #3943.
- Current phase PR: GLOB-007 admin runtime helper alias batch.
- Based on: `origin/main` after PR #3943 merged.
- Current phase PR: GLOB-007 storage/server runtime facade consumer batch.
- Based on: `origin/main` after PR #3944 merged.
- PR type for this branch: `ci-gate`.
- Runtime behavior changes: none intended.
- Rust code changes: route remaining admin IAM, KMS, OIDC, action-credential,
region, endpoint, replication, tier, scanner, TLS, and system runtime-source
reads through admin `current_*` helper names while preserving the existing
AppContext-first resolver behavior and fallback boundaries.
- Rust code changes: rename storage and server runtime facade accessors to
`current_*`, route storage access, ECFS extension, and node-service RPC
object-store lookups through the storage runtime facade, and remove the old
storage object-store resolver re-export.
- CI/script changes: none intended.
- Docs changes: update this progress ledger for the admin runtime helper alias
batch.
- Docs changes: update this progress ledger for the storage/server runtime
facade consumer batch.
## Phase 0 Tasks
@@ -2790,6 +2790,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
- Current slice: route remaining admin runtime-source reads for IAM, KMS,
OIDC, action credentials, region, endpoint, replication, tier, scanner,
TLS, and system runtime handles through admin `current_*` helper names.
- Current slice: route storage and server runtime consumers through
`current_*` facade helpers, remove the old storage object-store resolver
re-export, and keep all resolver fallback behavior unchanged.
- Remaining work: remove one fallback family per PR only after scans prove no
production caller depends on it; this slice keeps the fallback behavior
because broader app/storage/server consumers still use the root resolvers.
@@ -6059,6 +6062,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Expert | Status | Notes |
|---|---|---|
| Quality/architecture | pass | GLOB-007 renames storage and server runtime-source facade reads to `current_*`, moves remaining storage access/ECFS extension/RPC node-service object-store lookups behind the storage runtime facade, and removes the old storage object-store resolver re-export. |
| Migration preservation | pass | The facade helpers still delegate to the same root runtime resolvers, so storage authorization, ECFS validation, decommission RPC, server readiness, audit, event, layer, and module-switch behavior stays unchanged. |
| Testing/verification | pass | Focused compile, formatting, architecture guard, diff hygiene, storage/server resolver residual scan, and diff-added Rust risk scan are required before the full PR gate. |
| Quality/architecture | pass | GLOB-007 adds admin `current_*` helper aliases for the remaining runtime-source families and moves admin IAM, KMS, OIDC, action-credential, region, endpoint, replication, tier, scanner, TLS, and system consumers off direct root resolver names. |
| Migration preservation | pass | The helper aliases delegate to the same AppContext-first runtime resolvers and keep all existing fallback paths, so this is a naming/boundary cleanup with no admin auth, IAM, KMS, replication, tier, scanner, TLS, or route behavior change. |
| Testing/verification | pass | RustFS lib compile, formatting, architecture guard, diff hygiene, admin resolver residual scan, and diff-added Rust risk scan passed before the full PR gate. |
@@ -6425,6 +6431,19 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
Passed before push:
- Issue #660 GLOB-007 storage/server runtime facade consumer slice:
- Branch freshness check: rebased onto `origin/main` after PR #3944 merged.
- `cargo check -p rustfs --lib`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- Storage/server resolver residual scan: passed.
- Diff-added Rust risk scan: passed; no new production unwrap/expect,
unchecked narrow casts, or ad-hoc stdout/stderr.
- Three-expert review: passed.
- `make pre-pr`: passed, including 6912 nextest tests passed, 112 skipped,
and doctests.
- Issue #660 GLOB-007 admin runtime helper alias slice:
- Branch freshness check: created from `origin/main` after PR #3943 merged.
- `cargo check -p rustfs --lib`: passed.
+1 -1
View File
@@ -20,7 +20,7 @@ use tracing::{info, warn};
static AUDIT_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_AUDIT_ENABLE);
fn server_config_from_context() -> Option<rustfs_config::server_config::Config> {
runtime_sources::server_config()
runtime_sources::current_server_config()
}
pub fn refresh_audit_module_enabled() -> bool {
+2 -2
View File
@@ -25,7 +25,7 @@ use tracing::{error, info, instrument, warn};
static NOTIFY_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_NOTIFY_ENABLE);
fn server_config_from_context() -> Option<rustfs_config::server_config::Config> {
runtime_sources::server_config()
runtime_sources::current_server_config()
}
pub fn refresh_notify_module_enabled() -> bool {
@@ -117,7 +117,7 @@ fn install_ecstore_event_dispatch_hook() {
return;
};
spawn(async move {
runtime_sources::notify_interface().notify(notify_args).await;
runtime_sources::current_notify_interface().notify(notify_args).await;
});
});
+1 -1
View File
@@ -906,7 +906,7 @@ fn is_public_health_endpoint_request(method: &Method, path: &str) -> bool {
}
async fn health_kms_ready() -> bool {
let Some(service_manager) = runtime_sources::kms_runtime_service_manager() else {
let Some(service_manager) = runtime_sources::current_kms_runtime_service_manager() else {
return true;
};
+2 -2
View File
@@ -159,7 +159,7 @@ pub(crate) fn validate_module_switch_update(requested: PersistedModuleSwitches)
}
pub(crate) async fn refresh_persisted_module_switches_from_store() -> Result<PersistedModuleSwitches, String> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err("storage layer not initialized".to_string());
};
@@ -180,7 +180,7 @@ pub(crate) async fn refresh_persisted_module_switches_from_store() -> Result<Per
}
pub(crate) async fn save_persisted_module_switches_to_store(config: PersistedModuleSwitches) -> Result<(), String> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err("storage layer not initialized".to_string());
};
+10 -10
View File
@@ -560,7 +560,7 @@ fn collect_peer_health_readiness() -> bool {
return true;
}
runtime_sources::endpoints_handle()
runtime_sources::current_endpoints_handle()
.as_ref()
.is_some_and(peer_health_ready_from_endpoint_pools)
}
@@ -605,7 +605,7 @@ fn dependency_readiness_report_from_readiness(readiness: DependencyReadiness) ->
}
pub async fn collect_dependency_readiness_report() -> DependencyReadinessReport {
let iam_ready_raw = runtime_sources::iam_ready();
let iam_ready_raw = runtime_sources::current_iam_ready();
let storage_ready = if let Some(cached) = load_cached_storage_readiness().await {
cached
} else {
@@ -636,8 +636,8 @@ pub async fn collect_cluster_read_health_report() -> DependencyReadinessReport {
pub async fn collect_node_readiness_report() -> DependencyReadinessReport {
let readiness = DependencyReadiness {
storage_ready: runtime_sources::object_store_handle().is_some(),
iam_ready: runtime_sources::iam_ready(),
storage_ready: runtime_sources::current_object_store_handle().is_some(),
iam_ready: runtime_sources::current_iam_ready(),
lock_quorum_ready: collect_lock_quorum_status().await.ready,
peer_health_ready: collect_peer_health_readiness(),
};
@@ -688,7 +688,7 @@ async fn collect_node_readiness() -> DependencyReadiness {
}
pub async fn collect_cluster_read_dependency_readiness_report() -> DependencyReadinessReport {
let iam_ready_raw = runtime_sources::iam_ready();
let iam_ready_raw = runtime_sources::current_iam_ready();
let storage_ready = collect_storage_read_readiness_uncached().await;
let lock_quorum_status = collect_lock_quorum_status().await;
@@ -706,7 +706,7 @@ pub async fn collect_cluster_read_dependency_readiness_report() -> DependencyRea
pub(crate) async fn snapshot_dependency_readiness_report() -> DependencyReadinessReport {
let readiness = DependencyReadiness {
storage_ready: collect_storage_readiness_uncached().await,
iam_ready: runtime_sources::iam_ready(),
iam_ready: runtime_sources::current_iam_ready(),
lock_quorum_ready: collect_lock_quorum_status_uncached().await.ready,
peer_health_ready: collect_peer_health_readiness(),
};
@@ -725,7 +725,7 @@ async fn collect_lock_quorum_status() -> LockQuorumStatus {
}
async fn collect_storage_readiness_uncached() -> bool {
if let Some(store) = runtime_sources::object_store_handle() {
if let Some(store) = runtime_sources::current_object_store_handle() {
let storage_info = StorageAdminApi::storage_info(store.as_ref()).await;
storage_ready_from_runtime_state(&storage_info)
} else {
@@ -734,7 +734,7 @@ async fn collect_storage_readiness_uncached() -> bool {
}
async fn collect_storage_read_readiness_uncached() -> bool {
if let Some(store) = runtime_sources::object_store_handle() {
if let Some(store) = runtime_sources::current_object_store_handle() {
let storage_info = StorageAdminApi::storage_info(store.as_ref()).await;
storage_read_ready_from_runtime_state(&storage_info)
} else {
@@ -825,10 +825,10 @@ async fn collect_lock_quorum_status_uncached() -> LockQuorumStatus {
};
}
let Some(pool_endpoints) = runtime_sources::endpoints_handle() else {
let Some(pool_endpoints) = runtime_sources::current_endpoints_handle() else {
return LockQuorumStatus::default();
};
let Some(lock_clients) = runtime_sources::lock_clients_handle() else {
let Some(lock_clients) = runtime_sources::current_lock_clients_handle() else {
return LockQuorumStatus::default();
};
+7 -7
View File
@@ -22,30 +22,30 @@ use rustfs_lock::LockClient;
use std::collections::HashMap;
use std::sync::Arc;
pub(crate) fn kms_runtime_service_manager() -> Option<Arc<KmsServiceManager>> {
pub(crate) fn current_kms_runtime_service_manager() -> Option<Arc<KmsServiceManager>> {
resolve_kms_runtime_service_manager()
}
pub(crate) fn server_config() -> Option<rustfs_config::server_config::Config> {
pub(crate) fn current_server_config() -> Option<rustfs_config::server_config::Config> {
resolve_server_config()
}
pub(crate) fn notify_interface() -> Arc<dyn NotifyInterface> {
pub(crate) fn current_notify_interface() -> Arc<dyn NotifyInterface> {
resolve_notify_interface()
}
pub(crate) fn object_store_handle() -> Option<Arc<ECStore>> {
pub(crate) fn current_object_store_handle() -> Option<Arc<ECStore>> {
resolve_object_store_handle()
}
pub(crate) fn iam_ready() -> bool {
pub(crate) fn current_iam_ready() -> bool {
resolve_iam_ready()
}
pub(crate) fn endpoints_handle() -> Option<EndpointServerPools> {
pub(crate) fn current_endpoints_handle() -> Option<EndpointServerPools> {
resolve_endpoints_handle()
}
pub(crate) fn lock_clients_handle() -> Option<HashMap<String, Arc<dyn LockClient>>> {
pub(crate) fn current_lock_clients_handle() -> Option<HashMap<String, Arc<dyn LockClient>>> {
resolve_lock_clients_handle()
}
+6 -6
View File
@@ -14,7 +14,6 @@
use super::ECStore;
use super::ecfs::FS;
use super::resolve_object_store_handle;
use super::{
PolicySys, StorageError, get_bucket_metadata, get_bucket_policy_raw, get_public_access_block_config, is_err_bucket_not_found,
};
@@ -328,7 +327,7 @@ pub async fn authorize_request<T>(req: &mut S3Request<T>, action: Action) -> S3R
let version_id = req_info.version_id.clone();
if let Some(cred) = &cred {
let Ok(iam_store) = runtime_sources::ready_iam_handle() else {
let Ok(iam_store) = runtime_sources::current_ready_iam_handle() else {
return Err(S3Error::with_message(
S3ErrorCode::InternalError,
format!("authorize_request {:?}", IamError::IamSysNotInitialized),
@@ -785,7 +784,8 @@ fn table_data_plane_admin_action(action: Action) -> Option<AdminAction> {
}
fn table_catalog_store_for_data_plane() -> S3Result<crate::table_catalog::EcStoreTableCatalogStore<ECStore>> {
let store = resolve_object_store_handle().ok_or_else(|| s3_error!(InternalError, "object store not initialized"))?;
let store =
runtime_sources::current_object_store_handle().ok_or_else(|| s3_error!(InternalError, "object store not initialized"))?;
let backend = crate::table_catalog::EcStoreTableCatalogObjectBackend::new(store);
Ok(crate::table_catalog::ObjectTableCatalogStore::new(backend))
}
@@ -841,7 +841,7 @@ async fn authorize_table_data_plane_if_needed(
let Some(resource) = table_data_plane_resource_for_request(bucket, object).await? else {
return Ok(());
};
let Ok(iam_store) = runtime_sources::ready_iam_handle() else {
let Ok(iam_store) = runtime_sources::current_ready_iam_handle() else {
return Err(s3_error!(InternalError, "iam not init"));
};
@@ -931,7 +931,7 @@ impl S3Access for FS {
let req_info = ReqInfo {
cred,
is_owner,
region: runtime_sources::region(),
region: runtime_sources::current_region(),
request_context,
..Default::default()
};
@@ -1184,7 +1184,7 @@ impl S3Access for FS {
///
/// This method returns `Ok(())` by default.
async fn delete_object(&self, req: &mut S3Request<DeleteObjectInput>) -> S3Result<()> {
if let Some(store) = resolve_object_store_handle()
if let Some(store) = runtime_sources::current_object_store_handle()
&& let Err(err) = store.get_bucket_info(&req.input.bucket, &Default::default()).await
&& is_err_bucket_not_found(&err)
{
+2 -2
View File
@@ -118,7 +118,7 @@ impl ConcurrencyManager {
// Use global performance metrics instance for consistent metrics tracking
// This allows AutoTuner and other components to access the same metrics data
let performance_metrics = runtime_sources::performance_metrics();
let performance_metrics = runtime_sources::current_performance_metrics();
// Initialize metrics collector for I/O latency tracking
// Keep 1000 samples for P95/P99 calculation
@@ -235,7 +235,7 @@ impl ConcurrencyManager {
///
/// Arc-wrapped PerformanceMetrics instance
pub fn performance_metrics(&self) -> Arc<PerformanceMetrics> {
runtime_sources::performance_metrics()
runtime_sources::current_performance_metrics()
}
/// Calculate an adaptive I/O strategy based on disk permit wait time.
+23 -23
View File
@@ -99,7 +99,7 @@ impl FS {
object: &str,
version_id: Option<&str>,
) -> S3Result<std::collections::HashMap<String, Vec<String>>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Ok(std::collections::HashMap::new());
};
let opts = ObjectOptions {
@@ -343,7 +343,7 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketWebsiteInput>,
) -> S3Result<S3Response<DeleteBucketWebsiteOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
@@ -392,7 +392,7 @@ impl S3 for FS {
validate_table_catalog_object_mutation(&bucket, &object).await?;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
error!(
component = LOG_COMPONENT_STORAGE,
subsystem = LOG_SUBSYSTEM_TAGGING,
@@ -474,7 +474,7 @@ impl S3 for FS {
record_s3_op(S3Operation::GetBucketAcl, &req.input.bucket);
let GetBucketAclInput { bucket, .. } = req.input;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -490,7 +490,7 @@ impl S3 for FS {
&self,
req: S3Request<GetBucketAccelerateConfigurationInput>,
) -> S3Result<S3Response<GetBucketAccelerateConfigurationOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
@@ -580,7 +580,7 @@ impl S3 for FS {
&self,
req: S3Request<GetBucketRequestPaymentInput>,
) -> S3Result<S3Response<GetBucketRequestPaymentOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
@@ -628,7 +628,7 @@ impl S3 for FS {
}
async fn get_bucket_website(&self, req: S3Request<GetBucketWebsiteInput>) -> S3Result<S3Response<GetBucketWebsiteOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
@@ -666,7 +666,7 @@ impl S3 for FS {
bucket, key, version_id, ..
} = req.input;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -696,7 +696,7 @@ impl S3 for FS {
bucket, key, version_id, ..
} = req.input.clone();
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -757,7 +757,7 @@ impl S3 for FS {
record_s3_op(S3Operation::GetObjectLockConfiguration, &req.input.bucket);
let GetObjectLockConfigurationInput { bucket, .. } = req.input;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -805,7 +805,7 @@ impl S3 for FS {
bucket, key, version_id, ..
} = req.input.clone();
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -857,7 +857,7 @@ impl S3 for FS {
let bucket = req.input.bucket.as_str();
let object = req.input.key.as_str();
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
error!(
component = LOG_COMPONENT_STORAGE,
subsystem = LOG_SUBSYSTEM_TAGGING,
@@ -1015,7 +1015,7 @@ impl S3 for FS {
} = req.input;
record_s3_op(S3Operation::PutBucketAcl, &bucket);
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -1038,7 +1038,7 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketAccelerateConfigurationInput>,
) -> S3Result<S3Response<PutBucketAccelerateConfigurationOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
store
@@ -1063,7 +1063,7 @@ impl S3 for FS {
async fn get_bucket_logging(&self, req: S3Request<GetBucketLoggingInput>) -> S3Result<S3Response<GetBucketLoggingOutput>> {
record_s3_op(S3Operation::GetBucketLogging, &req.input.bucket);
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
store
@@ -1082,7 +1082,7 @@ impl S3 for FS {
async fn put_bucket_logging(&self, req: S3Request<PutBucketLoggingInput>) -> S3Result<S3Response<PutBucketLoggingOutput>> {
record_s3_op(S3Operation::PutBucketLogging, &req.input.bucket);
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
store
@@ -1141,7 +1141,7 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketRequestPaymentInput>,
) -> S3Result<S3Response<PutBucketRequestPaymentOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
store
@@ -1183,7 +1183,7 @@ impl S3 for FS {
}
async fn put_bucket_website(&self, req: S3Request<PutBucketWebsiteInput>) -> S3Result<S3Response<PutBucketWebsiteOutput>> {
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(s3_error!(InternalError, "Not init"));
};
store
@@ -1213,7 +1213,7 @@ impl S3 for FS {
let key = &req.input.key;
let version_id = req.input.version_id.clone();
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -1255,7 +1255,7 @@ impl S3 for FS {
validate_table_catalog_object_mutation(&bucket, &key).await?;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -1309,7 +1309,7 @@ impl S3 for FS {
let Some(input_cfg) = object_lock_configuration else { return Err(s3_error!(InvalidArgument)) };
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -1381,7 +1381,7 @@ impl S3 for FS {
validate_table_catalog_object_mutation(&bucket, &key).await?;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -1460,7 +1460,7 @@ impl S3 for FS {
crate::storage::s3_api::tagging::validate_object_tag_set(&tagging.tag_set)?;
let Some(store) = runtime_sources::object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
+2 -3
View File
@@ -15,7 +15,6 @@
use super::StorageReplicationConfigExt as _;
use super::{
StorageError, add_object_lock_years, get_bucket_cors_config, get_bucket_object_lock_config, get_bucket_replication_config,
resolve_object_store_handle,
};
use crate::config::{RustFSBufferConfig, WorkloadProfile, is_buffer_profile_enabled};
use crate::error::ApiError;
@@ -266,7 +265,7 @@ pub(crate) fn get_adaptive_buffer_size_with_profile(file_size: i64, profile: Opt
pub(crate) fn get_buffer_size_opt_in(file_size: i64) -> usize {
let buffer_size = if is_buffer_profile_enabled() {
// Use the AppContext-owned profile when available, with global fallback during migration.
let config = runtime_sources::buffer_config();
let config = runtime_sources::current_buffer_config();
config.get_buffer_size(file_size)
} else {
// Opt-out mode: Use GeneralPurpose profile for consistent behavior
@@ -748,7 +747,7 @@ pub(crate) async fn has_replication_rules(bucket: &str, objects: &[ObjectToDelet
/// Helper function to get store and validate bucket exists
pub(crate) async fn get_validated_store(bucket: &str) -> S3Result<Arc<super::ECStore>> {
let Some(store) = resolve_object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
+2 -2
View File
@@ -312,7 +312,7 @@ impl OperationHelper {
final_builder = final_builder.error(err);
}
if let Some(cred) = runtime_sources::action_credentials() {
if let Some(cred) = runtime_sources::current_action_credentials() {
final_builder = final_builder.access_key(&cred.access_key);
}
@@ -383,7 +383,7 @@ impl Drop for OperationHelper {
if !event_args.is_replication_request() {
let ctx = state.request_context.clone();
spawn_background_with_context(ctx, async move {
runtime_sources::notify_interface().notify(event_args).await;
runtime_sources::current_notify_interface().notify(event_args).await;
});
}
}
+5 -5
View File
@@ -75,11 +75,11 @@ pub(crate) use storage_api::{
is_err_bucket_not_found, is_err_object_not_found, is_err_version_not_found, is_valid_storage_class, load_bucket_metadata,
new_global_notification_sys, new_object_layer_fn, options_consumer, prewarm_local_disk_id_map, read_config,
record_replication_proxy, register_event_dispatch_hook, reload_transition_tier_config, replication_queue_current_count,
resolve_object_store_handle, rpc_consumer, runtime_sources_consumer, s3_api_consumer, save_config, serialize,
set_bucket_metadata, set_global_endpoints, set_global_region, set_global_rustfs_port, set_object_store_resolver,
set_workload_admission_snapshot_provider, shutdown_background_services, table_catalog_path_hash, to_s3s_etag,
topology_snapshot_from_endpoint_pools_with_capabilities, try_migrate_bucket_metadata, try_migrate_iam_config,
try_migrate_server_config, update_bucket_metadata_config, update_erasure_type, verify_rpc_signature, wrap_reader,
rpc_consumer, runtime_sources_consumer, s3_api_consumer, save_config, serialize, set_bucket_metadata, set_global_endpoints,
set_global_region, set_global_rustfs_port, set_object_store_resolver, set_workload_admission_snapshot_provider,
shutdown_background_services, table_catalog_path_hash, to_s3s_etag, topology_snapshot_from_endpoint_pools_with_capabilities,
try_migrate_bucket_metadata, try_migrate_iam_config, try_migrate_server_config, update_bucket_metadata_config,
update_erasure_type, verify_rpc_signature, wrap_reader,
};
#[cfg(test)]
+2 -2
View File
@@ -961,7 +961,7 @@ impl NodeService {
pub(super) async fn handle_write_all(&self, request: Request<WriteAllRequest>) -> Result<Response<WriteAllResponse>, Status> {
let request = request.into_inner();
let data_len = request.data.len();
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
metrics.record_incoming_request_for_operation_and_backend(
INTERNODE_OPERATION_GRPC_WRITE_ALL,
INTERNODE_TRANSPORT_BACKEND_GRPC,
@@ -1001,7 +1001,7 @@ impl NodeService {
debug!("read all");
let request = request.into_inner();
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
metrics.record_incoming_request_for_operation_and_backend(
INTERNODE_OPERATION_GRPC_READ_ALL,
INTERNODE_TRANSPORT_BACKEND_GRPC,
+6 -6
View File
@@ -30,7 +30,7 @@ impl NodeService {
&self,
_request: Request<GetProcInfoRequest>,
) -> Result<Response<GetProcInfoResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_proc_info(&addr);
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetProcInfoResponse {
@@ -50,7 +50,7 @@ impl NodeService {
&self,
_request: Request<GetMemInfoRequest>,
) -> Result<Response<GetMemInfoResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_mem_info(&addr);
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetMemInfoResponse {
@@ -70,7 +70,7 @@ impl NodeService {
&self,
_request: Request<GetSysErrorsRequest>,
) -> Result<Response<GetSysErrorsResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_sys_errors(&addr);
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetSysErrorsResponse {
@@ -90,7 +90,7 @@ impl NodeService {
&self,
_request: Request<GetSysConfigRequest>,
) -> Result<Response<GetSysConfigResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_sys_config(&addr);
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetSysConfigResponse {
@@ -110,7 +110,7 @@ impl NodeService {
&self,
_request: Request<GetSeLinuxInfoRequest>,
) -> Result<Response<GetSeLinuxInfoResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_sys_services(&addr);
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetSeLinuxInfoResponse {
@@ -168,7 +168,7 @@ impl NodeService {
&self,
_request: Request<GetNetInfoRequest>,
) -> Result<Response<GetNetInfoResponse>, Status> {
let addr = runtime_sources::local_node_name().await;
let addr = runtime_sources::current_local_node_name().await;
let info = get_net_info(&addr, "");
match encode_msgpack_map(&info) {
Ok(buf) => Ok(Response::new(GetNetInfoResponse {
+7 -7
View File
@@ -300,7 +300,7 @@ async fn handle_internode_rpc(req: Request<Incoming>) -> Response<Body> {
}
if let Some(operation) = operation {
runtime_sources::internode_metrics().record_duration_for_operation_and_backend(
runtime_sources::current_internode_metrics().record_duration_for_operation_and_backend(
operation,
INTERNODE_TRANSPORT_BACKEND_TCP_HTTP,
started_at.elapsed(),
@@ -320,7 +320,7 @@ fn internode_http_operation(path: &str) -> Option<&'static str> {
}
fn record_internode_rpc_error(operation: Option<&'static str>) {
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
match operation {
Some(operation) => metrics.record_error_for_operation_and_backend(operation, INTERNODE_TRANSPORT_BACKEND_TCP_HTTP),
None => metrics.record_error(),
@@ -408,7 +408,7 @@ async fn handle_read_file(req: Request<Incoming>) -> Response<Body> {
}
};
runtime_sources::internode_metrics().record_incoming_request_for_operation_and_backend(
runtime_sources::current_internode_metrics().record_incoming_request_for_operation_and_backend(
INTERNODE_OPERATION_READ_FILE_STREAM,
INTERNODE_TRANSPORT_BACKEND_TCP_HTTP,
);
@@ -428,7 +428,7 @@ fn read_file_body_stream<R>(
where
R: tokio::io::AsyncRead + Unpin + Send + Sync + 'static,
{
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
let stream = ReaderStream::with_capacity(reader, DEFAULT_READ_BUFFER_SIZE).map_ok(move |bytes| {
metrics.record_sent_bytes_for_operation_and_backend(operation, INTERNODE_TRANSPORT_BACKEND_TCP_HTTP, bytes.len());
bytes
@@ -543,9 +543,9 @@ async fn handle_walk_dir(req: Request<Incoming>) -> Response<Body> {
}
});
runtime_sources::internode_metrics()
runtime_sources::current_internode_metrics()
.record_incoming_request_for_operation_and_backend(INTERNODE_OPERATION_WALK_DIR, INTERNODE_TRANSPORT_BACKEND_TCP_HTTP);
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
let stream = ReaderStream::with_capacity(rd, DEFAULT_READ_BUFFER_SIZE).map_ok(move |bytes| {
metrics.record_sent_bytes_for_operation_and_backend(
INTERNODE_OPERATION_WALK_DIR,
@@ -612,7 +612,7 @@ async fn handle_put_file(req: Request<Incoming>) -> Response<Body> {
}
};
let metrics = runtime_sources::internode_metrics();
let metrics = runtime_sources::current_internode_metrics();
metrics.record_incoming_request_for_operation_and_backend(
INTERNODE_OPERATION_PUT_FILE_STREAM,
INTERNODE_TRANSPORT_BACKEND_TCP_HTTP,
+14 -14
View File
@@ -23,7 +23,7 @@ use crate::storage::storage_api::rpc_consumer::node_service::{CollectMetricsOpts
use crate::storage::storage_api::rpc_consumer::node_service::{
DiskStore, ECStore, Error, LocalPeerS3Client, PEER_RESTSIGNAL, PEER_RESTSUB_SYS, SERVICE_SIGNAL_REFRESH_CONFIG,
SERVICE_SIGNAL_RELOAD_DYNAMIC, StorageDiskRpcExt as _, StorageResult, all_local_disk_path, find_local_disk_by_ref,
reload_transition_tier_config, resolve_object_store_handle,
reload_transition_tier_config,
};
use crate::storage::storage_api::runtime_sources_consumer::runtime_sources;
use bytes::Bytes;
@@ -194,7 +194,7 @@ pub fn make_server_for_context(context: Option<Arc<runtime_sources::AppContext>>
impl NodeService {
fn resolve_object_store(&self) -> Option<Arc<ECStore>> {
let context = self.context.clone().or_else(runtime_sources::current_app_context);
runtime_sources::object_store_handle_for_context(context.as_deref())
runtime_sources::current_object_store_handle_for_context(context.as_deref())
}
async fn find_disk(&self, disk_path: &str) -> Option<DiskStore> {
@@ -207,7 +207,7 @@ impl NodeService {
/// Get the lock client, returning an error if not initialized
fn get_lock_client(&self) -> Result<Arc<dyn LockClient>, Status> {
runtime_sources::lock_client()
runtime_sources::current_lock_client()
.ok_or_else(|| Status::internal("Lock client not initialized. Please ensure storage is initialized first."))
}
}
@@ -666,7 +666,7 @@ impl Node for NodeService {
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(DeletePolicyResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -695,7 +695,7 @@ impl Node for NodeService {
error_info: Some("policy name is missing".to_string()),
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(LoadPolicyResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -734,7 +734,7 @@ impl Node for NodeService {
}));
};
let is_group = request.is_group;
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(LoadPolicyMappingResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -762,7 +762,7 @@ impl Node for NodeService {
error_info: Some("access_key name is missing".to_string()),
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(DeleteUserResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -794,7 +794,7 @@ impl Node for NodeService {
error_info: Some("access_key name is missing".to_string()),
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(DeleteServiceAccountResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -824,7 +824,7 @@ impl Node for NodeService {
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(LoadUserResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -860,7 +860,7 @@ impl Node for NodeService {
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(LoadServiceAccountResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -891,7 +891,7 @@ impl Node for NodeService {
}));
}
let Some(iam_sys) = runtime_sources::iam_handle() else {
let Some(iam_sys) = runtime_sources::current_iam_handle() else {
return Ok(Response::new(LoadGroupResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -1094,7 +1094,7 @@ impl Node for NodeService {
&self,
request: Request<StartDecommissionRequest>,
) -> Result<Response<StartDecommissionResponse>, Status> {
let Some(store) = resolve_object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Ok(Response::new(StartDecommissionResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -1125,7 +1125,7 @@ impl Node for NodeService {
&self,
request: Request<CancelDecommissionRequest>,
) -> Result<Response<CancelDecommissionResponse>, Status> {
let Some(store) = resolve_object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Ok(Response::new(CancelDecommissionResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
@@ -1157,7 +1157,7 @@ impl Node for NodeService {
&self,
request: Request<ClearDecommissionRequest>,
) -> Result<Response<ClearDecommissionResponse>, Status> {
let Some(store) = resolve_object_store_handle() else {
let Some(store) = runtime_sources::current_object_store_handle() else {
return Ok(Response::new(ClearDecommissionResponse {
success: false,
error_info: Some("errServerNotInitialized".to_string()),
+13 -13
View File
@@ -28,54 +28,54 @@ pub(crate) fn current_app_context() -> Option<Arc<AppContext>> {
root_runtime_sources::current_app_context()
}
pub(crate) fn object_store_handle() -> Option<Arc<ECStore>> {
pub(crate) fn current_object_store_handle() -> Option<Arc<ECStore>> {
root_runtime_sources::resolve_object_store_handle()
}
pub(crate) fn object_store_handle_for_context(context: Option<&AppContext>) -> Option<Arc<ECStore>> {
pub(crate) fn current_object_store_handle_for_context(context: Option<&AppContext>) -> Option<Arc<ECStore>> {
root_runtime_sources::resolve_object_store_handle_for_context(context)
}
pub(crate) fn buffer_config() -> RustFSBufferConfig {
pub(crate) fn current_buffer_config() -> RustFSBufferConfig {
root_runtime_sources::resolve_buffer_config()
}
pub(crate) fn internode_metrics() -> Arc<InternodeMetrics> {
pub(crate) fn current_internode_metrics() -> Arc<InternodeMetrics> {
root_runtime_sources::resolve_internode_metrics()
}
pub(crate) async fn local_node_name() -> String {
pub(crate) async fn current_local_node_name() -> String {
root_runtime_sources::resolve_local_node_name().await
}
pub(crate) fn action_credentials() -> Option<Credentials> {
pub(crate) fn current_action_credentials() -> Option<Credentials> {
root_runtime_sources::resolve_action_credentials()
}
pub(crate) fn notify_interface() -> Arc<dyn root_runtime_sources::NotifyInterface> {
pub(crate) fn current_notify_interface() -> Arc<dyn root_runtime_sources::NotifyInterface> {
root_runtime_sources::resolve_notify_interface()
}
pub(crate) fn performance_metrics() -> Arc<PerformanceMetrics> {
pub(crate) fn current_performance_metrics() -> Arc<PerformanceMetrics> {
root_runtime_sources::resolve_performance_metrics()
}
pub(crate) async fn encryption_service() -> Option<Arc<ObjectEncryptionService>> {
pub(crate) async fn current_encryption_service() -> Option<Arc<ObjectEncryptionService>> {
root_runtime_sources::resolve_encryption_service().await
}
pub(crate) fn region() -> Option<s3s::region::Region> {
pub(crate) fn current_region() -> Option<s3s::region::Region> {
root_runtime_sources::resolve_region()
}
pub(crate) fn ready_iam_handle() -> IamResult<Arc<IamSys<ObjectStore>>> {
pub(crate) fn current_ready_iam_handle() -> IamResult<Arc<IamSys<ObjectStore>>> {
root_runtime_sources::resolve_ready_iam_handle()
}
pub(crate) fn iam_handle() -> Option<Arc<IamSys<ObjectStore>>> {
pub(crate) fn current_iam_handle() -> Option<Arc<IamSys<ObjectStore>>> {
root_runtime_sources::resolve_iam_handle()
}
pub(crate) fn lock_client() -> Option<Arc<dyn LockClient>> {
pub(crate) fn current_lock_client() -> Option<Arc<dyn LockClient>> {
root_runtime_sources::resolve_lock_client()
}
+4 -4
View File
@@ -1533,7 +1533,7 @@ async fn apply_managed_encryption_material(
let mut kms_key_candidate = kms_key_id.clone();
if kms_key_candidate.is_none() {
// Try to get default key from KMS service (if available)
if let Some(service) = runtime_sources::encryption_service().await {
if let Some(service) = runtime_sources::current_encryption_service().await {
kms_key_candidate = service.get_default_key_id().cloned();
}
}
@@ -1626,7 +1626,7 @@ async fn apply_managed_decryption_material(
.cloned()
.unwrap_or_else(|| "AES256".to_string()),
)
} else if let Some(service) = runtime_sources::encryption_service().await {
} else if let Some(service) = runtime_sources::current_encryption_service().await {
// Production mode: use service for metadata parsing
let parsed = service
.headers_to_metadata(&normalized_metadata)
@@ -1804,7 +1804,7 @@ impl KmsSseDekProvider {
}
async fn current_service() -> Option<Arc<rustfs_kms::service::ObjectEncryptionService>> {
runtime_sources::encryption_service().await
runtime_sources::current_encryption_service().await
}
}
@@ -2082,7 +2082,7 @@ static GLOBAL_SSE_DEK_PROVIDER: LazyLock<RwLock<Option<Arc<dyn SseDekProvider>>>
/// .await?;
/// ```
pub async fn get_sse_dek_provider() -> Result<Arc<dyn SseDekProvider>, ApiError> {
if runtime_sources::encryption_service().await.is_some() {
if runtime_sources::current_encryption_service().await.is_some() {
debug!("Using KmsSseDekProvider (KMS configured)");
return Ok(Arc::new(KmsSseDekProvider::new().await?));
}
+3 -7
View File
@@ -189,7 +189,7 @@ pub(crate) mod rpc_consumer {
LocalPeerS3Client, MetricType, PEER_RESTSIGNAL, PEER_RESTSUB_SYS, ReadMultipleReq, ReadMultipleResp, ReadOptions,
SERVICE_SIGNAL_REFRESH_CONFIG, SERVICE_SIGNAL_RELOAD_DYNAMIC, StorageDiskRpcExt, StoragePeerS3ClientExt,
UpdateMetadataOpts, all_local_disk_path, collect_local_metrics, find_local_disk_by_ref, get_local_server_property,
load_bucket_metadata, reload_transition_tier_config, resolve_object_store_handle, set_bucket_metadata,
load_bucket_metadata, reload_transition_tier_config, set_bucket_metadata,
};
pub(crate) type StorageResult<T> = super::super::Result<T>;
@@ -378,8 +378,8 @@ pub(crate) mod ecstore_global {
pub(crate) use rustfs_ecstore::api::global::{
GLOBAL_BOOT_TIME, GLOBAL_TierConfigMgr, get_global_bucket_monitor, get_global_deployment_id, get_global_endpoints_opt,
get_global_lock_client, get_global_lock_clients, get_global_region, get_global_tier_config_mgr, global_rustfs_port,
is_dist_erasure, new_object_layer_fn, resolve_object_store_handle, set_global_endpoints, set_global_region,
set_global_rustfs_port, set_object_store_resolver, shutdown_background_services, update_erasure_type,
is_dist_erasure, new_object_layer_fn, set_global_endpoints, set_global_region, set_global_rustfs_port,
set_object_store_resolver, shutdown_background_services, update_erasure_type,
};
}
@@ -1133,10 +1133,6 @@ pub(crate) async fn is_dist_erasure() -> bool {
ecstore_global::is_dist_erasure().await
}
pub(crate) fn resolve_object_store_handle() -> Option<Arc<ECStore>> {
ecstore_global::resolve_object_store_handle()
}
pub(crate) async fn collect_local_metrics(
types: MetricType,
opts: &CollectMetricsOpts,