improve batch_send error handling (#33936)

This commit is contained in:
Jeff Biseda 2023-11-01 02:39:26 -04:00 committed by GitHub
parent 136ab21f34
commit 3f805ad06d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 110 additions and 100 deletions

View File

@ -457,9 +457,9 @@ impl RepairService {
let mut batch_send_repairs_elapsed = Measure::start("batch_send_repairs_elapsed"); let mut batch_send_repairs_elapsed = Measure::start("batch_send_repairs_elapsed");
if !batch.is_empty() { if !batch.is_empty() {
if let Err(SendPktsError::IoError(err, num_failed)) = match batch_send(repair_socket, &batch) {
batch_send(repair_socket, &batch) Ok(()) => (),
{ Err(SendPktsError::IoError(err, num_failed)) => {
error!( error!(
"{} batch_send failed to send {}/{} packets first error {:?}", "{} batch_send failed to send {}/{} packets first error {:?}",
id, id,
@ -469,6 +469,7 @@ impl RepairService {
); );
} }
} }
}
batch_send_repairs_elapsed.stop(); batch_send_repairs_elapsed.stop();
repair_timing.update( repair_timing.update(

View File

@ -1221,9 +1221,9 @@ impl ServeRepair {
} }
} }
if !pending_pongs.is_empty() { if !pending_pongs.is_empty() {
if let Err(SendPktsError::IoError(err, num_failed)) = match batch_send(repair_socket, &pending_pongs) {
batch_send(repair_socket, &pending_pongs) Ok(()) => (),
{ Err(SendPktsError::IoError(err, num_failed)) => {
warn!( warn!(
"batch_send failed to send {}/{} packets. First error: {:?}", "batch_send failed to send {}/{} packets. First error: {:?}",
num_failed, num_failed,
@ -1233,6 +1233,7 @@ impl ServeRepair {
} }
} }
} }
}
pub fn repair_proto_to_bytes(request: &RepairProtocol, keypair: &Keypair) -> Result<Vec<u8>> { pub fn repair_proto_to_bytes(request: &RepairProtocol, keypair: &Keypair) -> Result<Vec<u8>> {
debug_assert!(request.supports_signature()); debug_assert!(request.supports_signature());

View File

@ -139,8 +139,9 @@ fn retransmit_to(
.filter(|addr| socket_addr_space.check(addr)) .filter(|addr| socket_addr_space.check(addr))
.collect() .collect()
}; };
if let Err(SendPktsError::IoError(ioerr, num_failed)) = multi_target_send(socket, data, &dests) match multi_target_send(socket, data, &dests) {
{ Ok(()) => (),
Err(SendPktsError::IoError(ioerr, num_failed)) => {
error!( error!(
"retransmit_to multi_target_send error: {:?}, {}/{} packets failed", "retransmit_to multi_target_send error: {:?}, {}/{} packets failed",
ioerr, ioerr,
@ -149,6 +150,7 @@ fn retransmit_to(
); );
} }
} }
}
/// ring a -> b -> c -> d -> e -> a /// ring a -> b -> c -> d -> e -> a
#[test] #[test]

View File

@ -178,16 +178,10 @@ mod tests {
let dest_refs: Vec<_> = vec![&ip4, &ip6, &ip4]; let dest_refs: Vec<_> = vec![&ip4, &ip6, &ip4];
let sender = UdpSocket::bind("0.0.0.0:0").await.expect("bind"); let sender = UdpSocket::bind("0.0.0.0:0").await.expect("bind");
if let Err(SendPktsError::IoError(_, num_failed)) = let res = batch_send(&sender, &packet_refs[..]).await;
batch_send(&sender, &packet_refs[..]).await assert_matches!(res, Err(SendPktsError::IoError(_, /*num_failed*/ 1)));
{ let res = multi_target_send(&sender, &packets[0], &dest_refs).await;
assert_eq!(num_failed, 1); assert_matches!(res, Err(SendPktsError::IoError(_, /*num_failed*/ 1)));
}
if let Err(SendPktsError::IoError(_, num_failed)) =
multi_target_send(&sender, &packets[0], &dest_refs).await
{
assert_eq!(num_failed, 1);
}
} }
#[tokio::test] #[tokio::test]
@ -205,12 +199,13 @@ mod tests {
(&packets[3][..], &ipv4broadcast), (&packets[3][..], &ipv4broadcast),
(&packets[4][..], &ipv4local), (&packets[4][..], &ipv4local),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]).await {
batch_send(&sender, &packet_refs[..]).await Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test leading and trailing failures for batch_send // test leading and trailing failures for batch_send
let packet_refs: Vec<_> = vec![ let packet_refs: Vec<_> = vec![
@ -220,12 +215,13 @@ mod tests {
(&packets[3][..], &ipv4local), (&packets[3][..], &ipv4local),
(&packets[4][..], &ipv4broadcast), (&packets[4][..], &ipv4broadcast),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]).await {
batch_send(&sender, &packet_refs[..]).await Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 3); assert_eq!(num_failed, 3);
} }
}
// test consecutive intermediate failures for batch_send // test consecutive intermediate failures for batch_send
let packet_refs: Vec<_> = vec![ let packet_refs: Vec<_> = vec![
@ -235,12 +231,13 @@ mod tests {
(&packets[3][..], &ipv4broadcast), (&packets[3][..], &ipv4broadcast),
(&packets[4][..], &ipv4local), (&packets[4][..], &ipv4local),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]).await {
batch_send(&sender, &packet_refs[..]).await Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test intermediate failures for multi_target_send // test intermediate failures for multi_target_send
let dest_refs: Vec<_> = vec![ let dest_refs: Vec<_> = vec![
@ -250,12 +247,13 @@ mod tests {
&ipv4broadcast, &ipv4broadcast,
&ipv4local, &ipv4local,
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match multi_target_send(&sender, &packets[0], &dest_refs).await {
multi_target_send(&sender, &packets[0], &dest_refs).await Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test leading and trailing failures for multi_target_send // test leading and trailing failures for multi_target_send
let dest_refs: Vec<_> = vec![ let dest_refs: Vec<_> = vec![
@ -265,11 +263,12 @@ mod tests {
&ipv4local, &ipv4local,
&ipv4broadcast, &ipv4broadcast,
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match multi_target_send(&sender, &packets[0], &dest_refs).await {
multi_target_send(&sender, &packets[0], &dest_refs).await Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 3); assert_eq!(num_failed, 3);
} }
} }
} }
}

View File

@ -282,14 +282,10 @@ mod tests {
let dest_refs: Vec<_> = vec![&ip4, &ip6, &ip4]; let dest_refs: Vec<_> = vec![&ip4, &ip6, &ip4];
let sender = UdpSocket::bind("0.0.0.0:0").expect("bind"); let sender = UdpSocket::bind("0.0.0.0:0").expect("bind");
if let Err(SendPktsError::IoError(_, num_failed)) = batch_send(&sender, &packet_refs[..]) { let res = batch_send(&sender, &packet_refs[..]);
assert_eq!(num_failed, 1); assert_matches!(res, Err(SendPktsError::IoError(_, /*num_failed*/ 1)));
} let res = multi_target_send(&sender, &packets[0], &dest_refs);
if let Err(SendPktsError::IoError(_, num_failed)) = assert_matches!(res, Err(SendPktsError::IoError(_, /*num_failed*/ 1)));
multi_target_send(&sender, &packets[0], &dest_refs)
{
assert_eq!(num_failed, 1);
}
} }
#[test] #[test]
@ -307,12 +303,13 @@ mod tests {
(&packets[3][..], &ipv4broadcast), (&packets[3][..], &ipv4broadcast),
(&packets[4][..], &ipv4local), (&packets[4][..], &ipv4local),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]) {
batch_send(&sender, &packet_refs[..]) Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test leading and trailing failures for batch_send // test leading and trailing failures for batch_send
let packet_refs: Vec<_> = vec![ let packet_refs: Vec<_> = vec![
@ -322,12 +319,13 @@ mod tests {
(&packets[3][..], &ipv4local), (&packets[3][..], &ipv4local),
(&packets[4][..], &ipv4broadcast), (&packets[4][..], &ipv4broadcast),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]) {
batch_send(&sender, &packet_refs[..]) Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 3); assert_eq!(num_failed, 3);
} }
}
// test consecutive intermediate failures for batch_send // test consecutive intermediate failures for batch_send
let packet_refs: Vec<_> = vec![ let packet_refs: Vec<_> = vec![
@ -337,12 +335,13 @@ mod tests {
(&packets[3][..], &ipv4broadcast), (&packets[3][..], &ipv4broadcast),
(&packets[4][..], &ipv4local), (&packets[4][..], &ipv4local),
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match batch_send(&sender, &packet_refs[..]) {
batch_send(&sender, &packet_refs[..]) Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test intermediate failures for multi_target_send // test intermediate failures for multi_target_send
let dest_refs: Vec<_> = vec![ let dest_refs: Vec<_> = vec![
@ -352,12 +351,13 @@ mod tests {
&ipv4broadcast, &ipv4broadcast,
&ipv4local, &ipv4local,
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match multi_target_send(&sender, &packets[0], &dest_refs) {
multi_target_send(&sender, &packets[0], &dest_refs) Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 2); assert_eq!(num_failed, 2);
} }
}
// test leading and trailing failures for multi_target_send // test leading and trailing failures for multi_target_send
let dest_refs: Vec<_> = vec![ let dest_refs: Vec<_> = vec![
@ -367,11 +367,12 @@ mod tests {
&ipv4local, &ipv4local,
&ipv4broadcast, &ipv4broadcast,
]; ];
if let Err(SendPktsError::IoError(ioerror, num_failed)) = match multi_target_send(&sender, &packets[0], &dest_refs) {
multi_target_send(&sender, &packets[0], &dest_refs) Ok(()) => panic!(),
{ Err(SendPktsError::IoError(ioerror, num_failed)) => {
assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied); assert_matches!(ioerror.kind(), ErrorKind::PermissionDenied);
assert_eq!(num_failed, 3); assert_eq!(num_failed, 3);
} }
} }
} }
}

