Starting to implement aggregate peer stats
This commit is contained in:
parent
0c89ee9248
commit
22ea146ff6
1 changed files with 48 additions and 3 deletions
|
|
@ -4,7 +4,9 @@
|
||||||
// NOTE: deadlock notice:
|
// NOTE: deadlock notice:
|
||||||
// peers and stateLocked are behind 2 different locks.
|
// peers and stateLocked are behind 2 different locks.
|
||||||
// if you lock them in different order, this may deadlock.
|
// if you lock them in different order, this may deadlock.
|
||||||
// so always lock the peers one first, and unlock it before stateLocked is locked.
|
//
|
||||||
|
// so don't lock them both at the same time at all, or at the worst lock them in the
|
||||||
|
// same order (peers one first, then the global one).
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
|
@ -12,7 +14,7 @@ use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU32, AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
|
|
@ -62,9 +64,32 @@ pub struct InflightPiece {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PeerStates {
|
pub struct PeerStates {
|
||||||
|
stats: AggregatePeerStatsAtomic,
|
||||||
states: DashMap<PeerHandle, Peer>,
|
states: DashMap<PeerHandle, Peer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize)]
|
||||||
|
pub struct AggregatePeerStatsAtomic {
|
||||||
|
pub queued: AtomicU32,
|
||||||
|
pub connecting: AtomicU32,
|
||||||
|
pub live: AtomicU32,
|
||||||
|
pub seen: AtomicU32,
|
||||||
|
pub dead: AtomicU32,
|
||||||
|
pub not_needed: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AggregatePeerStatsAtomic {
|
||||||
|
fn counter(&self, state: &PeerState) -> &AtomicU32 {
|
||||||
|
match state {
|
||||||
|
PeerState::Connecting(_) => &self.connecting,
|
||||||
|
PeerState::Live(_) => &self.live,
|
||||||
|
PeerState::Queued => &self.queued,
|
||||||
|
PeerState::Dead => &self.dead,
|
||||||
|
PeerState::NotNeeded => &self.not_needed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize)]
|
#[derive(Debug, Default, Serialize)]
|
||||||
pub struct AggregatePeerStats {
|
pub struct AggregatePeerStats {
|
||||||
pub queued: usize,
|
pub queued: usize,
|
||||||
|
|
@ -75,6 +100,20 @@ pub struct AggregatePeerStats {
|
||||||
pub not_needed: usize,
|
pub not_needed: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AggregatePeerStatsAtomic> for AggregatePeerStats {
|
||||||
|
fn from(s: &'a AggregatePeerStatsAtomic) -> Self {
|
||||||
|
let ordering = Ordering::Relaxed;
|
||||||
|
Self {
|
||||||
|
queued: s.queued.load(ordering) as usize,
|
||||||
|
connecting: s.connecting.load(ordering) as usize,
|
||||||
|
live: s.live.load(ordering) as usize,
|
||||||
|
seen: s.seen.load(ordering) as usize,
|
||||||
|
dead: s.dead.load(ordering) as usize,
|
||||||
|
not_needed: s.not_needed.load(ordering) as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PeerStates {
|
impl PeerStates {
|
||||||
pub fn stats(&self) -> AggregatePeerStats {
|
pub fn stats(&self) -> AggregatePeerStats {
|
||||||
// TODO: it would be better to store these as atomic not to lock needlessly.
|
// TODO: it would be better to store these as atomic not to lock needlessly.
|
||||||
|
|
@ -95,12 +134,16 @@ impl PeerStates {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
pub fn stats_from_atomic(&self) -> AggregatePeerStats {
|
||||||
|
AggregatePeerStats::from(&self.stats)
|
||||||
|
}
|
||||||
pub fn add_if_not_seen(&self, addr: SocketAddr) -> Option<PeerHandle> {
|
pub fn add_if_not_seen(&self, addr: SocketAddr) -> Option<PeerHandle> {
|
||||||
use dashmap::mapref::entry::Entry;
|
use dashmap::mapref::entry::Entry;
|
||||||
match self.states.entry(addr) {
|
match self.states.entry(addr) {
|
||||||
Entry::Occupied(_) => None,
|
Entry::Occupied(_) => None,
|
||||||
Entry::Vacant(vac) => {
|
Entry::Vacant(vac) => {
|
||||||
vac.insert(Default::default());
|
vac.insert(Default::default());
|
||||||
|
self.stats.queued.fetch_add(1, Ordering::Relaxed);
|
||||||
Some(addr)
|
Some(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +185,9 @@ impl PeerStates {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
pub fn drop_peer(&self, handle: PeerHandle) -> Option<Peer> {
|
pub fn drop_peer(&self, handle: PeerHandle) -> Option<Peer> {
|
||||||
self.states.remove(&handle).map(|r| r.1)
|
let p = self.states.remove(&handle).map(|r| r.1)?;
|
||||||
|
self.stats.counter(&p.state).fetch_sub(1, Ordering::Relaxed);
|
||||||
|
Some(p)
|
||||||
}
|
}
|
||||||
pub fn mark_i_am_choked(&self, handle: PeerHandle, is_choked: bool) -> Option<bool> {
|
pub fn mark_i_am_choked(&self, handle: PeerHandle, is_choked: bool) -> Option<bool> {
|
||||||
self.with_live_mut(handle, "mark_i_am_choked", |live| {
|
self.with_live_mut(handle, "mark_i_am_choked", |live| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue