TOCTOU and lifecycle races across runtime boundaries fixes

This commit is contained in:
Alexey
2026-09-19 22:37:22 +03:00
parent acad414cc7
commit 89dacbd17e
20 changed files with 194 additions and 24 deletions
+11
View File
@@ -266,16 +266,22 @@ pub struct RoutingCore {
pub(super) writers: Arc<WritersState>,
pub(super) rr: AtomicU64,
pub(super) writer_epoch: watch::Sender<u64>,
/// Coherent immutable authority for endpoint maps and reverse indexes.
pub(super) endpoint_snapshot: ArcSwap<EndpointSnapshot>,
}
/// Immutable endpoint routing authority published as one coherent revision.
#[derive(Clone, Debug)]
pub(super) struct EndpointSnapshot {
/// Monotonic revision covering every endpoint-derived index in this snapshot.
pub(super) revision: u64,
/// IPv4 endpoint map by Telegram DC.
pub(super) map_v4: HashMap<i32, Vec<(IpAddr, u16)>>,
/// IPv6 endpoint map by Telegram DC.
pub(super) map_v6: HashMap<i32, Vec<(IpAddr, u16)>>,
/// Reverse lookup from an endpoint to its optional Telegram DC.
pub(super) endpoint_dc_map: HashMap<SocketAddr, Option<i32>>,
/// Ordered endpoint candidates used for per-DC writer selection.
pub(super) preferred_endpoints_by_dc: HashMap<i32, Vec<SocketAddr>>,
}
@@ -312,6 +318,7 @@ pub(super) struct ReinitPendingState {
pub(super) generation: u64,
pub(super) started_at_epoch_secs: u64,
pub(super) map_hash: u64,
/// Endpoint authority revision targeted by the pending generation.
pub(super) endpoint_revision: u64,
}
@@ -319,6 +326,7 @@ pub(super) struct ReinitPendingState {
pub(super) struct ReinitAttemptState {
pub(super) generation: u64,
pub(super) map_hash: u64,
/// Endpoint authority revision captured by this attempt.
pub(super) endpoint_revision: u64,
pub(super) hardswap: bool,
pub(super) committed: bool,
@@ -328,6 +336,7 @@ pub(super) struct ReinitCoordinatorState {
pub(super) next_attempt_id: u64,
pub(super) active_generation: u64,
pub(super) desired_map_hash: u64,
/// Latest endpoint authority revision accepted by the coordinator.
pub(super) endpoint_revision: u64,
pub(super) pending: Option<ReinitPendingState>,
pub(super) attempts: HashMap<u64, ReinitAttemptState>,
@@ -492,8 +501,10 @@ pub struct MePool {
pub(super) next_writer_id: AtomicU64,
pub(super) writer_connect_active_reserved: AtomicUsize,
pub(super) writer_connect_warm_reserved: AtomicUsize,
/// Replacement connections opened but not yet committed to writer visibility.
pub(super) writer_replacement_open_reserved: AtomicUsize,
pub(super) rtt_stats: Arc<Mutex<HashMap<u64, (f64, f64)>>>,
/// Coalesced refill state keyed by exact generation and contour ownership.
pub(super) refill_states: Arc<ParkingMutex<HashMap<RefillTargetKey, RefillTargetState>>>,
pub(super) refill_running: AtomicUsize,
pub(super) refill_pending: AtomicUsize,
@@ -144,6 +144,7 @@ impl MePool {
}
}
/// Builds all endpoint-derived indexes under one immutable revision.
pub(in crate::transport::middle_proxy) fn build_endpoint_snapshot(
decision: &NetworkDecision,
mut map_v4: HashMap<i32, Vec<(IpAddr, u16)>>,
@@ -272,6 +273,7 @@ impl MePool {
endpoint_dc_map
}
/// Removes runtime endpoint state absent from the current coherent snapshot.
pub(in crate::transport::middle_proxy) async fn prune_endpoint_runtime_state(&self) {
let configured_endpoints = self
.endpoint_snapshot
@@ -307,6 +307,7 @@ impl MePool {
self.desired_dc_endpoints_from_snapshot(&endpoint_snapshot)
}
/// Projects desired per-DC endpoint sets from one immutable endpoint revision.
pub(super) fn desired_dc_endpoints_from_snapshot(
&self,
endpoint_snapshot: &EndpointSnapshot,
@@ -30,6 +30,7 @@ impl MePool {
self.api_hardswap_snapshot_for_reinit(reinit.as_ref()).await
}
/// Builds the bounded projection from one coherent reinitialization snapshot.
pub(super) async fn api_hardswap_snapshot_for_reinit(
&self,
reinit: &ReinitStatusSnapshot,