WTF is going on with counters
This commit is contained in:
parent
22ea146ff6
commit
aa99872e52
2 changed files with 181 additions and 103 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{collections::HashSet, sync::Arc};
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
|
|
@ -5,8 +6,10 @@ use anyhow::Context;
|
||||||
use backoff::{ExponentialBackoff, ExponentialBackoffBuilder};
|
use backoff::{ExponentialBackoff, ExponentialBackoffBuilder};
|
||||||
use librqbit_core::id20::Id20;
|
use librqbit_core::id20::Id20;
|
||||||
use librqbit_core::lengths::{ChunkInfo, ValidPieceIndex};
|
use librqbit_core::lengths::{ChunkInfo, ValidPieceIndex};
|
||||||
|
use serde::Serialize;
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
use tokio::sync::{Notify, Semaphore};
|
use tokio::sync::{Notify, Semaphore};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::peer_connection::WriterRequest;
|
use crate::peer_connection::WriterRequest;
|
||||||
use crate::type_aliases::BF;
|
use crate::type_aliases::BF;
|
||||||
|
|
@ -63,10 +66,61 @@ impl Default for PeerStats {
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Peer {
|
pub struct Peer {
|
||||||
pub state: PeerState,
|
pub state: PeerStateNoMut,
|
||||||
pub stats: PeerStats,
|
pub stats: PeerStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atomic_inc(c: &AtomicU32) -> u32 {
|
||||||
|
c.fetch_add(1, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atomic_dec(c: &AtomicU32) -> u32 {
|
||||||
|
c.fetch_sub(1, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AggregatePeerStatsAtomic {
|
||||||
|
pub 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inc(&self, state: &PeerState) {
|
||||||
|
trace!(
|
||||||
|
"inc, new value = {}, state = {}",
|
||||||
|
atomic_inc(self.counter(state)),
|
||||||
|
state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dec(&self, state: &PeerState) {
|
||||||
|
trace!(
|
||||||
|
"dec, new value = {}, state = {}",
|
||||||
|
atomic_dec(self.counter(state)),
|
||||||
|
state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn incdec(&self, old: &PeerState, new: &PeerState) {
|
||||||
|
self.dec(old);
|
||||||
|
self.inc(new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub enum PeerState {
|
pub enum PeerState {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
@ -82,6 +136,12 @@ pub enum PeerState {
|
||||||
NotNeeded,
|
NotNeeded,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for PeerState {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PeerState {
|
impl PeerState {
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -93,70 +153,77 @@ impl PeerState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_connecting(&mut self) -> Option<PeerTx> {
|
pub fn take_live_no_counters(self) -> Option<LivePeerState> {
|
||||||
if let PeerState::Connecting(_) = self {
|
match self {
|
||||||
match std::mem::take(self) {
|
PeerState::Live(l) => Some(l),
|
||||||
PeerState::Connecting(tx) => Some(tx),
|
_ => None,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn take_live(&mut self) -> Option<LivePeerState> {
|
#[derive(Debug, Default)]
|
||||||
if let PeerState::Live(_) = self {
|
pub struct PeerStateNoMut(PeerState);
|
||||||
match std::mem::take(self) {
|
|
||||||
PeerState::Live(l) => Some(l),
|
impl PeerStateNoMut {
|
||||||
_ => unreachable!(),
|
pub fn get(&self) -> &PeerState {
|
||||||
}
|
&self.0
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
}
|
pub fn take(&mut self, counters: &AggregatePeerStatsAtomic) -> PeerState {
|
||||||
|
self.set(Default::default(), counters)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, new: PeerState, counters: &AggregatePeerStatsAtomic) -> PeerState {
|
||||||
|
counters.incdec(&self.0, &new);
|
||||||
|
std::mem::replace(&mut self.0, new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_live(&self) -> Option<&LivePeerState> {
|
pub fn get_live(&self) -> Option<&LivePeerState> {
|
||||||
match self {
|
match &self.0 {
|
||||||
PeerState::Live(l) => Some(l),
|
PeerState::Live(l) => Some(l),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_live_mut(&mut self) -> Option<&mut LivePeerState> {
|
pub fn get_live_mut(&mut self) -> Option<&mut LivePeerState> {
|
||||||
match self {
|
match &mut self.0 {
|
||||||
PeerState::Live(l) => Some(l),
|
PeerState::Live(l) => Some(l),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queued_to_connecting(&mut self) -> Option<PeerRx> {
|
pub fn queued_to_connecting(&mut self, counters: &AggregatePeerStatsAtomic) -> Option<PeerRx> {
|
||||||
if let PeerState::Queued = self {
|
if let PeerState::Queued = &self.0 {
|
||||||
let (tx, rx) = unbounded_channel();
|
let (tx, rx) = unbounded_channel();
|
||||||
*self = PeerState::Connecting(tx);
|
self.set(PeerState::Connecting(tx), counters);
|
||||||
Some(rx)
|
Some(rx)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn connecting_to_live(&mut self, peer_id: Id20) -> Option<&mut LivePeerState> {
|
pub fn connecting_to_live(
|
||||||
let tx = self.take_connecting()?;
|
&mut self,
|
||||||
*self = PeerState::Live(LivePeerState::new(peer_id, tx));
|
peer_id: Id20,
|
||||||
self.get_live_mut()
|
counters: &AggregatePeerStatsAtomic,
|
||||||
}
|
) -> Option<&mut LivePeerState> {
|
||||||
|
if let PeerState::Connecting(_) = &self.0 {
|
||||||
pub fn to_dead(&mut self) -> Option<Option<LivePeerState>> {
|
let tx = match self.take(counters) {
|
||||||
match std::mem::replace(self, PeerState::Dead) {
|
PeerState::Connecting(tx) => tx,
|
||||||
PeerState::Live(l) => Some(Some(l)),
|
_ => unreachable!(),
|
||||||
PeerState::Connecting(_) => Some(None),
|
};
|
||||||
_ => None,
|
self.set(PeerState::Live(LivePeerState::new(peer_id, tx)), counters);
|
||||||
|
self.get_live_mut()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_not_needed(&mut self) -> Option<LivePeerState> {
|
pub fn to_dead(&mut self, counters: &AggregatePeerStatsAtomic) -> PeerState {
|
||||||
match std::mem::replace(self, PeerState::NotNeeded) {
|
self.set(PeerState::Dead, counters)
|
||||||
PeerState::Live(l) => Some(l),
|
}
|
||||||
_ => None,
|
|
||||||
}
|
pub fn to_not_needed(&mut self, counters: &AggregatePeerStatsAtomic) -> PeerState {
|
||||||
|
self.set(PeerState::NotNeeded, counters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU32, AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
|
|
@ -52,7 +52,10 @@ use crate::{
|
||||||
peer_connection::{
|
peer_connection::{
|
||||||
PeerConnection, PeerConnectionHandler, PeerConnectionOptions, WriterRequest,
|
PeerConnection, PeerConnectionHandler, PeerConnectionOptions, WriterRequest,
|
||||||
},
|
},
|
||||||
peer_state::{InflightRequest, LivePeerState, Peer, PeerRx, PeerState, PeerTx, SendMany},
|
peer_state::{
|
||||||
|
atomic_inc, AggregatePeerStatsAtomic, InflightRequest, LivePeerState, Peer, PeerRx,
|
||||||
|
PeerState, PeerTx, SendMany,
|
||||||
|
},
|
||||||
spawn_utils::{spawn, BlockingSpawner},
|
spawn_utils::{spawn, BlockingSpawner},
|
||||||
type_aliases::{PeerHandle, BF},
|
type_aliases::{PeerHandle, BF},
|
||||||
};
|
};
|
||||||
|
|
@ -68,29 +71,7 @@ pub struct PeerStates {
|
||||||
states: DashMap<PeerHandle, Peer>,
|
states: DashMap<PeerHandle, Peer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize)]
|
#[derive(Debug, Default, Serialize, PartialEq, Eq)]
|
||||||
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)]
|
|
||||||
pub struct AggregatePeerStats {
|
pub struct AggregatePeerStats {
|
||||||
pub queued: usize,
|
pub queued: usize,
|
||||||
pub connecting: usize,
|
pub connecting: usize,
|
||||||
|
|
@ -123,7 +104,7 @@ impl PeerStates {
|
||||||
.iter()
|
.iter()
|
||||||
.fold(AggregatePeerStats::default(), |mut s, p| {
|
.fold(AggregatePeerStats::default(), |mut s, p| {
|
||||||
s.seen += 1;
|
s.seen += 1;
|
||||||
match &p.value().state {
|
match &p.value().state.get() {
|
||||||
PeerState::Connecting(_) => s.connecting += 1,
|
PeerState::Connecting(_) => s.connecting += 1,
|
||||||
PeerState::Live(_) => s.live += 1,
|
PeerState::Live(_) => s.live += 1,
|
||||||
PeerState::Queued => s.queued += 1,
|
PeerState::Queued => s.queued += 1,
|
||||||
|
|
@ -143,7 +124,8 @@ impl PeerStates {
|
||||||
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);
|
atomic_inc(&self.stats.queued);
|
||||||
|
atomic_inc(&self.stats.seen);
|
||||||
Some(addr)
|
Some(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -162,10 +144,12 @@ impl PeerStates {
|
||||||
.map(|e| f(TimedExistence::new(e, reason).value_mut()))
|
.map(|e| f(TimedExistence::new(e, reason).value_mut()))
|
||||||
}
|
}
|
||||||
pub fn with_live<R>(&self, addr: PeerHandle, f: impl FnOnce(&LivePeerState) -> R) -> Option<R> {
|
pub fn with_live<R>(&self, addr: PeerHandle, f: impl FnOnce(&LivePeerState) -> R) -> Option<R> {
|
||||||
self.states.get(&addr).and_then(|e| match &e.value().state {
|
self.states
|
||||||
PeerState::Live(l) => Some(f(l)),
|
.get(&addr)
|
||||||
_ => None,
|
.and_then(|e| match &e.value().state.get() {
|
||||||
})
|
PeerState::Live(l) => Some(f(l)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn with_live_mut<R>(
|
pub fn with_live_mut<R>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -173,20 +157,19 @@ impl PeerStates {
|
||||||
reason: &'static str,
|
reason: &'static str,
|
||||||
f: impl FnOnce(&mut LivePeerState) -> R,
|
f: impl FnOnce(&mut LivePeerState) -> R,
|
||||||
) -> Option<R> {
|
) -> Option<R> {
|
||||||
self.with_peer_mut(addr, reason, |peer| match &mut peer.state {
|
self.with_peer_mut(addr, reason, |peer| peer.state.get_live_mut().map(f))
|
||||||
PeerState::Live(l) => Some(f(l)),
|
.flatten()
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_peer_dead(&self, handle: PeerHandle) -> Option<Option<LivePeerState>> {
|
pub fn mark_peer_dead(&self, handle: PeerHandle) -> Option<Option<LivePeerState>> {
|
||||||
self.with_peer_mut(handle, "mark_peer_dead", |peer| peer.state.to_dead())
|
let prev = self.with_peer_mut(handle, "mark_peer_dead", |peer| {
|
||||||
.flatten()
|
peer.state.to_dead(&self.stats)
|
||||||
|
})?;
|
||||||
|
Some(prev.take_live_no_counters())
|
||||||
}
|
}
|
||||||
pub fn drop_peer(&self, handle: PeerHandle) -> Option<Peer> {
|
pub fn drop_peer(&self, handle: PeerHandle) -> Option<Peer> {
|
||||||
let p = 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);
|
self.stats.dec(p.state.get());
|
||||||
Some(p)
|
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> {
|
||||||
|
|
@ -216,12 +199,14 @@ impl PeerStates {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn mark_peer_connecting(&self, h: PeerHandle) -> anyhow::Result<PeerRx> {
|
pub fn mark_peer_connecting(&self, h: PeerHandle) -> anyhow::Result<PeerRx> {
|
||||||
self.with_peer_mut(h, "mark_peer_connecting", |peer| {
|
let rx = self
|
||||||
peer.state
|
.with_peer_mut(h, "mark_peer_connecting", |peer| {
|
||||||
.queued_to_connecting()
|
peer.state
|
||||||
.context("invalid peer state")
|
.queued_to_connecting(&self.stats)
|
||||||
})
|
.context("invalid peer state")
|
||||||
.context("peer not found in states")?
|
})
|
||||||
|
.context("peer not found in states")??;
|
||||||
|
Ok(rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_tx(&self, handle: PeerHandle) -> Option<PeerTx> {
|
pub fn clone_tx(&self, handle: PeerHandle) -> Option<PeerTx> {
|
||||||
|
|
@ -234,11 +219,11 @@ impl PeerStates {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_peer_not_needed(&self, handle: PeerHandle) -> Option<LivePeerState> {
|
fn mark_peer_not_needed(&self, handle: PeerHandle) -> Option<PeerState> {
|
||||||
self.with_peer_mut(handle, "mark_peer_not_needed", |peer| {
|
let prev = self.with_peer_mut(handle, "mark_peer_not_needed", |peer| {
|
||||||
peer.state.to_not_needed()
|
peer.state.to_not_needed(&self.stats)
|
||||||
})
|
})?;
|
||||||
.flatten()
|
Some(prev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,6 +274,7 @@ pub struct StatsSnapshot {
|
||||||
pub time: Instant,
|
pub time: Instant,
|
||||||
pub total_piece_download_ms: u64,
|
pub total_piece_download_ms: u64,
|
||||||
pub peer_stats: AggregatePeerStats,
|
pub peer_stats: AggregatePeerStats,
|
||||||
|
pub new_peer_stats: AggregatePeerStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatsSnapshot {
|
impl StatsSnapshot {
|
||||||
|
|
@ -677,10 +663,14 @@ impl TorrentState {
|
||||||
|
|
||||||
fn set_peer_live(&self, handle: PeerHandle, h: Handshake) {
|
fn set_peer_live(&self, handle: PeerHandle, h: Handshake) {
|
||||||
let result = self.peers.with_peer_mut(handle, "set_peer_live", |p| {
|
let result = self.peers.with_peer_mut(handle, "set_peer_live", |p| {
|
||||||
p.state.connecting_to_live(Id20(h.peer_id)).is_some()
|
p.state
|
||||||
|
.connecting_to_live(Id20(h.peer_id), &self.peers.stats)
|
||||||
|
.is_some()
|
||||||
});
|
});
|
||||||
match result {
|
match result {
|
||||||
Some(true) => debug!("set peer to live"),
|
Some(true) => {
|
||||||
|
debug!("set peer to live")
|
||||||
|
}
|
||||||
Some(false) => debug!("can't set peer live, it was in wrong state"),
|
Some(false) => debug!("can't set peer live, it was in wrong state"),
|
||||||
None => debug!("can't set peer live, it disappeared"),
|
None => debug!("can't set peer live, it disappeared"),
|
||||||
}
|
}
|
||||||
|
|
@ -694,7 +684,9 @@ impl TorrentState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match std::mem::take(&mut pe.value_mut().state) {
|
let prev = pe.value_mut().state.take(&self.peers.stats);
|
||||||
|
|
||||||
|
match prev {
|
||||||
PeerState::Connecting(_) => {}
|
PeerState::Connecting(_) => {}
|
||||||
PeerState::Live(live) => {
|
PeerState::Live(live) => {
|
||||||
let mut g = self.lock_write("mark_chunk_requests_canceled");
|
let mut g = self.lock_write("mark_chunk_requests_canceled");
|
||||||
|
|
@ -709,7 +701,9 @@ impl TorrentState {
|
||||||
}
|
}
|
||||||
PeerState::NotNeeded => {
|
PeerState::NotNeeded => {
|
||||||
// Restore it as std::mem::take() replaced it above.
|
// Restore it as std::mem::take() replaced it above.
|
||||||
pe.value_mut().state = PeerState::NotNeeded;
|
pe.value_mut()
|
||||||
|
.state
|
||||||
|
.set(PeerState::NotNeeded, &self.peers.stats);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s @ PeerState::Queued | s @ PeerState::Dead => {
|
s @ PeerState::Queued | s @ PeerState::Dead => {
|
||||||
|
|
@ -723,17 +717,21 @@ impl TorrentState {
|
||||||
|
|
||||||
if error.is_none() {
|
if error.is_none() {
|
||||||
debug!("peer died without errors, not re-queueing");
|
debug!("peer died without errors, not re-queueing");
|
||||||
pe.value_mut().state = PeerState::NotNeeded;
|
pe.value_mut()
|
||||||
|
.state
|
||||||
|
.set(PeerState::NotNeeded, &self.peers.stats);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_finished() {
|
if self.is_finished() {
|
||||||
debug!("torrent finished, not re-queueing");
|
debug!("torrent finished, not re-queueing");
|
||||||
pe.value_mut().state = PeerState::NotNeeded;
|
pe.value_mut()
|
||||||
|
.state
|
||||||
|
.set(PeerState::NotNeeded, &self.peers.stats);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pe.value_mut().state = PeerState::Dead;
|
pe.value_mut().state.set(PeerState::Dead, &self.peers.stats);
|
||||||
let backoff = pe.value_mut().stats.backoff.next_backoff();
|
let backoff = pe.value_mut().stats.backoff.next_backoff();
|
||||||
|
|
||||||
// Prevent deadlocks.
|
// Prevent deadlocks.
|
||||||
|
|
@ -754,8 +752,10 @@ impl TorrentState {
|
||||||
state
|
state
|
||||||
.peers
|
.peers
|
||||||
.with_peer_mut(handle, "dead_to_queued", |peer| {
|
.with_peer_mut(handle, "dead_to_queued", |peer| {
|
||||||
match &peer.state {
|
match peer.state.get() {
|
||||||
PeerState::Dead => peer.state = PeerState::Queued,
|
PeerState::Dead => {
|
||||||
|
peer.state.set(PeerState::Queued, &state.peers.stats)
|
||||||
|
}
|
||||||
other => bail!(
|
other => bail!(
|
||||||
"peer is in unexpected state: {}. Expected dead",
|
"peer is in unexpected state: {}. Expected dead",
|
||||||
other.name()
|
other.name()
|
||||||
|
|
@ -793,7 +793,7 @@ impl TorrentState {
|
||||||
let mut futures = Vec::new();
|
let mut futures = Vec::new();
|
||||||
|
|
||||||
for pe in self.peers.states.iter() {
|
for pe in self.peers.states.iter() {
|
||||||
match &pe.value().state {
|
match &pe.value().state.get() {
|
||||||
PeerState::Live(live) => {
|
PeerState::Live(live) => {
|
||||||
if !live.peer_interested {
|
if !live.peer_interested {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -856,11 +856,17 @@ impl TorrentState {
|
||||||
|
|
||||||
pub fn stats_snapshot(&self, with_peer_stats: bool) -> StatsSnapshot {
|
pub fn stats_snapshot(&self, with_peer_stats: bool) -> StatsSnapshot {
|
||||||
use Ordering::*;
|
use Ordering::*;
|
||||||
|
let new_peer_stats = self.peers.stats_from_atomic();
|
||||||
let peer_stats = if with_peer_stats {
|
let peer_stats = if with_peer_stats {
|
||||||
self.peers.stats()
|
let old_stats = self.peers.stats();
|
||||||
|
if old_stats != new_peer_stats {
|
||||||
|
warn!("old != new: {old_stats:?} != {new_peer_stats:?}")
|
||||||
|
}
|
||||||
|
old_stats
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let downloaded = self.stats.downloaded_and_checked.load(Relaxed);
|
let downloaded = self.stats.downloaded_and_checked.load(Relaxed);
|
||||||
let remaining = self.needed - downloaded;
|
let remaining = self.needed - downloaded;
|
||||||
StatsSnapshot {
|
StatsSnapshot {
|
||||||
|
|
@ -875,6 +881,7 @@ impl TorrentState {
|
||||||
remaining_bytes: remaining,
|
remaining_bytes: remaining,
|
||||||
total_piece_download_ms: self.stats.total_piece_download_ms.load(Relaxed),
|
total_piece_download_ms: self.stats.total_piece_download_ms.load(Relaxed),
|
||||||
peer_stats,
|
peer_stats,
|
||||||
|
new_peer_stats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1367,10 +1374,14 @@ impl PeerHandler {
|
||||||
|
|
||||||
fn disconnect_all_peers_that_have_full_torrent(&self) {
|
fn disconnect_all_peers_that_have_full_torrent(&self) {
|
||||||
for mut pe in self.state.peers.states.iter_mut() {
|
for mut pe in self.state.peers.states.iter_mut() {
|
||||||
if let PeerState::Live(l) = &pe.value().state {
|
if let PeerState::Live(l) = pe.value().state.get() {
|
||||||
if l.has_full_torrent(self.state.lengths.total_pieces() as usize) {
|
if l.has_full_torrent(self.state.lengths.total_pieces() as usize) {
|
||||||
let live = pe.value_mut().state.to_not_needed().unwrap();
|
let prev = pe.value_mut().state.to_not_needed(&self.state.peers.stats);
|
||||||
let _ = live.tx.send(WriterRequest::Disconnect);
|
let _ = prev
|
||||||
|
.take_live_no_counters()
|
||||||
|
.unwrap()
|
||||||
|
.tx
|
||||||
|
.send(WriterRequest::Disconnect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue