From c12b73e1ae5fc052edea5ceffa8b87088435c150 Mon Sep 17 00:00:00 2001 From: fanyang89 Date: Fri, 26 Jun 2026 23:31:34 +0800 Subject: [PATCH] fix(stats): use age-based GC check to avoid evicting fresh metrics The millis-since-base staleness check (last > now - 180s) saturated the cutoff to 0 early in process life, so metrics stamped at 0ms failed the strict > 0 test and were wrongly evicted by the immediate first GC tick. Switch to age-based (now - last < 180s), equivalent to the original Instant semantics and robust under clock saturation, which fixes the flaky peer_conn_secure_mode_pubkey_and_encryption test. --- easytier/src/common/stats_manager.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/easytier/src/common/stats_manager.rs b/easytier/src/common/stats_manager.rs index f748e678..00cd2c5a 100644 --- a/easytier/src/common/stats_manager.rs +++ b/easytier/src/common/stats_manager.rs @@ -580,7 +580,12 @@ impl StatsManager { // Drop metrics untouched for 180s and with no live handles. // Compare in the millis-since-base domain so neither the hot // path nor GC reconstructs an `Instant` or locks. - let cutoff_millis = now_millis().saturating_sub(180_000); + // + // Use an age-based check (`now - last < STALE`) rather than + // `last > now - STALE`: early in process life `now_millis()` is + // tiny, so `now - STALE` saturates to 0 and a metric stamped at + // 0 would fail a strict `> 0` test and be wrongly evicted. + let now = now_millis(); let Some(counters) = counters_clone.upgrade() else { break; @@ -588,7 +593,7 @@ impl StatsManager { counters.retain(|_, metric_data: &mut Arc| { Arc::strong_count(metric_data) > 1 - || metric_data.last_updated_millis() > cutoff_millis + || now.saturating_sub(metric_data.last_updated_millis()) < 180_000 }); counters.shrink_to_fit(); }