use crate::connection::path::PathMap;
use crate::connection::space::PacketNumSpaceMap;
use crate::connection::stream::StreamMap;
use crate::multipath_scheduler::MultipathScheduler;
use crate::Error;
use crate::MultipathConfig;
use crate::Path;
use crate::Result;
pub struct RoundRobinScheduler {
last: Option<usize>,
}
impl RoundRobinScheduler {
pub fn new(_conf: &MultipathConfig) -> RoundRobinScheduler {
RoundRobinScheduler { last: None }
}
}
impl RoundRobinScheduler {
fn find_last(&self, iter: &mut slab::IterMut<Path>, last: usize) -> bool {
for (pid, _) in iter.by_ref() {
if pid != last {
continue;
}
return true;
}
false
}
fn select(&mut self, iter: &mut slab::IterMut<Path>) -> Option<usize> {
for (pid, path) in iter.by_ref() {
if !path.active() || !path.recovery.can_send() {
continue;
}
self.last = Some(pid);
return Some(pid);
}
None
}
}
impl MultipathScheduler for RoundRobinScheduler {
fn on_select(
&mut self,
paths: &mut PathMap,
spaces: &mut PacketNumSpaceMap,
streams: &mut StreamMap,
) -> Result<usize> {
let mut iter = paths.iter_mut();
let mut exist_last = false;
if let Some(last) = self.last {
if self.find_last(&mut iter, last) {
exist_last = true;
} else {
iter = paths.iter_mut();
}
}
if let Some(pid) = self.select(&mut iter) {
return Ok(pid);
}
if !exist_last {
return Err(Error::Done);
}
let mut iter = paths.iter_mut();
if let Some(pid) = self.select(&mut iter) {
return Ok(pid);
}
Err(Error::Done)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::multipath_scheduler::tests::*;
#[test]
fn round_robin_single_available_path() -> Result<()> {
let mut t = MultipathTester::new()?;
let mut s = RoundRobinScheduler::new(&MultipathConfig::default());
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 0);
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 0);
Ok(())
}
#[test]
fn round_robin_multi_available_path() -> Result<()> {
let mut t = MultipathTester::new()?;
t.add_path("127.0.0.1:443", "127.0.0.2:8443", 50)?;
t.add_path("127.0.0.1:443", "127.0.0.3:8443", 150)?;
t.add_path("127.0.0.1:443", "127.0.0.4:8443", 100)?;
let mut s = RoundRobinScheduler::new(&MultipathConfig::default());
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 0);
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 1);
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 2);
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 3);
t.set_path_active(1, false)?;
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 0);
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 2);
t.set_path_active(3, false)?;
assert_eq!(s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams)?, 0);
Ok(())
}
#[test]
fn round_robin_no_available_path() -> Result<()> {
let mut t = MultipathTester::new()?;
t.set_path_active(0, false)?;
let mut s = RoundRobinScheduler::new(&MultipathConfig::default());
assert_eq!(
s.on_select(&mut t.paths, &mut t.spaces, &mut t.streams),
Err(Error::Done)
);
Ok(())
}
}