2020-03-22 13:47:21 +00:00
|
|
|
use crate::{
|
|
|
|
api::Stream,
|
2020-05-04 13:27:58 +00:00
|
|
|
channel::Channel,
|
2020-03-22 13:47:21 +00:00
|
|
|
message::{InCommingMessage, MessageBuffer, OutGoingMessage},
|
2020-05-24 23:17:03 +00:00
|
|
|
metrics::{NetworkMetrics, PidCidFrameCache},
|
2020-05-22 14:00:08 +00:00
|
|
|
prios::PrioManager,
|
2020-05-04 13:27:58 +00:00
|
|
|
protocols::Protocols,
|
2020-04-08 14:26:42 +00:00
|
|
|
types::{Cid, Frame, Pid, Prio, Promises, Sid},
|
2020-03-22 13:47:21 +00:00
|
|
|
};
|
|
|
|
use async_std::sync::RwLock;
|
|
|
|
use futures::{
|
|
|
|
channel::{mpsc, oneshot},
|
2020-04-08 14:26:42 +00:00
|
|
|
future::FutureExt,
|
|
|
|
select,
|
2020-03-22 13:47:21 +00:00
|
|
|
sink::SinkExt,
|
|
|
|
stream::StreamExt,
|
|
|
|
};
|
|
|
|
use std::{
|
2020-05-22 14:00:08 +00:00
|
|
|
collections::{HashMap, VecDeque},
|
2020-04-08 14:26:42 +00:00
|
|
|
sync::{
|
2020-05-22 14:00:08 +00:00
|
|
|
atomic::{AtomicBool, AtomicUsize, Ordering},
|
|
|
|
Arc,
|
2020-04-08 14:26:42 +00:00
|
|
|
},
|
2020-03-22 13:47:21 +00:00
|
|
|
};
|
|
|
|
use tracing::*;
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct ChannelInfo {
|
|
|
|
cid: Cid,
|
2020-05-24 23:17:03 +00:00
|
|
|
cid_string: String, //optimisation
|
2020-05-15 12:29:17 +00:00
|
|
|
b2w_frame_s: mpsc::UnboundedSender<Frame>,
|
|
|
|
b2r_read_shutdown: oneshot::Sender<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct StreamInfo {
|
|
|
|
prio: Prio,
|
|
|
|
promises: Promises,
|
|
|
|
b2a_msg_recv_s: mpsc::UnboundedSender<InCommingMessage>,
|
|
|
|
closed: Arc<AtomicBool>,
|
|
|
|
}
|
|
|
|
|
2020-03-22 13:47:21 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct ControlChannels {
|
2020-05-15 12:29:17 +00:00
|
|
|
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<()>)>,
|
|
|
|
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 */
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct BParticipant {
|
|
|
|
remote_pid: Pid,
|
2020-05-24 23:17:03 +00:00
|
|
|
remote_pid_string: String, //optimisation
|
2020-03-22 13:47:21 +00:00
|
|
|
offset_sid: Sid,
|
2020-05-15 12:29:17 +00:00
|
|
|
channels: Arc<RwLock<Vec<ChannelInfo>>>,
|
|
|
|
streams: RwLock<HashMap<Sid, StreamInfo>>,
|
|
|
|
running_mgr: AtomicUsize,
|
2020-03-22 13:47:21 +00:00
|
|
|
run_channels: Option<ControlChannels>,
|
2020-04-24 10:56:04 +00:00
|
|
|
metrics: Arc<NetworkMetrics>,
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BParticipant {
|
|
|
|
pub(crate) fn new(
|
|
|
|
remote_pid: Pid,
|
|
|
|
offset_sid: Sid,
|
2020-04-24 10:56:04 +00:00
|
|
|
metrics: Arc<NetworkMetrics>,
|
2020-03-22 13:47:21 +00:00
|
|
|
) -> (
|
|
|
|
Self,
|
|
|
|
mpsc::UnboundedSender<(Prio, Promises, oneshot::Sender<Stream>)>,
|
|
|
|
mpsc::UnboundedReceiver<Stream>,
|
2020-05-04 13:27:58 +00:00
|
|
|
mpsc::UnboundedSender<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
2020-05-15 12:29:17 +00:00
|
|
|
oneshot::Sender<oneshot::Sender<async_std::io::Result<()>>>,
|
2020-03-22 13:47:21 +00:00
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
let (a2b_steam_open_s, a2b_steam_open_r) =
|
2020-03-22 13:47:21 +00:00
|
|
|
mpsc::unbounded::<(Prio, Promises, oneshot::Sender<Stream>)>();
|
2020-05-15 12:29:17 +00:00
|
|
|
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) =
|
2020-05-04 13:27:58 +00:00
|
|
|
mpsc::unbounded::<(Cid, Sid, Protocols, oneshot::Sender<()>)>();
|
2020-03-22 13:47:21 +00:00
|
|
|
|
|
|
|
let run_channels = Some(ControlChannels {
|
2020-05-15 12:29:17 +00:00
|
|
|
a2b_steam_open_r,
|
|
|
|
b2a_stream_opened_s,
|
|
|
|
s2b_create_channel_r,
|
|
|
|
a2b_close_stream_r,
|
|
|
|
a2b_close_stream_s,
|
|
|
|
s2b_shutdown_bparticipant_r,
|
2020-03-22 13:47:21 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
(
|
|
|
|
Self {
|
|
|
|
remote_pid,
|
2020-05-24 23:17:03 +00:00
|
|
|
remote_pid_string: remote_pid.to_string(),
|
2020-03-22 13:47:21 +00:00
|
|
|
offset_sid,
|
2020-05-04 13:27:58 +00:00
|
|
|
channels: Arc::new(RwLock::new(vec![])),
|
2020-03-22 13:47:21 +00:00
|
|
|
streams: RwLock::new(HashMap::new()),
|
2020-05-15 12:29:17 +00:00
|
|
|
running_mgr: AtomicUsize::new(0),
|
2020-03-22 13:47:21 +00:00
|
|
|
run_channels,
|
2020-04-24 10:56:04 +00:00
|
|
|
metrics,
|
2020-03-22 13:47:21 +00:00
|
|
|
},
|
2020-05-15 12:29:17 +00:00
|
|
|
a2b_steam_open_s,
|
|
|
|
b2a_stream_opened_r,
|
|
|
|
s2b_create_channel_s,
|
|
|
|
s2b_shutdown_bparticipant_s,
|
2020-03-22 13:47:21 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn run(mut self) {
|
2020-04-08 14:26:42 +00:00
|
|
|
//those managers that listen on api::Participant need an additional oneshot for
|
|
|
|
// shutdown scenario, those handled by scheduler will be closed by it.
|
2020-05-22 14:00:08 +00:00
|
|
|
let (shutdown_send_mgr_sender, shutdown_send_mgr_receiver) = oneshot::channel();
|
2020-05-15 12:29:17 +00:00
|
|
|
let (shutdown_stream_close_mgr_sender, shutdown_stream_close_mgr_receiver) =
|
2020-04-08 14:26:42 +00:00
|
|
|
oneshot::channel();
|
2020-05-22 14:00:08 +00:00
|
|
|
let (shutdown_open_mgr_sender, shutdown_open_mgr_receiver) = oneshot::channel();
|
|
|
|
let (b2b_prios_flushed_s, b2b_prios_flushed_r) = oneshot::channel();
|
2020-05-15 12:29:17 +00:00
|
|
|
let (w2b_frames_s, w2b_frames_r) = mpsc::unbounded::<(Cid, Frame)>();
|
2020-05-26 13:06:03 +00:00
|
|
|
let (prios, a2p_msg_s, b2p_notify_empty_stream_s) = PrioManager::new();
|
2020-04-08 14:26:42 +00:00
|
|
|
|
2020-03-22 13:47:21 +00:00
|
|
|
let run_channels = self.run_channels.take().unwrap();
|
|
|
|
futures::join!(
|
2020-05-15 12:29:17 +00:00
|
|
|
self.open_mgr(
|
|
|
|
run_channels.a2b_steam_open_r,
|
|
|
|
run_channels.a2b_close_stream_s.clone(),
|
2020-05-22 14:00:08 +00:00
|
|
|
a2p_msg_s.clone(),
|
2020-05-15 12:29:17 +00:00
|
|
|
shutdown_open_mgr_receiver,
|
2020-03-22 13:47:21 +00:00
|
|
|
),
|
2020-05-15 12:29:17 +00:00
|
|
|
self.handle_frames_mgr(
|
|
|
|
w2b_frames_r,
|
|
|
|
run_channels.b2a_stream_opened_s,
|
|
|
|
run_channels.a2b_close_stream_s,
|
2020-05-22 14:00:08 +00:00
|
|
|
a2p_msg_s.clone(),
|
2020-05-04 13:27:58 +00:00
|
|
|
),
|
2020-05-15 12:29:17 +00:00
|
|
|
self.create_channel_mgr(run_channels.s2b_create_channel_r, w2b_frames_s,),
|
2020-05-22 14:00:08 +00:00
|
|
|
self.send_mgr(prios, shutdown_send_mgr_receiver, b2b_prios_flushed_s),
|
2020-05-15 12:29:17 +00:00
|
|
|
self.stream_close_mgr(
|
|
|
|
run_channels.a2b_close_stream_r,
|
|
|
|
shutdown_stream_close_mgr_receiver,
|
2020-05-26 13:06:03 +00:00
|
|
|
b2p_notify_empty_stream_s,
|
2020-04-08 14:26:42 +00:00
|
|
|
),
|
2020-05-15 12:29:17 +00:00
|
|
|
self.participant_shutdown_mgr(
|
|
|
|
run_channels.s2b_shutdown_bparticipant_r,
|
2020-05-22 14:00:08 +00:00
|
|
|
b2b_prios_flushed_r,
|
|
|
|
vec!(
|
|
|
|
shutdown_send_mgr_sender,
|
|
|
|
shutdown_open_mgr_sender,
|
|
|
|
shutdown_stream_close_mgr_sender
|
|
|
|
)
|
2020-04-08 14:26:42 +00:00
|
|
|
),
|
2020-03-22 13:47:21 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-05-22 14:00:08 +00:00
|
|
|
async fn send_mgr(
|
|
|
|
&self,
|
|
|
|
mut prios: PrioManager,
|
|
|
|
mut shutdown_send_mgr_receiver: oneshot::Receiver<()>,
|
|
|
|
b2b_prios_flushed_s: oneshot::Sender<()>,
|
|
|
|
) {
|
|
|
|
//This time equals the MINIMUM Latency in average, so keep it down and //Todo:
|
|
|
|
// make it configureable or switch to await E.g. Prio 0 = await, prio 50
|
|
|
|
// wait for more messages
|
|
|
|
const TICK_TIME: std::time::Duration = std::time::Duration::from_millis(10);
|
|
|
|
const FRAMES_PER_TICK: usize = 10005;
|
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
|
|
|
let mut closing_up = false;
|
|
|
|
trace!("start send_mgr");
|
2020-05-24 23:17:03 +00:00
|
|
|
let mut send_cache =
|
|
|
|
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
2020-05-22 14:00:08 +00:00
|
|
|
//while !self.closed.load(Ordering::Relaxed) {
|
|
|
|
loop {
|
|
|
|
let mut frames = VecDeque::new();
|
|
|
|
prios.fill_frames(FRAMES_PER_TICK, &mut frames).await;
|
|
|
|
let len = frames.len();
|
|
|
|
if len > 0 {
|
|
|
|
trace!("tick {}", len);
|
|
|
|
}
|
|
|
|
for (_, frame) in frames {
|
2020-05-24 23:17:03 +00:00
|
|
|
self.send_frame(frame, &mut send_cache).await;
|
2020-05-22 14:00:08 +00:00
|
|
|
}
|
|
|
|
async_std::task::sleep(TICK_TIME).await;
|
|
|
|
//shutdown after all msg are send!
|
|
|
|
if closing_up && (len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2020-05-26 13:06:03 +00:00
|
|
|
//this IF below the break IF to give it another chance to close all streams
|
|
|
|
// closed
|
|
|
|
if !closing_up && shutdown_send_mgr_receiver.try_recv().unwrap().is_some() {
|
|
|
|
closing_up = true;
|
|
|
|
}
|
2020-05-22 14:00:08 +00:00
|
|
|
}
|
|
|
|
trace!("stop send_mgr");
|
|
|
|
b2b_prios_flushed_s.send(()).unwrap();
|
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
|
2020-05-24 23:17:03 +00:00
|
|
|
async fn send_frame(&self, frame: Frame, frames_out_total_cache: &mut PidCidFrameCache) {
|
2020-04-08 14:26:42 +00:00
|
|
|
// find out ideal channel here
|
2020-03-22 13:47:21 +00:00
|
|
|
//TODO: just take first
|
2020-05-15 12:29:17 +00:00
|
|
|
if let Some(ci) = self.channels.write().await.get_mut(0) {
|
2020-05-24 23:17:03 +00:00
|
|
|
frames_out_total_cache
|
|
|
|
.with_label_values(ci.cid, &frame)
|
2020-05-04 13:27:58 +00:00
|
|
|
.inc();
|
2020-05-15 12:29:17 +00:00
|
|
|
ci.b2w_frame_s.send(frame).await.unwrap();
|
2020-03-22 13:47:21 +00:00
|
|
|
} else {
|
|
|
|
error!("participant has no channel to communicate on");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
async fn handle_frames_mgr(
|
2020-03-22 13:47:21 +00:00
|
|
|
&self,
|
2020-05-15 12:29:17 +00:00
|
|
|
mut w2b_frames_r: mpsc::UnboundedReceiver<(Cid, Frame)>,
|
|
|
|
mut b2a_stream_opened_s: mpsc::UnboundedSender<Stream>,
|
|
|
|
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
2020-05-22 14:00:08 +00:00
|
|
|
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
2020-03-22 13:47:21 +00:00
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
2020-05-22 14:00:08 +00:00
|
|
|
trace!("start handle_frames_mgr");
|
2020-03-22 13:47:21 +00:00
|
|
|
let mut messages = HashMap::new();
|
2020-05-15 12:29:17 +00:00
|
|
|
while let Some((cid, frame)) = w2b_frames_r.next().await {
|
2020-05-04 13:27:58 +00:00
|
|
|
let cid_string = cid.to_string();
|
2020-05-15 12:29:17 +00:00
|
|
|
//trace!("handling frame");
|
2020-05-04 13:27:58 +00:00
|
|
|
self.metrics
|
|
|
|
.frames_in_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string, &cid_string, frame.get_string()])
|
2020-05-04 13:27:58 +00:00
|
|
|
.inc();
|
2020-03-22 13:47:21 +00:00
|
|
|
match frame {
|
|
|
|
Frame::OpenStream {
|
|
|
|
sid,
|
|
|
|
prio,
|
|
|
|
promises,
|
|
|
|
} => {
|
2020-05-15 12:29:17 +00:00
|
|
|
let a2p_msg_s = a2p_msg_s.clone();
|
2020-03-22 13:47:21 +00:00
|
|
|
let stream = self
|
2020-05-15 12:29:17 +00:00
|
|
|
.create_stream(sid, prio, promises, a2p_msg_s, &a2b_close_stream_s)
|
2020-03-22 13:47:21 +00:00
|
|
|
.await;
|
2020-05-15 12:29:17 +00:00
|
|
|
b2a_stream_opened_s.send(stream).await.unwrap();
|
2020-03-22 13:47:21 +00:00
|
|
|
trace!("opened frame from remote");
|
|
|
|
},
|
|
|
|
Frame::CloseStream { sid } => {
|
2020-04-08 14:26:42 +00:00
|
|
|
// Closing is realised by setting a AtomicBool to true, however we also have a
|
|
|
|
// guarantee that send or recv fails if the other one is destroyed
|
|
|
|
// However Stream.send() is not async and their receiver isn't dropped if Steam
|
|
|
|
// is dropped, so i need a way to notify the Stream that it's send messages will
|
|
|
|
// be dropped... from remote, notify local
|
2020-05-15 12:29:17 +00:00
|
|
|
if let Some(si) = self.streams.write().await.remove(&sid) {
|
2020-04-24 10:56:04 +00:00
|
|
|
self.metrics
|
|
|
|
.streams_closed_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string])
|
2020-04-24 10:56:04 +00:00
|
|
|
.inc();
|
2020-05-15 12:29:17 +00:00
|
|
|
si.closed.store(true, Ordering::Relaxed);
|
2020-03-22 13:47:21 +00:00
|
|
|
} else {
|
2020-04-08 14:26:42 +00:00
|
|
|
error!(
|
|
|
|
"couldn't find stream to close, either this is a duplicate message, \
|
|
|
|
or the local copy of the Stream got closed simultaniously"
|
|
|
|
);
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
trace!("closed frame from remote");
|
|
|
|
},
|
|
|
|
Frame::DataHeader { mid, sid, length } => {
|
|
|
|
let imsg = InCommingMessage {
|
|
|
|
buffer: MessageBuffer { data: Vec::new() },
|
|
|
|
length,
|
|
|
|
mid,
|
|
|
|
sid,
|
|
|
|
};
|
|
|
|
messages.insert(mid, imsg);
|
|
|
|
},
|
|
|
|
Frame::Data {
|
2020-04-24 10:56:04 +00:00
|
|
|
mid,
|
2020-03-22 13:47:21 +00:00
|
|
|
start: _,
|
|
|
|
mut data,
|
|
|
|
} => {
|
2020-04-24 10:56:04 +00:00
|
|
|
let finished = if let Some(imsg) = messages.get_mut(&mid) {
|
2020-03-22 13:47:21 +00:00
|
|
|
imsg.buffer.data.append(&mut data);
|
|
|
|
imsg.buffer.data.len() as u64 == imsg.length
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
if finished {
|
2020-05-15 12:29:17 +00:00
|
|
|
//debug!(?mid, "finished receiving message");
|
2020-04-24 10:56:04 +00:00
|
|
|
let imsg = messages.remove(&mid).unwrap();
|
2020-05-15 12:29:17 +00:00
|
|
|
if let Some(si) = self.streams.write().await.get_mut(&imsg.sid) {
|
|
|
|
si.b2a_msg_recv_s.send(imsg).await.unwrap();
|
2020-04-08 14:26:42 +00:00
|
|
|
} else {
|
|
|
|
error!("dropping message as stream no longer seems to exist");
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => unreachable!("never reaches frame!"),
|
|
|
|
}
|
|
|
|
}
|
2020-05-22 14:00:08 +00:00
|
|
|
trace!("stop handle_frames_mgr");
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
async fn create_channel_mgr(
|
2020-05-04 13:27:58 +00:00
|
|
|
&self,
|
2020-05-15 12:29:17 +00:00
|
|
|
s2b_create_channel_r: mpsc::UnboundedReceiver<(Cid, Sid, Protocols, oneshot::Sender<()>)>,
|
|
|
|
w2b_frames_s: mpsc::UnboundedSender<(Cid, Frame)>,
|
2020-05-04 13:27:58 +00:00
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
|
|
|
trace!("start create_channel_mgr");
|
|
|
|
s2b_create_channel_r
|
2020-05-22 14:00:08 +00:00
|
|
|
.for_each_concurrent(None, |(cid, _, protocol, b2s_create_channel_done_s)| {
|
2020-05-04 13:27:58 +00:00
|
|
|
// This channel is now configured, and we are running it in scope of the
|
|
|
|
// participant.
|
2020-05-15 12:29:17 +00:00
|
|
|
let w2b_frames_s = w2b_frames_s.clone();
|
2020-05-04 13:27:58 +00:00
|
|
|
let channels = self.channels.clone();
|
|
|
|
async move {
|
2020-05-15 12:29:17 +00:00
|
|
|
let (channel, b2w_frame_s, b2r_read_shutdown) =
|
2020-05-22 14:00:08 +00:00
|
|
|
Channel::new(cid, self.remote_pid);
|
2020-05-15 12:29:17 +00:00
|
|
|
channels.write().await.push(ChannelInfo {
|
|
|
|
cid,
|
2020-05-24 23:17:03 +00:00
|
|
|
cid_string: cid.to_string(),
|
2020-05-15 12:29:17 +00:00
|
|
|
b2w_frame_s,
|
|
|
|
b2r_read_shutdown,
|
|
|
|
});
|
|
|
|
b2s_create_channel_done_s.send(()).unwrap();
|
2020-05-04 13:27:58 +00:00
|
|
|
self.metrics
|
|
|
|
.channels_connected_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string])
|
2020-05-04 13:27:58 +00:00
|
|
|
.inc();
|
2020-05-15 12:29:17 +00:00
|
|
|
trace!(?cid, "running channel in participant");
|
|
|
|
channel.run(protocol, w2b_frames_s).await;
|
2020-05-04 13:27:58 +00:00
|
|
|
self.metrics
|
|
|
|
.channels_disconnected_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string])
|
2020-05-04 13:27:58 +00:00
|
|
|
.inc();
|
|
|
|
trace!(?cid, "channel got closed");
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await;
|
2020-05-15 12:29:17 +00:00
|
|
|
trace!("stop create_channel_mgr");
|
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
2020-05-04 13:27:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
async fn open_mgr(
|
2020-03-22 13:47:21 +00:00
|
|
|
&self,
|
2020-05-15 12:29:17 +00:00
|
|
|
mut a2b_steam_open_r: mpsc::UnboundedReceiver<(Prio, Promises, oneshot::Sender<Stream>)>,
|
|
|
|
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
2020-05-22 14:00:08 +00:00
|
|
|
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
2020-05-15 12:29:17 +00:00
|
|
|
shutdown_open_mgr_receiver: oneshot::Receiver<()>,
|
2020-03-22 13:47:21 +00:00
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
|
|
|
trace!("start open_mgr");
|
2020-03-22 13:47:21 +00:00
|
|
|
let mut stream_ids = self.offset_sid;
|
2020-05-24 23:17:03 +00:00
|
|
|
let mut send_cache =
|
|
|
|
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
2020-05-15 12:29:17 +00:00
|
|
|
let mut shutdown_open_mgr_receiver = shutdown_open_mgr_receiver.fuse();
|
2020-04-08 14:26:42 +00:00
|
|
|
//from api or shutdown signal
|
2020-05-15 12:29:17 +00:00
|
|
|
while let Some((prio, promises, p2a_return_stream)) = select! {
|
|
|
|
next = a2b_steam_open_r.next().fuse() => next,
|
|
|
|
_ = shutdown_open_mgr_receiver => None,
|
2020-04-08 14:26:42 +00:00
|
|
|
} {
|
2020-03-22 13:47:21 +00:00
|
|
|
debug!(?prio, ?promises, "got request to open a new steam");
|
2020-05-22 14:00:08 +00:00
|
|
|
let a2p_msg_s = a2p_msg_s.clone();
|
2020-03-22 13:47:21 +00:00
|
|
|
let sid = stream_ids;
|
|
|
|
let stream = self
|
2020-05-22 14:00:08 +00:00
|
|
|
.create_stream(sid, prio, promises, a2p_msg_s, &a2b_close_stream_s)
|
2020-03-22 13:47:21 +00:00
|
|
|
.await;
|
2020-05-24 23:17:03 +00:00
|
|
|
self.send_frame(
|
|
|
|
Frame::OpenStream {
|
|
|
|
sid,
|
|
|
|
prio,
|
|
|
|
promises,
|
|
|
|
},
|
|
|
|
&mut send_cache,
|
|
|
|
)
|
2020-03-22 13:47:21 +00:00
|
|
|
.await;
|
2020-05-15 12:29:17 +00:00
|
|
|
p2a_return_stream.send(stream).unwrap();
|
2020-04-08 14:26:42 +00:00
|
|
|
stream_ids += Sid::from(1);
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
2020-05-15 12:29:17 +00:00
|
|
|
trace!("stop open_mgr");
|
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
/// when activated this function will drop the participant completly and
|
|
|
|
/// wait for everything to go right! Then return 1. Shutting down
|
|
|
|
/// Streams for API and End user! 2. Wait for all "prio queued" Messages
|
|
|
|
/// to be send. 3. Send Stream
|
|
|
|
async fn participant_shutdown_mgr(
|
2020-04-08 14:26:42 +00:00
|
|
|
&self,
|
2020-05-15 12:29:17 +00:00
|
|
|
s2b_shutdown_bparticipant_r: oneshot::Receiver<oneshot::Sender<async_std::io::Result<()>>>,
|
2020-05-22 14:00:08 +00:00
|
|
|
b2b_prios_flushed_r: oneshot::Receiver<()>,
|
2020-04-08 14:26:42 +00:00
|
|
|
mut to_shutdown: Vec<oneshot::Sender<()>>,
|
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
|
|
|
trace!("start participant_shutdown_mgr");
|
|
|
|
let sender = s2b_shutdown_bparticipant_r.await.unwrap();
|
2020-04-08 14:26:42 +00:00
|
|
|
debug!("closing all managers");
|
|
|
|
for sender in to_shutdown.drain(..) {
|
|
|
|
if sender.send(()).is_err() {
|
2020-05-15 12:29:17 +00:00
|
|
|
warn!("manager seems to be closed already, weird, maybe a bug");
|
2020-04-08 14:26:42 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
debug!("closing all streams");
|
2020-05-22 14:00:08 +00:00
|
|
|
for (sid, si) in self.streams.write().await.drain() {
|
2020-04-08 14:26:42 +00:00
|
|
|
trace!(?sid, "shutting down Stream");
|
2020-05-15 12:29:17 +00:00
|
|
|
si.closed.store(true, Ordering::Relaxed);
|
|
|
|
}
|
2020-05-22 14:00:08 +00:00
|
|
|
debug!("waiting for prios to be flushed");
|
|
|
|
b2b_prios_flushed_r.await.unwrap();
|
2020-05-15 12:29:17 +00:00
|
|
|
debug!("closing all channels");
|
|
|
|
for ci in self.channels.write().await.drain(..) {
|
2020-05-26 13:06:03 +00:00
|
|
|
if let Err(e) = ci.b2r_read_shutdown.send(()) {
|
|
|
|
debug!(?e, ?ci.cid, "seems like this read protocol got already dropped by closing the Stream itself, just ignoring the fact");
|
|
|
|
};
|
2020-04-08 14:26:42 +00:00
|
|
|
}
|
2020-05-15 12:29:17 +00:00
|
|
|
//Wait for other bparticipants mgr to close via AtomicUsize
|
|
|
|
const SLEEP_TIME: std::time::Duration = std::time::Duration::from_millis(5);
|
|
|
|
async_std::task::sleep(SLEEP_TIME).await;
|
|
|
|
let mut i: u32 = 1;
|
|
|
|
while self.running_mgr.load(Ordering::Relaxed) > 1 {
|
|
|
|
i += 1;
|
|
|
|
if i.rem_euclid(10) == 1 {
|
|
|
|
trace!(
|
|
|
|
"waiting for bparticipant mgr to shut down, remaining {}",
|
|
|
|
self.running_mgr.load(Ordering::Relaxed) - 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
async_std::task::sleep(SLEEP_TIME * i).await;
|
|
|
|
}
|
|
|
|
trace!("all bparticipant mgr (except me) are shut down now");
|
2020-04-24 10:56:04 +00:00
|
|
|
self.metrics.participants_disconnected_total.inc();
|
2020-05-15 12:29:17 +00:00
|
|
|
sender.send(Ok(())).unwrap();
|
|
|
|
trace!("stop participant_shutdown_mgr");
|
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
2020-04-08 14:26:42 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
async fn stream_close_mgr(
|
2020-04-08 14:26:42 +00:00
|
|
|
&self,
|
2020-05-15 12:29:17 +00:00
|
|
|
mut a2b_close_stream_r: mpsc::UnboundedReceiver<Sid>,
|
|
|
|
shutdown_stream_close_mgr_receiver: oneshot::Receiver<()>,
|
2020-05-26 13:06:03 +00:00
|
|
|
b2p_notify_empty_stream_s: std::sync::mpsc::Sender<(Sid, oneshot::Sender<()>)>,
|
2020-04-08 14:26:42 +00:00
|
|
|
) {
|
2020-05-15 12:29:17 +00:00
|
|
|
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
|
|
|
trace!("start stream_close_mgr");
|
2020-05-24 23:17:03 +00:00
|
|
|
let mut send_cache =
|
|
|
|
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
2020-05-15 12:29:17 +00:00
|
|
|
let mut shutdown_stream_close_mgr_receiver = shutdown_stream_close_mgr_receiver.fuse();
|
|
|
|
|
2020-04-08 14:26:42 +00:00
|
|
|
//from api or shutdown signal
|
|
|
|
while let Some(sid) = select! {
|
2020-05-15 12:29:17 +00:00
|
|
|
next = a2b_close_stream_r.next().fuse() => next,
|
|
|
|
_ = shutdown_stream_close_mgr_receiver => None,
|
2020-04-08 14:26:42 +00:00
|
|
|
} {
|
2020-05-15 12:29:17 +00:00
|
|
|
//TODO: make this concurrent!
|
|
|
|
//TODO: Performance, closing is slow!
|
2020-04-08 14:26:42 +00:00
|
|
|
trace!(?sid, "got request from api to close steam");
|
2020-05-15 12:29:17 +00:00
|
|
|
//This needs to first stop clients from sending any more.
|
|
|
|
//Then it will wait for all pending messages (in prio) to be send to the
|
|
|
|
// protocol After this happened the stream is closed
|
|
|
|
//Only after all messages are send to the prococol, we can send the CloseStream
|
|
|
|
// frame! If we would send it before, all followup messages couldn't
|
|
|
|
// be handled at the remote side.
|
2020-04-08 14:26:42 +00:00
|
|
|
|
2020-05-15 12:29:17 +00:00
|
|
|
trace!(?sid, "stopping api to use this stream");
|
|
|
|
self.streams
|
|
|
|
.read()
|
2020-04-08 14:26:42 +00:00
|
|
|
.await
|
2020-05-15 12:29:17 +00:00
|
|
|
.get(&sid)
|
|
|
|
.unwrap()
|
|
|
|
.closed
|
|
|
|
.store(true, Ordering::Relaxed);
|
|
|
|
|
|
|
|
trace!(?sid, "wait for stream to be flushed");
|
|
|
|
let (s2b_stream_finished_closed_s, s2b_stream_finished_closed_r) = oneshot::channel();
|
2020-05-26 13:06:03 +00:00
|
|
|
b2p_notify_empty_stream_s
|
2020-05-22 14:00:08 +00:00
|
|
|
.send((sid, s2b_stream_finished_closed_s))
|
2020-04-08 14:26:42 +00:00
|
|
|
.unwrap();
|
2020-05-15 12:29:17 +00:00
|
|
|
s2b_stream_finished_closed_r.await.unwrap();
|
|
|
|
|
2020-04-08 14:26:42 +00:00
|
|
|
trace!(?sid, "stream was successfully flushed");
|
2020-04-24 10:56:04 +00:00
|
|
|
self.metrics
|
|
|
|
.streams_closed_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string])
|
2020-04-24 10:56:04 +00:00
|
|
|
.inc();
|
2020-05-15 12:29:17 +00:00
|
|
|
//only now remove the Stream, that means we can still recv on it.
|
2020-03-22 13:47:21 +00:00
|
|
|
self.streams.write().await.remove(&sid);
|
2020-05-24 23:17:03 +00:00
|
|
|
self.send_frame(Frame::CloseStream { sid }, &mut send_cache)
|
|
|
|
.await;
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
2020-05-15 12:29:17 +00:00
|
|
|
trace!("stop stream_close_mgr");
|
|
|
|
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
2020-03-22 13:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn create_stream(
|
|
|
|
&self,
|
|
|
|
sid: Sid,
|
|
|
|
prio: Prio,
|
|
|
|
promises: Promises,
|
2020-05-22 14:00:08 +00:00
|
|
|
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutGoingMessage)>,
|
2020-05-15 12:29:17 +00:00
|
|
|
a2b_close_stream_s: &mpsc::UnboundedSender<Sid>,
|
2020-03-22 13:47:21 +00:00
|
|
|
) -> Stream {
|
2020-05-15 12:29:17 +00:00
|
|
|
let (b2a_msg_recv_s, b2a_msg_recv_r) = mpsc::unbounded::<InCommingMessage>();
|
2020-04-08 14:26:42 +00:00
|
|
|
let closed = Arc::new(AtomicBool::new(false));
|
2020-05-15 12:29:17 +00:00
|
|
|
self.streams.write().await.insert(sid, StreamInfo {
|
|
|
|
prio,
|
|
|
|
promises,
|
|
|
|
b2a_msg_recv_s,
|
|
|
|
closed: closed.clone(),
|
|
|
|
});
|
2020-04-24 10:56:04 +00:00
|
|
|
self.metrics
|
|
|
|
.streams_opened_total
|
2020-05-24 23:17:03 +00:00
|
|
|
.with_label_values(&[&self.remote_pid_string])
|
2020-04-24 10:56:04 +00:00
|
|
|
.inc();
|
2020-03-22 13:47:21 +00:00
|
|
|
Stream::new(
|
|
|
|
self.remote_pid,
|
|
|
|
sid,
|
|
|
|
prio,
|
|
|
|
promises,
|
2020-05-15 12:29:17 +00:00
|
|
|
a2p_msg_s,
|
|
|
|
b2a_msg_recv_r,
|
2020-04-08 14:26:42 +00:00
|
|
|
closed.clone(),
|
2020-05-15 12:29:17 +00:00
|
|
|
a2b_close_stream_s.clone(),
|
2020-03-22 13:47:21 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|