Refactor packet deduplication and harden bench test (#22080)
This commit is contained in:
parent
f10407dbc3
commit
93c776ce19
|
@ -5,7 +5,7 @@ use {
|
||||||
log::*,
|
log::*,
|
||||||
rand::{thread_rng, Rng},
|
rand::{thread_rng, Rng},
|
||||||
rayon::prelude::*,
|
rayon::prelude::*,
|
||||||
solana_core::banking_stage::BankingStage,
|
solana_core::{banking_stage::BankingStage, packet_deduper::PacketDeduper},
|
||||||
solana_gossip::cluster_info::{ClusterInfo, Node},
|
solana_gossip::cluster_info::{ClusterInfo, Node},
|
||||||
solana_ledger::{
|
solana_ledger::{
|
||||||
blockstore::Blockstore,
|
blockstore::Blockstore,
|
||||||
|
@ -235,6 +235,7 @@ fn main() {
|
||||||
None,
|
None,
|
||||||
replay_vote_sender,
|
replay_vote_sender,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
poh_recorder.lock().unwrap().set_bank(&bank);
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use {
|
||||||
rayon::prelude::*,
|
rayon::prelude::*,
|
||||||
solana_core::{
|
solana_core::{
|
||||||
banking_stage::{BankingStage, BankingStageStats},
|
banking_stage::{BankingStage, BankingStageStats},
|
||||||
|
packet_deduper::PacketDeduper,
|
||||||
qos_service::QosService,
|
qos_service::QosService,
|
||||||
},
|
},
|
||||||
solana_entry::entry::{next_hash, Entry},
|
solana_entry::entry::{next_hash, Entry},
|
||||||
|
@ -221,6 +222,7 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||||
);
|
);
|
||||||
let cluster_info = Arc::new(cluster_info);
|
let cluster_info = Arc::new(cluster_info);
|
||||||
let (s, _r) = unbounded();
|
let (s, _r) = unbounded();
|
||||||
|
let packet_deduper = PacketDeduper::default();
|
||||||
let _banking_stage = BankingStage::new(
|
let _banking_stage = BankingStage::new(
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
|
@ -230,6 +232,7 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||||
None,
|
None,
|
||||||
s,
|
s,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
packet_deduper.clone(),
|
||||||
);
|
);
|
||||||
poh_recorder.lock().unwrap().set_bank(&bank);
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
||||||
|
|
||||||
|
@ -264,6 +267,7 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||||
// in this chunk, but since we rotate between CHUNKS then
|
// in this chunk, but since we rotate between CHUNKS then
|
||||||
// we should clear them by the time we come around again to re-use that chunk.
|
// we should clear them by the time we come around again to re-use that chunk.
|
||||||
bank.clear_signatures();
|
bank.clear_signatures();
|
||||||
|
packet_deduper.reset();
|
||||||
trace!(
|
trace!(
|
||||||
"time: {} checked: {} sent: {}",
|
"time: {} checked: {} sent: {}",
|
||||||
duration_as_us(&now.elapsed()),
|
duration_as_us(&now.elapsed()),
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
//! to contruct a software pipeline. The stage uses all available CPU cores and
|
//! to contruct a software pipeline. The stage uses all available CPU cores and
|
||||||
//! can do its processing in parallel with signature verification on the GPU.
|
//! can do its processing in parallel with signature verification on the GPU.
|
||||||
use {
|
use {
|
||||||
crate::{packet_hasher::PacketHasher, qos_service::QosService},
|
crate::{packet_deduper::PacketDeduper, qos_service::QosService},
|
||||||
crossbeam_channel::{Receiver as CrossbeamReceiver, RecvTimeoutError},
|
crossbeam_channel::{Receiver as CrossbeamReceiver, RecvTimeoutError},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
lru::LruCache,
|
|
||||||
retain_mut::RetainMut,
|
retain_mut::RetainMut,
|
||||||
solana_entry::entry::hash_transactions,
|
solana_entry::entry::hash_transactions,
|
||||||
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
|
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
|
||||||
|
@ -53,7 +52,6 @@ use {
|
||||||
env,
|
env,
|
||||||
mem::size_of,
|
mem::size_of,
|
||||||
net::{SocketAddr, UdpSocket},
|
net::{SocketAddr, UdpSocket},
|
||||||
ops::DerefMut,
|
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, AtomicUsize, Ordering},
|
atomic::{AtomicU64, AtomicUsize, Ordering},
|
||||||
Arc, Mutex, RwLock,
|
Arc, Mutex, RwLock,
|
||||||
|
@ -80,8 +78,6 @@ const TOTAL_BUFFERED_PACKETS: usize = 500_000;
|
||||||
|
|
||||||
const MAX_NUM_TRANSACTIONS_PER_BATCH: usize = 128;
|
const MAX_NUM_TRANSACTIONS_PER_BATCH: usize = 128;
|
||||||
|
|
||||||
const DEFAULT_LRU_SIZE: usize = 200_000;
|
|
||||||
|
|
||||||
const NUM_VOTE_PROCESSING_THREADS: u32 = 2;
|
const NUM_VOTE_PROCESSING_THREADS: u32 = 2;
|
||||||
const MIN_THREADS_BANKING: u32 = 1;
|
const MIN_THREADS_BANKING: u32 = 1;
|
||||||
|
|
||||||
|
@ -93,7 +89,7 @@ pub struct BankingStageStats {
|
||||||
new_tx_count: AtomicUsize,
|
new_tx_count: AtomicUsize,
|
||||||
dropped_packet_batches_count: AtomicUsize,
|
dropped_packet_batches_count: AtomicUsize,
|
||||||
dropped_packets_count: AtomicUsize,
|
dropped_packets_count: AtomicUsize,
|
||||||
dropped_duplicated_packets_count: AtomicUsize,
|
pub(crate) dropped_duplicated_packets_count: AtomicUsize,
|
||||||
newly_buffered_packets_count: AtomicUsize,
|
newly_buffered_packets_count: AtomicUsize,
|
||||||
current_buffered_packets_count: AtomicUsize,
|
current_buffered_packets_count: AtomicUsize,
|
||||||
current_buffered_packet_batches_count: AtomicUsize,
|
current_buffered_packet_batches_count: AtomicUsize,
|
||||||
|
@ -105,7 +101,7 @@ pub struct BankingStageStats {
|
||||||
process_packets_elapsed: AtomicU64,
|
process_packets_elapsed: AtomicU64,
|
||||||
handle_retryable_packets_elapsed: AtomicU64,
|
handle_retryable_packets_elapsed: AtomicU64,
|
||||||
filter_pending_packets_elapsed: AtomicU64,
|
filter_pending_packets_elapsed: AtomicU64,
|
||||||
packet_duplicate_check_elapsed: AtomicU64,
|
pub(crate) packet_duplicate_check_elapsed: AtomicU64,
|
||||||
packet_conversion_elapsed: AtomicU64,
|
packet_conversion_elapsed: AtomicU64,
|
||||||
unprocessed_packet_conversion_elapsed: AtomicU64,
|
unprocessed_packet_conversion_elapsed: AtomicU64,
|
||||||
transaction_processing_elapsed: AtomicU64,
|
transaction_processing_elapsed: AtomicU64,
|
||||||
|
@ -296,6 +292,7 @@ impl BankingStage {
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
gossip_vote_sender: ReplayVoteSender,
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
cost_model: Arc<RwLock<CostModel>>,
|
cost_model: Arc<RwLock<CostModel>>,
|
||||||
|
packet_deduper: PacketDeduper,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new_num_threads(
|
Self::new_num_threads(
|
||||||
cluster_info,
|
cluster_info,
|
||||||
|
@ -307,9 +304,11 @@ impl BankingStage {
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
cost_model,
|
cost_model,
|
||||||
|
packet_deduper,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_num_threads(
|
fn new_num_threads(
|
||||||
cluster_info: &Arc<ClusterInfo>,
|
cluster_info: &Arc<ClusterInfo>,
|
||||||
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
||||||
|
@ -320,15 +319,12 @@ impl BankingStage {
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
gossip_vote_sender: ReplayVoteSender,
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
cost_model: Arc<RwLock<CostModel>>,
|
cost_model: Arc<RwLock<CostModel>>,
|
||||||
|
packet_deduper: PacketDeduper,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let batch_limit = TOTAL_BUFFERED_PACKETS / ((num_threads - 1) as usize * PACKETS_PER_BATCH);
|
let batch_limit = TOTAL_BUFFERED_PACKETS / ((num_threads - 1) as usize * PACKETS_PER_BATCH);
|
||||||
// Single thread to generate entries from many banks.
|
// Single thread to generate entries from many banks.
|
||||||
// This thread talks to poh_service and broadcasts the entries once they have been recorded.
|
// This thread talks to poh_service and broadcasts the entries once they have been recorded.
|
||||||
// Once an entry has been recorded, its blockhash is registered with the bank.
|
// Once an entry has been recorded, its blockhash is registered with the bank.
|
||||||
let duplicates = Arc::new(Mutex::new((
|
|
||||||
LruCache::new(DEFAULT_LRU_SIZE),
|
|
||||||
PacketHasher::default(),
|
|
||||||
)));
|
|
||||||
let data_budget = Arc::new(DataBudget::default());
|
let data_budget = Arc::new(DataBudget::default());
|
||||||
// Many banks that process transactions in parallel.
|
// Many banks that process transactions in parallel.
|
||||||
assert!(num_threads >= NUM_VOTE_PROCESSING_THREADS + MIN_THREADS_BANKING);
|
assert!(num_threads >= NUM_VOTE_PROCESSING_THREADS + MIN_THREADS_BANKING);
|
||||||
|
@ -352,7 +348,7 @@ impl BankingStage {
|
||||||
let mut recv_start = Instant::now();
|
let mut recv_start = Instant::now();
|
||||||
let transaction_status_sender = transaction_status_sender.clone();
|
let transaction_status_sender = transaction_status_sender.clone();
|
||||||
let gossip_vote_sender = gossip_vote_sender.clone();
|
let gossip_vote_sender = gossip_vote_sender.clone();
|
||||||
let duplicates = duplicates.clone();
|
let packet_deduper = packet_deduper.clone();
|
||||||
let data_budget = data_budget.clone();
|
let data_budget = data_budget.clone();
|
||||||
let cost_model = cost_model.clone();
|
let cost_model = cost_model.clone();
|
||||||
Builder::new()
|
Builder::new()
|
||||||
|
@ -368,7 +364,7 @@ impl BankingStage {
|
||||||
batch_limit,
|
batch_limit,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
&duplicates,
|
&packet_deduper,
|
||||||
&data_budget,
|
&data_budget,
|
||||||
cost_model,
|
cost_model,
|
||||||
);
|
);
|
||||||
|
@ -712,7 +708,7 @@ impl BankingStage {
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
gossip_vote_sender: ReplayVoteSender,
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
duplicates: &Arc<Mutex<(LruCache<u64, ()>, PacketHasher)>>,
|
packet_deduper: &PacketDeduper,
|
||||||
data_budget: &DataBudget,
|
data_budget: &DataBudget,
|
||||||
cost_model: Arc<RwLock<CostModel>>,
|
cost_model: Arc<RwLock<CostModel>>,
|
||||||
) {
|
) {
|
||||||
|
@ -769,7 +765,7 @@ impl BankingStage {
|
||||||
&gossip_vote_sender,
|
&gossip_vote_sender,
|
||||||
&mut buffered_packet_batches,
|
&mut buffered_packet_batches,
|
||||||
&banking_stage_stats,
|
&banking_stage_stats,
|
||||||
duplicates,
|
packet_deduper,
|
||||||
&recorder,
|
&recorder,
|
||||||
&qos_service,
|
&qos_service,
|
||||||
) {
|
) {
|
||||||
|
@ -1332,7 +1328,7 @@ impl BankingStage {
|
||||||
gossip_vote_sender: &ReplayVoteSender,
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
buffered_packet_batches: &mut UnprocessedPacketBatches,
|
buffered_packet_batches: &mut UnprocessedPacketBatches,
|
||||||
banking_stage_stats: &BankingStageStats,
|
banking_stage_stats: &BankingStageStats,
|
||||||
duplicates: &Arc<Mutex<(LruCache<u64, ()>, PacketHasher)>>,
|
packet_deduper: &PacketDeduper,
|
||||||
recorder: &TransactionRecorder,
|
recorder: &TransactionRecorder,
|
||||||
qos_service: &QosService,
|
qos_service: &QosService,
|
||||||
) -> Result<(), RecvTimeoutError> {
|
) -> Result<(), RecvTimeoutError> {
|
||||||
|
@ -1371,7 +1367,7 @@ impl BankingStage {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
duplicates,
|
packet_deduper,
|
||||||
banking_stage_stats,
|
banking_stage_stats,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1411,7 +1407,7 @@ impl BankingStage {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
duplicates,
|
packet_deduper,
|
||||||
banking_stage_stats,
|
banking_stage_stats,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1439,7 +1435,7 @@ impl BankingStage {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
duplicates,
|
packet_deduper,
|
||||||
banking_stage_stats,
|
banking_stage_stats,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1501,35 +1497,10 @@ impl BankingStage {
|
||||||
dropped_packets_count: &mut usize,
|
dropped_packets_count: &mut usize,
|
||||||
newly_buffered_packets_count: &mut usize,
|
newly_buffered_packets_count: &mut usize,
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
duplicates: &Arc<Mutex<(LruCache<u64, ()>, PacketHasher)>>,
|
packet_deduper: &PacketDeduper,
|
||||||
banking_stage_stats: &BankingStageStats,
|
banking_stage_stats: &BankingStageStats,
|
||||||
) {
|
) {
|
||||||
{
|
packet_deduper.dedupe_packets(&packet_batch, &mut packet_indexes, banking_stage_stats);
|
||||||
let original_packets_count = packet_indexes.len();
|
|
||||||
let mut packet_duplicate_check_time = Measure::start("packet_duplicate_check");
|
|
||||||
let mut duplicates = duplicates.lock().unwrap();
|
|
||||||
let (cache, hasher) = duplicates.deref_mut();
|
|
||||||
packet_indexes.retain(|i| {
|
|
||||||
let packet_hash = hasher.hash_packet(&packet_batch.packets[*i]);
|
|
||||||
match cache.get_mut(&packet_hash) {
|
|
||||||
Some(_hash) => false,
|
|
||||||
None => {
|
|
||||||
cache.put(packet_hash, ());
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
packet_duplicate_check_time.stop();
|
|
||||||
banking_stage_stats
|
|
||||||
.packet_duplicate_check_elapsed
|
|
||||||
.fetch_add(packet_duplicate_check_time.as_us(), Ordering::Relaxed);
|
|
||||||
banking_stage_stats
|
|
||||||
.dropped_duplicated_packets_count
|
|
||||||
.fetch_add(
|
|
||||||
original_packets_count.saturating_sub(packet_indexes.len()),
|
|
||||||
Ordering::Relaxed,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if Self::packet_has_more_unprocessed_transactions(&packet_indexes) {
|
if Self::packet_has_more_unprocessed_transactions(&packet_indexes) {
|
||||||
if unprocessed_packet_batches.len() >= batch_limit {
|
if unprocessed_packet_batches.len() >= batch_limit {
|
||||||
*dropped_packet_batches_count += 1;
|
*dropped_packet_batches_count += 1;
|
||||||
|
@ -1673,6 +1644,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
drop(verified_sender);
|
drop(verified_sender);
|
||||||
drop(gossip_verified_vote_sender);
|
drop(gossip_verified_vote_sender);
|
||||||
|
@ -1722,6 +1694,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
trace!("sending bank");
|
trace!("sending bank");
|
||||||
drop(verified_sender);
|
drop(verified_sender);
|
||||||
|
@ -1797,6 +1770,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// fund another account so we can send 2 good transactions in a single batch.
|
// fund another account so we can send 2 good transactions in a single batch.
|
||||||
|
@ -1948,6 +1922,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
gossip_vote_sender,
|
gossip_vote_sender,
|
||||||
Arc::new(RwLock::new(CostModel::default())),
|
Arc::new(RwLock::new(CostModel::default())),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// wait for banking_stage to eat the packets
|
// wait for banking_stage to eat the packets
|
||||||
|
@ -2940,10 +2915,7 @@ mod tests {
|
||||||
let new_packet_batch = PacketBatch::new(vec![Packet::default()]);
|
let new_packet_batch = PacketBatch::new(vec![Packet::default()]);
|
||||||
let packet_indexes = vec![];
|
let packet_indexes = vec![];
|
||||||
|
|
||||||
let duplicates = Arc::new(Mutex::new((
|
let packet_deduper = PacketDeduper::default();
|
||||||
LruCache::new(DEFAULT_LRU_SIZE),
|
|
||||||
PacketHasher::default(),
|
|
||||||
)));
|
|
||||||
let mut dropped_packet_batches_count = 0;
|
let mut dropped_packet_batches_count = 0;
|
||||||
let mut dropped_packets_count = 0;
|
let mut dropped_packets_count = 0;
|
||||||
let mut newly_buffered_packets_count = 0;
|
let mut newly_buffered_packets_count = 0;
|
||||||
|
@ -2958,7 +2930,7 @@ mod tests {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
&duplicates,
|
&packet_deduper,
|
||||||
&banking_stage_stats,
|
&banking_stage_stats,
|
||||||
);
|
);
|
||||||
assert_eq!(unprocessed_packets.len(), 1);
|
assert_eq!(unprocessed_packets.len(), 1);
|
||||||
|
@ -2977,7 +2949,7 @@ mod tests {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
&duplicates,
|
&packet_deduper,
|
||||||
&banking_stage_stats,
|
&banking_stage_stats,
|
||||||
);
|
);
|
||||||
assert_eq!(unprocessed_packets.len(), 2);
|
assert_eq!(unprocessed_packets.len(), 2);
|
||||||
|
@ -3001,7 +2973,7 @@ mod tests {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
&duplicates,
|
&packet_deduper,
|
||||||
&banking_stage_stats,
|
&banking_stage_stats,
|
||||||
);
|
);
|
||||||
assert_eq!(unprocessed_packets.len(), 2);
|
assert_eq!(unprocessed_packets.len(), 2);
|
||||||
|
@ -3022,7 +2994,7 @@ mod tests {
|
||||||
&mut dropped_packets_count,
|
&mut dropped_packets_count,
|
||||||
&mut newly_buffered_packets_count,
|
&mut newly_buffered_packets_count,
|
||||||
3,
|
3,
|
||||||
&duplicates,
|
&packet_deduper,
|
||||||
&banking_stage_stats,
|
&banking_stage_stats,
|
||||||
);
|
);
|
||||||
assert_eq!(unprocessed_packets.len(), 2);
|
assert_eq!(unprocessed_packets.len(), 2);
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub mod latest_validator_votes_for_frozen_banks;
|
||||||
pub mod ledger_cleanup_service;
|
pub mod ledger_cleanup_service;
|
||||||
pub mod optimistic_confirmation_verifier;
|
pub mod optimistic_confirmation_verifier;
|
||||||
pub mod outstanding_requests;
|
pub mod outstanding_requests;
|
||||||
|
pub mod packet_deduper;
|
||||||
pub mod packet_hasher;
|
pub mod packet_hasher;
|
||||||
pub mod progress_map;
|
pub mod progress_map;
|
||||||
pub mod qos_service;
|
pub mod qos_service;
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
use {
|
||||||
|
crate::{banking_stage::BankingStageStats, packet_hasher::PacketHasher},
|
||||||
|
lru::LruCache,
|
||||||
|
solana_measure::measure::Measure,
|
||||||
|
solana_perf::packet::PacketBatch,
|
||||||
|
std::{
|
||||||
|
ops::DerefMut,
|
||||||
|
sync::{atomic::Ordering, Arc, Mutex},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_LRU_SIZE: usize = 200_000;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketDeduper(Arc<Mutex<(LruCache<u64, ()>, PacketHasher)>>);
|
||||||
|
|
||||||
|
impl Default for PacketDeduper {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Arc::new(Mutex::new((
|
||||||
|
LruCache::new(DEFAULT_LRU_SIZE),
|
||||||
|
PacketHasher::default(),
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketDeduper {
|
||||||
|
pub fn dedupe_packets(
|
||||||
|
&self,
|
||||||
|
packet_batch: &PacketBatch,
|
||||||
|
packet_indexes: &mut Vec<usize>,
|
||||||
|
banking_stage_stats: &BankingStageStats,
|
||||||
|
) {
|
||||||
|
let original_packets_count = packet_indexes.len();
|
||||||
|
let mut packet_duplicate_check_time = Measure::start("packet_duplicate_check");
|
||||||
|
let mut duplicates = self.0.lock().unwrap();
|
||||||
|
let (cache, hasher) = duplicates.deref_mut();
|
||||||
|
packet_indexes.retain(|i| {
|
||||||
|
let packet_hash = hasher.hash_packet(&packet_batch.packets[*i]);
|
||||||
|
match cache.get_mut(&packet_hash) {
|
||||||
|
Some(_hash) => false,
|
||||||
|
None => {
|
||||||
|
cache.put(packet_hash, ());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
packet_duplicate_check_time.stop();
|
||||||
|
banking_stage_stats
|
||||||
|
.packet_duplicate_check_elapsed
|
||||||
|
.fetch_add(packet_duplicate_check_time.as_us(), Ordering::Relaxed);
|
||||||
|
banking_stage_stats
|
||||||
|
.dropped_duplicated_packets_count
|
||||||
|
.fetch_add(
|
||||||
|
original_packets_count.saturating_sub(packet_indexes.len()),
|
||||||
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&self) {
|
||||||
|
let mut duplicates = self.0.lock().unwrap();
|
||||||
|
duplicates.0.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ use {
|
||||||
GossipVerifiedVoteHashSender, VerifiedVoteSender, VoteTracker,
|
GossipVerifiedVoteHashSender, VerifiedVoteSender, VoteTracker,
|
||||||
},
|
},
|
||||||
fetch_stage::FetchStage,
|
fetch_stage::FetchStage,
|
||||||
|
packet_deduper::PacketDeduper,
|
||||||
sigverify::TransactionSigVerifier,
|
sigverify::TransactionSigVerifier,
|
||||||
sigverify_stage::SigVerifyStage,
|
sigverify_stage::SigVerifyStage,
|
||||||
},
|
},
|
||||||
|
@ -133,6 +134,7 @@ impl Tpu {
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_vote_sender,
|
replay_vote_sender,
|
||||||
cost_model.clone(),
|
cost_model.clone(),
|
||||||
|
PacketDeduper::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let broadcast_stage = broadcast_type.new_broadcast_stage(
|
let broadcast_stage = broadcast_type.new_broadcast_stage(
|
||||||
|
|
Loading…
Reference in New Issue