With pinger its not entirely bad now, but still pretty horrible
This commit is contained in:
parent
8d58a9f419
commit
fee2690aae
2 changed files with 49 additions and 59 deletions
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
self, CompactNodeInfo, ErrorDescription, FindNodeRequest, GetPeersRequest, Message,
|
self, CompactNodeInfo, ErrorDescription, FindNodeRequest, GetPeersRequest, Message,
|
||||||
MessageKind, Node, PingRequest, Response,
|
MessageKind, Node, PingRequest, Response,
|
||||||
},
|
},
|
||||||
routing_table::{InsertResult, RoutingTable},
|
routing_table::{InsertResult, NodeStatus, RoutingTable},
|
||||||
INACTIVITY_TIMEOUT, REQUERY_INTERVAL, RESPONSE_TIMEOUT,
|
INACTIVITY_TIMEOUT, REQUERY_INTERVAL, RESPONSE_TIMEOUT,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
|
|
@ -109,12 +109,10 @@ impl RecursiveRequestCallbacks for RecursiveRequestCallbacksGetPeers {
|
||||||
struct RecursiveRequestCallbacksFindNodes {}
|
struct RecursiveRequestCallbacksFindNodes {}
|
||||||
impl RecursiveRequestCallbacks for RecursiveRequestCallbacksFindNodes {
|
impl RecursiveRequestCallbacks for RecursiveRequestCallbacksFindNodes {
|
||||||
fn on_request_start(&self, req: &RecursiveRequest<Self>, target_node: Id20, addr: SocketAddr) {
|
fn on_request_start(&self, req: &RecursiveRequest<Self>, target_node: Id20, addr: SocketAddr) {
|
||||||
match req.dht.routing_table_add_node(target_node, addr) {
|
let mut rt = req.dht.routing_table.write();
|
||||||
|
match rt.add_node(target_node, addr) {
|
||||||
InsertResult::WasExisting | InsertResult::ReplacedBad(_) | InsertResult::Added => {
|
InsertResult::WasExisting | InsertResult::ReplacedBad(_) | InsertResult::Added => {
|
||||||
req.dht
|
rt.mark_outgoing_request(&target_node);
|
||||||
.routing_table
|
|
||||||
.write()
|
|
||||||
.mark_outgoing_request(&target_node);
|
|
||||||
}
|
}
|
||||||
InsertResult::Ignored => {}
|
InsertResult::Ignored => {}
|
||||||
}
|
}
|
||||||
|
|
@ -490,15 +488,12 @@ pub struct DhtState {
|
||||||
rate_limiter: RateLimiter,
|
rate_limiter: RateLimiter,
|
||||||
// This is to send raw messages
|
// This is to send raw messages
|
||||||
worker_sender: UnboundedSender<WorkerSendRequest>,
|
worker_sender: UnboundedSender<WorkerSendRequest>,
|
||||||
// This is to send pings.
|
|
||||||
ping_sender: UnboundedSender<(Id20, SocketAddr)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DhtState {
|
impl DhtState {
|
||||||
fn new_internal(
|
fn new_internal(
|
||||||
id: Id20,
|
id: Id20,
|
||||||
sender: UnboundedSender<WorkerSendRequest>,
|
sender: UnboundedSender<WorkerSendRequest>,
|
||||||
ping_sender: UnboundedSender<(Id20, SocketAddr)>,
|
|
||||||
routing_table: Option<RoutingTable>,
|
routing_table: Option<RoutingTable>,
|
||||||
listen_addr: SocketAddr,
|
listen_addr: SocketAddr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -510,7 +505,6 @@ impl DhtState {
|
||||||
routing_table: RwLock::new(routing_table),
|
routing_table: RwLock::new(routing_table),
|
||||||
worker_sender: sender,
|
worker_sender: sender,
|
||||||
listen_addr,
|
listen_addr,
|
||||||
ping_sender,
|
|
||||||
rate_limiter: make_rate_limiter(),
|
rate_limiter: make_rate_limiter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -716,14 +710,6 @@ impl DhtState {
|
||||||
routing_table_size: self.routing_table.read().len(),
|
routing_table_size: self.routing_table.read().len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn routing_table_add_node(self: &Arc<Self>, id: Id20, addr: SocketAddr) -> InsertResult {
|
|
||||||
let res = self.routing_table.write().add_node(id, addr, |id, addr| {
|
|
||||||
let _ = self.ping_sender.send((id, addr));
|
|
||||||
true
|
|
||||||
});
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -813,15 +799,20 @@ impl DhtWorker {
|
||||||
let filler = async {
|
let filler = async {
|
||||||
let mut interval = tokio::time::interval(INACTIVITY_TIMEOUT);
|
let mut interval = tokio::time::interval(INACTIVITY_TIMEOUT);
|
||||||
tokio::time::sleep(INACTIVITY_TIMEOUT).await;
|
tokio::time::sleep(INACTIVITY_TIMEOUT).await;
|
||||||
|
let mut iteration = 0;
|
||||||
loop {
|
loop {
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
|
let mut found = 0;
|
||||||
for bucket in self.dht.routing_table.read().iter_buckets() {
|
for bucket in self.dht.routing_table.read().iter_buckets() {
|
||||||
if bucket.leaf.last_refreshed.elapsed() < INACTIVITY_TIMEOUT {
|
if bucket.leaf.last_refreshed.elapsed() < INACTIVITY_TIMEOUT {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
found += 1;
|
||||||
let random_id = bucket.random_within();
|
let random_id = bucket.random_within();
|
||||||
tx.send(random_id).unwrap();
|
tx.send(random_id).unwrap();
|
||||||
}
|
}
|
||||||
|
trace!("iteration {}, refreshing {} buckets", iteration, found);
|
||||||
|
iteration += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -851,15 +842,36 @@ impl DhtWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn pinger(&self, mut rx: UnboundedReceiver<(Id20, SocketAddr)>) -> anyhow::Result<()> {
|
async fn pinger(&self) -> anyhow::Result<()> {
|
||||||
let mut futs = FuturesUnordered::new();
|
let mut futs = FuturesUnordered::new();
|
||||||
|
let mut interval = tokio::time::interval(INACTIVITY_TIMEOUT / 4);
|
||||||
|
let (tx, mut rx) = unbounded_channel();
|
||||||
|
let looper = async {
|
||||||
|
let mut iteration = 0;
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
let mut found = 0;
|
||||||
|
for node in self.dht.routing_table.read().iter() {
|
||||||
|
if matches!(
|
||||||
|
node.status(),
|
||||||
|
NodeStatus::Questionable | NodeStatus::Unknown
|
||||||
|
) {
|
||||||
|
found += 1;
|
||||||
|
tx.send((node.id(), node.addr())).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("iteration {}, pinging {} nodes", iteration, found);
|
||||||
|
iteration += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tokio::pin!(looper);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
_ = &mut looper => {},
|
||||||
r = rx.recv() => {
|
r = rx.recv() => {
|
||||||
let (id, addr) = match r {
|
let (id, addr) = r.unwrap();
|
||||||
Some(r) => r,
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
futs.push(async move {
|
futs.push(async move {
|
||||||
self.dht.routing_table.write().mark_outgoing_request(&id);
|
self.dht.routing_table.write().mark_outgoing_request(&id);
|
||||||
match self.dht.request(Request::Ping, addr).await {
|
match self.dht.request(Request::Ping, addr).await {
|
||||||
|
|
@ -944,7 +956,6 @@ impl DhtWorker {
|
||||||
async fn start(
|
async fn start(
|
||||||
self,
|
self,
|
||||||
in_rx: UnboundedReceiver<WorkerSendRequest>,
|
in_rx: UnboundedReceiver<WorkerSendRequest>,
|
||||||
ping_rx: UnboundedReceiver<(Id20, SocketAddr)>,
|
|
||||||
bootstrap_addrs: &[String],
|
bootstrap_addrs: &[String],
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let (out_tx, mut out_rx) = channel(1);
|
let (out_tx, mut out_rx) = channel(1);
|
||||||
|
|
@ -970,8 +981,10 @@ impl DhtWorker {
|
||||||
}
|
}
|
||||||
.instrument(debug_span!("dht_responese_reader"));
|
.instrument(debug_span!("dht_responese_reader"));
|
||||||
|
|
||||||
let pinger = self.pinger(ping_rx);
|
let pinger = self.pinger().instrument(error_span!("pinger"));
|
||||||
let bucket_refresher = self.bucket_refresher();
|
let bucket_refresher = self
|
||||||
|
.bucket_refresher()
|
||||||
|
.instrument(error_span!("bucket_refresher"));
|
||||||
|
|
||||||
tokio::pin!(framer);
|
tokio::pin!(framer);
|
||||||
tokio::pin!(bootstrap);
|
tokio::pin!(bootstrap);
|
||||||
|
|
@ -1034,11 +1047,9 @@ impl DhtState {
|
||||||
.unwrap_or_else(|| crate::DHT_BOOTSTRAP.iter().map(|v| v.to_string()).collect());
|
.unwrap_or_else(|| crate::DHT_BOOTSTRAP.iter().map(|v| v.to_string()).collect());
|
||||||
|
|
||||||
let (in_tx, in_rx) = unbounded_channel();
|
let (in_tx, in_rx) = unbounded_channel();
|
||||||
let (ping_tx, ping_rx) = unbounded_channel();
|
|
||||||
let state = Arc::new(Self::new_internal(
|
let state = Arc::new(Self::new_internal(
|
||||||
peer_id,
|
peer_id,
|
||||||
in_tx,
|
in_tx,
|
||||||
ping_tx,
|
|
||||||
config.routing_table,
|
config.routing_table,
|
||||||
listen_addr,
|
listen_addr,
|
||||||
));
|
));
|
||||||
|
|
@ -1047,7 +1058,7 @@ impl DhtState {
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
async move {
|
async move {
|
||||||
let worker = DhtWorker { socket, dht: state };
|
let worker = DhtWorker { socket, dht: state };
|
||||||
worker.start(in_rx, ping_rx, &bootstrap_addrs).await?;
|
worker.start(in_rx, &bootstrap_addrs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -348,15 +348,9 @@ impl BucketTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node(
|
pub fn add_node(&mut self, self_id: &Id20, id: Id20, addr: SocketAddr) -> InsertResult {
|
||||||
&mut self,
|
|
||||||
self_id: &Id20,
|
|
||||||
id: Id20,
|
|
||||||
addr: SocketAddr,
|
|
||||||
on_questionable_node: impl FnMut(Id20, SocketAddr) -> bool,
|
|
||||||
) -> InsertResult {
|
|
||||||
let idx = self.get_leaf(&id);
|
let idx = self.get_leaf(&id);
|
||||||
self.insert_into_leaf(idx, self_id, id, addr, on_questionable_node)
|
self.insert_into_leaf(idx, self_id, id, addr)
|
||||||
}
|
}
|
||||||
fn insert_into_leaf(
|
fn insert_into_leaf(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -364,7 +358,6 @@ impl BucketTree {
|
||||||
self_id: &Id20,
|
self_id: &Id20,
|
||||||
id: Id20,
|
id: Id20,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
mut on_questionable_node: impl FnMut(Id20, SocketAddr) -> bool,
|
|
||||||
) -> InsertResult {
|
) -> InsertResult {
|
||||||
// The loop here is for this case:
|
// The loop here is for this case:
|
||||||
// in case we split a node into two, and it degenerates into all the leaves
|
// in case we split a node into two, and it degenerates into all the leaves
|
||||||
|
|
@ -399,17 +392,6 @@ impl BucketTree {
|
||||||
return InsertResult::Added;
|
return InsertResult::Added;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping first questionable node
|
|
||||||
if let Some(questionable_node) = nodes
|
|
||||||
.nodes
|
|
||||||
.iter_mut()
|
|
||||||
.find(|r| matches!(r.status(), NodeStatus::Questionable))
|
|
||||||
{
|
|
||||||
if on_questionable_node(questionable_node.id, questionable_node.addr) {
|
|
||||||
questionable_node.mark_outgoing_request();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try replace a bad node
|
// Try replace a bad node
|
||||||
if let Some(bad_node) = nodes
|
if let Some(bad_node) = nodes
|
||||||
.nodes
|
.nodes
|
||||||
|
|
@ -633,15 +615,12 @@ impl RoutingTable {
|
||||||
self.buckets.iter_leaves()
|
self.buckets.iter_leaves()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node(
|
pub fn iter(&self) -> impl Iterator<Item = &'_ RoutingTableNode> + '_ {
|
||||||
&mut self,
|
self.buckets.iter()
|
||||||
id: Id20,
|
}
|
||||||
addr: SocketAddr,
|
|
||||||
on_questionable_node: impl FnMut(Id20, SocketAddr) -> bool,
|
pub fn add_node(&mut self, id: Id20, addr: SocketAddr) -> InsertResult {
|
||||||
) -> InsertResult {
|
let res = self.buckets.add_node(&self.id, id, addr);
|
||||||
let res = self
|
|
||||||
.buckets
|
|
||||||
.add_node(&self.id, id, addr, on_questionable_node);
|
|
||||||
let replaced = match &res {
|
let replaced = match &res {
|
||||||
InsertResult::WasExisting => false,
|
InsertResult::WasExisting => false,
|
||||||
InsertResult::ReplacedBad(..) => true,
|
InsertResult::ReplacedBad(..) => true,
|
||||||
|
|
@ -782,7 +761,7 @@ mod tests {
|
||||||
for _ in 0..length.unwrap_or(16536) {
|
for _ in 0..length.unwrap_or(16536) {
|
||||||
let other_id = random_id_20();
|
let other_id = random_id_20();
|
||||||
let addr = generate_socket_addr();
|
let addr = generate_socket_addr();
|
||||||
rtable.add_node(other_id, addr, |_, _| false);
|
rtable.add_node(other_id, addr);
|
||||||
}
|
}
|
||||||
rtable
|
rtable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue