use std::collections::HashSet;
use agp_datapath::pubsub::proto::pubsub::v1::Message;
use tracing::{debug, info, trace};
pub(crate) struct ReceiverBuffer {
last_sent: usize,
first_entry: usize,
lost_msgs: HashSet<usize>,
buffer: Vec<Option<Message>>,
}
impl Default for ReceiverBuffer {
fn default() -> Self {
ReceiverBuffer {
last_sent: usize::MAX,
first_entry: 0,
lost_msgs: HashSet::new(),
buffer: vec![],
}
}
}
impl ReceiverBuffer {
pub fn on_received_message(&mut self, msg: Message) -> (Vec<Option<Message>>, Vec<u32>) {
self.internal_on_received_message(msg.get_id() as usize, Some(msg))
}
pub fn on_lost_message(&mut self, msg_id: u32) -> Vec<Option<Message>> {
debug!("message {} is definitely lost", msg_id);
self.lost_msgs.insert(msg_id as usize);
self.release_msgs()
}
pub fn on_beacon_message(&mut self, msg_id: u32) -> Vec<u32> {
debug!("received beacon for msg {}", msg_id);
let (_recv, rtx) = self.internal_on_received_message(msg_id as usize, None);
rtx
}
fn internal_on_received_message(
&mut self,
msg_id: usize,
msg: Option<Message>,
) -> (Vec<Option<Message>>, Vec<u32>) {
debug!("Received message id {}", msg_id);
if self.last_sent == usize::MAX
|| (msg_id == (self.last_sent + 1)) && (self.buffer.is_empty())
{
match msg {
Some(m) => {
debug!("No loss detected, return message {}", msg_id);
self.last_sent = msg_id;
return (vec![Some(m)], vec![]);
}
None => {
return (vec![], vec![msg_id as u32]);
}
}
}
if msg_id <= self.last_sent {
debug!("Received possibly DUP message or beacon for a received message, drop it");
return (vec![], vec![]);
}
if self.buffer.is_empty() {
self.first_entry = 0;
let mut rtx: Vec<u32> = Vec::new();
match msg {
Some(m) => {
self.buffer = vec![None; msg_id - (self.last_sent + 1)];
debug!("Losses found, missing {} packets", self.buffer.len());
self.buffer.push(Some(m));
for i in (self.last_sent + 1)..(msg_id) {
trace!("add {} to rtx vector", i);
rtx.push(i as u32);
}
}
None => {
self.buffer = vec![None; msg_id - (self.last_sent + 1) + 1];
debug!("Losses found, missing {} packets", self.buffer.len());
for i in (self.last_sent + 1)..=(msg_id) {
trace!("add {} to rtx vector", i);
rtx.push(i as u32);
}
}
}
(vec![], rtx)
} else {
debug!(
"buffer is not empty and received OOO packet {}, process it",
msg_id
);
trace!(
"buffer status: last sent {}, first entry {}, len {}",
self.last_sent,
self.first_entry,
self.buffer.len()
);
if msg_id <= (self.last_sent + (self.buffer.len() - self.first_entry)) {
debug!(
"message {} is inside the buffer range {} - {}",
msg_id,
(self.last_sent + 1),
(self.buffer.len() - self.first_entry)
);
if msg.is_none() {
return (vec![], vec![]);
}
let pos = msg_id - (self.last_sent + 1) + self.first_entry;
debug!("try to insert message {} at pos {}", msg_id, pos);
if self.buffer[pos].is_some() {
info!("Received DUP message, drop it");
return (vec![], vec![]);
}
debug!(
"add message {} at pos {} and try to release msgs",
msg_id, pos
);
self.buffer[pos] = msg;
(self.release_msgs(), vec![])
} else {
let mut rtx = Vec::new();
for i in ((self.last_sent + 1) + (self.buffer.len() - self.first_entry))..msg_id {
self.buffer.push(None);
rtx.push(i as u32);
debug!("detect packet loss {} to add at the end of the buffer", i);
}
match msg {
Some(m) => {
debug!("add packet {} at the end of the buffer", msg_id);
self.buffer.push(Some(m));
}
None => {
rtx.push(msg_id as u32)
}
}
(vec![], rtx)
}
}
}
fn release_msgs(&mut self) -> Vec<Option<Message>> {
let mut i = self.first_entry;
let mut ret = vec![];
while i < self.buffer.len() {
if self.buffer[i].is_some() {
ret.push(self.buffer[i].take());
self.last_sent += 1;
self.first_entry += 1;
debug!(
"return message at pos {}, new buffer state: last_sent {}, first_index {}",
i, self.last_sent, self.first_entry
);
} else {
if self.lost_msgs.contains(&(self.last_sent + 1)) {
ret.push(None);
self.lost_msgs.remove(&(self.last_sent + 1));
self.last_sent += 1;
self.first_entry += 1;
debug!(
"message {} is lost, return none, new buffer state: last_sent {}, first_index {}",
self.last_sent, self.last_sent, self.first_entry
);
} else {
break;
}
}
i += 1;
}
if self.first_entry == self.buffer.len() {
debug!("clean reception buffer which is empty now");
self.first_entry = 0;
self.buffer = vec![];
}
let mut stop = false;
while !stop {
if self.lost_msgs.contains(&(self.last_sent + 1)) {
self.last_sent += 1;
ret.push(None);
self.lost_msgs.remove(&(self.last_sent));
debug!(
"found another lost message to release, last_sent {}",
self.last_sent
);
} else {
stop = true;
}
}
ret
}
}
#[cfg(test)]
mod tests {
use agp_datapath::messages::encoder::{Agent, AgentType};
use agp_datapath::pubsub::proto::pubsub::v1::SessionHeaderType;
use agp_datapath::pubsub::{AgpHeader, SessionHeader};
use tracing_test::traced_test;
use super::*;
#[test]
#[traced_test]
fn test_receiver_buffer() {
let src = Agent::from_strings("org", "ns", "type", 0);
let name_type = AgentType::from_strings("org", "ns", "type");
let agp_header = AgpHeader::new(&src, &name_type, Some(1), None);
let h0 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 0);
let h1 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 1);
let h2 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 2);
let h3 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 3);
let h4 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 4);
let h5 = SessionHeader::new(SessionHeaderType::Fnf.into(), 0, 5);
let p0 = Message::new_publish_with_headers(Some(agp_header), Some(h0), "", vec![]);
let p1 = Message::new_publish_with_headers(Some(agp_header), Some(h1), "", vec![]);
let p2 = Message::new_publish_with_headers(Some(agp_header), Some(h2), "", vec![]);
let p3 = Message::new_publish_with_headers(Some(agp_header), Some(h3), "", vec![]);
let p4 = Message::new_publish_with_headers(Some(agp_header), Some(h4), "", vec![]);
let p5 = Message::new_publish_with_headers(Some(agp_header), Some(h5), "", vec![]);
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p0.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p0.clone()));
let (recv, rtx) = buffer.on_received_message(p1.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p1.clone()));
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p2.clone()));
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p3.clone()));
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p4.clone()));
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p2.clone()));
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p3.clone()));
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p4.clone()));
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p4.clone()));
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p0.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p1.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p1.clone()));
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 2);
assert_eq!(rtx[0], 2);
assert_eq!(rtx[1], 3);
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p2.clone()));
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 2);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p3.clone()));
assert_eq!(recv[1], Some(p4.clone()));
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p0.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p0.clone()));
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 1);
assert_eq!(rtx[0], 1);
let (recv, rtx) = buffer.on_received_message(p5.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 2);
assert_eq!(rtx[0], 3);
assert_eq!(rtx[1], 4);
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p1.clone());
assert_eq!(recv.len(), 5);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p1.clone()));
assert_eq!(recv[1], Some(p2.clone()));
assert_eq!(recv[2], Some(p3.clone()));
assert_eq!(recv[3], Some(p4.clone()));
assert_eq!(recv[4], Some(p5.clone()));
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p0.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p0.clone()));
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 1);
assert_eq!(rtx[0], 1);
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 1);
assert_eq!(rtx[0], 3);
let recv = buffer.on_lost_message(1);
assert_eq!(recv.len(), 2);
assert_eq!(recv[0], None);
assert_eq!(recv[1], Some(p2.clone()));
let recv = buffer.on_lost_message(5);
assert_eq!(recv.len(), 0);
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 3);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p3.clone()));
assert_eq!(recv[1], Some(p4.clone()));
assert_eq!(recv[2], None);
let mut buffer = ReceiverBuffer::default();
let (recv, rtx) = buffer.on_received_message(p0.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p0.clone()));
let rtx = buffer.on_beacon_message(2);
assert_eq!(rtx.len(), 2);
assert_eq!(rtx[0], 1);
assert_eq!(rtx[1], 2);
let rtx = buffer.on_beacon_message(1);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p2.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p1.clone());
assert_eq!(recv.len(), 2);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p1.clone()));
assert_eq!(recv[1], Some(p2.clone()));
let (recv, rtx) = buffer.on_received_message(p4.clone());
assert_eq!(recv.len(), 0);
assert_eq!(rtx.len(), 1);
assert_eq!(rtx[0], 3);
let rtx = buffer.on_beacon_message(3);
assert_eq!(rtx.len(), 0);
let (recv, rtx) = buffer.on_received_message(p3.clone());
assert_eq!(recv.len(), 2);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p3.clone()));
assert_eq!(recv[1], Some(p4.clone()));
let (recv, rtx) = buffer.on_received_message(p5.clone());
assert_eq!(recv.len(), 1);
assert_eq!(rtx.len(), 0);
assert_eq!(recv[0], Some(p5.clone()));
}
}