View File

@ -466,10 +466,13 @@ pub fn broadcast_shreds(
transmit_stats.shred_select += shred_select.as_us(); transmit_stats.shred_select += shred_select.as_us();
let mut send_mmsg_time = Measure::start("send_mmsg"); let mut send_mmsg_time = Measure::start("send_mmsg");
if let Err(SendPktsError::IoError(ioerr, num_failed)) = batch_send(s, &packets[..]) { match batch_send(s, &packets[..]) {
Ok(()) => (),
Err(SendPktsError::IoError(ioerr, num_failed)) => {
transmit_stats.dropped_packets_udp += num_failed; transmit_stats.dropped_packets_udp += num_failed;
result = Err(Error::Io(ioerr)); result = Err(Error::Io(ioerr));
} }
}
send_mmsg_time.stop(); send_mmsg_time.stop();
transmit_stats.send_mmsg_elapsed += send_mmsg_time.as_us(); transmit_stats.send_mmsg_elapsed += send_mmsg_time.as_us();
transmit_stats.total_packets += packets.len() + quic_packets.len(); transmit_stats.total_packets += packets.len() + quic_packets.len();

View File

@ -376,9 +376,12 @@ impl BroadcastRun for BroadcastDuplicatesRun {
.flatten() .flatten()
.collect(); .collect();
if let Err(SendPktsError::IoError(ioerr, _)) = batch_send(sock, &packets) { match batch_send(sock, &packets) {
Ok(()) => (),
Err(SendPktsError::IoError(ioerr, _)) => {
return Err(Error::Io(ioerr)); return Err(Error::Io(ioerr));
} }
}
Ok(()) Ok(())
} }