mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fixing the DEADLOCK in handshake -> channel creation
- this bug was initially called imbris bug, as it happened on his runners and i couldn't reproduce it locally at fist :) - When in a Handshake a seperate mpsc::Channel was created for (Cid, Frame) transport however the protocol could already catch non handshake data any more and push in into this mpsc::Channel. Then this channel got dropped and a fresh one was created for the network::Channel. These droped Frames are ofc a BUG! I tried multiple things to solve this: - dont create a new mpsc::Channel, but instead bind it to the Protocol itself and always use 1. This would work theoretically, but in bParticipant side we are using 1 mpsc::Channel<(Cid, Frame)> to handle ALL the network::channel. If now ever Protocol would have it's own, and with that every network::Channel had it's own it would no longer work out Bad Idea... - using the first method but creating the mpsc::Channel inside the scheduler instead protocol neither works, as the scheduler doesnt know the remote_pid yet - i dont want a hack to say the protocol only listen to 2 messages and then stop no matter what So i switched over to the simply method now: - Do everything like before with 2 mpsc::Channels - after the handshake. close the receiver and listen for all remaining (cid, frame) combinations - when starting the channel, reapply them to the new sender/listener combination - added tracing - switched Protocol RwLock to Mutex, as it's only ever 1 - Additionally changed the layout and introduces the c2w_frame_s and w2s_cid_frame_s name schema - Fixed a bug in scheduler which WOULD cause a DEADLOCK if handshake would fail - fixd a but in api_send_send_main, i need to store the stream_p otherwise it's immeadiatly closed and a stream_a.send() isn't guaranteed - add extra test to verify that a send message is received even if the Stream is already closed - changed OutGoing to Outgoing - fixed a bug that `metrics.tick()` was never called - removed 2 unused nightly features and added `deny_code`
This commit is contained in:
parent
2a7c5807ff
commit
3324c08640
@ -21,7 +21,7 @@ enum Msg {
|
||||
Pong(u64),
|
||||
}
|
||||
|
||||
/// This utility checks if async functionatily of veloren-network works
|
||||
/// This utility checks if async functionality of veloren-network works
|
||||
/// correctly and outputs it at the end
|
||||
fn main() {
|
||||
let matches = App::new("Veloren Async Prove Utility")
|
||||
|
@ -3,7 +3,7 @@
|
||||
//!
|
||||
//! (cd network/examples/async_recv && RUST_BACKTRACE=1 cargo run)
|
||||
use crate::{
|
||||
message::{self, InCommingMessage, MessageBuffer, OutGoingMessage},
|
||||
message::{self, IncomingMessage, MessageBuffer, OutgoingMessage},
|
||||
scheduler::Scheduler,
|
||||
types::{Mid, Pid, Prio, Promises, Sid},
|
||||
};
|
||||
@ -76,8 +76,8 @@ pub struct Stream {
|
||||
mid: Mid,
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
a2b_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
b2a_msg_recv_r: mpsc::UnboundedReceiver<InCommingMessage>,
|
||||
a2b_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
b2a_msg_recv_r: mpsc::UnboundedReceiver<IncomingMessage>,
|
||||
closed: Arc<AtomicBool>,
|
||||
a2b_close_stream_s: Option<mpsc::UnboundedSender<Sid>>,
|
||||
}
|
||||
@ -586,8 +586,8 @@ impl Stream {
|
||||
sid: Sid,
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
a2b_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
b2a_msg_recv_r: mpsc::UnboundedReceiver<InCommingMessage>,
|
||||
a2b_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
b2a_msg_recv_r: mpsc::UnboundedReceiver<IncomingMessage>,
|
||||
closed: Arc<AtomicBool>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
) -> Self {
|
||||
@ -629,56 +629,27 @@ impl Stream {
|
||||
/// are also dropped.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use veloren_network::{Network, Address, Pid};
|
||||
/// # use veloren_network::{PROMISES_ORDERED, PROMISES_CONSISTENCY};
|
||||
/// use uvth::ThreadPoolBuilder;
|
||||
/// use futures::executor::block_on;
|
||||
/// use tracing::*;
|
||||
/// use tracing_subscriber::EnvFilter;
|
||||
///
|
||||
/// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
///
|
||||
/// std::thread::spawn(|| {
|
||||
/// let filter = EnvFilter::from_default_env()
|
||||
/// .add_directive("trace".parse().unwrap())
|
||||
/// .add_directive("async_std::task::block_on=warn".parse().unwrap())
|
||||
/// .add_directive("veloren_network::tests=trace".parse().unwrap())
|
||||
/// .add_directive("veloren_network::controller=trace".parse().unwrap())
|
||||
/// .add_directive("veloren_network::channel=trace".parse().unwrap())
|
||||
/// .add_directive("veloren_network::message=trace".parse().unwrap())
|
||||
/// .add_directive("veloren_network::metrics=trace".parse().unwrap())
|
||||
/// .add_directive("veloren_network::types=trace".parse().unwrap());
|
||||
/// let _sub = tracing_subscriber::FmtSubscriber::builder()
|
||||
/// // all spans/events with a level higher than TRACE (e.g, info, warn, etc.)
|
||||
/// // will be written to stdout.
|
||||
/// .with_max_level(Level::TRACE)
|
||||
/// .with_env_filter(filter)
|
||||
/// // sets this to be the default, global subscriber for this application.
|
||||
/// .try_init();
|
||||
///
|
||||
/// // Create a Network, listen on Port `2200` and wait for a Stream to be opened, then answer `Hello World`
|
||||
/// let network = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
/// # let remote = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
/// block_on(async {
|
||||
/// network.listen(Address::Tcp("127.0.0.1:2200".parse().unwrap())).await.unwrap();
|
||||
/// # let remote_p = remote.connect(Address::Tcp("127.0.0.1:2200".parse().unwrap())).await.unwrap();
|
||||
/// # remote_p.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY).await.unwrap();
|
||||
/// let participant_a = network.connected().await.unwrap();
|
||||
/// let mut stream_a = participant_a.opened().await.unwrap();
|
||||
/// network.listen(Address::Tcp("127.0.0.1:2200".parse().unwrap())).await?;
|
||||
/// # let remote_p = remote.connect(Address::Tcp("127.0.0.1:2200".parse().unwrap())).await?;
|
||||
/// # // keep it alive
|
||||
/// # let _stream_p = remote_p.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY).await?;
|
||||
/// let participant_a = network.connected().await?;
|
||||
/// let mut stream_a = participant_a.opened().await?;
|
||||
/// //Send Message
|
||||
/// stream_a.send("Hello World").unwrap();
|
||||
/// stream_a.send("Hello World")?;
|
||||
/// # Ok(())
|
||||
/// })
|
||||
/// });
|
||||
///
|
||||
/// std::thread::sleep(std::time::Duration::from_secs(70));
|
||||
/// println!("Sleep another 10s");
|
||||
/// std::thread::sleep(std::time::Duration::from_secs(10));
|
||||
/// println!("TRACING THE DEADLOCK");
|
||||
/// assert!(false);
|
||||
///
|
||||
/// std::thread::sleep(std::time::Duration::from_secs(150));
|
||||
/// Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
@ -740,7 +711,7 @@ impl Stream {
|
||||
return Err(StreamError::StreamClosed);
|
||||
}
|
||||
//debug!(?messagebuffer, "sending a message");
|
||||
self.a2b_msg_s.send((self.prio, self.sid, OutGoingMessage {
|
||||
self.a2b_msg_s.send((self.prio, self.sid, OutgoingMessage {
|
||||
buffer: messagebuffer,
|
||||
cursor: 0,
|
||||
mid: self.mid,
|
||||
@ -760,7 +731,7 @@ impl Stream {
|
||||
/// `Stream` got closed already.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use veloren_network::{Network, Address, Pid};
|
||||
/// # use veloren_network::{PROMISES_ORDERED, PROMISES_CONSISTENCY};
|
||||
/// use uvth::ThreadPoolBuilder;
|
||||
|
@ -18,26 +18,21 @@ use tracing::*;
|
||||
|
||||
pub(crate) struct Channel {
|
||||
cid: Cid,
|
||||
remote_pid: Pid,
|
||||
to_wire_receiver: Option<mpsc::UnboundedReceiver<Frame>>,
|
||||
c2w_frame_r: Option<mpsc::UnboundedReceiver<Frame>>,
|
||||
read_stop_receiver: Option<oneshot::Receiver<()>>,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn new(
|
||||
cid: u64,
|
||||
remote_pid: Pid,
|
||||
) -> (Self, mpsc::UnboundedSender<Frame>, oneshot::Sender<()>) {
|
||||
let (to_wire_sender, to_wire_receiver) = mpsc::unbounded::<Frame>();
|
||||
pub fn new(cid: u64) -> (Self, mpsc::UnboundedSender<Frame>, oneshot::Sender<()>) {
|
||||
let (c2w_frame_s, c2w_frame_r) = mpsc::unbounded::<Frame>();
|
||||
let (read_stop_sender, read_stop_receiver) = oneshot::channel();
|
||||
(
|
||||
Self {
|
||||
cid,
|
||||
remote_pid,
|
||||
to_wire_receiver: Some(to_wire_receiver),
|
||||
c2w_frame_r: Some(c2w_frame_r),
|
||||
read_stop_receiver: Some(read_stop_receiver),
|
||||
},
|
||||
to_wire_sender,
|
||||
c2w_frame_s,
|
||||
read_stop_sender,
|
||||
)
|
||||
}
|
||||
@ -45,28 +40,37 @@ impl Channel {
|
||||
pub async fn run(
|
||||
mut self,
|
||||
protocol: Protocols,
|
||||
from_wire_sender: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
mut w2c_cid_frame_s: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
mut leftover_cid_frame: Vec<(Cid, Frame)>,
|
||||
) {
|
||||
let to_wire_receiver = self.to_wire_receiver.take().unwrap();
|
||||
let c2w_frame_r = self.c2w_frame_r.take().unwrap();
|
||||
let read_stop_receiver = self.read_stop_receiver.take().unwrap();
|
||||
|
||||
trace!(?self.remote_pid, "start up channel");
|
||||
//reapply leftovers from handshake
|
||||
let cnt = leftover_cid_frame.len();
|
||||
trace!(?self.cid, ?cnt, "reapplying leftovers");
|
||||
for cid_frame in leftover_cid_frame.drain(..) {
|
||||
w2c_cid_frame_s.send(cid_frame).await.unwrap();
|
||||
}
|
||||
trace!(?self.cid, ?cnt, "all leftovers reapplied");
|
||||
|
||||
trace!(?self.cid, "start up channel");
|
||||
match protocol {
|
||||
Protocols::Tcp(tcp) => {
|
||||
futures::join!(
|
||||
tcp.read(self.cid, from_wire_sender, read_stop_receiver),
|
||||
tcp.write(self.cid, to_wire_receiver),
|
||||
tcp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
tcp.write_to_wire(self.cid, c2w_frame_r),
|
||||
);
|
||||
},
|
||||
Protocols::Udp(udp) => {
|
||||
futures::join!(
|
||||
udp.read(self.cid, from_wire_sender, read_stop_receiver),
|
||||
udp.write(self.cid, to_wire_receiver),
|
||||
udp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
udp.write_to_wire(self.cid, c2w_frame_r),
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
trace!(?self.remote_pid, "shut down channel");
|
||||
trace!(?self.cid, "shut down channel");
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,37 +110,55 @@ impl Handshake {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn setup(self, protocol: &Protocols) -> Result<(Pid, Sid, u128), ()> {
|
||||
let (to_wire_sender, to_wire_receiver) = mpsc::unbounded::<Frame>();
|
||||
let (from_wire_sender, from_wire_receiver) = mpsc::unbounded::<(Cid, Frame)>();
|
||||
let (read_stop_sender, read_stop_receiver) = oneshot::channel();
|
||||
pub async fn setup(
|
||||
self,
|
||||
protocol: &Protocols,
|
||||
) -> Result<(Pid, Sid, u128, Vec<(Cid, Frame)>), ()> {
|
||||
let (c2w_frame_s, c2w_frame_r) = mpsc::unbounded::<Frame>();
|
||||
let (mut w2c_cid_frame_s, mut w2c_cid_frame_r) = mpsc::unbounded::<(Cid, Frame)>();
|
||||
|
||||
let (read_stop_sender, read_stop_receiver) = oneshot::channel();
|
||||
let handler_future =
|
||||
self.frame_handler(from_wire_receiver, to_wire_sender, read_stop_sender);
|
||||
match protocol {
|
||||
self.frame_handler(&mut w2c_cid_frame_r, c2w_frame_s, read_stop_sender);
|
||||
let res = match protocol {
|
||||
Protocols::Tcp(tcp) => {
|
||||
(join! {
|
||||
tcp.read(self.cid, from_wire_sender, read_stop_receiver),
|
||||
tcp.write(self.cid, to_wire_receiver).fuse(),
|
||||
tcp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
tcp.write_to_wire(self.cid, c2w_frame_r).fuse(),
|
||||
handler_future,
|
||||
})
|
||||
.2
|
||||
},
|
||||
Protocols::Udp(udp) => {
|
||||
(join! {
|
||||
udp.read(self.cid, from_wire_sender, read_stop_receiver),
|
||||
udp.write(self.cid, to_wire_receiver),
|
||||
udp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
udp.write_to_wire(self.cid, c2w_frame_r),
|
||||
handler_future,
|
||||
})
|
||||
.2
|
||||
},
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(res) => {
|
||||
let mut leftover_frames = vec![];
|
||||
while let Ok(Some(cid_frame)) = w2c_cid_frame_r.try_next() {
|
||||
leftover_frames.push(cid_frame);
|
||||
}
|
||||
let cnt = leftover_frames.len();
|
||||
if cnt > 0 {
|
||||
debug!(?self.cid, ?cnt, "Some additional frames got already transfered, piping them to the bparticipant as leftover_frames");
|
||||
}
|
||||
Ok((res.0, res.1, res.2, leftover_frames))
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn frame_handler(
|
||||
&self,
|
||||
mut from_wire_receiver: mpsc::UnboundedReceiver<(Cid, Frame)>,
|
||||
mut to_wire_sender: mpsc::UnboundedSender<Frame>,
|
||||
w2c_cid_frame_r: &mut mpsc::UnboundedReceiver<(Cid, Frame)>,
|
||||
mut c2w_frame_s: mpsc::UnboundedSender<Frame>,
|
||||
_read_stop_sender: oneshot::Sender<()>,
|
||||
) -> Result<(Pid, Sid, u128), ()> {
|
||||
const ERR_S: &str = "Got A Raw Message, these are usually Debug Messages indicating that \
|
||||
@ -145,10 +167,10 @@ impl Handshake {
|
||||
let cid_string = self.cid.to_string();
|
||||
|
||||
if self.init_handshake {
|
||||
self.send_handshake(&mut to_wire_sender).await;
|
||||
self.send_handshake(&mut c2w_frame_s).await;
|
||||
}
|
||||
|
||||
match from_wire_receiver.next().await {
|
||||
match w2c_cid_frame_r.next().await {
|
||||
Some((
|
||||
_,
|
||||
Frame::Handshake {
|
||||
@ -170,11 +192,11 @@ impl Handshake {
|
||||
.with_label_values(&["", &cid_string, "Raw"])
|
||||
.inc();
|
||||
debug!("sending client instructions before killing");
|
||||
to_wire_sender
|
||||
c2w_frame_s
|
||||
.send(Frame::Raw(Self::WRONG_NUMBER.to_vec()))
|
||||
.await
|
||||
.unwrap();
|
||||
to_wire_sender.send(Frame::Shutdown).await.unwrap();
|
||||
c2w_frame_s.send(Frame::Shutdown).await.unwrap();
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
@ -187,7 +209,7 @@ impl Handshake {
|
||||
.frames_out_total
|
||||
.with_label_values(&["", &cid_string, "Raw"])
|
||||
.inc();
|
||||
to_wire_sender
|
||||
c2w_frame_s
|
||||
.send(Frame::Raw(
|
||||
format!(
|
||||
"{} Our Version: {:?}\nYour Version: {:?}\nClosing the \
|
||||
@ -201,15 +223,15 @@ impl Handshake {
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
to_wire_sender.send(Frame::Shutdown {}).await.unwrap();
|
||||
c2w_frame_s.send(Frame::Shutdown {}).await.unwrap();
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
debug!("handshake completed");
|
||||
if self.init_handshake {
|
||||
self.send_init(&mut to_wire_sender, &pid_string).await;
|
||||
self.send_init(&mut c2w_frame_s, &pid_string).await;
|
||||
} else {
|
||||
self.send_handshake(&mut to_wire_sender).await;
|
||||
self.send_handshake(&mut c2w_frame_s).await;
|
||||
}
|
||||
},
|
||||
Some((_, Frame::Shutdown)) => {
|
||||
@ -241,7 +263,7 @@ impl Handshake {
|
||||
None => return Err(()),
|
||||
};
|
||||
|
||||
match from_wire_receiver.next().await {
|
||||
match w2c_cid_frame_r.next().await {
|
||||
Some((_, Frame::Init { pid, secret })) => {
|
||||
debug!(?pid, "Participant send their ID");
|
||||
pid_string = pid.to_string();
|
||||
@ -252,7 +274,7 @@ impl Handshake {
|
||||
let stream_id_offset = if self.init_handshake {
|
||||
STREAM_ID_OFFSET1
|
||||
} else {
|
||||
self.send_init(&mut to_wire_sender, &pid_string).await;
|
||||
self.send_init(&mut c2w_frame_s, &pid_string).await;
|
||||
STREAM_ID_OFFSET2
|
||||
};
|
||||
info!(?pid, "this Handshake is now configured!");
|
||||
@ -288,12 +310,12 @@ impl Handshake {
|
||||
};
|
||||
}
|
||||
|
||||
async fn send_handshake(&self, to_wire_sender: &mut mpsc::UnboundedSender<Frame>) {
|
||||
async fn send_handshake(&self, c2w_frame_s: &mut mpsc::UnboundedSender<Frame>) {
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&["", &self.cid.to_string(), "Handshake"])
|
||||
.inc();
|
||||
to_wire_sender
|
||||
c2w_frame_s
|
||||
.send(Frame::Handshake {
|
||||
magic_number: VELOREN_MAGIC_NUMBER,
|
||||
version: VELOREN_NETWORK_VERSION,
|
||||
@ -302,12 +324,12 @@ impl Handshake {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn send_init(&self, to_wire_sender: &mut mpsc::UnboundedSender<Frame>, pid_string: &str) {
|
||||
async fn send_init(&self, c2w_frame_s: &mut mpsc::UnboundedSender<Frame>, pid_string: &str) {
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&[pid_string, &self.cid.to_string(), "ParticipantId"])
|
||||
.inc();
|
||||
to_wire_sender
|
||||
c2w_frame_s
|
||||
.send(Frame::Init {
|
||||
pid: self.local_pid,
|
||||
secret: self.secret,
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(trait_alias, try_trait, async_closure, const_if_match)]
|
||||
#![deny(unsafe_code)]
|
||||
#![feature(try_trait, const_if_match)]
|
||||
|
||||
//! Crate to handle high level networking of messages with different
|
||||
//! requirements and priorities over a number of protocols
|
||||
|
@ -19,7 +19,7 @@ pub struct MessageBuffer {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OutGoingMessage {
|
||||
pub(crate) struct OutgoingMessage {
|
||||
pub buffer: Arc<MessageBuffer>,
|
||||
pub cursor: u64,
|
||||
pub mid: Mid,
|
||||
@ -27,7 +27,7 @@ pub(crate) struct OutGoingMessage {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct InCommingMessage {
|
||||
pub(crate) struct IncomingMessage {
|
||||
pub buffer: MessageBuffer,
|
||||
pub length: u64,
|
||||
pub mid: Mid,
|
||||
@ -35,13 +35,20 @@ pub(crate) struct InCommingMessage {
|
||||
}
|
||||
|
||||
pub(crate) fn serialize<M: Serialize>(message: &M) -> MessageBuffer {
|
||||
//this will never fail: https://docs.rs/bincode/0.8.0/bincode/fn.serialize.html
|
||||
let writer = bincode::serialize(message).unwrap();
|
||||
MessageBuffer { data: writer }
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize<M: DeserializeOwned>(buffer: MessageBuffer) -> M {
|
||||
let span = buffer.data;
|
||||
let decoded: M = bincode::deserialize(span.as_slice()).unwrap();
|
||||
//this might fail if you choose the wrong type for M. in that case probably X
|
||||
// got transfered while you assume Y. probably this means your application
|
||||
// logic is wrong. E.g. You expect a String, but just get a u8.
|
||||
let decoded: M = bincode::deserialize(span.as_slice()).expect(
|
||||
"deserialisation failed, this is probably due to a programming error on YOUR side, \
|
||||
probably the type send by remote isn't what you are expecting. change the type of `M`",
|
||||
);
|
||||
decoded
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
api::Stream,
|
||||
channel::Channel,
|
||||
message::{InCommingMessage, MessageBuffer, OutGoingMessage},
|
||||
message::{IncomingMessage, MessageBuffer, OutgoingMessage},
|
||||
metrics::{NetworkMetrics, PidCidFrameCache},
|
||||
prios::PrioManager,
|
||||
protocols::Protocols,
|
||||
@ -37,7 +37,7 @@ struct ChannelInfo {
|
||||
struct StreamInfo {
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
b2a_msg_recv_s: mpsc::UnboundedSender<InCommingMessage>,
|
||||
b2a_msg_recv_s: mpsc::UnboundedSender<IncomingMessage>,
|
||||
closed: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
@ -45,7 +45,8 @@ struct StreamInfo {
|
||||
struct ControlChannels {
|
||||
a2b_steam_open_r: mpsc::UnboundedReceiver<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
b2a_stream_opened_s: mpsc::UnboundedSender<Stream>,
|
||||
s2b_create_channel_r: mpsc::UnboundedReceiver<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
||||
s2b_create_channel_r:
|
||||
mpsc::UnboundedReceiver<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
a2b_close_stream_r: mpsc::UnboundedReceiver<Sid>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
s2b_shutdown_bparticipant_r: oneshot::Receiver<oneshot::Sender<async_std::io::Result<()>>>, /* own */
|
||||
@ -72,7 +73,7 @@ impl BParticipant {
|
||||
Self,
|
||||
mpsc::UnboundedSender<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
mpsc::UnboundedReceiver<Stream>,
|
||||
mpsc::UnboundedSender<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
||||
mpsc::UnboundedSender<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
oneshot::Sender<oneshot::Sender<async_std::io::Result<()>>>,
|
||||
) {
|
||||
let (a2b_steam_open_s, a2b_steam_open_r) =
|
||||
@ -80,8 +81,7 @@ impl BParticipant {
|
||||
let (b2a_stream_opened_s, b2a_stream_opened_r) = mpsc::unbounded::<Stream>();
|
||||
let (a2b_close_stream_s, a2b_close_stream_r) = mpsc::unbounded();
|
||||
let (s2b_shutdown_bparticipant_s, s2b_shutdown_bparticipant_r) = oneshot::channel();
|
||||
let (s2b_create_channel_s, s2b_create_channel_r) =
|
||||
mpsc::unbounded::<(Cid, Sid, Protocols, oneshot::Sender<()>)>();
|
||||
let (s2b_create_channel_s, s2b_create_channel_r) = mpsc::unbounded();
|
||||
|
||||
let run_channels = Some(ControlChannels {
|
||||
a2b_steam_open_r,
|
||||
@ -136,7 +136,7 @@ impl BParticipant {
|
||||
run_channels.a2b_close_stream_s,
|
||||
a2p_msg_s.clone(),
|
||||
),
|
||||
self.create_channel_mgr(run_channels.s2b_create_channel_r, w2b_frames_s,),
|
||||
self.create_channel_mgr(run_channels.s2b_create_channel_r, w2b_frames_s),
|
||||
self.send_mgr(
|
||||
prios,
|
||||
shutdown_send_mgr_receiver,
|
||||
@ -243,7 +243,7 @@ impl BParticipant {
|
||||
mut w2b_frames_r: mpsc::UnboundedReceiver<(Cid, Frame)>,
|
||||
mut b2a_stream_opened_s: mpsc::UnboundedSender<Stream>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start handle_frames_mgr");
|
||||
@ -300,7 +300,7 @@ impl BParticipant {
|
||||
}
|
||||
},
|
||||
Frame::DataHeader { mid, sid, length } => {
|
||||
let imsg = InCommingMessage {
|
||||
let imsg = IncomingMessage {
|
||||
buffer: MessageBuffer { data: Vec::new() },
|
||||
length,
|
||||
mid,
|
||||
@ -367,40 +367,50 @@ impl BParticipant {
|
||||
|
||||
async fn create_channel_mgr(
|
||||
&self,
|
||||
s2b_create_channel_r: mpsc::UnboundedReceiver<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
||||
s2b_create_channel_r: mpsc::UnboundedReceiver<(
|
||||
Cid,
|
||||
Sid,
|
||||
Protocols,
|
||||
Vec<(Cid, Frame)>,
|
||||
oneshot::Sender<()>,
|
||||
)>,
|
||||
w2b_frames_s: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start create_channel_mgr");
|
||||
s2b_create_channel_r
|
||||
.for_each_concurrent(None, |(cid, _, protocol, b2s_create_channel_done_s)| {
|
||||
// This channel is now configured, and we are running it in scope of the
|
||||
// participant.
|
||||
let w2b_frames_s = w2b_frames_s.clone();
|
||||
let channels = self.channels.clone();
|
||||
async move {
|
||||
let (channel, b2w_frame_s, b2r_read_shutdown) =
|
||||
Channel::new(cid, self.remote_pid);
|
||||
channels.write().await.push(ChannelInfo {
|
||||
cid,
|
||||
cid_string: cid.to_string(),
|
||||
b2w_frame_s,
|
||||
b2r_read_shutdown,
|
||||
});
|
||||
b2s_create_channel_done_s.send(()).unwrap();
|
||||
self.metrics
|
||||
.channels_connected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "running channel in participant");
|
||||
channel.run(protocol, w2b_frames_s).await;
|
||||
self.metrics
|
||||
.channels_disconnected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "channel got closed");
|
||||
}
|
||||
})
|
||||
.for_each_concurrent(
|
||||
None,
|
||||
|(cid, _, protocol, leftover_cid_frame, b2s_create_channel_done_s)| {
|
||||
// This channel is now configured, and we are running it in scope of the
|
||||
// participant.
|
||||
let w2b_frames_s = w2b_frames_s.clone();
|
||||
let channels = self.channels.clone();
|
||||
async move {
|
||||
let (channel, b2w_frame_s, b2r_read_shutdown) = Channel::new(cid);
|
||||
channels.write().await.push(ChannelInfo {
|
||||
cid,
|
||||
cid_string: cid.to_string(),
|
||||
b2w_frame_s,
|
||||
b2r_read_shutdown,
|
||||
});
|
||||
b2s_create_channel_done_s.send(()).unwrap();
|
||||
self.metrics
|
||||
.channels_connected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "running channel in participant");
|
||||
channel
|
||||
.run(protocol, w2b_frames_s, leftover_cid_frame)
|
||||
.await;
|
||||
self.metrics
|
||||
.channels_disconnected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "channel got closed");
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
trace!("stop create_channel_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
@ -410,7 +420,7 @@ impl BParticipant {
|
||||
&self,
|
||||
mut a2b_steam_open_r: mpsc::UnboundedReceiver<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
shutdown_open_mgr_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
@ -562,10 +572,10 @@ impl BParticipant {
|
||||
sid: Sid,
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
a2b_close_stream_s: &mpsc::UnboundedSender<Sid>,
|
||||
) -> Stream {
|
||||
let (b2a_msg_recv_s, b2a_msg_recv_r) = mpsc::unbounded::<InCommingMessage>();
|
||||
let (b2a_msg_recv_s, b2a_msg_recv_r) = mpsc::unbounded::<IncomingMessage>();
|
||||
let closed = Arc::new(AtomicBool::new(false));
|
||||
self.streams.write().await.insert(sid, StreamInfo {
|
||||
prio,
|
||||
|
@ -6,7 +6,7 @@
|
||||
//! immeadiatly when found!
|
||||
|
||||
use crate::{
|
||||
message::OutGoingMessage,
|
||||
message::OutgoingMessage,
|
||||
metrics::NetworkMetrics,
|
||||
types::{Frame, Prio, Sid},
|
||||
};
|
||||
@ -30,8 +30,8 @@ struct PidSidInfo {
|
||||
|
||||
pub(crate) struct PrioManager {
|
||||
points: [u32; PRIO_MAX],
|
||||
messages: [VecDeque<(Sid, OutGoingMessage)>; PRIO_MAX],
|
||||
messages_rx: Receiver<(Prio, Sid, OutGoingMessage)>,
|
||||
messages: [VecDeque<(Sid, OutgoingMessage)>; PRIO_MAX],
|
||||
messages_rx: Receiver<(Prio, Sid, OutgoingMessage)>,
|
||||
sid_owned: HashMap<Sid, PidSidInfo>,
|
||||
//you can register to be notified if a pid_sid combination is flushed completly here
|
||||
sid_flushed_rx: Receiver<(Sid, oneshot::Sender<()>)>,
|
||||
@ -55,7 +55,7 @@ impl PrioManager {
|
||||
pid: String,
|
||||
) -> (
|
||||
Self,
|
||||
Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
Sender<(Sid, oneshot::Sender<()>)>,
|
||||
) {
|
||||
// (a2p_msg_s, a2p_msg_r)
|
||||
@ -205,7 +205,7 @@ impl PrioManager {
|
||||
|
||||
/// returns if msg is empty
|
||||
fn tick_msg<E: Extend<(Sid, Frame)>>(
|
||||
msg: &mut OutGoingMessage,
|
||||
msg: &mut OutgoingMessage,
|
||||
msg_sid: Sid,
|
||||
frames: &mut E,
|
||||
) -> bool {
|
||||
@ -311,7 +311,7 @@ impl std::fmt::Debug for PrioManager {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
message::{MessageBuffer, OutGoingMessage},
|
||||
message::{MessageBuffer, OutgoingMessage},
|
||||
metrics::NetworkMetrics,
|
||||
prios::*,
|
||||
types::{Frame, Pid, Prio, Sid},
|
||||
@ -327,7 +327,7 @@ mod tests {
|
||||
|
||||
fn mock_new() -> (
|
||||
PrioManager,
|
||||
Sender<(Prio, Sid, OutGoingMessage)>,
|
||||
Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
Sender<(Sid, oneshot::Sender<()>)>,
|
||||
) {
|
||||
let pid = Pid::fake(1);
|
||||
@ -337,9 +337,9 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn mock_out(prio: Prio, sid: u64) -> (Prio, Sid, OutGoingMessage) {
|
||||
fn mock_out(prio: Prio, sid: u64) -> (Prio, Sid, OutgoingMessage) {
|
||||
let sid = Sid::new(sid);
|
||||
(prio, sid, OutGoingMessage {
|
||||
(prio, sid, OutgoingMessage {
|
||||
buffer: Arc::new(MessageBuffer {
|
||||
data: vec![48, 49, 50],
|
||||
}),
|
||||
@ -349,12 +349,12 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
fn mock_out_large(prio: Prio, sid: u64) -> (Prio, Sid, OutGoingMessage) {
|
||||
fn mock_out_large(prio: Prio, sid: u64) -> (Prio, Sid, OutgoingMessage) {
|
||||
let sid = Sid::new(sid);
|
||||
let mut data = vec![48; USIZE];
|
||||
data.append(&mut vec![49; USIZE]);
|
||||
data.append(&mut vec![50; 20]);
|
||||
(prio, sid, OutGoingMessage {
|
||||
(prio, sid, OutgoingMessage {
|
||||
buffer: Arc::new(MessageBuffer { data }),
|
||||
cursor: 0,
|
||||
mid: 1,
|
||||
|
@ -5,11 +5,11 @@ use crate::{
|
||||
use async_std::{
|
||||
net::{TcpStream, UdpSocket},
|
||||
prelude::*,
|
||||
sync::RwLock,
|
||||
};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
future::FutureExt,
|
||||
lock::Mutex,
|
||||
select,
|
||||
sink::SinkExt,
|
||||
stream::StreamExt,
|
||||
@ -49,7 +49,7 @@ pub(crate) struct UdpProtocol {
|
||||
socket: Arc<UdpSocket>,
|
||||
remote_addr: SocketAddr,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
data_in: RwLock<mpsc::UnboundedReceiver<Vec<u8>>>,
|
||||
data_in: Mutex<mpsc::UnboundedReceiver<Vec<u8>>>,
|
||||
}
|
||||
|
||||
//TODO: PERFORMACE: Use BufWriter and BufReader from std::io!
|
||||
@ -63,25 +63,22 @@ impl TcpProtocol {
|
||||
cid: Cid,
|
||||
mut stream: &TcpStream,
|
||||
mut bytes: &mut [u8],
|
||||
from_wire_sender: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
) {
|
||||
match stream.read_exact(&mut bytes).await {
|
||||
Err(e) => {
|
||||
warn!(
|
||||
?e,
|
||||
"closing tcp protocol due to read error, sending close frame to gracefully \
|
||||
shutdown"
|
||||
);
|
||||
from_wire_sender.send((cid, Frame::Shutdown)).await.unwrap();
|
||||
},
|
||||
_ => (),
|
||||
if let Err(e) = stream.read_exact(&mut bytes).await {
|
||||
warn!(
|
||||
?e,
|
||||
"closing tcp protocol due to read error, sending close frame to gracefully \
|
||||
shutdown"
|
||||
);
|
||||
w2c_cid_frame_s.send((cid, Frame::Shutdown)).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read(
|
||||
pub async fn read_from_wire(
|
||||
&self,
|
||||
cid: Cid,
|
||||
mut from_wire_sender: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
end_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
trace!("starting up tcp read()");
|
||||
@ -107,8 +104,7 @@ impl TcpProtocol {
|
||||
let frame = match frame_no {
|
||||
FRAME_HANDSHAKE => {
|
||||
let mut bytes = [0u8; 19];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let magic_number = [
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
];
|
||||
@ -123,8 +119,7 @@ impl TcpProtocol {
|
||||
},
|
||||
FRAME_INIT => {
|
||||
let mut bytes = [0u8; 16];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let pid = Pid::from_le_bytes(bytes);
|
||||
stream.read_exact(&mut bytes).await.unwrap();
|
||||
let secret = u128::from_le_bytes(bytes);
|
||||
@ -133,8 +128,7 @@ impl TcpProtocol {
|
||||
FRAME_SHUTDOWN => Frame::Shutdown,
|
||||
FRAME_OPEN_STREAM => {
|
||||
let mut bytes = [0u8; 10];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
@ -149,8 +143,7 @@ impl TcpProtocol {
|
||||
},
|
||||
FRAME_CLOSE_STREAM => {
|
||||
let mut bytes = [0u8; 8];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
@ -159,8 +152,7 @@ impl TcpProtocol {
|
||||
},
|
||||
FRAME_DATA_HEADER => {
|
||||
let mut bytes = [0u8; 24];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
@ -177,8 +169,7 @@ impl TcpProtocol {
|
||||
},
|
||||
FRAME_DATA => {
|
||||
let mut bytes = [0u8; 18];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
@ -190,31 +181,27 @@ impl TcpProtocol {
|
||||
let length = u16::from_le_bytes([bytes[16], bytes[17]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
throughput_cache.inc_by(length as i64);
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Data { mid, start, data }
|
||||
},
|
||||
FRAME_RAW => {
|
||||
let mut bytes = [0u8; 2];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let length = u16::from_le_bytes([bytes[0], bytes[1]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Raw(data)
|
||||
},
|
||||
_ => {
|
||||
// report a RAW frame, but cannot rely on the next 2 bytes to be a size.
|
||||
// guessing 256 bytes, which might help to sort down issues
|
||||
let mut data = vec![0; 256];
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, &mut from_wire_sender)
|
||||
.await;
|
||||
Self::read_except_or_close(cid, &mut stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Raw(data)
|
||||
},
|
||||
};
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
from_wire_sender.send((cid, frame)).await.unwrap();
|
||||
w2c_cid_frame_s.send((cid, frame)).await.unwrap();
|
||||
}
|
||||
trace!("shutting down tcp read()");
|
||||
}
|
||||
@ -241,7 +228,7 @@ impl TcpProtocol {
|
||||
//dezerialize here as this is executed in a seperate thread PER channel.
|
||||
// Limites Throughput per single Receiver but stays in same thread (maybe as its
|
||||
// in a threadpool) for TCP, UDP and MPSC
|
||||
pub async fn write(&self, cid: Cid, mut to_wire_receiver: mpsc::UnboundedReceiver<Frame>) {
|
||||
pub async fn write_to_wire(&self, cid: Cid, mut c2w_frame_r: mpsc::UnboundedReceiver<Frame>) {
|
||||
trace!("starting up tcp write()");
|
||||
let mut stream = self.stream.clone();
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_out_total.clone(), cid);
|
||||
@ -249,7 +236,7 @@ impl TcpProtocol {
|
||||
.metrics
|
||||
.wire_out_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
while let Some(frame) = to_wire_receiver.next().await {
|
||||
while let Some(frame) = c2w_frame_r.next().await {
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
if match frame {
|
||||
Frame::Handshake {
|
||||
@ -259,47 +246,38 @@ impl TcpProtocol {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_HANDSHAKE.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &magic_number, &mut to_wire_receiver)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &magic_number, &mut c2w_frame_r).await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[0].to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[1].to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[2].to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::Init { pid, secret } => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_INIT.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&pid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
Self::write_or_close(&mut stream, &FRAME_INIT.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &pid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&secret.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
@ -307,7 +285,7 @@ impl TcpProtocol {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_SHUTDOWN.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
@ -319,25 +297,17 @@ impl TcpProtocol {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_OPEN_STREAM.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&sid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&prio.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &prio.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&promises.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
@ -345,84 +315,56 @@ impl TcpProtocol {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_CLOSE_STREAM.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&sid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
},
|
||||
Frame::DataHeader { mid, sid, length } => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_DATA_HEADER.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&mid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&sid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &mid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&length.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::Data { mid, start, data } => {
|
||||
throughput_cache.inc_by(data.len() as i64);
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_DATA.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&mid.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&start.to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
Self::write_or_close(&mut stream, &FRAME_DATA.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &mid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &start.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&(data.len() as u16).to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut to_wire_receiver).await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut c2w_frame_r).await
|
||||
},
|
||||
Frame::Raw(data) => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_RAW.to_be_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
)
|
||||
.await
|
||||
Self::write_or_close(&mut stream, &FRAME_RAW.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&(data.len() as u16).to_le_bytes(),
|
||||
&mut to_wire_receiver,
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut to_wire_receiver).await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut c2w_frame_r).await
|
||||
},
|
||||
} {
|
||||
//failure
|
||||
@ -444,14 +386,14 @@ impl UdpProtocol {
|
||||
socket,
|
||||
remote_addr,
|
||||
metrics,
|
||||
data_in: RwLock::new(data_in),
|
||||
data_in: Mutex::new(data_in),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read(
|
||||
pub async fn read_from_wire(
|
||||
&self,
|
||||
cid: Cid,
|
||||
mut from_wire_sender: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
end_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
trace!("starting up udp read()");
|
||||
@ -460,7 +402,7 @@ impl UdpProtocol {
|
||||
.metrics
|
||||
.wire_in_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
let mut data_in = self.data_in.write().await;
|
||||
let mut data_in = self.data_in.lock().await;
|
||||
let mut end_receiver = end_receiver.fuse();
|
||||
while let Some(bytes) = select! {
|
||||
r = data_in.next().fuse() => r,
|
||||
@ -559,12 +501,12 @@ impl UdpProtocol {
|
||||
_ => Frame::Raw(bytes),
|
||||
};
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
from_wire_sender.send((cid, frame)).await.unwrap();
|
||||
w2c_cid_frame_s.send((cid, frame)).await.unwrap();
|
||||
}
|
||||
trace!("shutting down udp read()");
|
||||
}
|
||||
|
||||
pub async fn write(&self, cid: Cid, mut to_wire_receiver: mpsc::UnboundedReceiver<Frame>) {
|
||||
pub async fn write_to_wire(&self, cid: Cid, mut c2w_frame_r: mpsc::UnboundedReceiver<Frame>) {
|
||||
trace!("starting up udp write()");
|
||||
let mut buffer = [0u8; 2000];
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_out_total.clone(), cid);
|
||||
@ -572,7 +514,7 @@ impl UdpProtocol {
|
||||
.metrics
|
||||
.wire_out_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
while let Some(frame) = to_wire_receiver.next().await {
|
||||
while let Some(frame) = c2w_frame_r.next().await {
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
let len = match frame {
|
||||
Frame::Handshake {
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
metrics::NetworkMetrics,
|
||||
participant::BParticipant,
|
||||
protocols::{Protocols, TcpProtocol, UdpProtocol},
|
||||
types::{Cid, Pid, Sid},
|
||||
types::{Cid, Frame, Pid, Sid},
|
||||
};
|
||||
use async_std::{
|
||||
io, net,
|
||||
@ -33,7 +33,8 @@ use tracing_futures::Instrument;
|
||||
#[derive(Debug)]
|
||||
struct ParticipantInfo {
|
||||
secret: u128,
|
||||
s2b_create_channel_s: mpsc::UnboundedSender<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
||||
s2b_create_channel_s:
|
||||
mpsc::UnboundedSender<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
s2b_shutdown_bparticipant_s:
|
||||
Option<oneshot::Sender<oneshot::Sender<async_std::io::Result<()>>>>,
|
||||
}
|
||||
@ -45,6 +46,7 @@ struct ParticipantInfo {
|
||||
/// - p: prios
|
||||
/// - r: protocol
|
||||
/// - w: wire
|
||||
/// - c: channel/handshake
|
||||
#[derive(Debug)]
|
||||
struct ControlChannels {
|
||||
a2s_listen_r: mpsc::UnboundedReceiver<(Address, oneshot::Sender<io::Result<()>>)>,
|
||||
@ -205,8 +207,10 @@ impl Scheduler {
|
||||
},
|
||||
};
|
||||
info!("Connecting Tcp to: {}", stream.peer_addr().unwrap());
|
||||
let protocol = Protocols::Tcp(TcpProtocol::new(stream, self.metrics.clone()));
|
||||
(protocol, false)
|
||||
(
|
||||
Protocols::Tcp(TcpProtocol::new(stream, self.metrics.clone())),
|
||||
false,
|
||||
)
|
||||
},
|
||||
Address::Udp(addr) => {
|
||||
self.metrics
|
||||
@ -226,17 +230,17 @@ impl Scheduler {
|
||||
};
|
||||
info!("Connecting Udp to: {}", addr);
|
||||
let (udp_data_sender, udp_data_receiver) = mpsc::unbounded::<Vec<u8>>();
|
||||
let protocol = Protocols::Udp(UdpProtocol::new(
|
||||
let protocol = UdpProtocol::new(
|
||||
socket.clone(),
|
||||
addr,
|
||||
self.metrics.clone(),
|
||||
udp_data_receiver,
|
||||
));
|
||||
);
|
||||
self.pool.spawn_ok(
|
||||
Self::udp_single_channel_connect(socket.clone(), udp_data_sender)
|
||||
.instrument(tracing::info_span!("udp", ?addr)),
|
||||
);
|
||||
(protocol, true)
|
||||
(Protocols::Udp(protocol), true)
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
@ -360,12 +364,9 @@ impl Scheduler {
|
||||
} {
|
||||
let stream = stream.unwrap();
|
||||
info!("Accepting Tcp from: {}", stream.peer_addr().unwrap());
|
||||
self.init_protocol(
|
||||
Protocols::Tcp(TcpProtocol::new(stream, self.metrics.clone())),
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.await;
|
||||
let protocol = TcpProtocol::new(stream, self.metrics.clone());
|
||||
self.init_protocol(Protocols::Tcp(protocol), None, true)
|
||||
.await;
|
||||
}
|
||||
},
|
||||
Address::Udp(addr) => {
|
||||
@ -400,13 +401,14 @@ impl Scheduler {
|
||||
info!("Accepting Udp from: {}", &remote_addr);
|
||||
let (udp_data_sender, udp_data_receiver) = mpsc::unbounded::<Vec<u8>>();
|
||||
listeners.insert(remote_addr.clone(), udp_data_sender);
|
||||
let protocol = Protocols::Udp(UdpProtocol::new(
|
||||
let protocol = UdpProtocol::new(
|
||||
socket.clone(),
|
||||
remote_addr.clone(),
|
||||
self.metrics.clone(),
|
||||
udp_data_receiver,
|
||||
));
|
||||
self.init_protocol(protocol, None, false).await;
|
||||
);
|
||||
self.init_protocol(Protocols::Udp(protocol), None, false)
|
||||
.await;
|
||||
}
|
||||
let udp_data_sender = listeners.get_mut(&remote_addr).unwrap();
|
||||
udp_data_sender.send(datavec).await.unwrap();
|
||||
@ -476,7 +478,7 @@ impl Scheduler {
|
||||
send_handshake,
|
||||
);
|
||||
match handshake.setup(&protocol).await {
|
||||
Ok((pid, sid, secret)) => {
|
||||
Ok((pid, sid, secret, leftover_cid_frame)) => {
|
||||
trace!(
|
||||
?cid,
|
||||
?pid,
|
||||
@ -515,13 +517,20 @@ impl Scheduler {
|
||||
//create a new channel within BParticipant and wait for it to run
|
||||
let (b2s_create_channel_done_s, b2s_create_channel_done_r) =
|
||||
oneshot::channel();
|
||||
//From now on wire connects directly with bparticipant!
|
||||
s2b_create_channel_s
|
||||
.send((cid, sid, protocol, b2s_create_channel_done_s))
|
||||
.send((
|
||||
cid,
|
||||
sid,
|
||||
protocol,
|
||||
leftover_cid_frame,
|
||||
b2s_create_channel_done_s,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
b2s_create_channel_done_r.await.unwrap();
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with connect, so give them their PID
|
||||
// someone is waiting with `connect`, so give them their PID
|
||||
pid_oneshot.send(Ok(participant)).unwrap();
|
||||
} else {
|
||||
// noone is waiting on this Participant, return in to Network
|
||||
@ -543,7 +552,7 @@ impl Scheduler {
|
||||
error!("just dropping here, TODO handle this correctly!");
|
||||
//TODO
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with connect, so give them their Error
|
||||
// someone is waiting with `connect`, so give them their Error
|
||||
pid_oneshot
|
||||
.send(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
@ -561,7 +570,17 @@ impl Scheduler {
|
||||
//From now on this CHANNEL can receiver other frames!
|
||||
// move directly to participant!
|
||||
},
|
||||
Err(()) => {},
|
||||
Err(()) => {
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with `connect`, so give them their Error
|
||||
pid_oneshot
|
||||
.send(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"handshake failed, denying connection",
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
.instrument(tracing::trace_span!("")),
|
||||
|
@ -46,6 +46,23 @@ fn close_stream() {
|
||||
);
|
||||
}
|
||||
|
||||
///THIS is actually a bug which currently luckily doesn't trigger, but with new
|
||||
/// async-std WE must make sure, if a stream is `drop`ed inside a `block_on`,
|
||||
/// that no panic is thrown.
|
||||
#[test]
|
||||
fn close_streams_in_block_on() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _p_a, s1_a, _n_b, _p_b, s1_b) = block_on(network_participant_stream(tcp()));
|
||||
block_on(async {
|
||||
//make it locally so that they are dropped later
|
||||
let mut s1_a = s1_a;
|
||||
let mut s1_b = s1_b;
|
||||
s1_a.send("ping").unwrap();
|
||||
assert_eq!(s1_b.recv().await, Ok("ping".to_string()));
|
||||
drop(s1_a);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple_3msg_then_close() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
@ -79,6 +96,19 @@ fn stream_send_first_then_receive() {
|
||||
assert_eq!(s1_b.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_1_then_close_stream() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
s1_a.send("this message must be received, even if stream is closed already!")
|
||||
.unwrap();
|
||||
drop(s1_a);
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
let exp = Ok("this message must be received, even if stream is closed already!".to_string());
|
||||
assert_eq!(block_on(s1_b.recv()), exp);
|
||||
println!("all received and done");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_100000_then_close_stream() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
|
@ -62,7 +62,7 @@ fn stream_simple_udp_3msg() {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn tcp_and_udp_2_connections() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(true, 0);
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let network = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
let remote = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
block_on(async {
|
||||
@ -110,23 +110,24 @@ fn failed_listen_on_used_ports() -> std::result::Result<(), Box<dyn std::error::
|
||||
/// There is a bug an impris-desktop-1 which fails the DOC tests,
|
||||
/// it fails exactly `api_stream_send_main` and `api_stream_recv_main` by
|
||||
/// deadlocking at different times!
|
||||
/// So i rather put the same test into a unit test, as my gues is that it's
|
||||
/// compiler related
|
||||
/// So i rather put the same test into a unit test, these are now duplicate to
|
||||
/// the api, but are left here, just to be save!
|
||||
#[test]
|
||||
fn api_stream_send_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
// Create a Network, listen on Port `2200` and wait for a Stream to be opened,
|
||||
// Create a Network, listen on Port `1200` and wait for a Stream to be opened,
|
||||
// then answer `Hello World`
|
||||
let network = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
let remote = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
block_on(async {
|
||||
network
|
||||
.listen(Address::Tcp("127.0.0.1:2200".parse().unwrap()))
|
||||
.listen(Address::Tcp("127.0.0.1:1200".parse().unwrap()))
|
||||
.await?;
|
||||
let remote_p = remote
|
||||
.connect(Address::Tcp("127.0.0.1:2200".parse().unwrap()))
|
||||
.connect(Address::Tcp("127.0.0.1:1200".parse().unwrap()))
|
||||
.await?;
|
||||
remote_p
|
||||
// keep it alive
|
||||
let _stream_p = remote_p
|
||||
.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
.await?;
|
||||
let participant_a = network.connected().await?;
|
||||
@ -140,16 +141,16 @@ fn api_stream_send_main() -> std::result::Result<(), Box<dyn std::error::Error>>
|
||||
#[test]
|
||||
fn api_stream_recv_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
// Create a Network, listen on Port `2220` and wait for a Stream to be opened,
|
||||
// Create a Network, listen on Port `1220` and wait for a Stream to be opened,
|
||||
// then listen on it
|
||||
let network = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
let remote = Network::new(Pid::new(), &ThreadPoolBuilder::new().build(), None);
|
||||
block_on(async {
|
||||
network
|
||||
.listen(Address::Tcp("127.0.0.1:2220".parse().unwrap()))
|
||||
.listen(Address::Tcp("127.0.0.1:1220".parse().unwrap()))
|
||||
.await?;
|
||||
let remote_p = remote
|
||||
.connect(Address::Tcp("127.0.0.1:2220".parse().unwrap()))
|
||||
.connect(Address::Tcp("127.0.0.1:1220".parse().unwrap()))
|
||||
.await?;
|
||||
let mut stream_p = remote_p
|
||||
.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
@ -158,7 +159,17 @@ fn api_stream_recv_main() -> std::result::Result<(), Box<dyn std::error::Error>>
|
||||
let participant_a = network.connected().await?;
|
||||
let mut stream_a = participant_a.opened().await?;
|
||||
//Send Message
|
||||
println!("{}", stream_a.recv::<String>().await?);
|
||||
assert_eq!("Hello World".to_string(), stream_a.recv::<String>().await?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn wrong_parse() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send(1337).unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("Hello World".to_string()));
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ pub struct Server {
|
||||
thread_pool: ThreadPool,
|
||||
|
||||
server_info: ServerInfo,
|
||||
_metrics: ServerMetrics,
|
||||
metrics: ServerMetrics,
|
||||
tick_metrics: TickMetrics,
|
||||
|
||||
server_settings: ServerSettings,
|
||||
@ -242,7 +242,7 @@ impl Server {
|
||||
git_date: common::util::GIT_DATE.to_string(),
|
||||
auth_provider: settings.auth_server_address.clone(),
|
||||
},
|
||||
_metrics: metrics,
|
||||
metrics,
|
||||
tick_metrics,
|
||||
server_settings: settings.clone(),
|
||||
};
|
||||
@ -494,6 +494,7 @@ impl Server {
|
||||
.tick_time
|
||||
.with_label_values(&["metrics"])
|
||||
.set(end_of_server_tick.elapsed().as_nanos() as i64);
|
||||
self.metrics.tick();
|
||||
|
||||
// 8) Finish the tick, pass control back to the frontend.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user