stats_accounting

This commit is contained in:
John Smith 2022-03-19 18:19:40 -04:00
parent babe176747
commit 3888a832a0
19 changed files with 285 additions and 67 deletions

3
.gitmodules vendored
View File

@ -25,3 +25,6 @@
[submodule "external/mdns"] [submodule "external/mdns"]
path = external/mdns path = external/mdns
url = ../mdns.git url = ../mdns.git
[submodule "external/hashlink"]
path = external/hashlink
url = ../hashlink.git

1
Cargo.lock generated
View File

@ -4201,6 +4201,7 @@ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.5",
"getrandom 0.2.5", "getrandom 0.2.5",
"hashbrown 0.12.0", "hashbrown 0.12.0",
"hashlink",
"hex", "hex",
"ifstructs", "ifstructs",
"jni", "jni",

1
external/hashlink vendored Submodule

@ -0,0 +1 @@
Subproject commit f5846ec3ff06865a204114bd710253e7e67e4498

View File

@ -26,6 +26,7 @@ generic-array = "^0"
secrecy = "^0" secrecy = "^0"
chacha20poly1305 = "^0" chacha20poly1305 = "^0"
uluru = "^3" uluru = "^3"
hashlink = "^0"
serde-big-array = "^0" serde-big-array = "^0"
futures-util = { version = "^0", default_features = false, features = ["alloc"] } futures-util = { version = "^0", default_features = false, features = ["alloc"] }
parking_lot = "^0" parking_lot = "^0"

View File

