Summary
The 3c.4 money test (two UDP-blocked peers via the TLS relay) surfaced that the relay's TLS-tunnel path (bin/yip-rendezvous/src/conn_tunnel.rs::route) never incremented the blind-relay forwarded counter — fixed in 3c.4 by adding RendezvousServer::record_relay_forward() and calling it once per routed RelaySend. That fix is correct, but it takes the global Arc<Mutex<RendezvousServer>> on every relayed frame, across all per-connection tasks, purely to bump a u64.
Impact
Under many concurrent TLS tunnels, this serializes forwarding on the server mutex — a lock that the try_send-based delivery path otherwise never touched. It's a scalability bottleneck, not a correctness issue (the lock is held only for a synchronous += 1, no .await inside the critical section — verified deadlock-free by the 3c.4 final review). But it converts the previously lock-free relay-forward hot path into a globally-serialized one.
Fix direction
Replace the forwarded: u64 field (and record_relay_forward/forwarded_count) with an AtomicU64 (e.g. Arc<AtomicU64> shared with, or a field read via &self without the mutex). route() then does a relaxed fetch_add(1) with no server lock at all, and the UDP path's own increment likewise. Keeps the relay-forwarded=<N> stderr observability while removing the per-frame global-mutex acquisition.
Scope
Relay-side (crates/yip-rendezvous), Minor. Surfaced by the 3c.4 final whole-branch review (finding I5).
Summary
The 3c.4 money test (two UDP-blocked peers via the TLS relay) surfaced that the relay's TLS-tunnel path (
bin/yip-rendezvous/src/conn_tunnel.rs::route) never incremented the blind-relayforwardedcounter — fixed in 3c.4 by addingRendezvousServer::record_relay_forward()and calling it once per routedRelaySend. That fix is correct, but it takes the globalArc<Mutex<RendezvousServer>>on every relayed frame, across all per-connection tasks, purely to bump au64.Impact
Under many concurrent TLS tunnels, this serializes forwarding on the
servermutex — a lock that thetry_send-based delivery path otherwise never touched. It's a scalability bottleneck, not a correctness issue (the lock is held only for a synchronous+= 1, no.awaitinside the critical section — verified deadlock-free by the 3c.4 final review). But it converts the previously lock-free relay-forward hot path into a globally-serialized one.Fix direction
Replace the
forwarded: u64field (andrecord_relay_forward/forwarded_count) with anAtomicU64(e.g.Arc<AtomicU64>shared with, or a field read via&selfwithout the mutex).route()then does a relaxedfetch_add(1)with noserverlock at all, and the UDP path's own increment likewise. Keeps therelay-forwarded=<N>stderr observability while removing the per-frame global-mutex acquisition.Scope
Relay-side (
crates/yip-rendezvous), Minor. Surfaced by the 3c.4 final whole-branch review (finding I5).