diff --git a/crates/ecstore/src/bucket/lifecycle/README.md b/crates/ecstore/src/bucket/lifecycle/README.md index a21e7aa8b..53c760f21 100644 --- a/crates/ecstore/src/bucket/lifecycle/README.md +++ b/crates/ecstore/src/bucket/lifecycle/README.md @@ -10,8 +10,8 @@ and tier services. | Module | Current role | Split blocker | |---|---|---| | `core.rs` | Lifecycle rule model, action evaluation, object options, and transition/expiry decisions. | Uses ECStore object metadata types and compatibility DTO re-exports. | -| `bucket_lifecycle_ops.rs` | Worker orchestration, expiry, transition, stale multipart cleanup, audit, replication delete scheduling, and queue state. | Depends on `ECStore`, `SetDisks`, runtime globals, bucket metadata/versioning/replication, object-lock checks, disk internals, event notification, and tier services. | -| `evaluator.rs` | Bucket lifecycle evaluation wrapper. | Uses lifecycle-local object-lock boundary and still reads replication config from ECStore bucket modules. | +| `bucket_lifecycle_ops.rs` | Worker orchestration, expiry, transition, stale multipart cleanup, audit, replication delete scheduling, and queue state. | Depends on `ECStore`, `SetDisks`, runtime globals, bucket metadata/versioning, disk internals, event notification, tier services, and lifecycle-local object-lock/replication boundaries. | +| `evaluator.rs` | Bucket lifecycle evaluation wrapper. | Uses lifecycle-local object-lock boundary and replication state through lifecycle-local replication sink. | | `rule.rs` | Lifecycle rule filter helpers. | Uses lifecycle-local tagging boundary. | | `tier_delete_journal.rs` | Remote tier delete journal persistence and recovery. | Uses lifecycle-local config persistence boundary, object IO contracts, metadata bucket paths, and `ECStore`. | | `tier_free_version_recovery.rs` | Free-version recovery queue and object restoration path. | Depends on `ECStore`, object metadata, storage-api contracts, and lifecycle queue callbacks. | @@ -24,12 +24,12 @@ and tier services. | Contract | Responsibility | Current dependency to remove | |---|---|---| | `LifecycleObjectStore` | Object stat, delete, transition, restore, multipart cleanup, and version-aware metadata operations. | Direct `ECStore`, `SetDisks`, disk, and object API access in worker paths. | -| `LifecycleMetadataStore` | Lifecycle, object-lock, replication, bucket versioning, and stale multipart metadata reads. | Direct bucket metadata, object-lock, versioning, and replication module imports. | +| `LifecycleMetadataStore` | Lifecycle, object-lock, replication, bucket versioning, and stale multipart metadata reads. | Direct bucket metadata/versioning imports; object-lock and replication are still backed by local ECStore boundaries. | | `LifecycleRuntime` | Expiry state, transition state, tier config, deployment ID, local node name, queue metrics, cancellation, and worker sizing. | Direct runtime source/global access and process environment reads inside worker code. | | `LifecycleConfigStore` | Persist, read, and remove lifecycle-owned journal/config objects. | Direct ECStore config persistence helper imports from worker paths. | | `LifecycleTagFilter` | Decode object tag strings for lifecycle rule matching. | Direct bucket tagging helper imports from lifecycle rule paths. | | `LifecycleObjectLockStore` | Object-lock retention and deletion checks used by lifecycle evaluation and worker deletion paths. | Direct object-lock module imports from lifecycle code. | -| `LifecycleReplicationSink` | Lifecycle-originated delete and version-purge replication scheduling. | Direct imports from bucket replication modules. | +| `LifecycleReplicationSink` | Lifecycle-originated delete and version-purge replication scheduling. | Boundary is local, but still backed by ECStore bucket replication internals. | | `LifecycleAuditSink` | Lifecycle audit and notification event emission. | Direct event notification service calls and audit-side effects from worker code. | ## Migration Rules @@ -61,3 +61,6 @@ tier delete journal recovery while preserving the existing ECStore config store. existing ECStore bucket tagging implementation. `object_lock_boundary.rs` centralizes lifecycle object-lock checks while preserving the existing ECStore object-lock implementation. +`replication_sink.rs` centralizes lifecycle-originated replication config checks +and delete scheduling while preserving the existing ECStore replication worker +path. diff --git a/crates/ecstore/src/bucket/lifecycle/bucket_lifecycle_ops.rs b/crates/ecstore/src/bucket/lifecycle/bucket_lifecycle_ops.rs index 0ab7d529c..5e3fca5c6 100644 --- a/crates/ecstore/src/bucket/lifecycle/bucket_lifecycle_ops.rs +++ b/crates/ecstore/src/bucket/lifecycle/bucket_lifecycle_ops.rs @@ -21,13 +21,11 @@ use crate::bucket::lifecycle::evaluator::Evaluator; use crate::bucket::lifecycle::lifecycle::{ self, Lifecycle, ObjectOpts, TransitionOptions, abort_incomplete_multipart_upload_due, }; +use crate::bucket::lifecycle::replication_sink; use crate::bucket::lifecycle::tier_delete_journal::{process_tier_delete_journal_entry, run_tier_delete_journal_recovery_loop}; use crate::bucket::lifecycle::tier_free_version_recovery::{DEFAULT_FREE_VERSION_RECOVERY_LIMIT, recover_tier_free_versions}; use crate::bucket::lifecycle::tier_last_day_stats::{DailyAllTierStats, LastDayTierStats}; use crate::bucket::lifecycle::tier_sweeper::{Jentry, delete_object_from_remote_tier_idempotent}; -use crate::bucket::replication::{ - DeletedObjectReplicationInfo, ReplicationConfig, check_replicate_delete, schedule_replication_delete, -}; use crate::bucket::{metadata_sys, metadata_sys::get_lifecycle_config, versioning_sys::BucketVersioningSys}; use crate::client::object_api_utils::new_getobjectreader; use crate::disk::error::DiskError; @@ -61,8 +59,8 @@ use rustfs_config::{ }; use rustfs_data_usage::TierStats; use rustfs_filemeta::{ - FileInfo, FileInfoOpts, NULL_VERSION_ID, REPLICATE_INCOMING_DELETE, ReplicateDecision, ReplicationState, RestoreStatusOps, - VersionPurgeStatusType, get_file_info, is_restored_object_on_disk, + FileInfo, FileInfoOpts, NULL_VERSION_ID, ReplicateDecision, ReplicationState, RestoreStatusOps, VersionPurgeStatusType, + get_file_info, is_restored_object_on_disk, }; use rustfs_utils::{get_env_i64, get_env_usize, path::encode_dir_object, string::strings_has_prefix_fold}; use s3s::dto::{ @@ -1948,7 +1946,7 @@ pub async fn enqueue_immediate_expiry(oi: &ObjectInfo, src: LcEventSrc) { Err(_) => None, }; let replication = match metadata_sys::get_replication_config(&oi.bucket).await { - Ok((cfg, _)) if !cfg.rules.is_empty() => Some(Arc::new(ReplicationConfig::new(Some(cfg), None))), + Ok((cfg, _)) if !cfg.rules.is_empty() => Some(Arc::new(replication_sink::new_replication_config(cfg))), _ => None, }; @@ -2703,13 +2701,7 @@ async fn schedule_lifecycle_replication_delete_if_needed(oi: &ObjectInfo, dobj: delete_object.replication_state = replication_state; - schedule_replication_delete(DeletedObjectReplicationInfo { - delete_object, - bucket: oi.bucket.clone(), - event_type: REPLICATE_INCOMING_DELETE.to_string(), - ..Default::default() - }) - .await; + replication_sink::schedule_delete(oi.bucket.clone(), delete_object).await; } fn should_reuse_lifecycle_delete_replication_state(oi: &ObjectInfo, version_delete: bool) -> bool { @@ -2752,9 +2744,9 @@ async fn lifecycle_delete_replication_state(oi: &ObjectInfo, version_id: Option< return Some(state); } - let dsc = check_replicate_delete( + let dsc = replication_sink::check_delete_replication( &oi.bucket, - &ObjectToDelete { + ObjectToDelete { object_name: oi.name.clone(), version_id, ..Default::default() @@ -2765,7 +2757,6 @@ async fn lifecycle_delete_replication_state(oi: &ObjectInfo, version_id: Option< versioned: BucketVersioningSys::prefix_enabled(&oi.bucket, &oi.name).await, ..Default::default() }, - None, ) .await; if !dsc.replicate_any() { diff --git a/crates/ecstore/src/bucket/lifecycle/evaluator.rs b/crates/ecstore/src/bucket/lifecycle/evaluator.rs index cf0767e39..406a674eb 100644 --- a/crates/ecstore/src/bucket/lifecycle/evaluator.rs +++ b/crates/ecstore/src/bucket/lifecycle/evaluator.rs @@ -20,7 +20,7 @@ use tracing::info; use super::object_lock_boundary; use crate::bucket::lifecycle::lifecycle::{Event, Lifecycle, ObjectOpts}; -use crate::bucket::replication::ReplicationConfig; +use crate::bucket::lifecycle::replication_sink::{self, LifecycleReplicationConfig}; use rustfs_common::metrics::IlmAction; const LOG_COMPONENT_ECSTORE: &str = "ecstore"; @@ -32,7 +32,7 @@ const EVENT_LIFECYCLE_VERSION_SCAN_SKIPPED: &str = "lifecycle_version_scan_skipp pub struct Evaluator { policy: Arc, lock_retention: Option>, - repl_cfg: Option>, + repl_cfg: Option>, } impl Evaluator { @@ -52,27 +52,16 @@ impl Evaluator { } /// WithReplicationConfig - sets the replication configuration for the evaluator - pub fn with_replication_config(mut self, rcfg: Option>) -> Self { + pub fn with_replication_config(mut self, rcfg: Option>) -> Self { self.repl_cfg = rcfg; self } /// IsPendingReplication checks if the object is pending replication. pub fn is_pending_replication(&self, obj: &ObjectOpts) -> bool { - use crate::bucket::replication::ReplicationConfigurationExt; - if self.repl_cfg.is_none() { - return false; - } - if let Some(rcfg) = &self.repl_cfg - && rcfg - .config - .as_ref() - .is_some_and(|config| config.has_active_rules(obj.name.as_str(), true)) - && !obj.version_purge_status.is_empty() - { - return true; - } - false + self.repl_cfg + .as_ref() + .is_some_and(|rcfg| replication_sink::has_pending_version_purge(rcfg, obj)) } /// IsObjectLocked checks if it is appropriate to remove an diff --git a/crates/ecstore/src/bucket/lifecycle/mod.rs b/crates/ecstore/src/bucket/lifecycle/mod.rs index 55b65a6b0..35d2fc24b 100644 --- a/crates/ecstore/src/bucket/lifecycle/mod.rs +++ b/crates/ecstore/src/bucket/lifecycle/mod.rs @@ -19,6 +19,7 @@ pub mod core; pub mod evaluator; mod object_lock_boundary; pub use self::core as lifecycle; +mod replication_sink; pub mod rule; mod runtime_boundary; mod tagging_boundary; diff --git a/crates/ecstore/src/bucket/lifecycle/replication_sink.rs b/crates/ecstore/src/bucket/lifecycle/replication_sink.rs new file mode 100644 index 000000000..18f1f0057 --- /dev/null +++ b/crates/ecstore/src/bucket/lifecycle/replication_sink.rs @@ -0,0 +1,115 @@ +// 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. + +use rustfs_filemeta::{REPLICATE_INCOMING_DELETE, ReplicateDecision}; +use s3s::dto::ReplicationConfiguration; + +use crate::bucket::lifecycle::lifecycle::ObjectOpts; +use crate::bucket::replication::{self, DeletedObjectReplicationInfo, ReplicationConfig, ReplicationConfigurationExt as _}; +use crate::object_api::{ObjectInfo, ObjectOptions}; +use crate::storage_api_contracts::object::{DeletedObject, ObjectToDelete}; + +pub(crate) type LifecycleReplicationConfig = ReplicationConfig; + +pub(crate) fn new_replication_config(config: ReplicationConfiguration) -> LifecycleReplicationConfig { + ReplicationConfig::new(Some(config), None) +} + +pub(crate) fn has_pending_version_purge(config: &LifecycleReplicationConfig, obj: &ObjectOpts) -> bool { + config + .config + .as_ref() + .is_some_and(|config| config.has_active_rules(obj.name.as_str(), true)) + && !obj.version_purge_status.is_empty() +} + +pub(crate) async fn check_delete_replication( + bucket: &str, + object: ObjectToDelete, + source: &ObjectInfo, + opts: &ObjectOptions, +) -> ReplicateDecision { + replication::check_replicate_delete(bucket, &object, source, opts, None).await +} + +pub(crate) async fn schedule_delete(bucket: String, delete_object: DeletedObject) { + replication::schedule_replication_delete(DeletedObjectReplicationInfo { + delete_object, + bucket, + event_type: REPLICATE_INCOMING_DELETE.to_string(), + ..Default::default() + }) + .await; +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use rustfs_filemeta::{ReplicationStatusType, VersionPurgeStatusType}; + use s3s::dto::{Destination, ReplicationRule, ReplicationRuleStatus}; + + use super::*; + + fn replication_rule() -> ReplicationRule { + ReplicationRule { + delete_marker_replication: None, + delete_replication: None, + destination: Destination { + bucket: "arn:aws:s3:::target-bucket".to_string(), + ..Default::default() + }, + existing_object_replication: None, + filter: None, + id: Some("rule".to_string()), + prefix: Some(String::new()), + priority: Some(1), + source_selection_criteria: None, + status: ReplicationRuleStatus::from_static(ReplicationRuleStatus::ENABLED), + } + } + + fn object_opts(version_purge_status: VersionPurgeStatusType) -> ObjectOpts { + ObjectOpts { + name: "logs/object".to_string(), + user_tags: String::new(), + mod_time: None, + size: 0, + version_id: None, + is_latest: true, + delete_marker: false, + num_versions: 1, + successor_mod_time: None, + transition_status: String::new(), + restore_ongoing: false, + restore_expires: None, + versioned: true, + version_suspended: false, + user_defined: HashMap::new(), + version_purge_status, + replication_status: ReplicationStatusType::default(), + } + } + + #[test] + fn has_pending_version_purge_preserves_replication_active_rule_behavior() { + let config = new_replication_config(ReplicationConfiguration { + role: String::new(), + rules: vec![replication_rule()], + }); + + assert!(has_pending_version_purge(&config, &object_opts(VersionPurgeStatusType::Pending))); + assert!(!has_pending_version_purge(&config, &object_opts(VersionPurgeStatusType::default()))); + } +} diff --git a/docs/architecture/global-state-inventory.md b/docs/architecture/global-state-inventory.md index 826b82173..c0c280052 100644 --- a/docs/architecture/global-state-inventory.md +++ b/docs/architecture/global-state-inventory.md @@ -50,11 +50,13 @@ migration PR removes or replaces each item. | `GLOBAL_LOCAL_LOCK_CLIENT`, `GLOBAL_LOCK_CLIENTS`, `GLOBAL_LOCK_MANAGER` | `crates/ecstore/src/runtime/global.rs`, `crates/lock` | Runtime migration target / process-global split | ECStore lock client direct access now stays behind ECStore runtime helpers; preserve lock quorum and lock client selection while keeping the process-level lock manager separate from endpoint-specific clients. | | `GLOBAL_CONN_MAP`, `GLOBAL_LOCAL_NODE_NAME`, `GLOBAL_RUSTFS_HOST`, `GLOBAL_RUSTFS_ADDR`, `GLOBAL_ROOT_CERT`, `GLOBAL_MTLS_IDENTITY`, `GLOBAL_OUTBOUND_TLS_GENERATION` | `crates/common`, `crates/tls-runtime`, `crates/ecstore/src/runtime/sources.rs` | Runtime migration target / process-global split | Internode connection cache, common local node name, RustFS host/address reads, and outbound TLS material reads are now owned behind `rustfs_common` helpers; migrate the remaining transport and TLS state only after internode transport and outbound TLS ownership are explicit, without changing cached channel reuse or TLS reload semantics. | | `GLOBAL_RUSTFS_RPC_SECRET` | `crates/credentials`, `crates/ecstore/src/runtime/sources.rs` | Runtime migration target / process-global split | RPC auth token writes now stay behind the `rustfs_credentials` helper boundary; migrate only if runtime secret ownership changes, preserving lazy environment and credential-derived token semantics. | -| `GLOBAL_HEAL_MANAGER`, `GLOBAL_HEAL_CHANNEL_PROCESSOR`, `GLOBAL_AHM_SERVICES_CANCEL_TOKEN` | `crates/heal` and `crates/common` | Runtime migration target | Needs heal runtime owner handles and queue tests; do not combine with ECStore disk-state movement. | -| `AUDIT_SYSTEM`, `GLOBAL_CAPACITY_MANAGER`, `GLOBAL_BUCKET_TARGET_SYS` | Owner crates | Runtime migration target / process-global split | Track as owner-specific follow-ups; each owner must decide whether AppContext, a runtime-source facade, or process-global state is the right final shape. | +| `GLOBAL_HEAL_MANAGER`, `GLOBAL_HEAL_CHANNEL_PROCESSOR`, `GLOBAL_AHM_SERVICES_CANCEL_TOKEN` | `crates/heal/src/lib.rs` | Runtime migration target / process-global split | Direct access now stays inside the heal owner; callers use heal helper functions until heal runtime ownership moves behind explicit owner handles. | +| `AUDIT_SYSTEM` | `crates/audit/src/global.rs` | Runtime migration target / process-global split | Direct global access now stays inside the audit owner; callers use audit helper functions until audit lifecycle ownership moves behind AppContext or a runtime-source boundary. | | `GLOBAL_PROCESSORS` | `crates/ecstore/src/services/batch_processor.rs`, `crates/ecstore/src/runtime/sources.rs` | Runtime migration target / owner helper | Direct static access now stays inside the ECStore batch processor owner; callers use `get_global_processors` or the ECStore runtime-source helper until processor ownership moves into an injected runtime context. | | `INTERNODE_DATA_TRANSPORT` | `crates/ecstore/src/cluster/rpc/internode_data_transport.rs` | Runtime migration target / owner helper | Direct static access now stays inside the ECStore internode transport owner; callers use `build_internode_data_transport_from_env` until backend selection moves into an injected runtime context. | | `GLOBAL_KMS_SERVICE_MANAGER` | `crates/kms/src/service_manager.rs`, RustFS KMS runtime sources | Runtime migration target / owner helper | Direct static access now stays inside the `rustfs_kms` service manager owner; RustFS callers use KMS helpers or AppContext/runtime-source handles until KMS ownership fully moves into runtime context. | +| `GLOBAL_CAPACITY_MANAGER` | `crates/object-capacity/src/capacity_manager.rs`, RustFS capacity service | Runtime migration target / owner helper | Direct static access now stays inside the object-capacity owner; callers use `get_capacity_manager` or isolated manager factories until capacity ownership moves into an injected runtime context. | +| `GLOBAL_BUCKET_TARGET_SYS` | `crates/ecstore/src/bucket/bucket_target_sys.rs`, admin/app/scanner/replication target paths | Runtime migration target / owner helper | Direct static access now stays inside the ECStore bucket target owner; callers still use `BucketTargetSys::get()` until bucket target ownership moves behind a runtime-source or replication target boundary. | ## First Code-Bearing Candidate diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index 4f90827fd..7c739901f 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -126,6 +126,7 @@ LIFECYCLE_AUDIT_SINK_BYPASS_HITS_FILE="${TMP_DIR}/lifecycle_audit_sink_bypass_hi LIFECYCLE_CONFIG_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/lifecycle_config_boundary_bypass_hits.txt" LIFECYCLE_TAGGING_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/lifecycle_tagging_boundary_bypass_hits.txt" LIFECYCLE_OBJECT_LOCK_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/lifecycle_object_lock_boundary_bypass_hits.txt" +LIFECYCLE_REPLICATION_SINK_BYPASS_HITS_FILE="${TMP_DIR}/lifecycle_replication_sink_bypass_hits.txt" STORE_API_EXTERNAL_LIST_CONSUMER_HITS_FILE="${TMP_DIR}/store_api_external_list_consumer_hits.txt" STORE_API_EXTERNAL_OPERATION_CONSUMER_HITS_FILE="${TMP_DIR}/store_api_external_operation_consumer_hits.txt" STORE_API_OBJECT_OPERATION_LOCAL_METHOD_HITS_FILE="${TMP_DIR}/store_api_object_operation_local_method_hits.txt" @@ -196,6 +197,7 @@ REPLICATION_TAGGING_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/replication_tagging_bo REPLICATION_VERSIONING_BOUNDARY_BYPASS_HITS_FILE="${TMP_DIR}/replication_versioning_boundary_bypass_hits.txt" REPLICATION_RUNTIME_SOURCE_BYPASS_HITS_FILE="${TMP_DIR}/replication_runtime_source_bypass_hits.txt" GLOBAL_REPLICATION_STATE_BYPASS_HITS_FILE="${TMP_DIR}/global_replication_state_bypass_hits.txt" +GLOBAL_BUCKET_TARGET_SYS_BYPASS_HITS_FILE="${TMP_DIR}/global_bucket_target_sys_bypass_hits.txt" GLOBAL_BUCKET_MONITOR_BYPASS_HITS_FILE="${TMP_DIR}/global_bucket_monitor_bypass_hits.txt" GLOBAL_ENDPOINTS_BYPASS_HITS_FILE="${TMP_DIR}/global_endpoints_bypass_hits.txt" GLOBAL_IS_ERASURE_BYPASS_HITS_FILE="${TMP_DIR}/global_is_erasure_bypass_hits.txt" @@ -211,9 +213,12 @@ GLOBAL_BOOT_TIME_BYPASS_HITS_FILE="${TMP_DIR}/global_boot_time_bypass_hits.txt" GLOBAL_ECSTORE_LOCAL_NODE_NAME_BYPASS_HITS_FILE="${TMP_DIR}/global_ecstore_local_node_name_bypass_hits.txt" GLOBAL_RUNTIME_SCALAR_BYPASS_HITS_FILE="${TMP_DIR}/global_runtime_scalar_bypass_hits.txt" GLOBAL_BACKGROUND_CANCEL_BYPASS_HITS_FILE="${TMP_DIR}/global_background_cancel_bypass_hits.txt" +AUDIT_SYSTEM_BYPASS_HITS_FILE="${TMP_DIR}/audit_system_bypass_hits.txt" +HEAL_OWNER_GLOBAL_BYPASS_HITS_FILE="${TMP_DIR}/heal_owner_global_bypass_hits.txt" GLOBAL_LOCK_CLIENTS_BYPASS_HITS_FILE="${TMP_DIR}/global_lock_clients_bypass_hits.txt" GLOBAL_BATCH_PROCESSORS_BYPASS_HITS_FILE="${TMP_DIR}/global_batch_processors_bypass_hits.txt" INTERNODE_DATA_TRANSPORT_BYPASS_HITS_FILE="${TMP_DIR}/internode_data_transport_bypass_hits.txt" +GLOBAL_CAPACITY_MANAGER_BYPASS_HITS_FILE="${TMP_DIR}/global_capacity_manager_bypass_hits.txt" GLOBAL_CONN_MAP_BYPASS_HITS_FILE="${TMP_DIR}/global_conn_map_bypass_hits.txt" GLOBAL_LOCAL_NODE_NAME_BYPASS_HITS_FILE="${TMP_DIR}/global_local_node_name_bypass_hits.txt" GLOBAL_RUSTFS_ADDR_BYPASS_HITS_FILE="${TMP_DIR}/global_rustfs_addr_bypass_hits.txt" @@ -843,6 +848,18 @@ if [[ -s "$LIFECYCLE_OBJECT_LOCK_BOUNDARY_BYPASS_HITS_FILE" ]]; then report_failure "lifecycle object-lock checks must stay behind lifecycle object_lock_boundary: $(paste -sd '; ' "$LIFECYCLE_OBJECT_LOCK_BOUNDARY_BYPASS_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --with-filename 'crate::bucket::replication' \ + crates/ecstore/src/bucket/lifecycle \ + --glob '*.rs' | + rg -v '^crates/ecstore/src/bucket/lifecycle/replication_sink\.rs:' || true +) >"$LIFECYCLE_REPLICATION_SINK_BYPASS_HITS_FILE" + +if [[ -s "$LIFECYCLE_REPLICATION_SINK_BYPASS_HITS_FILE" ]]; then + report_failure "lifecycle replication scheduling must stay behind lifecycle replication_sink: $(paste -sd '; ' "$LIFECYCLE_REPLICATION_SINK_BYPASS_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'rustfs_ecstore::store_api(?:::\{[^}]*\b(?:ListObjectVersionsInfo|ListObjectsV2Info|ObjectInfoOrErr)\b|::(?:ListObjectVersionsInfo|ListObjectsV2Info|ObjectInfoOrErr)\b)' \ @@ -2498,6 +2515,18 @@ if [[ -s "$GLOBAL_REPLICATION_STATE_BYPASS_HITS_FILE" ]]; then report_failure "GLOBAL_REPLICATION_POOL/STATS access must stay behind replication owner or ECStore runtime-source helpers: $(paste -sd '; ' "$GLOBAL_REPLICATION_STATE_BYPASS_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --with-filename '\bGLOBAL_BUCKET_TARGET_SYS\b' \ + crates rustfs fuzz \ + --glob '*.rs' | + rg -v '^crates/ecstore/src/bucket/bucket_target_sys\.rs:' || true +) >"$GLOBAL_BUCKET_TARGET_SYS_BYPASS_HITS_FILE" + +if [[ -s "$GLOBAL_BUCKET_TARGET_SYS_BYPASS_HITS_FILE" ]]; then + report_failure "GLOBAL_BUCKET_TARGET_SYS access must stay behind ECStore bucket target owner helpers: $(paste -sd '; ' "$GLOBAL_BUCKET_TARGET_SYS_BYPASS_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --with-filename '\bGLOBAL_BUCKET_MONITOR\b' \ @@ -2678,6 +2707,30 @@ if [[ -s "$GLOBAL_BACKGROUND_CANCEL_BYPASS_HITS_FILE" ]]; then report_failure "background service cancellation must stay behind ECStore runtime-source helpers: $(paste -sd '; ' "$GLOBAL_BACKGROUND_CANCEL_BYPASS_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --with-filename '\bAUDIT_SYSTEM\b' \ + crates rustfs fuzz \ + --glob '*.rs' | + rg -v '^crates/audit/src/global\.rs:' || true +) >"$AUDIT_SYSTEM_BYPASS_HITS_FILE" + +if [[ -s "$AUDIT_SYSTEM_BYPASS_HITS_FILE" ]]; then + report_failure "AUDIT_SYSTEM access must stay behind audit owner helpers: $(paste -sd '; ' "$AUDIT_SYSTEM_BYPASS_HITS_FILE")" +fi + +( + cd "$ROOT_DIR" + rg -n --with-filename '\bGLOBAL_(HEAL_MANAGER|HEAL_CHANNEL_PROCESSOR|AHM_SERVICES_CANCEL_TOKEN)\b' \ + crates rustfs fuzz \ + --glob '*.rs' | + rg -v '^crates/heal/src/lib\.rs:' || true +) >"$HEAL_OWNER_GLOBAL_BYPASS_HITS_FILE" + +if [[ -s "$HEAL_OWNER_GLOBAL_BYPASS_HITS_FILE" ]]; then + report_failure "heal owner globals must stay behind heal owner helpers: $(paste -sd '; ' "$HEAL_OWNER_GLOBAL_BYPASS_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --with-filename '\bGLOBAL_(LOCAL_LOCK_CLIENT|LOCK_CLIENTS)\b' \ @@ -2714,6 +2767,18 @@ if [[ -s "$INTERNODE_DATA_TRANSPORT_BYPASS_HITS_FILE" ]]; then report_failure "internode data transport static must stay behind ECStore internode transport helpers: $(paste -sd '; ' "$INTERNODE_DATA_TRANSPORT_BYPASS_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --with-filename '\bGLOBAL_CAPACITY_MANAGER\b' \ + crates rustfs fuzz \ + --glob '*.rs' | + rg -v '^crates/object-capacity/src/capacity_manager\.rs:' || true +) >"$GLOBAL_CAPACITY_MANAGER_BYPASS_HITS_FILE" + +if [[ -s "$GLOBAL_CAPACITY_MANAGER_BYPASS_HITS_FILE" ]]; then + report_failure "GLOBAL_CAPACITY_MANAGER access must stay behind rustfs_object_capacity helpers: $(paste -sd '; ' "$GLOBAL_CAPACITY_MANAGER_BYPASS_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --with-filename '\bGLOBAL_CONN_MAP\b' \