From 916d365ab75796313e236d2022943171fb2ac47b Mon Sep 17 00:00:00 2001 From: overtrue Date: Sun, 16 Aug 2026 23:30:54 +0800 Subject: [PATCH] refactor(rustfs): move module switches below the layer boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backlog#1834 PR5. Whether the scanner, heal, audit and notify modules are on gets read from infra (storage helpers, node-service RPC) and from interface (admin handlers), but the switches lived in startup_background (composition) and server (interface). Every one of those reads was an upward edge carried in the layer-dependency baseline. The env-derived scanner/heal predicates and the audit/notify state cells now live in rustfs/src/module_switches.rs, at the bottom of the layer order, so the same reads are ordinary downward edges. startup_background and server import from there; server keeps re-exporting the getters for its own consumers. The issue's plan was to move is/refresh_audit/notify_module_enabled as a group. Moving refresh_* wholesale would have dragged resolve_audit_module_state and resolve_notify_module_state — server-side configuration logic — down into infra, which breaks more layering than it fixes. State and resolution are split instead: module_switches owns the atomics plus is_*/set_* accessors, and server's refresh_* keeps the configuration logic and publishes through the setter. That leaves storage/helper.rs's test module importing refresh_* from server, so two infra->interface edges stay. Those tests assert that a configuration change takes effect through refresh, which a plain setter would no longer exercise; the edges are worth more than the two baseline lines. Baseline drops 44 -> 36 lines, deletions only: - 4 interface/infra -> composition edges for ENV_SCANNER_ENABLED, scanner_enabled_from_env and heal_enabled_from_env - 2 infra -> interface edges for is_audit_module_enabled and is_notify_module_enabled - cycle|composition<->infra and cycle|composition<->interface The two cycles were not expected to go until whole subsystems moved out; clearing composition's inbound upward edges dissolved both, leaving three of the original five. Verification: scripts/check_layer_dependencies.sh passes, cargo check -p rustfs warning-free, make pre-commit exit 0. --- rustfs/src/admin/handlers/scanner.rs | 2 +- rustfs/src/lib.rs | 1 + rustfs/src/module_switches.rs | 68 +++++++++++++++++++++ rustfs/src/server/audit.rs | 9 +-- rustfs/src/server/event.rs | 9 +-- rustfs/src/startup_background.rs | 14 +---- rustfs/src/storage/helper.rs | 2 +- rustfs/src/storage/rpc/node_service/heal.rs | 2 +- scripts/layer-dependency-baseline.txt | 8 --- 9 files changed, 78 insertions(+), 37 deletions(-) create mode 100644 rustfs/src/module_switches.rs diff --git a/rustfs/src/admin/handlers/scanner.rs b/rustfs/src/admin/handlers/scanner.rs index b9ff901c5..fde894e9c 100644 --- a/rustfs/src/admin/handlers/scanner.rs +++ b/rustfs/src/admin/handlers/scanner.rs @@ -16,8 +16,8 @@ use crate::admin::auth::validate_admin_request; use crate::admin::router::{AdminOperation, Operation, S3Router}; use crate::admin::runtime_sources::current_scanner_metrics_report; use crate::auth::{check_key_valid, get_session_token}; +use crate::module_switches::{ENV_SCANNER_ENABLED, scanner_enabled_from_env}; use crate::server::{ADMIN_PREFIX, RemoteAddr}; -use crate::startup_background::{ENV_SCANNER_ENABLED, scanner_enabled_from_env}; use chrono::Utc; use http::{HeaderMap, HeaderValue}; use hyper::{Method, StatusCode}; diff --git a/rustfs/src/lib.rs b/rustfs/src/lib.rs index 077365569..f8e9d893d 100644 --- a/rustfs/src/lib.rs +++ b/rustfs/src/lib.rs @@ -88,6 +88,7 @@ pub mod inspect; pub(crate) mod kms_deletion_gate; pub mod license; pub mod memory_observability; +pub mod module_switches; pub mod profiling; #[cfg(any(feature = "ftps", feature = "webdav", feature = "sftp"))] pub mod protocols; diff --git a/rustfs/src/module_switches.rs b/rustfs/src/module_switches.rs new file mode 100644 index 000000000..fcb0ffcef --- /dev/null +++ b/rustfs/src/module_switches.rs @@ -0,0 +1,68 @@ +// Copyright 2024 RustFS Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Layer-neutral module switches (backlog#1834). +//! +//! Whether the scanner, heal, audit and notify modules are on is read from the +//! infra layer (storage helpers, node-service RPC) and from the interface layer +//! (admin handlers), but the switches used to live in `startup_background` +//! (composition) and `server` (interface). Every lower-layer read was therefore +//! an upward edge that had to be baselined by the layer-dependency guard. +//! +//! The env-derived scanner/heal predicates and the audit/notify state cells now +//! live here, at the bottom of the layer order, so those reads are ordinary +//! downward edges. Resolving the audit/notify state still needs server-side +//! configuration, so `server::refresh_audit_module_enabled` and its notify twin +//! keep that logic and publish the result through the setters below. + +use rustfs_utils::get_env_bool_with_aliases; +use std::sync::atomic::{AtomicBool, Ordering}; + +pub(crate) const ENV_SCANNER_ENABLED: &str = "RUSTFS_SCANNER_ENABLED"; +pub(crate) const ENV_SCANNER_ENABLED_DEPRECATED: &str = "RUSTFS_ENABLE_SCANNER"; +pub(crate) const ENV_HEAL_ENABLED: &str = "RUSTFS_HEAL_ENABLED"; +pub(crate) const ENV_HEAL_ENABLED_DEPRECATED: &str = "RUSTFS_ENABLE_HEAL"; + +static AUDIT_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_AUDIT_ENABLE); +static NOTIFY_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_NOTIFY_ENABLE); + +/// Whether the data scanner is enabled, defaulting to on. +pub(crate) fn scanner_enabled_from_env() -> bool { + get_env_bool_with_aliases(ENV_SCANNER_ENABLED, &[ENV_SCANNER_ENABLED_DEPRECATED], true) +} + +/// Whether background heal is enabled, defaulting to on. +pub(crate) fn heal_enabled_from_env() -> bool { + get_env_bool_with_aliases(ENV_HEAL_ENABLED, &[ENV_HEAL_ENABLED_DEPRECATED], true) +} + +/// Last published audit-module state. +pub fn is_audit_module_enabled() -> bool { + AUDIT_MODULE_ENABLED.load(Ordering::Relaxed) +} + +/// Publish the audit-module state resolved by `server::refresh_audit_module_enabled`. +pub(crate) fn set_audit_module_enabled(enabled: bool) { + AUDIT_MODULE_ENABLED.store(enabled, Ordering::Relaxed); +} + +/// Last published notify-module state. +pub fn is_notify_module_enabled() -> bool { + NOTIFY_MODULE_ENABLED.load(Ordering::Relaxed) +} + +/// Publish the notify-module state resolved by `server::refresh_notify_module_enabled`. +pub(crate) fn set_notify_module_enabled(enabled: bool) { + NOTIFY_MODULE_ENABLED.store(enabled, Ordering::Relaxed); +} diff --git a/rustfs/src/server/audit.rs b/rustfs/src/server/audit.rs index 6fb01a8a5..72a0b21c6 100644 --- a/rustfs/src/server/audit.rs +++ b/rustfs/src/server/audit.rs @@ -19,11 +19,8 @@ use super::{ use crate::runtime_sources::AppContext; use rustfs_audit::{AuditError, AuditResult, audit_system, init_audit_system, system::AuditSystemState}; use std::collections::HashSet; -use std::sync::atomic::{AtomicBool, Ordering}; use tracing::{info, warn}; -static AUDIT_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_AUDIT_ENABLE); - fn server_config_from_context() -> Option { runtime_sources::current_server_config() } @@ -37,13 +34,11 @@ fn server_config_for_context(context: Option<&AppContext>) -> Option bool { let enabled = resolve_audit_module_state().enabled; - AUDIT_MODULE_ENABLED.store(enabled, Ordering::Relaxed); + crate::module_switches::set_audit_module_enabled(enabled); enabled } -pub fn is_audit_module_enabled() -> bool { - AUDIT_MODULE_ENABLED.load(Ordering::Relaxed) -} +pub use crate::module_switches::is_audit_module_enabled; fn has_any_persisted_audit_targets(config: &rustfs_config::server_config::Config) -> bool { for &subsystem in rustfs_config::audit::AUDIT_SUB_SYSTEMS { diff --git a/rustfs/src/server/event.rs b/rustfs/src/server/event.rs index b9ca8e6e5..6f0769774 100644 --- a/rustfs/src/server/event.rs +++ b/rustfs/src/server/event.rs @@ -34,7 +34,6 @@ use tokio::time::{Instant, MissedTickBehavior}; use tokio_util::sync::CancellationToken; use tracing::{info, instrument, warn}; -static NOTIFY_MODULE_ENABLED: AtomicBool = AtomicBool::new(rustfs_config::DEFAULT_NOTIFY_ENABLE); static NOTIFY_RUNTIME_RECONCILED: AtomicBool = AtomicBool::new(false); static NOTIFY_BUCKET_RULES_RECONCILED: AtomicBool = AtomicBool::new(false); static ECSTORE_EVENT_DISPATCH_HOOK: OnceLock<()> = OnceLock::new(); @@ -70,13 +69,11 @@ fn should_reconcile_bucket_notification_rules(runtime_changed: bool, notify_enab pub fn refresh_notify_module_enabled() -> bool { let enabled = resolve_notify_module_state().enabled; - NOTIFY_MODULE_ENABLED.store(enabled, Ordering::Relaxed); + crate::module_switches::set_notify_module_enabled(enabled); enabled } -pub fn is_notify_module_enabled() -> bool { - NOTIFY_MODULE_ENABLED.load(Ordering::Relaxed) -} +pub use crate::module_switches::is_notify_module_enabled; pub(crate) use crate::shared_types::convert_ecstore_object_info; @@ -171,7 +168,7 @@ pub(crate) async fn reconcile_event_notifier_from_store( let transition_system = system.clone(); let transition_store = store.clone(); let transition = with_refreshed_notify_module_state_from(store.clone(), move |resolution| async move { - NOTIFY_MODULE_ENABLED.store(resolution.enabled, Ordering::Relaxed); + crate::module_switches::set_notify_module_enabled(resolution.enabled); let read_store = transition_store.clone(); let config_system = transition_system.clone(); with_server_config_read_lock(transition_store, move || async move { diff --git a/rustfs/src/startup_background.rs b/rustfs/src/startup_background.rs index dfbdc257e..8cee2c502 100644 --- a/rustfs/src/startup_background.rs +++ b/rustfs/src/startup_background.rs @@ -12,32 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::module_switches::{heal_enabled_from_env, scanner_enabled_from_env}; use crate::storage_api::startup::background::{ECStore, set_workload_admission_snapshot_provider}; use crate::workload_admission::RustFsWorkloadAdmissionSnapshotProvider; use rustfs_concurrency::WorkloadAdmissionSnapshotProvider; use rustfs_heal::{ create_ahm_services_cancel_token, heal::storage::ECStoreHealStorage, init_heal_manager_with_workload_provider, }; -use rustfs_utils::get_env_bool_with_aliases; use std::{io::Result, sync::Arc}; use tracing::{debug, info}; -pub(crate) const ENV_SCANNER_ENABLED: &str = "RUSTFS_SCANNER_ENABLED"; -pub(crate) const ENV_SCANNER_ENABLED_DEPRECATED: &str = "RUSTFS_ENABLE_SCANNER"; -pub(crate) const ENV_HEAL_ENABLED: &str = "RUSTFS_HEAL_ENABLED"; -pub(crate) const ENV_HEAL_ENABLED_DEPRECATED: &str = "RUSTFS_ENABLE_HEAL"; const LOG_COMPONENT_MAIN: &str = "main"; const LOG_SUBSYSTEM_STARTUP: &str = "startup"; const EVENT_BACKGROUND_SERVICES_CONFIGURED: &str = "background_services_configured"; -pub(crate) fn scanner_enabled_from_env() -> bool { - get_env_bool_with_aliases(ENV_SCANNER_ENABLED, &[ENV_SCANNER_ENABLED_DEPRECATED], true) -} - -pub(crate) fn heal_enabled_from_env() -> bool { - get_env_bool_with_aliases(ENV_HEAL_ENABLED, &[ENV_HEAL_ENABLED_DEPRECATED], true) -} - pub(crate) async fn init_background_service_runtime(store: Arc) -> Result { let _ = create_ahm_services_cancel_token(); diff --git a/rustfs/src/storage/helper.rs b/rustfs/src/storage/helper.rs index 074d30f55..26f5476c0 100644 --- a/rustfs/src/storage/helper.rs +++ b/rustfs/src/storage/helper.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::server::{is_audit_module_enabled, is_notify_module_enabled}; +use crate::module_switches::{is_audit_module_enabled, is_notify_module_enabled}; use crate::shared_types::convert_ecstore_object_info; use crate::storage::access::{ReqInfo, request_context_from_req}; use crate::storage::request_context::RequestContext; diff --git a/rustfs/src/storage/rpc/node_service/heal.rs b/rustfs/src/storage/rpc/node_service/heal.rs index ea398125e..f9b990bf3 100644 --- a/rustfs/src/storage/rpc/node_service/heal.rs +++ b/rustfs/src/storage/rpc/node_service/heal.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::startup_background::{heal_enabled_from_env, scanner_enabled_from_env}; +use crate::module_switches::{heal_enabled_from_env, scanner_enabled_from_env}; use crate::storage::storage_api::runtime_sources_consumer::EndpointServerPools; use jiff::Timestamp; use rmp_serde::Deserializer; diff --git a/scripts/layer-dependency-baseline.txt b/scripts/layer-dependency-baseline.txt index 08aea30d2..c705152a4 100644 --- a/scripts/layer-dependency-baseline.txt +++ b/scripts/layer-dependency-baseline.txt @@ -16,11 +16,7 @@ # cycle|left_layer<->right_layer cycle|app<->infra cycle|app<->interface -cycle|composition<->infra -cycle|composition<->interface cycle|infra<->interface -dep|rustfs/src/admin/handlers/scanner.rs|interface->composition|crate::startup_background::ENV_SCANNER_ENABLED -dep|rustfs/src/admin/handlers/scanner.rs|interface->composition|crate::startup_background::scanner_enabled_from_env dep|rustfs/src/app/admin_usecase.rs|app->interface|crate::server::collect_dependency_readiness_report dep|rustfs/src/app/bucket_usecase.rs|app->interface|crate::admin::handlers::site_replication::site_replication_bucket_meta_hook dep|rustfs/src/app/bucket_usecase.rs|app->interface|crate::admin::handlers::site_replication::site_replication_delete_bucket_hook @@ -29,8 +25,6 @@ dep|rustfs/src/cluster_snapshot.rs|infra->interface|crate::server::snapshot_depe dep|rustfs/src/runtime_sources.rs|infra->app|crate::app::context dep|rustfs/src/storage/ecfs_extend.rs|infra->interface|crate::server::cors dep|rustfs/src/storage/ecfs_extend.rs|infra->interface|crate::storage::ecfs::ListObjectUnorderedQuery -dep|rustfs/src/storage/helper.rs|infra->interface|crate::server::is_audit_module_enabled -dep|rustfs/src/storage/helper.rs|infra->interface|crate::server::is_notify_module_enabled dep|rustfs/src/storage/helper.rs|infra->interface|crate::server::refresh_audit_module_enabled dep|rustfs/src/storage/helper.rs|infra->interface|crate::server::refresh_notify_module_enabled dep|rustfs/src/storage/rpc/http_service.rs|infra->interface|crate::server::RPC_PREFIX @@ -40,5 +34,3 @@ dep|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::servic dep|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::service::config::reload_runtime_config_snapshot dep|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::service::site_replication::reload_site_replication_runtime_state dep|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::server::MODULE_SWITCHES_SIGNAL_SUBSYSTEM -dep|rustfs/src/storage/rpc/node_service/heal.rs|infra->composition|crate::startup_background::heal_enabled_from_env -dep|rustfs/src/storage/rpc/node_service/heal.rs|infra->composition|crate::startup_background::scanner_enabled_from_env