refactor: expose runtime fallback boundaries (#3954)

This commit is contained in:
Zhengchao An
2026-06-27 18:57:51 +08:00
committed by GitHub
parent cdebdeca61
commit 4732f4ee2d
2 changed files with 162 additions and 244 deletions
+33 -11
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-runtime-context-fallback-signature-cleanup`
- Branch: `overtrue/arch-runtime-fallback-boundary-cleanup`
- 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
@@ -20,18 +20,19 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
runtime facade consumer batch from PR #3948, the GLOB-007 runtime facade
alias sweep from PR #3949, the GLOB-007 object-store fallback removal from
PR #3950, the GLOB-007 notification-system/server-config fallback removal
from PR #3951, and the GLOB-007 optional runtime handle fallback removal
from PR #3952.
- Current phase PR: GLOB-007 AppContext-only fallback signature cleanup.
- Based on: `origin/main` after PR #3952 merged.
from PR #3951, the GLOB-007 optional runtime handle fallback removal from
PR #3952, and the GLOB-007 AppContext-only fallback signature cleanup from
PR #3953.
- Current phase PR: GLOB-007 runtime resolver fallback boundary cleanup.
- Based on: `origin/main` after PR #3953 merged.
- PR type for this branch: `ci-gate`.
- Runtime behavior changes: none intended beyond the PR #3952 optional
no-context behavior.
- Rust code changes: remove stale fallback closure parameters from
AppContext-only resolver helpers for object-store, notification-system,
server-config, and optional runtime handles.
- Runtime behavior changes: none intended; public runtime facades keep their
existing no-AppContext fallback behavior.
- Rust code changes: move remaining resolver helper fallback parameters to the
public facade boundary for KMS, IAM, TLS, metrics, S3 Select, node identity,
tier/expiry, credentials, runtime port, and buffer config reads.
- CI/script changes: none intended.
- Docs changes: update this progress ledger for the fallback signature cleanup.
- Docs changes: update this progress ledger for the fallback boundary cleanup.
## Phase 0 Tasks
@@ -2822,6 +2823,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
- Current slice: remove stale fallback closure parameters from
AppContext-only resolver helpers after their no-context behavior no longer
consults legacy globals.
- Current slice: move the remaining resolver helper fallback parameters to
public runtime facade boundaries, preserving no-AppContext fallback behavior
while making private helpers context-only.
- Remaining work: remove the next fallback family per PR only after scans
prove no production caller depends on it.
- Verification: focused RustFS compile and admin test-target compile,
@@ -6090,6 +6094,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Expert | Status | Notes |
|---|---|---|
| Quality/architecture | pass | GLOB-007 moves the remaining resolver helper fallback parameters out to public facade boundaries, making private helper paths context-only without hiding fallback closures. |
| Migration preservation | pass | Public runtime facade names, return types, and no-AppContext fallback behavior are preserved; only helper signatures and focused resolver tests change. |
| Testing/verification | pass | Focused resolver test, compile, formatting, architecture guard, fallback-boundary residual scan, diff hygiene, diff-added Rust risk scan, Rust quality scan, and full `make pre-pr` passed before PR. |
| Quality/architecture | pass | GLOB-007 removes stale fallback closure parameters from resolver helpers whose no-context behavior is already AppContext-only, making hidden fallback reintroduction harder. |
| Migration preservation | pass | Public runtime facade names and return types stay unchanged; this is a signature cleanup for private helper paths and test coverage after PR #3952. |
| Testing/verification | pass | Focused resolver test passed; compile, formatting, architecture guard, fallback-parameter residual scan, diff hygiene, diff-added Rust risk scan, and full `make pre-pr` are required before PR. |
@@ -6480,6 +6487,21 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
Passed before push:
- Issue #660 GLOB-007 runtime resolver fallback boundary cleanup:
- Branch freshness check: moved onto `origin/main` after PR #3953 merged.
- `cargo test -p rustfs --lib app::context::tests::resolver_helpers_are_context_first_and_empty_when_context_is_absent`:
passed.
- `cargo check -p rustfs --lib`: passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- Resolver fallback-boundary residual scan: passed.
- Diff-added Rust risk scan: passed.
- Rust code quality scan: passed.
- Three-expert review: passed.
- `make pre-pr`: passed (`nextest`: 6917 passed, 112 skipped; doctests passed).
- Issue #660 GLOB-007 AppContext-only fallback signature cleanup:
- Branch freshness check: rebased onto `origin/main` after PR #3952 merged.
- `cargo test -p rustfs --lib app::context::tests::resolver_helpers_are_context_first_and_fallback_when_context_is_absent`:
+129 -233
View File
@@ -42,27 +42,34 @@ use rustfs_lock::LockClient;
use rustfs_s3select_api::{QueryResult, server::dbms::DatabaseManagerSystem};
use rustfs_tls_runtime::{GlobalPublishedOutboundTlsState, TlsGeneration};
use s3s::dto::SelectObjectContentInput;
use std::{collections::HashMap, future::Future, sync::Arc, time::SystemTime};
use std::{collections::HashMap, sync::Arc, time::SystemTime};
use tokio::sync::RwLock;
/// Resolve KMS runtime service manager using AppContext-first precedence.
pub fn resolve_kms_runtime_service_manager() -> Option<Arc<KmsServiceManager>> {
resolve_kms_runtime_service_manager_with(get_global_app_context(), || default_kms_runtime_interface().service_manager())
resolve_kms_runtime_service_manager_with(get_global_app_context())
.or_else(|| default_kms_runtime_interface().service_manager())
}
/// Resolve or initialize the KMS runtime service manager using AppContext-first precedence.
pub fn resolve_or_init_kms_runtime_service_manager() -> Arc<KmsServiceManager> {
resolve_or_init_kms_runtime_service_manager_with(get_global_app_context(), runtime_sources::init_kms_service_manager)
resolve_or_init_kms_runtime_service_manager_with(get_global_app_context())
.unwrap_or_else(runtime_sources::init_kms_service_manager)
}
/// Resolve KMS encryption service using AppContext-first precedence.
pub async fn resolve_encryption_service() -> Option<Arc<ObjectEncryptionService>> {
resolve_encryption_service_with(get_global_app_context(), runtime_sources::encryption_service).await
if let Some(service) = resolve_encryption_service_with(get_global_app_context()).await {
return Some(service);
}
runtime_sources::encryption_service().await
}
/// Resolve outbound TLS generation using AppContext-first precedence.
pub fn resolve_outbound_tls_generation() -> TlsGeneration {
resolve_outbound_tls_generation_with(get_global_app_context(), || default_outbound_tls_runtime_interface().generation())
resolve_outbound_tls_generation_with(get_global_app_context())
.unwrap_or_else(|| default_outbound_tls_runtime_interface().generation())
}
#[cfg(test)]
@@ -77,12 +84,12 @@ pub async fn resolve_outbound_tls_state() -> GlobalPublishedOutboundTlsState {
/// Resolve IAM readiness using AppContext-first precedence.
pub fn resolve_iam_ready() -> bool {
resolve_iam_ready_with(get_global_app_context(), runtime_sources::iam_is_ready)
resolve_iam_ready_with(get_global_app_context()).unwrap_or_else(runtime_sources::iam_is_ready)
}
/// Resolve IAM system handle using AppContext-first precedence.
pub fn resolve_iam_handle() -> Option<Arc<IamSys<ObjectStore>>> {
resolve_iam_handle_with(get_global_app_context(), runtime_sources::iam_handle)
resolve_iam_handle_with(get_global_app_context()).or_else(runtime_sources::iam_handle)
}
/// Resolve OIDC system handle using AppContext-first precedence.
@@ -97,7 +104,11 @@ pub fn publish_oidc_handle(oidc: Arc<OidcSys>) -> bool {
/// Resolve a ready IAM system handle using AppContext-first precedence.
pub fn resolve_ready_iam_handle() -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>> {
resolve_ready_iam_handle_with(get_global_app_context(), runtime_sources::ready_iam_handle)
if let Some(context) = get_global_app_context() {
return resolve_ready_iam_handle_with(context);
}
runtime_sources::ready_iam_handle()
}
/// Resolve token signing key using AppContext-first precedence.
@@ -171,13 +182,16 @@ pub fn resolve_boot_time() -> Option<SystemTime> {
/// Resolve daily tier transition statistics using AppContext-first precedence.
pub fn resolve_daily_tier_stats() -> DailyAllTierStats {
resolve_daily_tier_stats_with(get_global_app_context(), || default_tier_stats_interface().daily_all())
resolve_daily_tier_stats_with(get_global_app_context()).unwrap_or_else(|| default_tier_stats_interface().daily_all())
}
/// Resolve scanner metrics report using AppContext-first precedence.
pub async fn resolve_scanner_metrics_report() -> ScannerMetricsReport {
resolve_scanner_metrics_report_with(get_global_app_context(), || async { default_scanner_metrics_interface().report().await })
.await
if let Some(report) = resolve_scanner_metrics_report_with(get_global_app_context()).await {
return report;
}
default_scanner_metrics_interface().report().await
}
/// Resolve deployment identity using AppContext-first precedence.
@@ -187,7 +201,7 @@ pub fn resolve_deployment_id() -> Option<String> {
/// Resolve runtime port using AppContext-first precedence.
pub fn resolve_runtime_port() -> u16 {
resolve_runtime_port_with(get_global_app_context(), || default_runtime_port_interface().get())
resolve_runtime_port_with(get_global_app_context()).unwrap_or_else(|| default_runtime_port_interface().get())
}
/// Resolve lock client using AppContext-first precedence.
@@ -202,12 +216,12 @@ pub fn resolve_lock_clients_handle() -> Option<HashMap<String, Arc<dyn LockClien
/// Resolve performance metrics using AppContext-first precedence.
pub fn resolve_performance_metrics() -> Arc<PerformanceMetrics> {
resolve_performance_metrics_with(get_global_app_context(), || default_performance_metrics_interface().handle())
resolve_performance_metrics_with(get_global_app_context()).unwrap_or_else(|| default_performance_metrics_interface().handle())
}
/// Resolve internode metrics using AppContext-first precedence.
pub fn resolve_internode_metrics() -> Arc<InternodeMetrics> {
resolve_internode_metrics_with(get_global_app_context(), || default_internode_metrics_interface().handle())
resolve_internode_metrics_with(get_global_app_context()).unwrap_or_else(|| default_internode_metrics_interface().handle())
}
/// Resolve S3 Select database using AppContext-first precedence.
@@ -215,20 +229,29 @@ pub async fn resolve_s3select_db(
input: SelectObjectContentInput,
enable_debug: bool,
) -> QueryResult<Arc<dyn DatabaseManagerSystem + Send + Sync>> {
resolve_s3select_db_with(get_global_app_context(), input, enable_debug, |input, enable_debug| async move {
default_s3select_db_interface().get(input, enable_debug).await
})
.await
if let Some(context) = get_global_app_context() {
return resolve_s3select_db_with(context, input, enable_debug).await;
}
default_s3select_db_interface().get(input, enable_debug).await
}
/// Resolve local node name using AppContext-first precedence.
pub async fn resolve_local_node_name() -> String {
resolve_local_node_name_with(get_global_app_context(), runtime_sources::local_node_name).await
if let Some(node_name) = resolve_local_node_name_with(get_global_app_context()).await {
return node_name;
}
runtime_sources::local_node_name().await
}
/// Resolve action credentials using AppContext-first precedence.
pub fn resolve_action_credentials() -> Option<Credentials> {
resolve_action_credentials_with(get_global_app_context(), || default_action_credential_interface().get())
if let Some(context) = get_global_app_context() {
return resolve_action_credentials_with(context);
}
default_action_credential_interface().get()
}
/// Resolve region using AppContext-first precedence.
@@ -238,12 +261,12 @@ pub fn resolve_region() -> Option<s3s::region::Region> {
/// Resolve tier config handle using AppContext-first precedence.
pub fn resolve_tier_config_handle() -> Arc<RwLock<TierConfigMgr>> {
resolve_tier_config_handle_with(get_global_app_context(), || default_tier_config_interface().handle())
resolve_tier_config_handle_with(get_global_app_context()).unwrap_or_else(|| default_tier_config_interface().handle())
}
/// Resolve lifecycle expiry state using AppContext-first precedence.
pub fn resolve_expiry_state_handle() -> Arc<RwLock<ExpiryState>> {
resolve_expiry_state_handle_with(get_global_app_context(), || default_expiry_state_interface().handle())
resolve_expiry_state_handle_with(get_global_app_context()).unwrap_or_else(|| default_expiry_state_interface().handle())
}
/// Resolve server config using AppContext-first precedence.
@@ -270,47 +293,24 @@ pub fn publish_storage_class_config(config: StorageClassConfig) {
/// Resolve buffer profile config using AppContext-first precedence.
pub fn resolve_buffer_config() -> RustFSBufferConfig {
resolve_buffer_config_with(get_global_app_context(), || default_buffer_config_interface().get())
resolve_buffer_config_with(get_global_app_context()).unwrap_or_else(|| default_buffer_config_interface().get())
}
fn resolve_kms_runtime_service_manager_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<KmsServiceManager>>,
) -> Option<Arc<KmsServiceManager>> {
context
.and_then(|context| context.kms_runtime().service_manager())
.or_else(fallback)
fn resolve_kms_runtime_service_manager_with(context: Option<Arc<AppContext>>) -> Option<Arc<KmsServiceManager>> {
context.and_then(|context| context.kms_runtime().service_manager())
}
fn resolve_or_init_kms_runtime_service_manager_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Arc<KmsServiceManager>,
) -> Arc<KmsServiceManager> {
context
.and_then(|context| context.kms_runtime().service_manager())
.unwrap_or_else(fallback)
fn resolve_or_init_kms_runtime_service_manager_with(context: Option<Arc<AppContext>>) -> Option<Arc<KmsServiceManager>> {
context.and_then(|context| context.kms_runtime().service_manager())
}
async fn resolve_encryption_service_with<F, Fut>(
context: Option<Arc<AppContext>>,
fallback: F,
) -> Option<Arc<ObjectEncryptionService>>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Option<Arc<ObjectEncryptionService>>>,
{
if let Some(manager) = context.and_then(|context| context.kms_runtime().service_manager()) {
return manager.get_encryption_service().await;
}
fallback().await
async fn resolve_encryption_service_with(context: Option<Arc<AppContext>>) -> Option<Arc<ObjectEncryptionService>> {
let manager = context.and_then(|context| context.kms_runtime().service_manager())?;
manager.get_encryption_service().await
}
fn resolve_outbound_tls_generation_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> TlsGeneration,
) -> TlsGeneration {
context.map_or_else(fallback, |context| context.outbound_tls_runtime().generation())
fn resolve_outbound_tls_generation_with(context: Option<Arc<AppContext>>) -> Option<TlsGeneration> {
context.map(|context| context.outbound_tls_runtime().generation())
}
async fn resolve_outbound_tls_state_with(context: Option<Arc<AppContext>>) -> GlobalPublishedOutboundTlsState {
@@ -321,15 +321,12 @@ async fn resolve_outbound_tls_state_with(context: Option<Arc<AppContext>>) -> Gl
default_outbound_tls_runtime_interface().state().await
}
fn resolve_iam_ready_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> bool) -> bool {
context.map_or_else(fallback, |context| context.iam().is_ready())
fn resolve_iam_ready_with(context: Option<Arc<AppContext>>) -> Option<bool> {
context.map(|context| context.iam().is_ready())
}
fn resolve_iam_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<IamSys<ObjectStore>>>,
) -> Option<Arc<IamSys<ObjectStore>>> {
context.map(|context| context.iam().handle()).or_else(fallback)
fn resolve_iam_handle_with(context: Option<Arc<AppContext>>) -> Option<Arc<IamSys<ObjectStore>>> {
context.map(|context| context.iam().handle())
}
fn resolve_oidc_handle_with(context: Option<Arc<AppContext>>) -> Option<Arc<OidcSys>> {
@@ -340,19 +337,12 @@ fn publish_oidc_handle_with(context: Option<Arc<AppContext>>, oidc: Arc<OidcSys>
context.is_some_and(|context| context.publish_oidc_handle(oidc))
}
fn resolve_ready_iam_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>>,
) -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>> {
if let Some(context) = context {
if context.iam().is_ready() {
return Ok(context.iam().handle());
}
return Err(IamError::IamSysNotInitialized);
fn resolve_ready_iam_handle_with(context: Arc<AppContext>) -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>> {
if context.iam().is_ready() {
return Ok(context.iam().handle());
}
fallback()
Err(IamError::IamSysNotInitialized)
}
fn resolve_token_signing_key_with(context: Option<Arc<AppContext>>) -> Option<String> {
@@ -383,23 +373,16 @@ fn resolve_boot_time_with(context: Option<Arc<AppContext>>) -> Option<SystemTime
context.and_then(|context| context.boot_time().get())
}
fn resolve_daily_tier_stats_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> DailyAllTierStats,
) -> DailyAllTierStats {
context.map_or_else(fallback, |context| context.tier_stats().daily_all())
fn resolve_daily_tier_stats_with(context: Option<Arc<AppContext>>) -> Option<DailyAllTierStats> {
context.map(|context| context.tier_stats().daily_all())
}
async fn resolve_scanner_metrics_report_with<F, Fut>(context: Option<Arc<AppContext>>, fallback: F) -> ScannerMetricsReport
where
F: FnOnce() -> Fut,
Fut: Future<Output = ScannerMetricsReport>,
{
async fn resolve_scanner_metrics_report_with(context: Option<Arc<AppContext>>) -> Option<ScannerMetricsReport> {
if let Some(context) = context {
return context.scanner_metrics().report().await;
return Some(context.scanner_metrics().report().await);
}
fallback().await
None
}
#[cfg(test)]
@@ -415,8 +398,8 @@ fn resolve_deployment_id_with(context: Option<Arc<AppContext>>) -> Option<String
context.and_then(|context| context.deployment_id().get())
}
fn resolve_runtime_port_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> u16) -> u16 {
context.map_or_else(fallback, |context| context.runtime_port().get())
fn resolve_runtime_port_with(context: Option<Arc<AppContext>>) -> Option<u16> {
context.map(|context| context.runtime_port().get())
}
fn resolve_lock_client_with(context: Option<Arc<AppContext>>) -> Option<Arc<dyn LockClient>> {
@@ -427,76 +410,44 @@ fn resolve_lock_clients_handle_with(context: Option<Arc<AppContext>>) -> Option<
context.and_then(|context| context.lock_clients().handle())
}
fn resolve_performance_metrics_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Arc<PerformanceMetrics>,
) -> Arc<PerformanceMetrics> {
context.map_or_else(fallback, |context| context.performance_metrics().handle())
fn resolve_performance_metrics_with(context: Option<Arc<AppContext>>) -> Option<Arc<PerformanceMetrics>> {
context.map(|context| context.performance_metrics().handle())
}
fn resolve_internode_metrics_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Arc<InternodeMetrics>,
) -> Arc<InternodeMetrics> {
context.map_or_else(fallback, |context| context.internode_metrics().handle())
fn resolve_internode_metrics_with(context: Option<Arc<AppContext>>) -> Option<Arc<InternodeMetrics>> {
context.map(|context| context.internode_metrics().handle())
}
async fn resolve_s3select_db_with<F, Fut>(
context: Option<Arc<AppContext>>,
async fn resolve_s3select_db_with(
context: Arc<AppContext>,
input: SelectObjectContentInput,
enable_debug: bool,
fallback: F,
) -> QueryResult<Arc<dyn DatabaseManagerSystem + Send + Sync>>
where
F: FnOnce(SelectObjectContentInput, bool) -> Fut,
Fut: Future<Output = QueryResult<Arc<dyn DatabaseManagerSystem + Send + Sync>>>,
{
if let Some(context) = context {
return context.s3select_db().get(input, enable_debug).await;
}
fallback(input, enable_debug).await
) -> QueryResult<Arc<dyn DatabaseManagerSystem + Send + Sync>> {
context.s3select_db().get(input, enable_debug).await
}
async fn resolve_local_node_name_with<F, Fut>(context: Option<Arc<AppContext>>, fallback: F) -> String
where
F: FnOnce() -> Fut,
Fut: Future<Output = String>,
{
async fn resolve_local_node_name_with(context: Option<Arc<AppContext>>) -> Option<String> {
if let Some(context) = context {
return context.local_node_name().get().await;
return Some(context.local_node_name().get().await);
}
fallback().await
None
}
fn resolve_action_credentials_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Credentials>,
) -> Option<Credentials> {
context
.map(|context| context.action_credentials().get())
.unwrap_or_else(fallback)
fn resolve_action_credentials_with(context: Arc<AppContext>) -> Option<Credentials> {
context.action_credentials().get()
}
fn resolve_region_with(context: Option<Arc<AppContext>>) -> Option<s3s::region::Region> {
context.and_then(|context| context.region().get())
}
fn resolve_tier_config_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Arc<RwLock<TierConfigMgr>>,
) -> Arc<RwLock<TierConfigMgr>> {
context.map(|context| context.tier_config().handle()).unwrap_or_else(fallback)
fn resolve_tier_config_handle_with(context: Option<Arc<AppContext>>) -> Option<Arc<RwLock<TierConfigMgr>>> {
context.map(|context| context.tier_config().handle())
}
fn resolve_expiry_state_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Arc<RwLock<ExpiryState>>,
) -> Arc<RwLock<ExpiryState>> {
context
.map(|context| context.expiry_state().handle())
.unwrap_or_else(fallback)
fn resolve_expiry_state_handle_with(context: Option<Arc<AppContext>>) -> Option<Arc<RwLock<ExpiryState>>> {
context.map(|context| context.expiry_state().handle())
}
fn resolve_server_config_with(context: Option<Arc<AppContext>>) -> Option<Config> {
@@ -523,11 +474,8 @@ fn publish_storage_class_config_with(
}
}
fn resolve_buffer_config_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> RustFSBufferConfig,
) -> RustFSBufferConfig {
context.map_or_else(fallback, |context| context.buffer_config().get())
fn resolve_buffer_config_with(context: Option<Arc<AppContext>>) -> Option<RustFSBufferConfig> {
context.map(|context| context.buffer_config().get())
}
#[cfg(test)]
@@ -954,28 +902,20 @@ mod tests {
}
#[tokio::test]
async fn resolver_helpers_are_context_first_and_fallback_when_context_is_absent() {
async fn resolver_helpers_are_context_first_and_empty_when_context_is_absent() {
let (_temp_dir, object_store, endpoints) = test_store().await;
let context_kms = Arc::new(KmsServiceManager::new());
let fallback_kms = Arc::new(KmsServiceManager::new());
let bucket_metadata = Arc::new(RwLock::new(BucketMetadataSys::new(object_store.clone())));
let context_replication_stats = Arc::new(ReplicationStats::new());
let context_boot_time = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
let mut context_daily_tier_stats = DailyAllTierStats::new();
context_daily_tier_stats.insert("CONTEXT".to_string(), Default::default());
let mut fallback_daily_tier_stats = DailyAllTierStats::new();
fallback_daily_tier_stats.insert("FALLBACK".to_string(), Default::default());
let context_scanner_metrics = ScannerMetricsReport {
current_cycle: 7,
..Default::default()
};
let fallback_scanner_metrics = ScannerMetricsReport {
current_cycle: 13,
..Default::default()
};
let tier_config = TierConfigMgr::new();
let context_expiry_state = ExpiryState::new();
let fallback_expiry_state = ExpiryState::new();
let server_config = Config::new();
let context_server_config_published = Arc::new(AtomicUsize::new(0));
let fallback_server_config_published = Arc::new(AtomicUsize::new(0));
@@ -984,18 +924,13 @@ mod tests {
let buffer_config = RustFSBufferConfig::new(WorkloadProfile::AiTraining);
let context_lock_client: Arc<dyn LockClient> = Arc::new(LocalClient::new());
let context_node_name = "context-node".to_string();
let fallback_node_name = "fallback-node".to_string();
let context_deployment_id = "context-deployment".to_string();
let context_runtime_port = 19000;
let fallback_runtime_port = 29000;
let mut context_lock_clients = HashMap::new();
context_lock_clients.insert("context-node:9000".to_string(), context_lock_client.clone());
let context_performance_metrics = Arc::new(PerformanceMetrics::new());
let fallback_performance_metrics = Arc::new(PerformanceMetrics::new());
let context_internode_metrics = Arc::new(InternodeMetrics::default());
let fallback_internode_metrics = Arc::new(InternodeMetrics::default());
let context_s3select_db: Arc<dyn DatabaseManagerSystem + Send + Sync> = Arc::new(TestS3SelectDb);
let fallback_s3select_db: Arc<dyn DatabaseManagerSystem + Send + Sync> = Arc::new(TestS3SelectDb);
let context_outbound_tls_state = GlobalPublishedOutboundTlsState {
generation: TlsGeneration(41),
root_ca_pem: Some(b"context-root-ca".to_vec()),
@@ -1005,10 +940,6 @@ mod tests {
access_key: "context-access-key".to_string(),
..Default::default()
};
let fallback_credentials = Credentials {
access_key: "fallback-access-key".to_string(),
..Default::default()
};
let context_region: s3s::region::Region = "context-region".parse().expect("test region");
let context_oidc_sys = match OidcSys::empty() {
Ok(sys) => sys,
@@ -1109,23 +1040,22 @@ mod tests {
));
assert!(Arc::ptr_eq(
&resolve_kms_runtime_service_manager_with(Some(context.clone()), || Some(fallback_kms.clone()))
.expect("context KMS runtime"),
&resolve_kms_runtime_service_manager_with(Some(context.clone())).expect("context KMS runtime"),
&context_kms
));
assert!(Arc::ptr_eq(
&resolve_or_init_kms_runtime_service_manager_with(Some(context.clone()), || fallback_kms.clone()),
&resolve_or_init_kms_runtime_service_manager_with(Some(context.clone())).expect("context KMS runtime"),
&context_kms
));
assert_eq!(
resolve_outbound_tls_generation_with(Some(context.clone()), || TlsGeneration(99)),
resolve_outbound_tls_generation_with(Some(context.clone())).expect("context outbound TLS generation"),
context_outbound_tls_state.generation
);
assert_eq!(
resolve_outbound_tls_state_with(Some(context.clone())).await.generation,
context_outbound_tls_state.generation
);
assert!(resolve_iam_ready_with(Some(context.clone()), || false));
assert!(resolve_iam_ready_with(Some(context.clone())).expect("context IAM ready"));
let resolved_oidc = resolve_oidc_handle_with(Some(context.clone()));
assert!(resolved_oidc.as_ref().is_some_and(|oidc| Arc::ptr_eq(oidc, &context_oidc)));
assert!(publish_oidc_handle_with(Some(context.clone()), fallback_oidc.clone()));
@@ -1152,11 +1082,14 @@ mod tests {
context_boot_time
);
assert!(
resolve_daily_tier_stats_with(Some(context.clone()), || fallback_daily_tier_stats.clone()).contains_key("CONTEXT")
resolve_daily_tier_stats_with(Some(context.clone()))
.expect("context daily tier stats")
.contains_key("CONTEXT")
);
assert_eq!(
resolve_scanner_metrics_report_with(Some(context.clone()), || async { fallback_scanner_metrics.clone() })
resolve_scanner_metrics_report_with(Some(context.clone()))
.await
.expect("context scanner metrics")
.current_cycle,
context_scanner_metrics.current_cycle
);
@@ -1172,7 +1105,7 @@ mod tests {
context_deployment_id
);
assert_eq!(
resolve_runtime_port_with(Some(context.clone()), || fallback_runtime_port),
resolve_runtime_port_with(Some(context.clone())).expect("context runtime port"),
context_runtime_port
);
assert!(Arc::ptr_eq(
@@ -1187,38 +1120,38 @@ mod tests {
&context_lock_client
));
assert!(Arc::ptr_eq(
&resolve_performance_metrics_with(Some(context.clone()), || fallback_performance_metrics.clone()),
&resolve_performance_metrics_with(Some(context.clone())).expect("context performance metrics"),
&context_performance_metrics
));
assert!(Arc::ptr_eq(
&resolve_internode_metrics_with(Some(context.clone()), || fallback_internode_metrics.clone()),
&resolve_internode_metrics_with(Some(context.clone())).expect("context internode metrics"),
&context_internode_metrics
));
assert!(Arc::ptr_eq(
&resolve_s3select_db_with(Some(context.clone()), test_select_input(), false, |_input, _enable_debug| async {
Ok(fallback_s3select_db.clone())
})
.await
.expect("context S3 Select DB"),
&resolve_s3select_db_with(context.clone(), test_select_input(), false)
.await
.expect("context S3 Select DB"),
&context_s3select_db
));
assert_eq!(
resolve_local_node_name_with(Some(context.clone()), || async { fallback_node_name.clone() }).await,
resolve_local_node_name_with(Some(context.clone()))
.await
.expect("context local node name"),
context_node_name
);
assert_eq!(
resolve_action_credentials_with(Some(context.clone()), || Some(fallback_credentials.clone()))
resolve_action_credentials_with(context.clone())
.expect("context action credentials")
.access_key,
context_credentials.access_key
);
assert_eq!(resolve_region_with(Some(context.clone())).expect("context region"), context_region);
assert!(Arc::ptr_eq(
&resolve_tier_config_handle_with(Some(context.clone()), TierConfigMgr::new),
&resolve_tier_config_handle_with(Some(context.clone())).expect("context tier config"),
&tier_config
));
assert!(Arc::ptr_eq(
&resolve_expiry_state_handle_with(Some(context.clone()), || fallback_expiry_state.clone()),
&resolve_expiry_state_handle_with(Some(context.clone())).expect("context expiry state"),
&context_expiry_state
));
assert_eq!(
@@ -1238,21 +1171,17 @@ mod tests {
assert_eq!(context_storage_class_published.load(Ordering::SeqCst), 1);
assert_eq!(fallback_storage_class_published.load(Ordering::SeqCst), 0);
assert_eq!(
resolve_buffer_config_with(Some(context), || RustFSBufferConfig::new(WorkloadProfile::GeneralPurpose)).workload,
resolve_buffer_config_with(Some(context))
.expect("context buffer config")
.workload,
WorkloadProfile::AiTraining
);
assert!(Arc::ptr_eq(
&resolve_kms_runtime_service_manager_with(None, || Some(fallback_kms.clone())).expect("fallback KMS runtime"),
&fallback_kms
));
assert!(Arc::ptr_eq(
&resolve_or_init_kms_runtime_service_manager_with(None, || fallback_kms.clone()),
&fallback_kms
));
assert_eq!(resolve_outbound_tls_generation_with(None, || TlsGeneration(99)), TlsGeneration(99));
assert!(!resolve_iam_ready_with(None, || false));
assert!(resolve_iam_handle_with(None, || None).is_none());
assert!(resolve_kms_runtime_service_manager_with(None).is_none());
assert!(resolve_or_init_kms_runtime_service_manager_with(None).is_none());
assert!(resolve_outbound_tls_generation_with(None).is_none());
assert!(resolve_iam_ready_with(None).is_none());
assert!(resolve_iam_handle_with(None).is_none());
assert!(resolve_oidc_handle_with(None).is_none());
assert!(resolve_token_signing_key_with(None).is_none());
assert!(!publish_oidc_handle_with(None, context_oidc));
@@ -1262,50 +1191,20 @@ mod tests {
assert!(resolve_object_store_handle_with(None).is_none());
assert!(resolve_replication_stats_handle_with(None).is_none());
assert!(resolve_boot_time_with(None).is_none());
assert!(resolve_daily_tier_stats_with(None, || fallback_daily_tier_stats.clone()).contains_key("FALLBACK"));
assert_eq!(
resolve_scanner_metrics_report_with(None, || async { fallback_scanner_metrics.clone() })
.await
.current_cycle,
fallback_scanner_metrics.current_cycle
);
assert!(resolve_daily_tier_stats_with(None).is_none());
assert!(resolve_scanner_metrics_report_with(None).await.is_none());
assert!(resolve_endpoints_handle_with(None).is_none());
assert!(resolve_deployment_id_with(None).is_none());
assert_eq!(resolve_runtime_port_with(None, || fallback_runtime_port), fallback_runtime_port);
assert!(resolve_runtime_port_with(None).is_none());
assert!(resolve_lock_client_with(None).is_none());
assert!(resolve_lock_clients_handle_with(None).is_none());
assert!(Arc::ptr_eq(
&resolve_performance_metrics_with(None, || fallback_performance_metrics.clone()),
&fallback_performance_metrics
));
assert!(Arc::ptr_eq(
&resolve_internode_metrics_with(None, || fallback_internode_metrics.clone()),
&fallback_internode_metrics
));
assert!(Arc::ptr_eq(
&resolve_s3select_db_with(None, test_select_input(), false, |_input, _enable_debug| async {
Ok(fallback_s3select_db.clone())
})
.await
.expect("fallback S3 Select DB"),
&fallback_s3select_db
));
assert_eq!(
resolve_local_node_name_with(None, || async { fallback_node_name.clone() }).await,
fallback_node_name
);
assert_eq!(
resolve_action_credentials_with(None, || Some(fallback_credentials.clone()))
.expect("fallback action credentials")
.access_key,
fallback_credentials.access_key
);
assert!(resolve_performance_metrics_with(None).is_none());
assert!(resolve_internode_metrics_with(None).is_none());
assert!(resolve_local_node_name_with(None).await.is_none());
assert!(resolve_action_credentials().is_none());
assert!(resolve_region_with(None).is_none());
assert!(Arc::ptr_eq(&resolve_tier_config_handle_with(None, || tier_config.clone()), &tier_config));
assert!(Arc::ptr_eq(
&resolve_expiry_state_handle_with(None, || fallback_expiry_state.clone()),
&fallback_expiry_state
));
assert!(resolve_tier_config_handle_with(None).is_none());
assert!(resolve_expiry_state_handle_with(None).is_none());
assert!(resolve_server_config_with(None).is_none());
publish_server_config_with(None, Config::new(), |config| {
drop(config);
@@ -1317,9 +1216,6 @@ mod tests {
fallback_storage_class_published.fetch_add(1, Ordering::SeqCst);
});
assert_eq!(fallback_storage_class_published.load(Ordering::SeqCst), 1);
assert_eq!(
resolve_buffer_config_with(None, || RustFSBufferConfig::new(WorkloadProfile::DataAnalytics)).workload,
WorkloadProfile::DataAnalytics
);
assert!(resolve_buffer_config_with(None).is_none());
}
}