adds code-path broadcasting shreds using QUIC (#31610)
adds quic connection cache to turbine Working towards migrating turbine to QUIC.
This commit is contained in:
parent
b89ce94d33
commit
ec0001ef85
|
@ -5514,6 +5514,7 @@ dependencies = [
|
||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-poh",
|
"solana-poh",
|
||||||
"solana-program-runtime",
|
"solana-program-runtime",
|
||||||
|
"solana-quic-client",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-rpc",
|
"solana-rpc",
|
||||||
"solana-rpc-client-api",
|
"solana-rpc-client-api",
|
||||||
|
|
|
@ -50,6 +50,7 @@ solana-net-utils = { workspace = true }
|
||||||
solana-perf = { workspace = true }
|
solana-perf = { workspace = true }
|
||||||
solana-poh = { workspace = true }
|
solana-poh = { workspace = true }
|
||||||
solana-program-runtime = { workspace = true }
|
solana-program-runtime = { workspace = true }
|
||||||
|
solana-quic-client = { workspace = true }
|
||||||
solana-rayon-threadlimit = { workspace = true }
|
solana-rayon-threadlimit = { workspace = true }
|
||||||
solana-rpc = { workspace = true }
|
solana-rpc = { workspace = true }
|
||||||
solana-rpc-client-api = { workspace = true }
|
solana-rpc-client-api = { workspace = true }
|
||||||
|
|
|
@ -9,6 +9,7 @@ use {
|
||||||
broadcast_metrics::TransmitShredsStats, broadcast_shreds, BroadcastStage,
|
broadcast_metrics::TransmitShredsStats, broadcast_shreds, BroadcastStage,
|
||||||
},
|
},
|
||||||
cluster_nodes::ClusterNodesCache,
|
cluster_nodes::ClusterNodesCache,
|
||||||
|
validator::TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
},
|
},
|
||||||
solana_gossip::{
|
solana_gossip::{
|
||||||
cluster_info::{ClusterInfo, Node},
|
cluster_info::{ClusterInfo, Node},
|
||||||
|
@ -18,16 +19,17 @@ use {
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
shred::{Shred, ShredFlags},
|
shred::{Shred, ShredFlags},
|
||||||
},
|
},
|
||||||
|
solana_quic_client::new_quic_connection_cache,
|
||||||
solana_runtime::{bank::Bank, bank_forks::BankForks},
|
solana_runtime::{bank::Bank, bank_forks::BankForks},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
pubkey,
|
pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
timing::{timestamp, AtomicInterval},
|
timing::{timestamp, AtomicInterval},
|
||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::{socket::SocketAddrSpace, streamer::StakedNodes},
|
||||||
std::{
|
std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
net::UdpSocket,
|
net::{IpAddr, Ipv4Addr, UdpSocket},
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
},
|
},
|
||||||
|
@ -38,6 +40,14 @@ use {
|
||||||
fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
let leader_keypair = Arc::new(Keypair::new());
|
let leader_keypair = Arc::new(Keypair::new());
|
||||||
|
let quic_connection_cache = new_quic_connection_cache(
|
||||||
|
"connection_cache_test",
|
||||||
|
&leader_keypair,
|
||||||
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
&Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let leader_info = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
|
let leader_info = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
|
||||||
let cluster_info = ClusterInfo::new(
|
let cluster_info = ClusterInfo::new(
|
||||||
leader_info.info,
|
leader_info.info,
|
||||||
|
@ -45,7 +55,6 @@ fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||||
SocketAddrSpace::Unspecified,
|
SocketAddrSpace::Unspecified,
|
||||||
);
|
);
|
||||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
|
|
||||||
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
||||||
let bank = Bank::new_for_benches(&genesis_config);
|
let bank = Bank::new_for_benches(&genesis_config);
|
||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
|
@ -74,6 +83,7 @@ fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||||
&socket,
|
&socket,
|
||||||
&shreds,
|
&shreds,
|
||||||
&cluster_nodes_cache,
|
&cluster_nodes_cache,
|
||||||
|
&quic_connection_cache,
|
||||||
&last_datapoint,
|
&last_datapoint,
|
||||||
&mut TransmitShredsStats::default(),
|
&mut TransmitShredsStats::default(),
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate test;
|
||||||
use {
|
use {
|
||||||
crossbeam_channel::unbounded,
|
crossbeam_channel::unbounded,
|
||||||
log::*,
|
log::*,
|
||||||
solana_core::retransmit_stage::retransmitter,
|
solana_core::{retransmit_stage::retransmitter, validator::TURBINE_QUIC_CONNECTION_POOL_SIZE},
|
||||||
solana_entry::entry::Entry,
|
solana_entry::entry::Entry,
|
||||||
solana_gossip::{
|
solana_gossip::{
|
||||||
cluster_info::{ClusterInfo, Node},
|
cluster_info::{ClusterInfo, Node},
|
||||||
|
@ -26,10 +26,10 @@ use {
|
||||||
system_transaction,
|
system_transaction,
|
||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::{socket::SocketAddrSpace, streamer::StakedNodes},
|
||||||
std::{
|
std::{
|
||||||
iter::repeat_with,
|
iter::repeat_with,
|
||||||
net::{Ipv4Addr, UdpSocket},
|
net::{IpAddr, Ipv4Addr, UdpSocket},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
Arc, RwLock,
|
Arc, RwLock,
|
||||||
|
@ -100,6 +100,16 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
|
let quic_connection_cache = Arc::new(
|
||||||
|
solana_quic_client::new_quic_connection_cache(
|
||||||
|
"connection_cache_test",
|
||||||
|
&keypair,
|
||||||
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
&Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
let slot = 0;
|
let slot = 0;
|
||||||
let parent = 0;
|
let parent = 0;
|
||||||
let shredder = Shredder::new(slot, parent, 0, 0).unwrap();
|
let shredder = Shredder::new(slot, parent, 0, 0).unwrap();
|
||||||
|
@ -118,6 +128,7 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||||
|
|
||||||
let retransmitter_handles = retransmitter(
|
let retransmitter_handles = retransmitter(
|
||||||
Arc::new(sockets),
|
Arc::new(sockets),
|
||||||
|
quic_connection_cache,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
leader_schedule_cache,
|
leader_schedule_cache,
|
||||||
cluster_info,
|
cluster_info,
|
||||||
|
|
|
@ -9,11 +9,12 @@ use {
|
||||||
standard_broadcast_run::StandardBroadcastRun,
|
standard_broadcast_run::StandardBroadcastRun,
|
||||||
},
|
},
|
||||||
crate::{
|
crate::{
|
||||||
cluster_nodes::{ClusterNodes, ClusterNodesCache},
|
cluster_nodes::{self, ClusterNodes, ClusterNodesCache},
|
||||||
result::{Error, Result},
|
result::{Error, Result},
|
||||||
},
|
},
|
||||||
crossbeam_channel::{unbounded, Receiver, RecvError, RecvTimeoutError, Sender},
|
crossbeam_channel::{unbounded, Receiver, RecvError, RecvTimeoutError, Sender},
|
||||||
itertools::Itertools,
|
itertools::{Either, Itertools},
|
||||||
|
solana_client::tpu_connection::TpuConnection,
|
||||||
solana_gossip::{
|
solana_gossip::{
|
||||||
cluster_info::{ClusterInfo, ClusterInfoError},
|
cluster_info::{ClusterInfo, ClusterInfoError},
|
||||||
contact_info::Protocol,
|
contact_info::Protocol,
|
||||||
|
@ -22,6 +23,7 @@ use {
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_metrics::{inc_new_counter_error, inc_new_counter_info},
|
solana_metrics::{inc_new_counter_error, inc_new_counter_info},
|
||||||
solana_poh::poh_recorder::WorkingBankEntry,
|
solana_poh::poh_recorder::WorkingBankEntry,
|
||||||
|
solana_quic_client::QuicConnectionCache,
|
||||||
solana_runtime::bank_forks::BankForks,
|
solana_runtime::bank_forks::BankForks,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
|
@ -87,6 +89,7 @@ impl BroadcastStageType {
|
||||||
blockstore: Arc<Blockstore>,
|
blockstore: Arc<Blockstore>,
|
||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
shred_version: u16,
|
shred_version: u16,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
) -> BroadcastStage {
|
) -> BroadcastStage {
|
||||||
match self {
|
match self {
|
||||||
BroadcastStageType::Standard => BroadcastStage::new(
|
BroadcastStageType::Standard => BroadcastStage::new(
|
||||||
|
@ -97,7 +100,7 @@ impl BroadcastStageType {
|
||||||
exit_sender,
|
exit_sender,
|
||||||
blockstore,
|
blockstore,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
StandardBroadcastRun::new(shred_version),
|
StandardBroadcastRun::new(shred_version, quic_connection_cache),
|
||||||
),
|
),
|
||||||
|
|
||||||
BroadcastStageType::FailEntryVerification => BroadcastStage::new(
|
BroadcastStageType::FailEntryVerification => BroadcastStage::new(
|
||||||
|
@ -108,7 +111,7 @@ impl BroadcastStageType {
|
||||||
exit_sender,
|
exit_sender,
|
||||||
blockstore,
|
blockstore,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
FailEntryVerificationBroadcastRun::new(shred_version),
|
FailEntryVerificationBroadcastRun::new(shred_version, quic_connection_cache),
|
||||||
),
|
),
|
||||||
|
|
||||||
BroadcastStageType::BroadcastFakeShreds => BroadcastStage::new(
|
BroadcastStageType::BroadcastFakeShreds => BroadcastStage::new(
|
||||||
|
@ -392,6 +395,7 @@ pub fn broadcast_shreds(
|
||||||
s: &UdpSocket,
|
s: &UdpSocket,
|
||||||
shreds: &[Shred],
|
shreds: &[Shred],
|
||||||
cluster_nodes_cache: &ClusterNodesCache<BroadcastStage>,
|
cluster_nodes_cache: &ClusterNodesCache<BroadcastStage>,
|
||||||
|
quic_connection_cache: &QuicConnectionCache,
|
||||||
last_datapoint_submit: &AtomicInterval,
|
last_datapoint_submit: &AtomicInterval,
|
||||||
transmit_stats: &mut TransmitShredsStats,
|
transmit_stats: &mut TransmitShredsStats,
|
||||||
cluster_info: &ClusterInfo,
|
cluster_info: &ClusterInfo,
|
||||||
|
@ -404,7 +408,7 @@ pub fn broadcast_shreds(
|
||||||
let bank_forks = bank_forks.read().unwrap();
|
let bank_forks = bank_forks.read().unwrap();
|
||||||
(bank_forks.root_bank(), bank_forks.working_bank())
|
(bank_forks.root_bank(), bank_forks.working_bank())
|
||||||
};
|
};
|
||||||
let packets: Vec<_> = shreds
|
let (packets, quic_packets): (Vec<_>, Vec<_>) = shreds
|
||||||
.iter()
|
.iter()
|
||||||
.group_by(|shred| shred.slot())
|
.group_by(|shred| shred.slot())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -413,26 +417,40 @@ pub fn broadcast_shreds(
|
||||||
cluster_nodes_cache.get(slot, &root_bank, &working_bank, cluster_info);
|
cluster_nodes_cache.get(slot, &root_bank, &working_bank, cluster_info);
|
||||||
update_peer_stats(&cluster_nodes, last_datapoint_submit);
|
update_peer_stats(&cluster_nodes, last_datapoint_submit);
|
||||||
shreds.filter_map(move |shred| {
|
shreds.filter_map(move |shred| {
|
||||||
|
let key = shred.id();
|
||||||
|
let protocol = cluster_nodes::get_broadcast_protocol(&key);
|
||||||
cluster_nodes
|
cluster_nodes
|
||||||
.get_broadcast_peer(&shred.id())?
|
.get_broadcast_peer(&key)?
|
||||||
.tvu(Protocol::UDP)
|
.tvu(protocol)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|addr| socket_addr_space.check(addr))
|
.filter(|addr| socket_addr_space.check(addr))
|
||||||
.map(|addr| (shred.payload(), addr))
|
.map(|addr| {
|
||||||
|
(match protocol {
|
||||||
|
Protocol::QUIC => Either::Right,
|
||||||
|
Protocol::UDP => Either::Left,
|
||||||
|
})((shred.payload(), addr))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.partition_map(std::convert::identity);
|
||||||
shred_select.stop();
|
shred_select.stop();
|
||||||
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[..]) {
|
if let Err(SendPktsError::IoError(ioerr, num_failed)) = batch_send(s, &packets[..]) {
|
||||||
transmit_stats.dropped_packets += 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();
|
for (shred, addr) in &quic_packets {
|
||||||
|
let conn = quic_connection_cache.get_connection(addr);
|
||||||
|
if let Err(err) = conn.send_data(shred) {
|
||||||
|
transmit_stats.dropped_packets_quic += 1;
|
||||||
|
result = Err(Error::from(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transmit_stats.total_packets += packets.len() + quic_packets.len();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +458,7 @@ pub fn broadcast_shreds(
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
|
crate::validator::TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
crossbeam_channel::unbounded,
|
crossbeam_channel::unbounded,
|
||||||
solana_entry::entry::create_ticks,
|
solana_entry::entry::create_ticks,
|
||||||
solana_gossip::cluster_info::{ClusterInfo, Node},
|
solana_gossip::cluster_info::{ClusterInfo, Node},
|
||||||
|
@ -454,7 +473,9 @@ pub mod test {
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
},
|
},
|
||||||
|
solana_streamer::streamer::StakedNodes,
|
||||||
std::{
|
std::{
|
||||||
|
net::{IpAddr, Ipv4Addr},
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
|
@ -586,6 +607,16 @@ pub mod test {
|
||||||
) -> MockBroadcastStage {
|
) -> MockBroadcastStage {
|
||||||
// Make the database ledger
|
// Make the database ledger
|
||||||
let blockstore = Arc::new(Blockstore::open(ledger_path).unwrap());
|
let blockstore = Arc::new(Blockstore::open(ledger_path).unwrap());
|
||||||
|
let quic_connection_cache = Arc::new(
|
||||||
|
solana_quic_client::new_quic_connection_cache(
|
||||||
|
"connection_cache_test",
|
||||||
|
&leader_keypair,
|
||||||
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
&Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
// Make the leader node and scheduler
|
// Make the leader node and scheduler
|
||||||
let leader_info = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
|
let leader_info = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
|
||||||
|
@ -619,7 +650,7 @@ pub mod test {
|
||||||
exit_sender,
|
exit_sender,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
bank_forks,
|
bank_forks,
|
||||||
StandardBroadcastRun::new(0),
|
StandardBroadcastRun::new(0, quic_connection_cache),
|
||||||
);
|
);
|
||||||
|
|
||||||
MockBroadcastStage {
|
MockBroadcastStage {
|
||||||
|
|
|
@ -21,7 +21,8 @@ pub struct TransmitShredsStats {
|
||||||
pub shred_select: u64,
|
pub shred_select: u64,
|
||||||
pub num_shreds: usize,
|
pub num_shreds: usize,
|
||||||
pub total_packets: usize,
|
pub total_packets: usize,
|
||||||
pub dropped_packets: usize,
|
pub(crate) dropped_packets_udp: usize,
|
||||||
|
pub(crate) dropped_packets_quic: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BroadcastStats for TransmitShredsStats {
|
impl BroadcastStats for TransmitShredsStats {
|
||||||
|
@ -32,7 +33,8 @@ impl BroadcastStats for TransmitShredsStats {
|
||||||
self.num_shreds += new_stats.num_shreds;
|
self.num_shreds += new_stats.num_shreds;
|
||||||
self.shred_select += new_stats.shred_select;
|
self.shred_select += new_stats.shred_select;
|
||||||
self.total_packets += new_stats.total_packets;
|
self.total_packets += new_stats.total_packets;
|
||||||
self.dropped_packets += new_stats.dropped_packets;
|
self.dropped_packets_udp += new_stats.dropped_packets_udp;
|
||||||
|
self.dropped_packets_quic += new_stats.dropped_packets_quic;
|
||||||
}
|
}
|
||||||
fn report_stats(&mut self, slot: Slot, slot_start: Instant, was_interrupted: bool) {
|
fn report_stats(&mut self, slot: Slot, slot_start: Instant, was_interrupted: bool) {
|
||||||
if was_interrupted {
|
if was_interrupted {
|
||||||
|
@ -45,7 +47,12 @@ impl BroadcastStats for TransmitShredsStats {
|
||||||
("num_shreds", self.num_shreds as i64, i64),
|
("num_shreds", self.num_shreds as i64, i64),
|
||||||
("shred_select", self.shred_select as i64, i64),
|
("shred_select", self.shred_select as i64, i64),
|
||||||
("total_packets", self.total_packets as i64, i64),
|
("total_packets", self.total_packets as i64, i64),
|
||||||
("dropped_packets", self.dropped_packets as i64, i64),
|
("dropped_packets_udp", self.dropped_packets_udp as i64, i64),
|
||||||
|
(
|
||||||
|
"dropped_packets_quic",
|
||||||
|
self.dropped_packets_quic as i64,
|
||||||
|
i64
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
|
@ -64,7 +71,12 @@ impl BroadcastStats for TransmitShredsStats {
|
||||||
("num_shreds", self.num_shreds as i64, i64),
|
("num_shreds", self.num_shreds as i64, i64),
|
||||||
("shred_select", self.shred_select as i64, i64),
|
("shred_select", self.shred_select as i64, i64),
|
||||||
("total_packets", self.total_packets as i64, i64),
|
("total_packets", self.total_packets as i64, i64),
|
||||||
("dropped_packets", self.dropped_packets as i64, i64),
|
("dropped_packets_udp", self.dropped_packets_udp as i64, i64),
|
||||||
|
(
|
||||||
|
"dropped_packets_quic",
|
||||||
|
self.dropped_packets_quic as i64,
|
||||||
|
i64
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +222,8 @@ mod test {
|
||||||
shred_select: 4,
|
shred_select: 4,
|
||||||
num_shreds: 5,
|
num_shreds: 5,
|
||||||
total_packets: 6,
|
total_packets: 6,
|
||||||
dropped_packets: 7,
|
dropped_packets_udp: 7,
|
||||||
|
dropped_packets_quic: 8,
|
||||||
},
|
},
|
||||||
&Some(BroadcastShredBatchInfo {
|
&Some(BroadcastShredBatchInfo {
|
||||||
slot: 0,
|
slot: 0,
|
||||||
|
@ -230,7 +243,8 @@ mod test {
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.shred_select, 4);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.shred_select, 4);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.num_shreds, 5);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.num_shreds, 5);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.total_packets, 6);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.total_packets, 6);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets, 7);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets_udp, 7);
|
||||||
|
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets_quic, 8);
|
||||||
|
|
||||||
slot_broadcast_stats.update(
|
slot_broadcast_stats.update(
|
||||||
&TransmitShredsStats {
|
&TransmitShredsStats {
|
||||||
|
@ -240,7 +254,8 @@ mod test {
|
||||||
shred_select: 14,
|
shred_select: 14,
|
||||||
num_shreds: 15,
|
num_shreds: 15,
|
||||||
total_packets: 16,
|
total_packets: 16,
|
||||||
dropped_packets: 17,
|
dropped_packets_udp: 17,
|
||||||
|
dropped_packets_quic: 18,
|
||||||
},
|
},
|
||||||
&None,
|
&None,
|
||||||
);
|
);
|
||||||
|
@ -255,7 +270,8 @@ mod test {
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.shred_select, 4);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.shred_select, 4);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.num_shreds, 5);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.num_shreds, 5);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.total_packets, 6);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.total_packets, 6);
|
||||||
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets, 7);
|
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets_udp, 7);
|
||||||
|
assert_eq!(slot_0_stats.broadcast_shred_stats.dropped_packets_quic, 8);
|
||||||
|
|
||||||
// If another batch is given, then total number of batches == num_expected_batches == 2,
|
// If another batch is given, then total number of batches == num_expected_batches == 2,
|
||||||
// so the batch should be purged from the HashMap
|
// so the batch should be purged from the HashMap
|
||||||
|
@ -267,7 +283,8 @@ mod test {
|
||||||
shred_select: 1,
|
shred_select: 1,
|
||||||
num_shreds: 1,
|
num_shreds: 1,
|
||||||
total_packets: 1,
|
total_packets: 1,
|
||||||
dropped_packets: 1,
|
dropped_packets_udp: 1,
|
||||||
|
dropped_packets_quic: 1,
|
||||||
},
|
},
|
||||||
&Some(BroadcastShredBatchInfo {
|
&Some(BroadcastShredBatchInfo {
|
||||||
slot: 0,
|
slot: 0,
|
||||||
|
|
|
@ -17,11 +17,12 @@ pub(super) struct FailEntryVerificationBroadcastRun {
|
||||||
next_shred_index: u32,
|
next_shred_index: u32,
|
||||||
next_code_index: u32,
|
next_code_index: u32,
|
||||||
cluster_nodes_cache: Arc<ClusterNodesCache<BroadcastStage>>,
|
cluster_nodes_cache: Arc<ClusterNodesCache<BroadcastStage>>,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
reed_solomon_cache: Arc<ReedSolomonCache>,
|
reed_solomon_cache: Arc<ReedSolomonCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FailEntryVerificationBroadcastRun {
|
impl FailEntryVerificationBroadcastRun {
|
||||||
pub(super) fn new(shred_version: u16) -> Self {
|
pub(super) fn new(shred_version: u16, quic_connection_cache: Arc<QuicConnectionCache>) -> Self {
|
||||||
let cluster_nodes_cache = Arc::new(ClusterNodesCache::<BroadcastStage>::new(
|
let cluster_nodes_cache = Arc::new(ClusterNodesCache::<BroadcastStage>::new(
|
||||||
CLUSTER_NODES_CACHE_NUM_EPOCH_CAP,
|
CLUSTER_NODES_CACHE_NUM_EPOCH_CAP,
|
||||||
CLUSTER_NODES_CACHE_TTL,
|
CLUSTER_NODES_CACHE_TTL,
|
||||||
|
@ -33,6 +34,7 @@ impl FailEntryVerificationBroadcastRun {
|
||||||
next_shred_index: 0,
|
next_shred_index: 0,
|
||||||
next_code_index: 0,
|
next_code_index: 0,
|
||||||
cluster_nodes_cache,
|
cluster_nodes_cache,
|
||||||
|
quic_connection_cache,
|
||||||
reed_solomon_cache: Arc::<ReedSolomonCache>::default(),
|
reed_solomon_cache: Arc::<ReedSolomonCache>::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +170,7 @@ impl BroadcastRun for FailEntryVerificationBroadcastRun {
|
||||||
sock,
|
sock,
|
||||||
&shreds,
|
&shreds,
|
||||||
&self.cluster_nodes_cache,
|
&self.cluster_nodes_cache,
|
||||||
|
&self.quic_connection_cache,
|
||||||
&AtomicInterval::default(),
|
&AtomicInterval::default(),
|
||||||
&mut TransmitShredsStats::default(),
|
&mut TransmitShredsStats::default(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub struct StandardBroadcastRun {
|
||||||
last_datapoint_submit: Arc<AtomicInterval>,
|
last_datapoint_submit: Arc<AtomicInterval>,
|
||||||
num_batches: usize,
|
num_batches: usize,
|
||||||
cluster_nodes_cache: Arc<ClusterNodesCache<BroadcastStage>>,
|
cluster_nodes_cache: Arc<ClusterNodesCache<BroadcastStage>>,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
reed_solomon_cache: Arc<ReedSolomonCache>,
|
reed_solomon_cache: Arc<ReedSolomonCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ enum BroadcastError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StandardBroadcastRun {
|
impl StandardBroadcastRun {
|
||||||
pub(super) fn new(shred_version: u16) -> Self {
|
pub(super) fn new(shred_version: u16, quic_connection_cache: Arc<QuicConnectionCache>) -> Self {
|
||||||
let cluster_nodes_cache = Arc::new(ClusterNodesCache::<BroadcastStage>::new(
|
let cluster_nodes_cache = Arc::new(ClusterNodesCache::<BroadcastStage>::new(
|
||||||
CLUSTER_NODES_CACHE_NUM_EPOCH_CAP,
|
CLUSTER_NODES_CACHE_NUM_EPOCH_CAP,
|
||||||
CLUSTER_NODES_CACHE_TTL,
|
CLUSTER_NODES_CACHE_TTL,
|
||||||
|
@ -58,6 +59,7 @@ impl StandardBroadcastRun {
|
||||||
last_datapoint_submit: Arc::default(),
|
last_datapoint_submit: Arc::default(),
|
||||||
num_batches: 0,
|
num_batches: 0,
|
||||||
cluster_nodes_cache,
|
cluster_nodes_cache,
|
||||||
|
quic_connection_cache,
|
||||||
reed_solomon_cache: Arc::<ReedSolomonCache>::default(),
|
reed_solomon_cache: Arc::<ReedSolomonCache>::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,6 +415,7 @@ impl StandardBroadcastRun {
|
||||||
sock,
|
sock,
|
||||||
&shreds,
|
&shreds,
|
||||||
&self.cluster_nodes_cache,
|
&self.cluster_nodes_cache,
|
||||||
|
&self.quic_connection_cache,
|
||||||
&self.last_datapoint_submit,
|
&self.last_datapoint_submit,
|
||||||
&mut transmit_stats,
|
&mut transmit_stats,
|
||||||
cluster_info,
|
cluster_info,
|
||||||
|
@ -506,6 +509,7 @@ fn should_use_merkle_variant(slot: Slot, cluster_type: ClusterType, shred_versio
|
||||||
mod test {
|
mod test {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
|
crate::validator::TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
solana_entry::entry::create_ticks,
|
solana_entry::entry::create_ticks,
|
||||||
solana_gossip::cluster_info::{ClusterInfo, Node},
|
solana_gossip::cluster_info::{ClusterInfo, Node},
|
||||||
solana_ledger::{
|
solana_ledger::{
|
||||||
|
@ -517,8 +521,13 @@ mod test {
|
||||||
genesis_config::GenesisConfig,
|
genesis_config::GenesisConfig,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::{socket::SocketAddrSpace, streamer::StakedNodes},
|
||||||
std::{ops::Deref, sync::Arc, time::Duration},
|
std::{
|
||||||
|
net::{IpAddr, Ipv4Addr},
|
||||||
|
ops::Deref,
|
||||||
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
@ -564,10 +573,24 @@ mod test {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_quic_connection_cache(keypair: &Keypair) -> Arc<QuicConnectionCache> {
|
||||||
|
Arc::new(
|
||||||
|
solana_quic_client::new_quic_connection_cache(
|
||||||
|
"connection_cache_test",
|
||||||
|
keypair,
|
||||||
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
&Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interrupted_slot_last_shred() {
|
fn test_interrupted_slot_last_shred() {
|
||||||
let keypair = Arc::new(Keypair::new());
|
let keypair = Arc::new(Keypair::new());
|
||||||
let mut run = StandardBroadcastRun::new(0);
|
let quic_connection_cache = new_quic_connection_cache(&keypair);
|
||||||
|
let mut run = StandardBroadcastRun::new(0, quic_connection_cache);
|
||||||
|
|
||||||
// Set up the slot to be interrupted
|
// Set up the slot to be interrupted
|
||||||
let next_shred_index = 10;
|
let next_shred_index = 10;
|
||||||
|
@ -609,6 +632,7 @@ mod test {
|
||||||
let num_shreds_per_slot = 2;
|
let num_shreds_per_slot = 2;
|
||||||
let (blockstore, genesis_config, cluster_info, bank0, leader_keypair, socket, bank_forks) =
|
let (blockstore, genesis_config, cluster_info, bank0, leader_keypair, socket, bank_forks) =
|
||||||
setup(num_shreds_per_slot);
|
setup(num_shreds_per_slot);
|
||||||
|
let quic_connection_cache = new_quic_connection_cache(&leader_keypair);
|
||||||
|
|
||||||
// Insert 1 less than the number of ticks needed to finish the slot
|
// Insert 1 less than the number of ticks needed to finish the slot
|
||||||
let ticks0 = create_ticks(genesis_config.ticks_per_slot - 1, 0, genesis_config.hash());
|
let ticks0 = create_ticks(genesis_config.ticks_per_slot - 1, 0, genesis_config.hash());
|
||||||
|
@ -621,7 +645,7 @@ mod test {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 1: Make an incomplete transmission for slot 0
|
// Step 1: Make an incomplete transmission for slot 0
|
||||||
let mut standard_broadcast_run = StandardBroadcastRun::new(0);
|
let mut standard_broadcast_run = StandardBroadcastRun::new(0, quic_connection_cache);
|
||||||
standard_broadcast_run
|
standard_broadcast_run
|
||||||
.test_process_receive_results(
|
.test_process_receive_results(
|
||||||
&leader_keypair,
|
&leader_keypair,
|
||||||
|
@ -739,10 +763,11 @@ mod test {
|
||||||
let num_shreds_per_slot = 2;
|
let num_shreds_per_slot = 2;
|
||||||
let (blockstore, genesis_config, _cluster_info, bank, leader_keypair, _socket, _bank_forks) =
|
let (blockstore, genesis_config, _cluster_info, bank, leader_keypair, _socket, _bank_forks) =
|
||||||
setup(num_shreds_per_slot);
|
setup(num_shreds_per_slot);
|
||||||
|
let quic_connection_cache = new_quic_connection_cache(&leader_keypair);
|
||||||
let (bsend, brecv) = unbounded();
|
let (bsend, brecv) = unbounded();
|
||||||
let (ssend, _srecv) = unbounded();
|
let (ssend, _srecv) = unbounded();
|
||||||
let mut last_tick_height = 0;
|
let mut last_tick_height = 0;
|
||||||
let mut standard_broadcast_run = StandardBroadcastRun::new(0);
|
let mut standard_broadcast_run = StandardBroadcastRun::new(0, quic_connection_cache);
|
||||||
let mut process_ticks = |num_ticks| {
|
let mut process_ticks = |num_ticks| {
|
||||||
let ticks = create_ticks(num_ticks, 0, genesis_config.hash());
|
let ticks = create_ticks(num_ticks, 0, genesis_config.hash());
|
||||||
last_tick_height += (ticks.len() - 1) as u64;
|
last_tick_height += (ticks.len() - 1) as u64;
|
||||||
|
@ -787,6 +812,7 @@ mod test {
|
||||||
let num_shreds_per_slot = 2;
|
let num_shreds_per_slot = 2;
|
||||||
let (blockstore, genesis_config, cluster_info, bank0, leader_keypair, socket, bank_forks) =
|
let (blockstore, genesis_config, cluster_info, bank0, leader_keypair, socket, bank_forks) =
|
||||||
setup(num_shreds_per_slot);
|
setup(num_shreds_per_slot);
|
||||||
|
let quic_connection_cache = new_quic_connection_cache(&leader_keypair);
|
||||||
|
|
||||||
// Insert complete slot of ticks needed to finish the slot
|
// Insert complete slot of ticks needed to finish the slot
|
||||||
let ticks = create_ticks(genesis_config.ticks_per_slot, 0, genesis_config.hash());
|
let ticks = create_ticks(genesis_config.ticks_per_slot, 0, genesis_config.hash());
|
||||||
|
@ -798,7 +824,7 @@ mod test {
|
||||||
last_tick_height: ticks.len() as u64,
|
last_tick_height: ticks.len() as u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut standard_broadcast_run = StandardBroadcastRun::new(0);
|
let mut standard_broadcast_run = StandardBroadcastRun::new(0, quic_connection_cache);
|
||||||
standard_broadcast_run
|
standard_broadcast_run
|
||||||
.test_process_receive_results(
|
.test_process_receive_results(
|
||||||
&leader_keypair,
|
&leader_keypair,
|
||||||
|
@ -815,9 +841,10 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn entries_to_shreds_max() {
|
fn entries_to_shreds_max() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
let mut bs = StandardBroadcastRun::new(0);
|
|
||||||
bs.current_slot_and_parent = Some((1, 0));
|
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
|
let quic_connection_cache = new_quic_connection_cache(&keypair);
|
||||||
|
let mut bs = StandardBroadcastRun::new(0, quic_connection_cache);
|
||||||
|
bs.current_slot_and_parent = Some((1, 0));
|
||||||
let entries = create_ticks(10_000, 1, solana_sdk::hash::Hash::default());
|
let entries = create_ticks(10_000, 1, solana_sdk::hash::Hash::default());
|
||||||
|
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
|
|
|
@ -176,10 +176,11 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
addrs,
|
addrs,
|
||||||
frwds,
|
frwds,
|
||||||
} = self.get_retransmit_peers(slot_leader, shred, root_bank, fanout)?;
|
} = self.get_retransmit_peers(slot_leader, shred, root_bank, fanout)?;
|
||||||
|
let protocol = get_broadcast_protocol(shred);
|
||||||
if neighbors.is_empty() {
|
if neighbors.is_empty() {
|
||||||
let peers = children.into_iter().filter_map(|node| {
|
let peers = children.into_iter().filter_map(|node| {
|
||||||
node.contact_info()?
|
node.contact_info()?
|
||||||
.tvu(Protocol::UDP)
|
.tvu(protocol)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|addr| addrs.get(addr) == Some(&node.pubkey()))
|
.filter(|addr| addrs.get(addr) == Some(&node.pubkey()))
|
||||||
});
|
});
|
||||||
|
@ -209,7 +210,7 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
})
|
})
|
||||||
.chain(children.into_iter().filter_map(|node| {
|
.chain(children.into_iter().filter_map(|node| {
|
||||||
node.contact_info()?
|
node.contact_info()?
|
||||||
.tvu(Protocol::UDP)
|
.tvu(protocol)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|addr| addrs.get(addr) == Some(&node.pubkey()))
|
.filter(|addr| addrs.get(addr) == Some(&node.pubkey()))
|
||||||
}));
|
}));
|
||||||
|
@ -239,12 +240,13 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
let mut frwds = HashMap::<SocketAddr, Pubkey>::with_capacity(self.nodes.len());
|
let mut frwds = HashMap::<SocketAddr, Pubkey>::with_capacity(self.nodes.len());
|
||||||
let mut rng = ChaChaRng::from_seed(shred_seed);
|
let mut rng = ChaChaRng::from_seed(shred_seed);
|
||||||
let drop_redundant_turbine_path = drop_redundant_turbine_path(shred.slot(), root_bank);
|
let drop_redundant_turbine_path = drop_redundant_turbine_path(shred.slot(), root_bank);
|
||||||
|
let protocol = get_broadcast_protocol(shred);
|
||||||
let nodes: Vec<_> = weighted_shuffle
|
let nodes: Vec<_> = weighted_shuffle
|
||||||
.shuffle(&mut rng)
|
.shuffle(&mut rng)
|
||||||
.map(|index| &self.nodes[index])
|
.map(|index| &self.nodes[index])
|
||||||
.inspect(|node| {
|
.inspect(|node| {
|
||||||
if let Some(node) = node.contact_info() {
|
if let Some(node) = node.contact_info() {
|
||||||
if let Ok(addr) = node.tvu(Protocol::UDP) {
|
if let Ok(addr) = node.tvu(protocol) {
|
||||||
addrs.entry(addr).or_insert(*node.pubkey());
|
addrs.entry(addr).or_insert(*node.pubkey());
|
||||||
}
|
}
|
||||||
if !drop_redundant_turbine_path {
|
if !drop_redundant_turbine_path {
|
||||||
|
@ -469,6 +471,11 @@ impl From<Pubkey> for NodeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn get_broadcast_protocol(_: &ShredId) -> Protocol {
|
||||||
|
Protocol::UDP
|
||||||
|
}
|
||||||
|
|
||||||
pub fn make_test_cluster<R: Rng>(
|
pub fn make_test_cluster<R: Rng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
num_nodes: usize,
|
num_nodes: usize,
|
||||||
|
|
|
@ -27,6 +27,8 @@ pub enum Error {
|
||||||
RecvTimeout(#[from] crossbeam_channel::RecvTimeoutError),
|
RecvTimeout(#[from] crossbeam_channel::RecvTimeoutError),
|
||||||
#[error("Send")]
|
#[error("Send")]
|
||||||
Send,
|
Send,
|
||||||
|
#[error(transparent)]
|
||||||
|
TransportError(#[from] solana_sdk::transport::TransportError),
|
||||||
#[error("TrySend")]
|
#[error("TrySend")]
|
||||||
TrySend,
|
TrySend,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -8,15 +8,15 @@ use {
|
||||||
lru::LruCache,
|
lru::LruCache,
|
||||||
rand::Rng,
|
rand::Rng,
|
||||||
rayon::{prelude::*, ThreadPool, ThreadPoolBuilder},
|
rayon::{prelude::*, ThreadPool, ThreadPoolBuilder},
|
||||||
solana_gossip::{
|
solana_client::tpu_connection::TpuConnection,
|
||||||
cluster_info::ClusterInfo, legacy_contact_info::LegacyContactInfo as ContactInfo,
|
solana_gossip::{cluster_info::ClusterInfo, contact_info::Protocol},
|
||||||
},
|
|
||||||
solana_ledger::{
|
solana_ledger::{
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
shred::{self, ShredId},
|
shred::{self, ShredId},
|
||||||
},
|
},
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_perf::deduper::Deduper,
|
solana_perf::deduper::Deduper,
|
||||||
|
solana_quic_client::QuicConnectionCache,
|
||||||
solana_rayon_threadlimit::get_thread_count,
|
solana_rayon_threadlimit::get_thread_count,
|
||||||
solana_rpc::{max_slots::MaxSlots, rpc_subscriptions::RpcSubscriptions},
|
solana_rpc::{max_slots::MaxSlots, rpc_subscriptions::RpcSubscriptions},
|
||||||
solana_rpc_client_api::response::SlotUpdate,
|
solana_rpc_client_api::response::SlotUpdate,
|
||||||
|
@ -173,6 +173,7 @@ fn retransmit(
|
||||||
cluster_info: &ClusterInfo,
|
cluster_info: &ClusterInfo,
|
||||||
shreds_receiver: &Receiver<Vec</*shred:*/ Vec<u8>>>,
|
shreds_receiver: &Receiver<Vec</*shred:*/ Vec<u8>>>,
|
||||||
sockets: &[UdpSocket],
|
sockets: &[UdpSocket],
|
||||||
|
quic_connection_cache: &QuicConnectionCache,
|
||||||
stats: &mut RetransmitStats,
|
stats: &mut RetransmitStats,
|
||||||
cluster_nodes_cache: &ClusterNodesCache<RetransmitStage>,
|
cluster_nodes_cache: &ClusterNodesCache<RetransmitStage>,
|
||||||
shred_deduper: &mut ShredDeduper<2>,
|
shred_deduper: &mut ShredDeduper<2>,
|
||||||
|
@ -259,6 +260,7 @@ fn retransmit(
|
||||||
&cluster_nodes,
|
&cluster_nodes,
|
||||||
socket_addr_space,
|
socket_addr_space,
|
||||||
&sockets[index % sockets.len()],
|
&sockets[index % sockets.len()],
|
||||||
|
quic_connection_cache,
|
||||||
stats,
|
stats,
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
@ -283,6 +285,7 @@ fn retransmit(
|
||||||
&cluster_nodes,
|
&cluster_nodes,
|
||||||
socket_addr_space,
|
socket_addr_space,
|
||||||
&sockets[index % sockets.len()],
|
&sockets[index % sockets.len()],
|
||||||
|
quic_connection_cache,
|
||||||
stats,
|
stats,
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
@ -311,6 +314,7 @@ fn retransmit_shred(
|
||||||
cluster_nodes: &ClusterNodes<RetransmitStage>,
|
cluster_nodes: &ClusterNodes<RetransmitStage>,
|
||||||
socket_addr_space: &SocketAddrSpace,
|
socket_addr_space: &SocketAddrSpace,
|
||||||
socket: &UdpSocket,
|
socket: &UdpSocket,
|
||||||
|
quic_connection_cache: &QuicConnectionCache,
|
||||||
stats: &RetransmitStats,
|
stats: &RetransmitStats,
|
||||||
) -> Result<(/*root_distance:*/ usize, /*num_nodes:*/ usize), Error> {
|
) -> Result<(/*root_distance:*/ usize, /*num_nodes:*/ usize), Error> {
|
||||||
let mut compute_turbine_peers = Measure::start("turbine_start");
|
let mut compute_turbine_peers = Measure::start("turbine_start");
|
||||||
|
@ -319,7 +323,7 @@ fn retransmit_shred(
|
||||||
cluster_nodes.get_retransmit_addrs(slot_leader, key, root_bank, data_plane_fanout)?;
|
cluster_nodes.get_retransmit_addrs(slot_leader, key, root_bank, data_plane_fanout)?;
|
||||||
let addrs: Vec<_> = addrs
|
let addrs: Vec<_> = addrs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|addr| ContactInfo::is_valid_address(addr, socket_addr_space))
|
.filter(|addr| socket_addr_space.check(addr))
|
||||||
.collect();
|
.collect();
|
||||||
compute_turbine_peers.stop();
|
compute_turbine_peers.stop();
|
||||||
stats
|
stats
|
||||||
|
@ -327,22 +331,33 @@ fn retransmit_shred(
|
||||||
.fetch_add(compute_turbine_peers.as_us(), Ordering::Relaxed);
|
.fetch_add(compute_turbine_peers.as_us(), Ordering::Relaxed);
|
||||||
|
|
||||||
let mut retransmit_time = Measure::start("retransmit_to");
|
let mut retransmit_time = Measure::start("retransmit_to");
|
||||||
let num_nodes = match multi_target_send(socket, shred, &addrs) {
|
let num_nodes = match cluster_nodes::get_broadcast_protocol(key) {
|
||||||
Ok(()) => addrs.len(),
|
Protocol::QUIC => addrs
|
||||||
Err(SendPktsError::IoError(ioerr, num_failed)) => {
|
.iter()
|
||||||
stats
|
.filter_map(|addr| {
|
||||||
.num_addrs_failed
|
quic_connection_cache
|
||||||
.fetch_add(num_failed, Ordering::Relaxed);
|
.get_connection(addr)
|
||||||
error!(
|
.send_data(shred)
|
||||||
"retransmit_to multi_target_send error: {:?}, {}/{} packets failed",
|
.ok()
|
||||||
ioerr,
|
})
|
||||||
num_failed,
|
.count(),
|
||||||
addrs.len(),
|
Protocol::UDP => match multi_target_send(socket, shred, &addrs) {
|
||||||
);
|
Ok(()) => addrs.len(),
|
||||||
addrs.len() - num_failed
|
Err(SendPktsError::IoError(ioerr, num_failed)) => {
|
||||||
}
|
error!(
|
||||||
|
"retransmit_to multi_target_send error: {:?}, {}/{} packets failed",
|
||||||
|
ioerr,
|
||||||
|
num_failed,
|
||||||
|
addrs.len(),
|
||||||
|
);
|
||||||
|
addrs.len() - num_failed
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
retransmit_time.stop();
|
retransmit_time.stop();
|
||||||
|
stats
|
||||||
|
.num_addrs_failed
|
||||||
|
.fetch_add(addrs.len() - num_nodes, Ordering::Relaxed);
|
||||||
stats.num_nodes.fetch_add(num_nodes, Ordering::Relaxed);
|
stats.num_nodes.fetch_add(num_nodes, Ordering::Relaxed);
|
||||||
stats
|
stats
|
||||||
.retransmit_total
|
.retransmit_total
|
||||||
|
@ -360,6 +375,7 @@ fn retransmit_shred(
|
||||||
/// * `r` - Receive channel for shreds to be retransmitted to all the layer 1 nodes.
|
/// * `r` - Receive channel for shreds to be retransmitted to all the layer 1 nodes.
|
||||||
pub fn retransmitter(
|
pub fn retransmitter(
|
||||||
sockets: Arc<Vec<UdpSocket>>,
|
sockets: Arc<Vec<UdpSocket>>,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
|
@ -391,6 +407,7 @@ pub fn retransmitter(
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
&shreds_receiver,
|
&shreds_receiver,
|
||||||
&sockets,
|
&sockets,
|
||||||
|
&quic_connection_cache,
|
||||||
&mut stats,
|
&mut stats,
|
||||||
&cluster_nodes_cache,
|
&cluster_nodes_cache,
|
||||||
&mut shred_deduper,
|
&mut shred_deduper,
|
||||||
|
@ -415,12 +432,14 @@ impl RetransmitStage {
|
||||||
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
retransmit_sockets: Arc<Vec<UdpSocket>>,
|
retransmit_sockets: Arc<Vec<UdpSocket>>,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
retransmit_receiver: Receiver<Vec</*shred:*/ Vec<u8>>>,
|
retransmit_receiver: Receiver<Vec</*shred:*/ Vec<u8>>>,
|
||||||
max_slots: Arc<MaxSlots>,
|
max_slots: Arc<MaxSlots>,
|
||||||
rpc_subscriptions: Option<Arc<RpcSubscriptions>>,
|
rpc_subscriptions: Option<Arc<RpcSubscriptions>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let retransmit_thread_handle = retransmitter(
|
let retransmit_thread_handle = retransmitter(
|
||||||
retransmit_sockets,
|
retransmit_sockets,
|
||||||
|
quic_connection_cache,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
leader_schedule_cache,
|
leader_schedule_cache,
|
||||||
cluster_info,
|
cluster_info,
|
||||||
|
|
|
@ -24,8 +24,8 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_QUIC_CONNECTIONS_PER_PEER: usize = 8;
|
const MAX_QUIC_CONNECTIONS_PER_PEER: usize = 8;
|
||||||
const MAX_STAKED_QUIC_CONNECTIONS: usize = 2000;
|
const MAX_STAKED_QUIC_CONNECTIONS: usize = 4000;
|
||||||
const MAX_UNSTAKED_QUIC_CONNECTIONS: usize = 1000;
|
const MAX_UNSTAKED_QUIC_CONNECTIONS: usize = 2000;
|
||||||
const QUIC_WAIT_FOR_CHUNK_TIMEOUT: Duration = Duration::from_secs(5);
|
const QUIC_WAIT_FOR_CHUNK_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
const QUIC_COALESCE_WAIT: Duration = Duration::from_millis(10);
|
const QUIC_COALESCE_WAIT: Duration = Duration::from_millis(10);
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ use {
|
||||||
entry_notifier_service::EntryNotifierSender,
|
entry_notifier_service::EntryNotifierSender,
|
||||||
},
|
},
|
||||||
solana_poh::poh_recorder::{PohRecorder, WorkingBankEntry},
|
solana_poh::poh_recorder::{PohRecorder, WorkingBankEntry},
|
||||||
|
solana_quic_client::QuicConnectionCache,
|
||||||
solana_rpc::{
|
solana_rpc::{
|
||||||
optimistically_confirmed_bank_tracker::BankNotificationSender,
|
optimistically_confirmed_bank_tracker::BankNotificationSender,
|
||||||
rpc_subscriptions::RpcSubscriptions,
|
rpc_subscriptions::RpcSubscriptions,
|
||||||
|
@ -101,6 +102,7 @@ impl Tpu {
|
||||||
tpu_coalesce: Duration,
|
tpu_coalesce: Duration,
|
||||||
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
|
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
|
||||||
connection_cache: &Arc<ConnectionCache>,
|
connection_cache: &Arc<ConnectionCache>,
|
||||||
|
turbine_quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
keypair: &Keypair,
|
keypair: &Keypair,
|
||||||
log_messages_bytes_limit: Option<usize>,
|
log_messages_bytes_limit: Option<usize>,
|
||||||
staked_nodes: &Arc<RwLock<StakedNodes>>,
|
staked_nodes: &Arc<RwLock<StakedNodes>>,
|
||||||
|
@ -254,6 +256,7 @@ impl Tpu {
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
bank_forks,
|
bank_forks,
|
||||||
shred_version,
|
shred_version,
|
||||||
|
turbine_quic_connection_cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -40,6 +40,7 @@ use {
|
||||||
entry_notifier_service::EntryNotifierSender, leader_schedule_cache::LeaderScheduleCache,
|
entry_notifier_service::EntryNotifierSender, leader_schedule_cache::LeaderScheduleCache,
|
||||||
},
|
},
|
||||||
solana_poh::poh_recorder::PohRecorder,
|
solana_poh::poh_recorder::PohRecorder,
|
||||||
|
solana_quic_client::QuicConnectionCache,
|
||||||
solana_rpc::{
|
solana_rpc::{
|
||||||
max_slots::MaxSlots, optimistically_confirmed_bank_tracker::BankNotificationSenderConfig,
|
max_slots::MaxSlots, optimistically_confirmed_bank_tracker::BankNotificationSenderConfig,
|
||||||
rpc_subscriptions::RpcSubscriptions,
|
rpc_subscriptions::RpcSubscriptions,
|
||||||
|
@ -141,6 +142,7 @@ impl Tvu {
|
||||||
prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
|
prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
|
||||||
banking_tracer: Arc<BankingTracer>,
|
banking_tracer: Arc<BankingTracer>,
|
||||||
staked_nodes: Arc<RwLock<StakedNodes>>,
|
staked_nodes: Arc<RwLock<StakedNodes>>,
|
||||||
|
quic_connection_cache: Arc<QuicConnectionCache>,
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
let TvuSockets {
|
let TvuSockets {
|
||||||
repair: repair_socket,
|
repair: repair_socket,
|
||||||
|
@ -188,6 +190,7 @@ impl Tvu {
|
||||||
leader_schedule_cache.clone(),
|
leader_schedule_cache.clone(),
|
||||||
cluster_info.clone(),
|
cluster_info.clone(),
|
||||||
Arc::new(retransmit_sockets),
|
Arc::new(retransmit_sockets),
|
||||||
|
quic_connection_cache,
|
||||||
retransmit_receiver,
|
retransmit_receiver,
|
||||||
max_slots.clone(),
|
max_slots.clone(),
|
||||||
Some(rpc_subscriptions.clone()),
|
Some(rpc_subscriptions.clone()),
|
||||||
|
@ -374,6 +377,7 @@ impl Tvu {
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
|
crate::validator::TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
serial_test::serial,
|
serial_test::serial,
|
||||||
solana_gossip::cluster_info::{ClusterInfo, Node},
|
solana_gossip::cluster_info::{ClusterInfo, Node},
|
||||||
solana_ledger::{
|
solana_ledger::{
|
||||||
|
@ -387,7 +391,10 @@ pub mod tests {
|
||||||
solana_runtime::bank::Bank,
|
solana_runtime::bank::Bank,
|
||||||
solana_sdk::signature::{Keypair, Signer},
|
solana_sdk::signature::{Keypair, Signer},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
std::sync::atomic::{AtomicU64, Ordering},
|
std::{
|
||||||
|
net::{IpAddr, Ipv4Addr},
|
||||||
|
sync::atomic::{AtomicU64, Ordering},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
|
@ -404,12 +411,20 @@ pub mod tests {
|
||||||
|
|
||||||
let bank_forks = BankForks::new(Bank::new_for_tests(&genesis_config));
|
let bank_forks = BankForks::new(Bank::new_for_tests(&genesis_config));
|
||||||
|
|
||||||
//start cluster_info1
|
let keypair = Arc::new(Keypair::new());
|
||||||
let cluster_info1 = ClusterInfo::new(
|
let quic_connection_cache = Arc::new(
|
||||||
target1.info.clone(),
|
solana_quic_client::new_quic_connection_cache(
|
||||||
Arc::new(Keypair::new()),
|
"connection_cache_test",
|
||||||
SocketAddrSpace::Unspecified,
|
&keypair,
|
||||||
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
&Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
//start cluster_info1
|
||||||
|
let cluster_info1 =
|
||||||
|
ClusterInfo::new(target1.info.clone(), keypair, SocketAddrSpace::Unspecified);
|
||||||
cluster_info1.insert_info(leader.info);
|
cluster_info1.insert_info(leader.info);
|
||||||
let cref1 = Arc::new(cluster_info1);
|
let cref1 = Arc::new(cluster_info1);
|
||||||
|
|
||||||
|
@ -491,6 +506,7 @@ pub mod tests {
|
||||||
&ignored_prioritization_fee_cache,
|
&ignored_prioritization_fee_cache,
|
||||||
BankingTracer::new_disabled(),
|
BankingTracer::new_disabled(),
|
||||||
Arc::<RwLock<StakedNodes>>::default(),
|
Arc::<RwLock<StakedNodes>>::default(),
|
||||||
|
quic_connection_cache,
|
||||||
)
|
)
|
||||||
.expect("assume success");
|
.expect("assume success");
|
||||||
exit.store(true, Ordering::Relaxed);
|
exit.store(true, Ordering::Relaxed);
|
||||||
|
|
|
@ -129,6 +129,8 @@ use {
|
||||||
const MAX_COMPLETED_DATA_SETS_IN_CHANNEL: usize = 100_000;
|
const MAX_COMPLETED_DATA_SETS_IN_CHANNEL: usize = 100_000;
|
||||||
const WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT: u64 = 80;
|
const WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT: u64 = 80;
|
||||||
|
|
||||||
|
pub const TURBINE_QUIC_CONNECTION_POOL_SIZE: usize = 4;
|
||||||
|
|
||||||
#[derive(Clone, EnumString, EnumVariantNames, Default, IntoStaticStr, Display)]
|
#[derive(Clone, EnumString, EnumVariantNames, Default, IntoStaticStr, Display)]
|
||||||
#[strum(serialize_all = "kebab-case")]
|
#[strum(serialize_all = "kebab-case")]
|
||||||
pub enum BlockVerificationMethod {
|
pub enum BlockVerificationMethod {
|
||||||
|
@ -1107,6 +1109,19 @@ impl Validator {
|
||||||
let entry_notification_sender = entry_notifier_service
|
let entry_notification_sender = entry_notifier_service
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|service| service.sender_cloned());
|
.map(|service| service.sender_cloned());
|
||||||
|
let turbine_quic_connection_cache = Arc::new(
|
||||||
|
solana_quic_client::new_quic_connection_cache(
|
||||||
|
"connection_cache_tvu_quic",
|
||||||
|
&identity_keypair,
|
||||||
|
node.info
|
||||||
|
.tvu(Protocol::QUIC)
|
||||||
|
.expect("Operator must spin up node with valid TVU address")
|
||||||
|
.ip(),
|
||||||
|
&staked_nodes,
|
||||||
|
TURBINE_QUIC_CONNECTION_POOL_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
let (replay_vote_sender, replay_vote_receiver) = unbounded();
|
let (replay_vote_sender, replay_vote_receiver) = unbounded();
|
||||||
let tvu = Tvu::new(
|
let tvu = Tvu::new(
|
||||||
vote_account,
|
vote_account,
|
||||||
|
@ -1160,6 +1175,7 @@ impl Validator {
|
||||||
&prioritization_fee_cache,
|
&prioritization_fee_cache,
|
||||||
banking_tracer.clone(),
|
banking_tracer.clone(),
|
||||||
staked_nodes.clone(),
|
staked_nodes.clone(),
|
||||||
|
turbine_quic_connection_cache.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let tpu = Tpu::new(
|
let tpu = Tpu::new(
|
||||||
|
@ -1192,6 +1208,7 @@ impl Validator {
|
||||||
config.tpu_coalesce,
|
config.tpu_coalesce,
|
||||||
cluster_confirmed_slot_sender,
|
cluster_confirmed_slot_sender,
|
||||||
&connection_cache,
|
&connection_cache,
|
||||||
|
turbine_quic_connection_cache,
|
||||||
&identity_keypair,
|
&identity_keypair,
|
||||||
config.runtime_config.log_messages_bytes_limit,
|
config.runtime_config.log_messages_bytes_limit,
|
||||||
&staked_nodes,
|
&staked_nodes,
|
||||||
|
|
|
@ -4744,6 +4744,7 @@ dependencies = [
|
||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-poh",
|
"solana-poh",
|
||||||
"solana-program-runtime",
|
"solana-program-runtime",
|
||||||
|
"solana-quic-client",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-rpc",
|
"solana-rpc",
|
||||||
"solana-rpc-client-api",
|
"solana-rpc-client-api",
|
||||||
|
|
|
@ -18,12 +18,15 @@ use {
|
||||||
rcgen::RcgenError,
|
rcgen::RcgenError,
|
||||||
solana_connection_cache::{
|
solana_connection_cache::{
|
||||||
connection_cache::{
|
connection_cache::{
|
||||||
BaseClientConnection, ClientError, ConnectionManager, ConnectionPool,
|
BaseClientConnection, ClientError, ConnectionCache, ConnectionManager, ConnectionPool,
|
||||||
ConnectionPoolError, Protocol,
|
ConnectionPoolError, Protocol,
|
||||||
},
|
},
|
||||||
connection_cache_stats::ConnectionCacheStats,
|
connection_cache_stats::ConnectionCacheStats,
|
||||||
},
|
},
|
||||||
solana_sdk::{pubkey::Pubkey, signature::Keypair},
|
solana_sdk::{
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::{Keypair, Signer},
|
||||||
|
},
|
||||||
solana_streamer::{
|
solana_streamer::{
|
||||||
nonblocking::quic::{compute_max_allowed_uni_streams, ConnectionPeerType},
|
nonblocking::quic::{compute_max_allowed_uni_streams, ConnectionPeerType},
|
||||||
streamer::StakedNodes,
|
streamer::StakedNodes,
|
||||||
|
@ -214,6 +217,23 @@ impl QuicConnectionManager {
|
||||||
Self { connection_config }
|
Self { connection_config }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type QuicConnectionCache = ConnectionCache<QuicPool, QuicConnectionManager, QuicConfig>;
|
||||||
|
|
||||||
|
pub fn new_quic_connection_cache(
|
||||||
|
name: &'static str,
|
||||||
|
keypair: &Keypair,
|
||||||
|
ipaddr: IpAddr,
|
||||||
|
staked_nodes: &Arc<RwLock<StakedNodes>>,
|
||||||
|
connection_pool_size: usize,
|
||||||
|
) -> Result<QuicConnectionCache, ClientError> {
|
||||||
|
let mut config = QuicConfig::new()?;
|
||||||
|
config.update_client_certificate(keypair, ipaddr)?;
|
||||||
|
config.set_staked_nodes(staked_nodes, &keypair.pubkey());
|
||||||
|
let connection_manager = QuicConnectionManager::new_with_connection_config(config);
|
||||||
|
ConnectionCache::new(name, connection_manager, connection_pool_size)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
|
|
Loading…
Reference in New Issue