This commit is contained in:
Alexey
2026-03-21 15:45:29 +03:00
parent 7a8f946029
commit d7bbb376c9
154 changed files with 6194 additions and 3775 deletions
@@ -10,9 +10,9 @@ use tokio_util::sync::CancellationToken;
use super::codec::WriterCommand;
use super::health::{health_drain_close_budget, reap_draining_writers};
use super::me_health_monitor;
use super::pool::{MePool, MeWriter, WriterContour};
use super::registry::ConnMeta;
use super::me_health_monitor;
use crate::config::{GeneralConfig, MeRouteNoWriterMode, MeSocksKdfPolicy, MeWriterPickMode};
use crate::crypto::SecureRandom;
use crate::network::probe::NetworkDecision;
@@ -241,14 +241,7 @@ async fn reap_draining_writers_respects_threshold_across_multiple_overflow_cycle
let now_epoch_secs = MePool::now_epoch_secs();
for writer_id in 1..=60u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(20),
1,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(20), 1, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -267,17 +260,12 @@ async fn reap_draining_writers_respects_threshold_across_multiple_overflow_cycle
async fn reap_draining_writers_handles_large_empty_writer_population() {
let (pool, _rng) = make_pool(128, 1, 1).await;
let now_epoch_secs = MePool::now_epoch_secs();
let total = health_drain_close_budget().saturating_mul(3).saturating_add(27);
let total = health_drain_close_budget()
.saturating_mul(3)
.saturating_add(27);
for writer_id in 1..=total as u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(120),
0,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(120), 0, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -295,7 +283,9 @@ async fn reap_draining_writers_handles_large_empty_writer_population() {
async fn reap_draining_writers_processes_mass_deadline_expiry_without_unbounded_growth() {
let (pool, _rng) = make_pool(128, 1, 1).await;
let now_epoch_secs = MePool::now_epoch_secs();
let total = health_drain_close_budget().saturating_mul(4).saturating_add(31);
let total = health_drain_close_budget()
.saturating_mul(4)
.saturating_add(31);
for writer_id in 1..=total as u64 {
insert_draining_writer(
@@ -580,14 +570,7 @@ async fn reap_draining_writers_repeated_draining_flips_never_leave_stale_warn_st
let now_epoch_secs = MePool::now_epoch_secs();
for writer_id in 1..=24u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(240),
1,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(240), 1, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -9,9 +9,9 @@ use tokio_util::sync::CancellationToken;
use super::codec::WriterCommand;
use super::health::health_drain_close_budget;
use super::me_health_monitor;
use super::pool::{MePool, MeWriter, WriterContour};
use super::registry::ConnMeta;
use super::me_health_monitor;
use crate::config::{GeneralConfig, MeRouteNoWriterMode, MeSocksKdfPolicy, MeWriterPickMode};
use crate::crypto::SecureRandom;
use crate::network::probe::NetworkDecision;
@@ -185,7 +185,9 @@ async fn wait_for_pool_empty(pool: &Arc<MePool>, timeout: Duration) {
async fn me_health_monitor_drains_expired_backlog_over_multiple_cycles() {
let (pool, rng) = make_pool(128, 1, 1).await;
let now_epoch_secs = MePool::now_epoch_secs();
let writer_total = health_drain_close_budget().saturating_mul(2).saturating_add(9);
let writer_total = health_drain_close_budget()
.saturating_mul(2)
.saturating_add(9);
for writer_id in 1..=writer_total as u64 {
insert_draining_writer(
&pool,
@@ -270,14 +270,7 @@ async fn reap_draining_writers_limits_closes_per_health_tick() {
let close_budget = health_drain_close_budget();
let writer_total = close_budget.saturating_add(20);
for writer_id in 1..=writer_total as u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(20),
1,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(20), 1, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -304,10 +297,7 @@ async fn reap_draining_writers_keeps_warn_state_for_deadline_backlog_writers() {
}
let target_writer_id = writer_total as u64;
let mut warn_next_allowed = HashMap::new();
warn_next_allowed.insert(
target_writer_id,
Instant::now() + Duration::from_secs(300),
);
warn_next_allowed.insert(target_writer_id, Instant::now() + Duration::from_secs(300));
reap_draining_writers(&pool, &mut warn_next_allowed).await;
@@ -333,10 +323,7 @@ async fn reap_draining_writers_keeps_warn_state_for_overflow_backlog_writers() {
}
let target_writer_id = writer_total.saturating_sub(1) as u64;
let mut warn_next_allowed = HashMap::new();
warn_next_allowed.insert(
target_writer_id,
Instant::now() + Duration::from_secs(300),
);
warn_next_allowed.insert(target_writer_id, Instant::now() + Duration::from_secs(300));
reap_draining_writers(&pool, &mut warn_next_allowed).await;
@@ -382,10 +369,7 @@ async fn reap_draining_writers_preserves_warn_state_across_multiple_budget_defer
let tail_writer_id = writer_total as u64;
let mut warn_next_allowed = HashMap::new();
warn_next_allowed.insert(
tail_writer_id,
Instant::now() + Duration::from_secs(300),
);
warn_next_allowed.insert(tail_writer_id, Instant::now() + Duration::from_secs(300));
reap_draining_writers(&pool, &mut warn_next_allowed).await;
assert!(writer_exists(&pool, tail_writer_id).await);
@@ -410,14 +394,7 @@ async fn reap_draining_writers_backlog_drains_across_ticks() {
let close_budget = health_drain_close_budget();
let writer_total = close_budget.saturating_mul(2).saturating_add(7);
for writer_id in 1..=writer_total as u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(20),
0,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(20), 0, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -439,14 +416,7 @@ async fn reap_draining_writers_threshold_backlog_converges_to_threshold() {
let close_budget = health_drain_close_budget();
let writer_total = threshold as usize + close_budget.saturating_add(12);
for writer_id in 1..=writer_total as u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(20),
1,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(20), 1, 0).await;
}
let mut warn_next_allowed = HashMap::new();
@@ -480,17 +450,17 @@ async fn reap_draining_writers_prioritizes_force_close_before_empty_cleanup() {
let now_epoch_secs = MePool::now_epoch_secs();
let close_budget = health_drain_close_budget();
for writer_id in 1..=close_budget.saturating_add(1) as u64 {
insert_draining_writer(
&pool,
writer_id,
now_epoch_secs.saturating_sub(20),
1,
0,
)
.await;
insert_draining_writer(&pool, writer_id, now_epoch_secs.saturating_sub(20), 1, 0).await;
}
let empty_writer_id = close_budget.saturating_add(2) as u64;
insert_draining_writer(&pool, empty_writer_id, now_epoch_secs.saturating_sub(20), 0, 0).await;
insert_draining_writer(
&pool,
empty_writer_id,
now_epoch_secs.saturating_sub(20),
0,
0,
)
.await;
let mut warn_next_allowed = HashMap::new();
reap_draining_writers(&pool, &mut warn_next_allowed).await;
@@ -622,14 +592,18 @@ fn general_config_default_drain_threshold_remains_enabled() {
GeneralConfig::default().me_pool_drain_soft_evict_cooldown_ms,
1000
);
assert_eq!(GeneralConfig::default().me_bind_stale_mode, MeBindStaleMode::Never);
assert_eq!(
GeneralConfig::default().me_bind_stale_mode,
MeBindStaleMode::Never
);
}
#[tokio::test]
async fn prune_closed_writers_closes_bound_clients_when_writer_is_non_empty() {
let pool = make_pool(128).await;
let now_epoch_secs = MePool::now_epoch_secs();
let conn_ids = insert_draining_writer(&pool, 910, now_epoch_secs.saturating_sub(60), 1, 0).await;
let conn_ids =
insert_draining_writer(&pool, 910, now_epoch_secs.saturating_sub(60), 1, 0).await;
pool.prune_closed_writers().await;
@@ -132,7 +132,8 @@ async fn connectable_endpoints_releases_quarantine_lock_before_sleep() {
}
let pool_for_task = Arc::clone(&pool);
let task = tokio::spawn(async move { pool_for_task.connectable_endpoints_for_test(&[addr]).await });
let task =
tokio::spawn(async move { pool_for_task.connectable_endpoints_for_test(&[addr]).await });
tokio::time::sleep(Duration::from_millis(10)).await;
@@ -230,7 +230,10 @@ async fn negative_unknown_writer_removal_is_noop() {
assert!(pool.writers.read().await.is_empty());
assert_eq!(pool.conn_count.load(Ordering::Relaxed), 0);
assert_eq!(pool.stats.get_me_endpoint_quarantine_total(), before_quarantine);
assert_eq!(
pool.stats.get_me_endpoint_quarantine_total(),
before_quarantine
);
}
#[tokio::test]
@@ -241,7 +244,10 @@ async fn edge_draining_only_detach_rejects_active_writer() {
insert_writer(&pool, writer_id, 2, addr, false, Instant::now()).await;
let removed = pool.remove_draining_writer_hard_detach(writer_id).await;
assert!(!removed, "active writer must not be detached by draining-only path");
assert!(
!removed,
"active writer must not be detached by draining-only path"
);
assert!(current_writer_ids(&pool).await.contains(&writer_id));
assert_eq!(pool.conn_count.load(Ordering::Relaxed), 1);
@@ -324,8 +330,14 @@ async fn light_fuzz_insert_remove_schedule_preserves_pool_invariants() {
}
let actual_ids = current_writer_ids(&pool).await;
assert_eq!(actual_ids, model, "writer-id set must match model under fuzz schedule");
assert_eq!(pool.conn_count.load(Ordering::Relaxed) as usize, model.len());
assert_eq!(
actual_ids, model,
"writer-id set must match model under fuzz schedule"
);
assert_eq!(
pool.conn_count.load(Ordering::Relaxed) as usize,
model.len()
);
}
for writer_id in model {
@@ -341,7 +353,12 @@ async fn stress_parallel_duplicate_removals_are_idempotent() {
for writer_id in 1..=48u64 {
let addr = SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(127, 14, (writer_id / 250) as u8, (writer_id % 250) as u8)),
IpAddr::V4(Ipv4Addr::new(
127,
14,
(writer_id / 250) as u8,
(writer_id % 250) as u8,
)),
5000 + writer_id as u16,
);
insert_writer(
@@ -363,7 +380,8 @@ async fn stress_parallel_duplicate_removals_are_idempotent() {
if ((writer_id + worker) & 1) == 0 {
pool.remove_writer_and_close_clients(writer_id).await;
} else {
pool.remove_writer_and_close_clients(100_000 + writer_id).await;
pool.remove_writer_and_close_clients(100_000 + writer_id)
.await;
}
}
}));
@@ -205,8 +205,14 @@ async fn send_proxy_req_does_not_replay_when_first_bind_commit_fails() {
.await;
assert!(result.is_ok());
assert_eq!(recv_data_count(&mut stale_rx, Duration::from_millis(50)).await, 0);
assert_eq!(recv_data_count(&mut live_rx, Duration::from_millis(50)).await, 1);
assert_eq!(
recv_data_count(&mut stale_rx, Duration::from_millis(50)).await,
0
);
assert_eq!(
recv_data_count(&mut live_rx, Duration::from_millis(50)).await,
1
);
let bound = pool.registry.get_writer(conn_id).await;
assert!(bound.is_some());
@@ -258,9 +264,18 @@ async fn send_proxy_req_prunes_iterative_stale_bind_failures_without_data_replay
.await;
assert!(result.is_ok());
assert_eq!(recv_data_count(&mut stale_rx_1, Duration::from_millis(50)).await, 0);
assert_eq!(recv_data_count(&mut stale_rx_2, Duration::from_millis(50)).await, 0);
assert_eq!(recv_data_count(&mut live_rx, Duration::from_millis(50)).await, 1);
assert_eq!(
recv_data_count(&mut stale_rx_1, Duration::from_millis(50)).await,
0
);
assert_eq!(
recv_data_count(&mut stale_rx_2, Duration::from_millis(50)).await,
0
);
assert_eq!(
recv_data_count(&mut live_rx, Duration::from_millis(50)).await,
1
);
let writers = pool.writers.read().await;
let writer_ids = writers.iter().map(|w| w.id).collect::<Vec<_>>();