Skip to content

Commit 34eb32a

Browse files
committed
Clean up Mutex/Instant::now() use for send message error logging
Using mods to reduce the number of #[cfg] attributes needed and make everything more readable Converting to SendErrorSink Removing overzealous clippy attribute Fixing typo in fallback Eliminating an Instant::now() in BBR bandwidth estimation code This was the only case where `Instant::now()` is used in quinn-proto or quinn-udp for anything other than tests or rate-limiting logging. Making this change to keep these two crates more IO-agnostic. Fixing wrong unused variables lint Eliminating an Instant::now() in BBR bandwidth estimation code This was the only case where `Instant::now()` is used in quinn-proto or quinn-udp for anything other than tests or rate-limiting logging. Making this change to keep these two crates more IO-agnostic. Fixing wrong unused variables lint
1 parent 5b42a04 commit 34eb32a

File tree

5 files changed

+58
-84
lines changed

5 files changed

+58
-84
lines changed

quinn-proto/src/congestion/bbr/bw_estimation.rs

+9-29
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ use std::fmt::{Debug, Display, Formatter};
33
use super::min_max::MinMax;
44
use crate::{Duration, Instant};
55

6-
#[derive(Clone, Debug)]
6+
#[derive(Clone, Debug, Default)]
77
pub(crate) struct BandwidthEstimation {
88
total_acked: u64,
99
prev_total_acked: u64,
1010
acked_time: Option<Instant>,
1111
prev_acked_time: Option<Instant>,
1212
total_sent: u64,
1313
prev_total_sent: u64,
14-
sent_time: Instant,
14+
sent_time: Option<Instant>,
1515
prev_sent_time: Option<Instant>,
1616
max_filter: MinMax,
1717
acked_at_last_window: u64,
@@ -21,8 +21,8 @@ impl BandwidthEstimation {
2121
pub(crate) fn on_sent(&mut self, now: Instant, bytes: u64) {
2222
self.prev_total_sent = self.total_sent;
2323
self.total_sent += bytes;
24-
self.prev_sent_time = Some(self.sent_time);
25-
self.sent_time = now;
24+
self.prev_sent_time = self.sent_time;
25+
self.sent_time = Some(now);
2626
}
2727

2828
pub(crate) fn on_ack(
@@ -43,14 +43,13 @@ impl BandwidthEstimation {
4343
None => return,
4444
};
4545

46-
let send_rate = if self.sent_time > prev_sent_time {
47-
Self::bw_from_delta(
46+
let send_rate = match self.sent_time {
47+
Some(sent_time) if sent_time > prev_sent_time => Self::bw_from_delta(
4848
self.total_sent - self.prev_total_sent,
49-
self.sent_time - prev_sent_time,
49+
sent_time - prev_sent_time,
5050
)
51-
.unwrap_or(0)
52-
} else {
53-
u64::MAX // will take the min of send and ack, so this is just a skip
51+
.unwrap_or(0),
52+
_ => u64::MAX, // will take the min of send and ack, so this is just a skip
5453
};
5554

5655
let ack_rate = match self.prev_acked_time {
@@ -91,25 +90,6 @@ impl BandwidthEstimation {
9190
}
9291
}
9392

94-
impl Default for BandwidthEstimation {
95-
fn default() -> Self {
96-
Self {
97-
total_acked: 0,
98-
prev_total_acked: 0,
99-
acked_time: None,
100-
prev_acked_time: None,
101-
total_sent: 0,
102-
prev_total_sent: 0,
103-
// The `sent_time` value set here is ignored; it is used in `on_ack()`, but will
104-
// have been reset by `on_sent()` before that method is called.
105-
sent_time: Instant::now(),
106-
prev_sent_time: None,
107-
max_filter: MinMax::default(),
108-
acked_at_last_window: 0,
109-
}
110-
}
111-
}
112-
11393
impl Display for BandwidthEstimation {
11494
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
11595
write!(

quinn-udp/src/fallback.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use std::io::{self, IoSliceMut};
22

3-
use super::{last_send_error, log_sendmsg_error, LastSendError, RecvMeta, Transmit, UdpSockRef};
3+
use super::{RecvMeta, SendErrorSink, Transmit, UdpSockRef};
44

55
/// Fallback UDP socket interface that stubs out all special functionality
66
///
77
/// Used when a better implementation is not available for a particular target, at the cost of
88
/// reduced performance compared to that enabled by some target-specific interfaces.
99
#[derive(Debug)]
1010
pub struct UdpSocketState {
11-
last_send_error: LastSendError,
11+
last_send_error: SendErrorSink,
1212
}
1313

1414
impl UdpSocketState {
1515
pub fn new(socket: UdpSockRef<'_>) -> io::Result<Self> {
1616
socket.0.set_nonblocking(true)?;
1717
Ok(Self {
18-
last_send_error: last_send_error(),
18+
last_send_error: SendErrorSink::new(),
1919
})
2020
}
2121

@@ -35,7 +35,7 @@ impl UdpSocketState {
3535
Ok(()) => Ok(()),
3636
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e),
3737
Err(e) => {
38-
log_sendmsg_error(&self.last_send_error, e, transmit);
38+
self.last_send_error.log_sendmsg_error(e, transmit);
3939

4040
Ok(())
4141
}

quinn-udp/src/lib.rs

+37-39
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::net::{IpAddr, Ipv6Addr, SocketAddr};
3232
use std::os::unix::io::AsFd;
3333
#[cfg(windows)]
3434
use std::os::windows::io::AsSocket;
35-
#[cfg(not(wasm_browser))]
35+
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
3636
use std::{
3737
sync::Mutex,
3838
time::{Duration, Instant},
@@ -146,49 +146,47 @@ pub struct Transmit<'a> {
146146
pub src_ip: Option<IpAddr>,
147147
}
148148

149-
/// Log at most 1 IO error per minute
150-
#[cfg(not(wasm_browser))]
151-
const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60);
152-
153149
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
154-
type LastSendError = Mutex<Instant>;
155-
#[cfg(not(any(wasm_browser, feature = "tracing", feature = "direct-log")))]
156-
type LastSendError = ();
157-
158-
/// Logs a warning message when sendmsg fails
159-
///
160-
/// Logging will only be performed if at least [`IO_ERROR_LOG_INTERVAL`]
161-
/// has elapsed since the last error was logged.
162-
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
163-
fn log_sendmsg_error(
164-
last_send_error: &LastSendError,
165-
err: impl core::fmt::Debug,
166-
transmit: &Transmit,
167-
) {
168-
let now = Instant::now();
169-
let last_send_error = &mut *last_send_error.lock().expect("poisoned lock");
170-
if now.saturating_duration_since(*last_send_error) > IO_ERROR_LOG_INTERVAL {
171-
*last_send_error = now;
172-
log::warn!(
173-
"sendmsg error: {:?}, Transmit: {{ destination: {:?}, src_ip: {:?}, ecn: {:?}, len: {:?}, segment_size: {:?} }}",
174-
err, transmit.destination, transmit.src_ip, transmit.ecn, transmit.contents.len(), transmit.segment_size);
175-
}
176-
}
150+
const IO_ERROR_LOG_INTERVAL: Duration = Duration::from_secs(60);
177151

178-
/// Helper for recording the last send error in socket state for error reporting.
179-
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
180-
fn last_send_error() -> LastSendError {
181-
let now = Instant::now();
182-
Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now))
152+
/// Helper for rate-limiting the logging of sendmsg errors.
153+
#[derive(Debug)]
154+
struct SendErrorSink {
155+
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
156+
last_send_error: Mutex<Instant>,
183157
}
184158

185-
// No-op
186-
#[cfg(not(any(wasm_browser, feature = "tracing", feature = "direct-log")))]
187-
fn log_sendmsg_error(_: &LastSendError, _: impl core::fmt::Debug, _: &Transmit) {}
159+
impl SendErrorSink {
160+
/// Produces a record the last send error in socket state for error reporting
161+
fn new() -> Self {
162+
Self {
163+
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
164+
last_send_error: {
165+
let now = Instant::now();
166+
Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now))
167+
},
168+
}
169+
}
188170

189-
// No-op
190-
#[cfg(not(any(wasm_browser, feature = "tracing", feature = "direct-log")))]
191-
fn last_send_error() -> LastSendError {}
171+
/// Logs a warning message when sendmsg fails
172+
///
173+
/// Logging will only be performed if at least [`IO_ERROR_LOG_INTERVAL`]
174+
/// has elapsed since the last error was logged.
175+
#[allow(unused_variables)]
176+
fn log_sendmsg_error(&self, err: impl core::fmt::Debug, transmit: &Transmit) {
177+
#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))]
178+
{
179+
let now = Instant::now();
180+
let last_send_error = &mut *self.last_send_error.lock().expect("poisoned lock");
181+
if now.saturating_duration_since(*last_send_error) > IO_ERROR_LOG_INTERVAL {
182+
*last_send_error = now;
183+
log::warn!(
184+
"sendmsg error: {:?}, Transmit: {{ destination: {:?}, src_ip: {:?}, ecn: {:?}, len: {:?}, segment_size: {:?} }}",
185+
err, transmit.destination, transmit.src_ip, transmit.ecn, transmit.contents.len(), transmit.segment_size);
186+
}
187+
}
188+
}
189+
}
192190

193191
/// A borrowed UDP socket
194192
///

quinn-udp/src/unix.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ use std::{
1010

1111
use socket2::SockRef;
1212

13-
use super::{
14-
cmsg, last_send_error, log_sendmsg_error, EcnCodepoint, LastSendError, RecvMeta, Transmit,
15-
UdpSockRef,
16-
};
13+
use super::{cmsg, EcnCodepoint, RecvMeta, SendErrorSink, Transmit, UdpSockRef};
1714

1815
// Adapted from https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/sys/socket_private.h
1916
#[cfg(apple_fast)]
@@ -66,7 +63,7 @@ type IpTosTy = libc::c_int;
6663
/// platforms.
6764
#[derive(Debug)]
6865
pub struct UdpSocketState {
69-
last_send_error: LastSendError,
66+
last_send_error: SendErrorSink,
7067
max_gso_segments: AtomicUsize,
7168
gro_segments: usize,
7269
may_fragment: bool,
@@ -181,7 +178,7 @@ impl UdpSocketState {
181178
}
182179

183180
Ok(Self {
184-
last_send_error: last_send_error(),
181+
last_send_error: SendErrorSink::new(),
185182
max_gso_segments: AtomicUsize::new(gso::max_gso_segments()),
186183
gro_segments: gro::gro_segments(),
187184
may_fragment,
@@ -205,7 +202,7 @@ impl UdpSocketState {
205202
Ok(()) => Ok(()),
206203
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e),
207204
Err(e) => {
208-
log_sendmsg_error(&self.last_send_error, e, transmit);
205+
self.last_send_error.log_sendmsg_error(e, transmit);
209206

210207
Ok(())
211208
}

quinn-udp/src/windows.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ use windows_sys::Win32::Networking::WinSock;
1212

1313
use crate::{
1414
cmsg::{self, CMsgHdr},
15-
last_send_error,
1615
log::debug,
17-
log_sendmsg_error, EcnCodepoint, LastSendError, RecvMeta, Transmit, UdpSockRef,
16+
EcnCodepoint, RecvMeta, SendErrorSink, Transmit, UdpSockRef,
1817
};
1918

2019
/// QUIC-friendly UDP socket for Windows
2120
///
2221
/// Unlike a standard Windows UDP socket, this allows ECN bits to be read and written.
2322
#[derive(Debug)]
2423
pub struct UdpSocketState {
25-
last_send_error: LastSendError,
24+
last_send_error: SendErrorSink,
2625
}
2726

2827
impl UdpSocketState {
@@ -112,7 +111,7 @@ impl UdpSocketState {
112111
}
113112

114113
Ok(Self {
115-
last_send_error: last_send_error(),
114+
last_send_error: SendErrorSink::new(),
116115
})
117116
}
118117

@@ -154,7 +153,7 @@ impl UdpSocketState {
154153
Ok(()) => Ok(()),
155154
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e),
156155
Err(e) => {
157-
log_sendmsg_error(&self.last_send_error, e, transmit);
156+
self.last_send_error.log_sendmsg_error(e, transmit);
158157

159158
Ok(())
160159
}

0 commit comments

Comments
 (0)