// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
//! Round-robin buffer for incoming messages.
//!
//! This takes batches of messages associated with a sender as input,
//! and yields messages in a fair order by sender.
use std::collections::{Bound, BTreeMap, VecDeque};
use futures::prelude::*;
use futures::stream::Fuse;
/// Implementation of the round-robin buffer for incoming messages.
#[derive(Debug)]
pub struct RoundRobinBuffer {
buffer: BTreeMap>,
last_processed_from: Option,
stored_messages: usize,
max_messages: usize,
inner: Fuse,
}
impl RoundRobinBuffer {
/// Create a new round-robin buffer which holds up to a maximum
/// amount of messages.
pub fn new(stream: S, buffer_size: usize) -> Self {
RoundRobinBuffer {
buffer: BTreeMap::new(),
last_processed_from: None,
stored_messages: 0,
max_messages: buffer_size,
inner: stream.fuse(),
}
}
}
impl RoundRobinBuffer {
fn next_message(&mut self) -> Option<(V, M)> {
if self.stored_messages == 0 {
return None
}
// first pick up from the last authority we processed a message from
let mut next = {
let lower_bound = match self.last_processed_from {
None => Bound::Unbounded,
Some(ref x) => Bound::Excluded(x.clone()),
};
self.buffer.range_mut((lower_bound, Bound::Unbounded))
.filter_map(|(k, v)| v.pop_front().map(|v| (k.clone(), v)))
.next()
};
// but wrap around to the beginning again if we got nothing.
if next.is_none() {
next = self.buffer.iter_mut()
.filter_map(|(k, v)| v.pop_front().map(|v| (k.clone(), v)))
.next();
}
if let Some((ref authority, _)) = next {
self.stored_messages -= 1;
self.last_processed_from = Some(authority.clone());
}
next
}
// import messages, discarding when the buffer is full.
fn import_messages(&mut self, sender: V, messages: Vec) {
let space_remaining = self.max_messages - self.stored_messages;
self.stored_messages += ::std::cmp::min(space_remaining, messages.len());
let v = self.buffer.entry(sender).or_insert_with(VecDeque::new);
v.extend(messages.into_iter().take(space_remaining));
}
}
impl Stream for RoundRobinBuffer
where S: Stream)>
{
type Item = (V, M);
type Error = S::Error;
fn poll(&mut self) -> Poll