@ -4,8 +4,8 @@ use crate::network_connection::*;
use crate::network_manager::*; use crate::network_manager::*;
use crate::xx::*; use crate::xx::*;
use crate::*; use crate::*;
use futures_util::future::{select, Either};
use futures_util::stream::{FuturesUnordered, StreamExt}; use futures_util::stream::{FuturesUnordered, StreamExt};
use futures_util::{select, FutureExt};
const CONNECTION_PROCESSOR_CHANNEL_SIZE: usize = 128usize; const CONNECTION_PROCESSOR_CHANNEL_SIZE: usize = 128usize;
@ -162,14 +162,30 @@ impl ConnectionManager {
Box::pin(async move { Box::pin(async move {
// //
let descriptor = conn.connection_descriptor(); let descriptor = conn.connection_descriptor();
let inactivity_timeout = this
.network_manager()
.config()
.get()
.network
.connection_inactivity_timeout_ms;
loop { loop {
let res = conn.clone().recv().await; // process inactivity timeout on receives only
let message = match res { // if you want a keepalive, it has to be requested from the other side
let message = select! {
res = conn.recv().fuse() => {
match res {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
log_net!(error e); log_net!(error e);
break; break;
} }
}
}
_ = intf::sleep(inactivity_timeout).fuse()=> {
// timeout
log_net!("connection timeout on {:?}", descriptor);
break;
}
}; };
if let Err(e) = network_manager if let Err(e) = network_manager
.on_recv_envelope(message.as_slice(), descriptor) .on_recv_envelope(message.as_slice(), descriptor)
@ -201,8 +217,8 @@ impl ConnectionManager {
FuturesUnordered::new(); FuturesUnordered::new();
loop { loop {
// Either process an existing connection, or receive a new one to add to our list // Either process an existing connection, or receive a new one to add to our list
match select(connection_futures.next(), Box::pin(rx.recv_async())).await { select! {
Either::Left((x, _)) => { x = connection_futures.next().fuse() => {
// Processed some connection to completion, or there are none left // Processed some connection to completion, or there are none left
match x { match x {
Some(()) => { Some(()) => {
@ -222,7 +238,7 @@ impl ConnectionManager {
} }
} }
} }
Either::Right((x, _)) => { x = rx.recv_async().fuse() => {
// Got a new connection future // Got a new connection future
match x { match x {
Ok(v) => { Ok(v) => {

View File

@ -8,7 +8,6 @@ use core::convert::TryInto;
use curve25519_dalek as cd; use curve25519_dalek as cd;
use ed25519_dalek as ed; use ed25519_dalek as ed;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_big_array::*;
use uluru; use uluru;
use x25519_dalek as xd; use x25519_dalek as xd;
@ -18,11 +17,6 @@ pub type Nonce = [u8; 24];
const DH_CACHE_SIZE: usize = 1024; const DH_CACHE_SIZE: usize = 1024;
pub const ENCRYPTION_OVERHEAD: usize = 16; pub const ENCRYPTION_OVERHEAD: usize = 16;
big_array! {
BigArray;
DH_CACHE_SIZE
}
type DHCache = uluru::LRUCache<DHCacheEntry, DH_CACHE_SIZE>; type DHCache = uluru::LRUCache<DHCacheEntry, DH_CACHE_SIZE>;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]

View File

@ -55,16 +55,21 @@ impl DummyNetworkConnection {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// Top-level protocol independent network connection object // Top-level protocol independent network connection object
#[derive(Debug)] #[derive(Debug, Clone)]
struct NetworkConnectionInner { pub struct NetworkConnectionStats {
last_message_sent_time: Option<u64>, last_message_sent_time: Option<u64>,
last_message_recv_time: Option<u64>, last_message_recv_time: Option<u64>,
established_time: u64,
}
#[derive(Debug)]
struct NetworkConnectionInner {
stats: NetworkConnectionStats,
} }
#[derive(Debug)] #[derive(Debug)]
struct NetworkConnectionArc { struct NetworkConnectionArc {
descriptor: ConnectionDescriptor, descriptor: ConnectionDescriptor,
established_time: u64,
protocol_connection: ProtocolNetworkConnection, protocol_connection: ProtocolNetworkConnection,
inner: Mutex<NetworkConnectionInner>, inner: Mutex<NetworkConnectionInner>,
} }
@ -84,8 +89,11 @@ impl Eq for NetworkConnection {}
impl NetworkConnection { impl NetworkConnection {
fn new_inner() -> NetworkConnectionInner { fn new_inner() -> NetworkConnectionInner {
NetworkConnectionInner { NetworkConnectionInner {
stats: NetworkConnectionStats {
last_message_sent_time: None, last_message_sent_time: None,
last_message_recv_time: None, last_message_recv_time: None,
established_time: intf::get_timestamp(),
},
} }
} }
fn new_arc( fn new_arc(
@ -94,7 +102,6 @@ impl NetworkConnection {
) -> NetworkConnectionArc { ) -> NetworkConnectionArc {
NetworkConnectionArc { NetworkConnectionArc {
descriptor, descriptor,
established_time: intf::get_timestamp(),
protocol_connection, protocol_connection,
inner: Mutex::new(Self::new_inner()), inner: Mutex::new(Self::new_inner()),
} }
@ -136,7 +143,7 @@ impl NetworkConnection {
let out = self.arc.protocol_connection.send(message).await; let out = self.arc.protocol_connection.send(message).await;
if out.is_ok() { if out.is_ok() {
let mut inner = self.arc.inner.lock(); let mut inner = self.arc.inner.lock();
inner.last_message_sent_time.max_assign(Some(ts)); inner.stats.last_message_sent_time.max_assign(Some(ts));
} }
out out
} }
@ -145,8 +152,13 @@ impl NetworkConnection {
let out = self.arc.protocol_connection.recv().await; let out = self.arc.protocol_connection.recv().await;
if out.is_ok() { if out.is_ok() {
let mut inner = self.arc.inner.lock(); let mut inner = self.arc.inner.lock();
inner.last_message_recv_time.max_assign(Some(ts)); inner.stats.last_message_recv_time.max_assign(Some(ts));
} }
out out
} }
pub fn stats(&self) -> NetworkConnectionStats {
let inner = self.arc.inner.lock();
inner.stats.clone()
}
} }

View File

@ -11,6 +11,8 @@ use xx::*;
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
pub const MAX_MESSAGE_SIZE: usize = MAX_ENVELOPE_SIZE; pub const MAX_MESSAGE_SIZE: usize = MAX_ENVELOPE_SIZE;
pub const IPADDR_TABLE_SIZE: usize = 1024;
pub const IPADDR_MAX_INACTIVE_DURATION_US: u64 = 300_000_000u64; // 5 minutes
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum NetworkClass { pub enum NetworkClass {
@ -79,11 +81,33 @@ struct NetworkComponents {
receipt_manager: ReceiptManager, receipt_manager: ReceiptManager,
} }
// Statistics per address
#[derive(Clone, Default)]
pub struct PerAddressStats {
last_seen_ts: u64,
transfer_stats_accounting: TransferStatsAccounting,
transfer_stats: TransferStatsDownUp,
}
// Statistics about the low-level network
#[derive(Clone, Default)]
pub struct NetworkManagerStats {
self_stats: PerAddressStats,
per_address_stats: HashMap<IpAddr, PerAddressStats>,
recent_addresses: VecDeque<IpAddr>,
}
// The mutable state of the network manager // The mutable state of the network manager
pub struct NetworkManagerInner { struct NetworkManagerInner {
routing_table: Option<RoutingTable>, routing_table: Option<RoutingTable>,
components: Option<NetworkComponents>, components: Option<NetworkComponents>,
network_class: Option<NetworkClass>, network_class: Option<NetworkClass>,
stats: NetworkManagerStats,
}
struct NetworkManagerUnlockedInner {
// Background processes
rolling_transfers_task: TickTask,
} }
#[derive(Clone)] #[derive(Clone)]
@ -92,6 +116,7 @@ pub struct NetworkManager {
table_store: TableStore, table_store: TableStore,
crypto: Crypto, crypto: Crypto,
inner: Arc<Mutex<NetworkManagerInner>>, inner: Arc<Mutex<NetworkManagerInner>>,
unlocked_inner: Arc<NetworkManagerUnlockedInner>,
} }
impl NetworkManager { impl NetworkManager {
@ -100,16 +125,34 @@ impl NetworkManager {
routing_table: None, routing_table: None,
components: None, components: None,
network_class: None, network_class: None,
stats: NetworkManagerStats::default(),
}
}
fn new_unlocked_inner(_config: VeilidConfig) -> NetworkManagerUnlockedInner {
//let c = config.get();
NetworkManagerUnlockedInner {
rolling_transfers_task: TickTask::new(ROLLING_TRANSFERS_INTERVAL_SECS),
} }
} }
pub fn new(config: VeilidConfig, table_store: TableStore, crypto: Crypto) -> Self { pub fn new(config: VeilidConfig, table_store: TableStore, crypto: Crypto) -> Self {
Self { let this = Self {
config, config: config.clone(),
table_store, table_store,
crypto, crypto,
inner: Arc::new(Mutex::new(Self::new_inner())), inner: Arc::new(Mutex::new(Self::new_inner())),
unlocked_inner: Arc::new(Self::new_unlocked_inner(config)),
};
// Set rolling transfers tick task
{
let this2 = this.clone();
this.unlocked_inner
.rolling_transfers_task
.set_routine(move |l, t| {
Box::pin(this2.clone().rolling_transfers_task_routine(l, t))
});
} }
this
} }
pub fn config(&self) -> VeilidConfig { pub fn config(&self) -> VeilidConfig {
self.config.clone() self.config.clone()
@ -546,4 +589,76 @@ impl NetworkManager {
// Inform caller that we dealt with the envelope locally // Inform caller that we dealt with the envelope locally
Ok(true) Ok(true)
} }
// Compute transfer statistics for the low level network
async fn rolling_transfers_task_routine(self, last_ts: u64, cur_ts: u64) -> Result<(), String> {
log_net!("--- network manager rolling_transfers task");
let inner = &mut *self.inner.lock();
// Roll the low level network transfer stats for our address
inner
.stats
.self_stats
.transfer_stats_accounting
.roll_transfers(last_ts, cur_ts, &mut inner.stats.self_stats.transfer_stats);
// Roll all per-address transfers
let mut dead_addrs: HashSet<IpAddr> = HashSet::new();
for (addr, stats) in &mut inner.stats.per_address_stats {
stats.transfer_stats_accounting.roll_transfers(
last_ts,
cur_ts,
&mut stats.transfer_stats,
);
// While we're here, lets see if this address has timed out
if cur_ts - stats.last_seen_ts >= IPADDR_MAX_INACTIVE_DURATION_US {
// it's dead, put it in the dead list
dead_addrs.insert(*addr);
}
}
// Remove the dead addresses from our tables
for da in &dead_addrs {
inner.stats.per_address_stats.remove(da);
}
inner
.stats
.recent_addresses
.retain(|a| !dead_addrs.contains(a));
Ok(())
}
// Callbacks from low level network for statistics gathering
fn packet_sent(&self, addr: IpAddr, bytes: u64) {
let inner = &mut *self.inner.lock();
inner
.stats
.self_stats
.transfer_stats_accounting
.add_up(bytes);
inner
.stats
.per_address_stats
.entry(addr)
.or_default()
.transfer_stats_accounting
.add_up(bytes);
}
fn packet_rcvd(&self, addr: IpAddr, bytes: u64) {
let inner = &mut *self.inner.lock();
inner
.stats
.self_stats
.transfer_stats_accounting
.add_down(bytes);
inner
.stats
.per_address_stats
.entry(addr)
.or_default()
.transfer_stats_accounting
.add_down(bytes);
}
} }

View File

@ -32,7 +32,8 @@ pub struct BucketEntry {
min_max_version: Option<(u8, u8)>, min_max_version: Option<(u8, u8)>,
last_connection: Option<(ConnectionDescriptor, u64)>, last_connection: Option<(ConnectionDescriptor, u64)>,
dial_infos: Vec<DialInfo>, dial_infos: Vec<DialInfo>,
stats_accounting: StatsAccounting, latency_stats_accounting: LatencyStatsAccounting,
transfer_stats_accounting: TransferStatsAccounting,
peer_stats: PeerStats, peer_stats: PeerStats,
} }
@ -44,7 +45,8 @@ impl BucketEntry {
min_max_version: None, min_max_version: None,
last_connection: None, last_connection: None,
dial_infos: Vec::new(), dial_infos: Vec::new(),
stats_accounting: StatsAccounting::new(), latency_stats_accounting: LatencyStatsAccounting::new(),
transfer_stats_accounting: TransferStatsAccounting::new(),
peer_stats: PeerStats { peer_stats: PeerStats {
time_added: now, time_added: now,
last_seen: None, last_seen: None,
@ -133,13 +135,16 @@ impl BucketEntry {
///// stats methods ///// stats methods
// called every ROLLING_TRANSFERS_INTERVAL_SECS seconds // called every ROLLING_TRANSFERS_INTERVAL_SECS seconds
pub(super) fn roll_transfers(&mut self, last_ts: u64, cur_ts: u64) { pub(super) fn roll_transfers(&mut self, last_ts: u64, cur_ts: u64) {
self.stats_accounting self.transfer_stats_accounting.roll_transfers(
.roll_transfers(last_ts, cur_ts, &mut self.peer_stats.transfer); last_ts,
cur_ts,
&mut self.peer_stats.transfer,
);
} }
// Called for every round trip packet we receive // Called for every round trip packet we receive
fn record_latency(&mut self, latency: u64) { fn record_latency(&mut self, latency: u64) {
self.peer_stats.latency = Some(self.stats_accounting.record_latency(latency)); self.peer_stats.latency = Some(self.latency_stats_accounting.record_latency(latency));
} }
///// state machine handling ///// state machine handling
@ -255,7 +260,7 @@ impl BucketEntry {
pub(super) fn ping_sent(&mut self, ts: u64, bytes: u64) { pub(super) fn ping_sent(&mut self, ts: u64, bytes: u64) {
self.peer_stats.ping_stats.total_sent += 1; self.peer_stats.ping_stats.total_sent += 1;
self.stats_accounting.add_up(bytes); self.transfer_stats_accounting.add_up(bytes);
self.peer_stats.ping_stats.in_flight += 1; self.peer_stats.ping_stats.in_flight += 1;
self.peer_stats.ping_stats.last_pinged = Some(ts); self.peer_stats.ping_stats.last_pinged = Some(ts);
// if we haven't heard from this node yet and it's our first attempt at contacting it // if we haven't heard from this node yet and it's our first attempt at contacting it
@ -265,14 +270,14 @@ impl BucketEntry {
} }
} }
pub(super) fn ping_rcvd(&mut self, ts: u64, bytes: u64) { pub(super) fn ping_rcvd(&mut self, ts: u64, bytes: u64) {
self.stats_accounting.add_down(bytes); self.transfer_stats_accounting.add_down(bytes);
self.touch_last_seen(ts); self.touch_last_seen(ts);
} }
pub(super) fn pong_sent(&mut self, _ts: u64, bytes: u64) { pub(super) fn pong_sent(&mut self, _ts: u64, bytes: u64) {
self.stats_accounting.add_up(bytes); self.transfer_stats_accounting.add_up(bytes);
} }
pub(super) fn pong_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) { pub(super) fn pong_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) {
self.stats_accounting.add_down(bytes); self.transfer_stats_accounting.add_down(bytes);
self.peer_stats.ping_stats.in_flight -= 1; self.peer_stats.ping_stats.in_flight -= 1;
self.peer_stats.ping_stats.total_returned += 1; self.peer_stats.ping_stats.total_returned += 1;
self.peer_stats.ping_stats.consecutive_pongs += 1; self.peer_stats.ping_stats.consecutive_pongs += 1;
@ -294,7 +299,7 @@ impl BucketEntry {
self.peer_stats.ping_stats.first_consecutive_pong_time = None; self.peer_stats.ping_stats.first_consecutive_pong_time = None;
} }
pub(super) fn question_sent(&mut self, ts: u64, bytes: u64) { pub(super) fn question_sent(&mut self, ts: u64, bytes: u64) {
self.stats_accounting.add_up(bytes); self.transfer_stats_accounting.add_up(bytes);
// if we haven't heard from this node yet and it's our first attempt at contacting it // if we haven't heard from this node yet and it's our first attempt at contacting it
// then we set the last_seen time // then we set the last_seen time
if self.peer_stats.last_seen.is_none() { if self.peer_stats.last_seen.is_none() {
@ -302,14 +307,14 @@ impl BucketEntry {
} }
} }
pub(super) fn question_rcvd(&mut self, ts: u64, bytes: u64) { pub(super) fn question_rcvd(&mut self, ts: u64, bytes: u64) {
self.stats_accounting.add_down(bytes); self.transfer_stats_accounting.add_down(bytes);
self.touch_last_seen(ts); self.touch_last_seen(ts);
} }
pub(super) fn answer_sent(&mut self, _ts: u64, bytes: u64) { pub(super) fn answer_sent(&mut self, _ts: u64, bytes: u64) {
self.stats_accounting.add_up(bytes); self.transfer_stats_accounting.add_up(bytes);
} }
pub(super) fn answer_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) { pub(super) fn answer_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) {
self.stats_accounting.add_down(bytes); self.transfer_stats_accounting.add_down(bytes);
self.record_latency(recv_ts - send_ts); self.record_latency(recv_ts - send_ts);
self.touch_last_seen(recv_ts); self.touch_last_seen(recv_ts);
} }

View File

@ -7,8 +7,14 @@ impl RoutingTable {
out += "Routing Table Info:\n"; out += "Routing Table Info:\n";
out += &format!(" Node Id: {}\n", inner.node_id.encode()); out += &format!(" Node Id: {}\n", inner.node_id.encode());
out += &format!(" Stats Accounting: {:#?}\n\n", inner.stats_accounting); out += &format!(
out += &format!(" Transfer Stats: {:#?}\n\n", inner.transfer_stats); " Self Transfer Stats Accounting: {:#?}\n\n",
inner.self_transfer_stats_accounting
);
out += &format!(
" Self Transfer Stats: {:#?}\n\n",
inner.self_transfer_stats
);
out out
} }

View File

@ -50,12 +50,14 @@ struct RoutingTableInner {
buckets: Vec<Bucket>, buckets: Vec<Bucket>,
dial_info_details: Vec<DialInfoDetail>, dial_info_details: Vec<DialInfoDetail>,
bucket_entry_count: usize, bucket_entry_count: usize,
// Waiters // Waiters
eventual_changed_dial_info: Eventual, eventual_changed_dial_info: Eventual,
// Transfer stats for this node // Transfer stats for this node
stats_accounting: StatsAccounting, self_latency_stats_accounting: LatencyStatsAccounting,
// latency: Option<LatencyStats>, self_transfer_stats_accounting: TransferStatsAccounting,
transfer_stats: TransferStatsDownUp, self_transfer_stats: TransferStatsDownUp,
} }
struct RoutingTableUnlockedInner { struct RoutingTableUnlockedInner {
@ -83,8 +85,9 @@ impl RoutingTable {
dial_info_details: Vec::new(), dial_info_details: Vec::new(),
bucket_entry_count: 0, bucket_entry_count: 0,
eventual_changed_dial_info: Eventual::new(), eventual_changed_dial_info: Eventual::new(),
stats_accounting: StatsAccounting::new(), self_latency_stats_accounting: LatencyStatsAccounting::new(),
transfer_stats: TransferStatsDownUp::default(), self_transfer_stats_accounting: TransferStatsAccounting::new(),
self_transfer_stats: TransferStatsDownUp::default(),
} }
} }
fn new_unlocked_inner(config: VeilidConfig) -> RoutingTableUnlockedInner { fn new_unlocked_inner(config: VeilidConfig) -> RoutingTableUnlockedInner {
@ -609,9 +612,11 @@ impl RoutingTable {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
// Roll our own node's transfers // Roll our own node's transfers
inner inner.self_transfer_stats_accounting.roll_transfers(
.stats_accounting last_ts,
.roll_transfers(last_ts, cur_ts, &mut inner.transfer_stats); cur_ts,
&mut inner.self_transfer_stats,
);
// Roll all bucket entry transfers // Roll all bucket entry transfers
for b in &mut inner.buckets { for b in &mut inner.buckets {
@ -649,25 +654,37 @@ impl RoutingTable {
// Stats Accounting // Stats Accounting
pub fn ping_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn ping_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_up(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_up(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.ping_sent(ts, bytes); e.ping_sent(ts, bytes);
}) })
} }
pub fn ping_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn ping_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_down(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_down(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.ping_rcvd(ts, bytes); e.ping_rcvd(ts, bytes);
}) })
} }
pub fn pong_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn pong_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_up(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_up(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.pong_sent(ts, bytes); e.pong_sent(ts, bytes);
}) })
} }
pub fn pong_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) { pub fn pong_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_down(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_down(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.pong_rcvd(send_ts, recv_ts, bytes); e.pong_rcvd(send_ts, recv_ts, bytes);
}) })
@ -678,25 +695,37 @@ impl RoutingTable {
}) })
} }
pub fn question_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn question_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_up(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_up(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.question_sent(ts, bytes); e.question_sent(ts, bytes);
}) })
} }
pub fn question_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn question_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_down(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_down(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.question_rcvd(ts, bytes); e.question_rcvd(ts, bytes);
}) })
} }
pub fn answer_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { pub fn answer_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_up(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_up(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.answer_sent(ts, bytes); e.answer_sent(ts, bytes);
}) })
} }
pub fn answer_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) { pub fn answer_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) {
self.inner.lock().stats_accounting.add_down(bytes); self.inner
.lock()
.self_transfer_stats_accounting
.add_down(bytes);
node_ref.operate(|e| { node_ref.operate(|e| {
e.answer_rcvd(send_ts, recv_ts, bytes); e.answer_rcvd(send_ts, recv_ts, bytes);
}) })

View File

@ -19,16 +19,14 @@ pub struct TransferCount {
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct StatsAccounting { pub struct TransferStatsAccounting {
rolling_latencies: VecDeque<u64>,
rolling_transfers: VecDeque<TransferCount>, rolling_transfers: VecDeque<TransferCount>,
current_transfer: TransferCount, current_transfer: TransferCount,
} }
impl StatsAccounting { impl TransferStatsAccounting {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
rolling_latencies: VecDeque::new(),
rolling_transfers: VecDeque::new(), rolling_transfers: VecDeque::new(),
current_transfer: TransferCount::default(), current_transfer: TransferCount::default(),
} }
@ -79,6 +77,19 @@ impl StatsAccounting {
transfer_stats.down.average /= len; transfer_stats.down.average /= len;
transfer_stats.up.average /= len; transfer_stats.up.average /= len;
} }
}
#[derive(Debug, Clone, Default)]
pub struct LatencyStatsAccounting {
rolling_latencies: VecDeque<u64>,
}
impl LatencyStatsAccounting {
pub fn new() -> Self {
Self {
rolling_latencies: VecDeque::new(),
}
}
pub fn record_latency(&mut self, latency: u64) -> veilid_api::LatencyStats { pub fn record_latency(&mut self, latency: u64) -> veilid_api::LatencyStats {
while self.rolling_latencies.len() >= ROLLING_LATENCIES_SIZE { while self.rolling_latencies.len() >= ROLLING_LATENCIES_SIZE {

View File

@ -187,6 +187,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
"protected_store.delete" => Ok(Box::new(false)), "protected_store.delete" => Ok(Box::new(false)),
"network.max_connections" => Ok(Box::new(16u32)), "network.max_connections" => Ok(Box::new(16u32)),
"network.connection_initial_timeout_ms" => Ok(Box::new(2_000u32)), "network.connection_initial_timeout_ms" => Ok(Box::new(2_000u32)),
"network.connection_inactivity_timeout_ms" => Ok(Box::new(60_000u32)),
"network.node_id" => Ok(Box::new(dht::key::DHTKey::default())), "network.node_id" => Ok(Box::new(dht::key::DHTKey::default())),
"network.node_id_secret" => Ok(Box::new(dht::key::DHTKeySecret::default())), "network.node_id_secret" => Ok(Box::new(dht::key::DHTKeySecret::default())),
"network.bootstrap" => Ok(Box::new(Vec::<String>::new())), "network.bootstrap" => Ok(Box::new(Vec::<String>::new())),
@ -291,6 +292,7 @@ pub async fn test_config() {
assert_eq!(inner.protected_store.delete, false); assert_eq!(inner.protected_store.delete, false);
assert_eq!(inner.network.max_connections, 16); assert_eq!(inner.network.max_connections, 16);
assert_eq!(inner.network.connection_initial_timeout_ms, 2_000u32); assert_eq!(inner.network.connection_initial_timeout_ms, 2_000u32);
assert_eq!(inner.network.connection_inactivity_timeout_ms, 60_000u32);
assert!(!inner.network.node_id.valid); assert!(!inner.network.node_id.valid);
assert!(!inner.network.node_id_secret.valid); assert!(!inner.network.node_id_secret.valid);
assert_eq!(inner.network.bootstrap, Vec::<String>::new()); assert_eq!(inner.network.bootstrap, Vec::<String>::new());

View File

@ -880,12 +880,6 @@ pub struct LatencyStats {
pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies
} }
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStatsDownUp {
pub down: TransferStats,
pub up: TransferStats,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStats { pub struct TransferStats {
pub total: u64, // total amount transferred ever pub total: u64, // total amount transferred ever
@ -894,6 +888,12 @@ pub struct TransferStats {
pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts
} }
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStatsDownUp {
pub down: TransferStats,
pub up: TransferStats,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PingStats { pub struct PingStats {
pub in_flight: u32, // number of pings issued that have yet to be answered pub in_flight: u32, // number of pings issued that have yet to be answered

View File

@ -128,6 +128,7 @@ pub struct VeilidConfigLeases {
pub struct VeilidConfigNetwork { pub struct VeilidConfigNetwork {
pub max_connections: u32, pub max_connections: u32,
pub connection_initial_timeout_ms: u32, pub connection_initial_timeout_ms: u32,
pub connection_inactivity_timeout_ms: u32,
pub node_id: key::DHTKey, pub node_id: key::DHTKey,
pub node_id_secret: key::DHTKeySecret, pub node_id_secret: key::DHTKeySecret,
pub bootstrap: Vec<String>, pub bootstrap: Vec<String>,
@ -282,6 +283,7 @@ impl VeilidConfig {
get_config!(inner.network.node_id_secret); get_config!(inner.network.node_id_secret);
get_config!(inner.network.max_connections); get_config!(inner.network.max_connections);
get_config!(inner.network.connection_initial_timeout_ms); get_config!(inner.network.connection_initial_timeout_ms);
get_config!(inner.network.connection_inactivity_timeout_ms);
get_config!(inner.network.bootstrap); get_config!(inner.network.bootstrap);
get_config!(inner.network.dht.resolve_node_timeout_ms); get_config!(inner.network.dht.resolve_node_timeout_ms);
get_config!(inner.network.dht.resolve_node_count); get_config!(inner.network.dht.resolve_node_count);

View File

@ -31,8 +31,12 @@ cfg_if! {
if #[cfg(target_arch = "wasm32")] { if #[cfg(target_arch = "wasm32")] {
pub use alloc::string::String; pub use alloc::string::String;
pub use alloc::vec::Vec; pub use alloc::vec::Vec;
pub use alloc::collections::LinkedList;
pub use alloc::collections::VecDeque;
pub use alloc::collections::btree_map::BTreeMap; pub use alloc::collections::btree_map::BTreeMap;
pub use alloc::collections::btree_set::BTreeSet; pub use alloc::collections::btree_set::BTreeSet;
pub use hashbrown::hash_map::HashMap;
pub use hashbrown::hash_set::HashSet;
pub use alloc::boxed::Box; pub use alloc::boxed::Box;
pub use alloc::borrow::{Cow, ToOwned}; pub use alloc::borrow::{Cow, ToOwned};
pub use wasm_bindgen::prelude::*; pub use wasm_bindgen::prelude::*;
@ -54,8 +58,12 @@ cfg_if! {
} else { } else {
pub use std::string::String; pub use std::string::String;
pub use std::vec::Vec; pub use std::vec::Vec;
pub use std::collections::LinkedList;
pub use std::collections::VecDeque;
pub use std::collections::btree_map::BTreeMap; pub use std::collections::btree_map::BTreeMap;
pub use std::collections::btree_set::BTreeSet; pub use std::collections::btree_set::BTreeSet;
pub use std::collections::hash_map::HashMap;
pub use std::collections::hash_set::HashSet;
pub use std::boxed::Box; pub use std::boxed::Box;
pub use std::borrow::{Cow, ToOwned}; pub use std::borrow::{Cow, ToOwned};
pub use std::cmp; pub use std::cmp;

View File

@ -40,6 +40,7 @@ Future<VeilidConfig> getDefaultVeilidConfig() async {
network: VeilidConfigNetwork( network: VeilidConfigNetwork(
maxConnections: 16, maxConnections: 16,
connectionInitialTimeoutMs: 2000, connectionInitialTimeoutMs: 2000,
connectionInactivityTimeoutMs: 60000,
nodeId: "", nodeId: "",
nodeIdSecret: "", nodeIdSecret: "",
bootstrap: [], bootstrap: [],

View File

@ -516,6 +516,7 @@ class VeilidConfigLeases {
class VeilidConfigNetwork { class VeilidConfigNetwork {
int maxConnections; int maxConnections;
int connectionInitialTimeoutMs; int connectionInitialTimeoutMs;
int connectionInactivityTimeoutMs;
String nodeId; String nodeId;
String nodeIdSecret; String nodeIdSecret;
List<String> bootstrap; List<String> bootstrap;
@ -533,6 +534,7 @@ class VeilidConfigNetwork {
VeilidConfigNetwork({ VeilidConfigNetwork({
required this.maxConnections, required this.maxConnections,
required this.connectionInitialTimeoutMs, required this.connectionInitialTimeoutMs,
required this.connectionInactivityTimeoutMs,
required this.nodeId, required this.nodeId,
required this.nodeIdSecret, required this.nodeIdSecret,
required this.bootstrap, required this.bootstrap,
@ -552,6 +554,7 @@ class VeilidConfigNetwork {
return { return {
'max_connections': maxConnections, 'max_connections': maxConnections,
'connection_initial_timeout_ms': connectionInitialTimeoutMs, 'connection_initial_timeout_ms': connectionInitialTimeoutMs,
'connection_inactivity_timeout_ms': connectionInactivityTimeoutMs,
'node_id': nodeId, 'node_id': nodeId,
'node_id_secret': nodeIdSecret, 'node_id_secret': nodeIdSecret,
'bootstrap': bootstrap, 'bootstrap': bootstrap,
@ -571,6 +574,8 @@ class VeilidConfigNetwork {
VeilidConfigNetwork.fromJson(Map<String, dynamic> json) VeilidConfigNetwork.fromJson(Map<String, dynamic> json)
: maxConnections = json['max_connections'], : maxConnections = json['max_connections'],
connectionInitialTimeoutMs = json['connection_initial_timeout_ms'], connectionInitialTimeoutMs = json['connection_initial_timeout_ms'],
connectionInactivityTimeoutMs =
json['connection_inactivity_timeout_ms'],
nodeId = json['node_id'], nodeId = json['node_id'],
nodeIdSecret = json['node_id_secret'], nodeIdSecret = json['node_id_secret'],
bootstrap = json['bootstrap'], bootstrap = json['bootstrap'],

View File

@ -50,6 +50,7 @@ core:
network: network:
max_connections: 16 max_connections: 16
connection_initial_timeout_ms: 2000 connection_initial_timeout_ms: 2000
connection_inactivity_timeout_ms: 60000
node_id: '' node_id: ''
node_id_secret: '' node_id_secret: ''
bootstrap: [] bootstrap: []
@ -523,6 +524,7 @@ pub struct Leases {
pub struct Network { pub struct Network {
pub max_connections: u32, pub max_connections: u32,
pub connection_initial_timeout_ms: u32, pub connection_initial_timeout_ms: u32,
pub connection_inactivity_timeout_ms: u32,
pub node_id: veilid_core::DHTKey, pub node_id: veilid_core::DHTKey,
pub node_id_secret: veilid_core::DHTKeySecret, pub node_id_secret: veilid_core::DHTKeySecret,
pub bootstrap: Vec<ParsedNodeDialInfo>, pub bootstrap: Vec<ParsedNodeDialInfo>,
@ -794,6 +796,9 @@ impl Settings {
"network.connection_initial_timeout_ms" => { "network.connection_initial_timeout_ms" => {
Ok(Box::new(inner.core.network.connection_initial_timeout_ms)) Ok(Box::new(inner.core.network.connection_initial_timeout_ms))
} }
"network.connection_inactivity_timeout_ms" => Ok(Box::new(
inner.core.network.connection_inactivity_timeout_ms,
)),
"network.node_id" => Ok(Box::new(inner.core.network.node_id)), "network.node_id" => Ok(Box::new(inner.core.network.node_id)),
"network.node_id_secret" => Ok(Box::new(inner.core.network.node_id_secret)), "network.node_id_secret" => Ok(Box::new(inner.core.network.node_id_secret)),
"network.bootstrap" => Ok(Box::new( "network.bootstrap" => Ok(Box::new(
@ -1131,6 +1136,7 @@ mod tests {
assert_eq!(s.core.network.max_connections, 16); assert_eq!(s.core.network.max_connections, 16);
assert_eq!(s.core.network.connection_initial_timeout_ms, 2_000u32); assert_eq!(s.core.network.connection_initial_timeout_ms, 2_000u32);
assert_eq!(s.core.network.connection_inactivity_timeout_ms, 60_000u32);
assert_eq!(s.core.network.node_id, veilid_core::DHTKey::default()); assert_eq!(s.core.network.node_id, veilid_core::DHTKey::default());
assert_eq!( assert_eq!(
s.core.network.node_id_secret, s.core.network.node_id_secret,