use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
use std::sync::atomic::AtomicBool;
use std::net::SocketAddr;
use rand::Rng;
use rand::seq::SliceRandom;
use std::error::Error;
use std::sync::mpsc::Receiver;
use std::collections::{HashSet, VecDeque};
use std::iter::FromIterator;
use crate::PeerSamplingConfig;
use crate::peer::Peer;
use crate::message::sampling::PeerSamplingMessage;
use crate::message::{NoopMessage, MessageType};
pub struct PeerSamplingService {
address: SocketAddr,
config: PeerSamplingConfig,
view: Arc<Mutex<View>>,
thread_handles: Vec<JoinHandle<()>>,
shutdown: Arc<AtomicBool>,
}
impl PeerSamplingService {
pub fn new(address: SocketAddr, config: PeerSamplingConfig) -> PeerSamplingService {
PeerSamplingService {
address,
view: Arc::new(Mutex::new(View::new(address.to_string()))),
config,
thread_handles: Vec::new(),
shutdown: Arc::new(AtomicBool::new(false)),
}
}
pub fn init(&mut self, initial_peer: Box<dyn FnOnce() -> Option<Vec<Peer>>>, receiver: Receiver<PeerSamplingMessage>) {
if let Some(initial_peers) = initial_peer() {
let mut view = self.view.lock().unwrap();
for peer in initial_peers {
if peer.address() != &self.address.to_string() {
view.peers.push(peer);
}
}
}
let receiver_handle = self.start_receiver(receiver);
self.thread_handles.push(receiver_handle);
let sampling_handle = self.start_sampling_activity();
self.thread_handles.push(sampling_handle);
log::info!("All activity threads were started");
}
pub fn get_peer(&mut self) -> Option<Peer> {
self.view.lock().unwrap().get_peer()
}
pub fn peers(&self) -> Vec<Peer> {
self.view.lock().unwrap()
.peers.iter().map(|peer| peer.clone())
.collect()
}
pub fn shutdown(&mut self) -> Result<(), Box<dyn Error>> {
self.shutdown.store(true, std::sync::atomic::Ordering::SeqCst);
{
let guard = self.view.lock().unwrap();
crate::network::send(&guard.host_address.parse()?, Box::new(NoopMessage))?;
}
let handles = self.thread_handles.drain(..);
let mut join_error = false;
for handle in handles {
if let Err(e) = handle.join() {
log::error!("Error joining thread: {:?}", e);
join_error = true;
}
}
log::info!("All activity threads were stopped");
if join_error {
Err("An error occurred during thread joining")?
}
else {
Ok(())
}
}
fn build_buffer(address: String, config: &PeerSamplingConfig, view: &mut View) -> Vec<Peer> {
let mut buffer = vec![ Peer::new(address) ];
view.permute();
view.move_oldest_to_end(config.healing_factor());
buffer.append(&mut view.head(config.view_size()));
buffer
}
fn start_receiver(&self, receiver: Receiver<PeerSamplingMessage>) -> JoinHandle<()>{
let address = self.address.to_string();
let sampling_config = self.config.clone();
let view_arc = self.view.clone();
std::thread::Builder::new().name(format!("{} - gbps receiver", &address)).spawn(move|| {
log::info!("Started message handling thread");
while let Ok(message) = receiver.recv() {
log::debug!("Received: {:?}", message);
let mut view = view_arc.lock().unwrap();
if let MessageType::Request = message.message_type() {
if sampling_config.is_pull() {
let buffer = Self::build_buffer(address.clone(), &sampling_config, &mut view);
log::debug!("Built response buffer: {:?}", buffer);
if let Ok(remote_address) = message.sender().parse::<SocketAddr>() {
match crate::network::send(&remote_address, Box::new(PeerSamplingMessage::new_response(address.clone(), Some(buffer)))) {
Ok(written) => log::trace!("Buffer sent successfully ({} bytes)", written),
Err(e) => log::error!("Error sending buffer: {}", e),
}
}
else {
log::error!("Could not parse sender address {}", &message.sender());
}
}
}
if let Some(buffer) = message.view() {
view.select(sampling_config.view_size(), sampling_config.healing_factor(), sampling_config.swapping_factor(), &buffer);
}
else {
log::warn!("received a response with an empty buffer");
}
view.increase_age();
}
log::info!("Message handling thread exiting");
}).unwrap()
}
fn start_sampling_activity(&self) -> JoinHandle<()> {
let address = self.address.to_string();
let config = self.config.clone();
let view_arc = self.view.clone();
let shutdown_requested = Arc::clone(&self.shutdown);
std::thread::Builder::new().name(format!("{} - gbps sampling", address)).spawn(move || {
log::info!("Started peer sampling thread");
loop {
let deviation =
if config.sampling_deviation() == 0 { 0 }
else { rand::thread_rng().gen_range(0, config.sampling_deviation()) };
let sleep_time = config.sampling_period() + deviation;
std::thread::sleep(std::time::Duration::from_millis(sleep_time));
let mut view = view_arc.lock().unwrap();
if let Some(peer) = view.select_peer() {
if config.is_push() {
let buffer = Self::build_buffer(address.clone(), &config, &mut view);
if let Ok(remote_address) = &peer.address().parse::<SocketAddr>() {
match crate::network::send(remote_address, Box::new(PeerSamplingMessage::new_request(address.clone(), Some(buffer)))) {
Ok(written) => log::trace!("Buffer sent successfully ({} bytes)", written),
Err(e) => log::error!("Error sending buffer: {}", e),
}
}
else {
log::error!("Could not parse sender address {}", &peer.address());
}
}
else {
if let Ok(remote_address) = &peer.address().parse::<SocketAddr>() {
match crate::network::send(remote_address, Box::new(PeerSamplingMessage::new_request(address.clone(), None))) {
Ok(written) => log::trace!("Empty view sent successfully ({} bytes)", written),
Err(e) => log::error!("Error sending empty view: {}", e),
}
}
else {
log::error!("Could not parse sender address {}", &peer.address());
}
}
view.increase_age();
}
else {
log::warn!("No peer found for sampling")
}
if shutdown_requested.load(std::sync::atomic::Ordering::SeqCst) {
break;
}
}
log::info!("Peer sampling thread exiting");
}).unwrap()
}
}
struct View {
host_address: String,
peers: Vec<Peer>,
queue: VecDeque<Peer>,
}
impl View {
fn new(host_address: String) -> View {
View {
host_address,
peers: vec![],
queue: VecDeque::new(),
}
}
fn select_peer(&self) -> Option<Peer> {
if self.peers.is_empty() {
None
}
else {
let selected_peer = rand::thread_rng().gen_range(0, self.peers.len());
Some(self.peers[selected_peer].clone())
}
}
fn permute(&mut self) {
self.peers.shuffle(&mut rand::thread_rng());
}
fn move_oldest_to_end(&mut self, h: usize) {
if self.peers.len() > h {
let mut h_oldest_peers = self.peers.clone();
h_oldest_peers.sort_by_key(|peer| peer.age());
h_oldest_peers.reverse();
h_oldest_peers.truncate(h); let mut new_view_start = vec![];
let mut new_view_end = vec![];
for peer in &self.peers {
if h_oldest_peers.contains(&peer) {
new_view_end.push(peer.clone());
}
else {
new_view_start.push(peer.clone());
}
}
new_view_start.append(&mut new_view_end);
std::mem::replace(&mut self.peers, new_view_start);
}
}
fn head(&self, c: usize) -> Vec<Peer> {
let count = std::cmp::min(c / 2 - 1, self.peers.len());
let mut head = Vec::new();
for i in 0..count {
head.push(self.peers[i].clone());
}
head
}
fn increase_age(&mut self) {
for peer in self.peers.iter_mut() {
peer.increment_age();
}
}
fn select(&mut self, c:usize, h: usize, s: usize, buffer: &Vec<Peer>) {
let my_address = self.host_address.clone();
buffer.iter()
.filter(|peer| peer.address() != my_address)
.for_each(|peer| self.peers.push(peer.clone()));
self.remove_duplicates();
self.remove_old_items(c, h);
self.remove_head(c, s);
self.remove_at_random(c);
self.update_queue();
}
fn remove_duplicates(&mut self) {
let mut unique_peers: HashSet<Peer> = HashSet::new();
self.peers.iter().for_each(|peer| {
if let Some(entry) = unique_peers.get(peer) {
if peer.age() < entry.age() {
unique_peers.replace(peer.clone());
}
}
else {
unique_peers.insert(peer.clone());
}
});
let new_view = Vec::from_iter(unique_peers);
std::mem::replace(&mut self.peers, new_view);
}
fn remove_old_items(&mut self, c: usize, h: usize) {
let min = if self.peers.len() > c { self.peers.len() - c } else { 0 };
let removal_count = std::cmp::min(h, min);
if removal_count > 0 {
let mut kept_peers = self.peers.clone();
kept_peers.sort_by_key(|peer| peer.age());
kept_peers.truncate(kept_peers.len() - removal_count);
let mut new_view = vec![];
for peer in &self.peers {
if kept_peers.contains(&peer) {
new_view.push(peer.clone());
}
}
std::mem::replace(&mut self.peers, new_view);
}
}
fn remove_head(&mut self, c: usize, s: usize) {
let min = if self.peers.len() > c { self.peers.len() - c } else { 0 };
let removal_count = std::cmp::min(s, min);
self.peers.drain(0..removal_count);
}
fn remove_at_random(&mut self, c: usize) {
if self.peers.len() > c {
for _ in 0..(self.peers.len() - c) {
let remove_index = rand::thread_rng().gen_range(0, self.peers.len());
self.peers.remove(remove_index);
}
}
}
fn update_queue(&mut self) {
let removed_peers = self.queue.iter().enumerate()
.filter(|(_, peer)| !self.peers.contains(peer))
.map(|(index, _)| index)
.collect::<Vec<usize>>();
let added_peers = self.peers.iter()
.filter(|peer| !self.queue.contains(peer))
.map(|peer| peer.to_owned())
.collect::<Vec<Peer>>();
removed_peers.iter().rev().for_each(|index| { self.queue.remove(*index); });
for peer in added_peers {
self.queue.push_back(peer);
}
}
pub fn get_peer(&mut self) -> Option<Peer> {
if let Some(peer) = self.queue.pop_front() {
Some(peer)
}
else {
self.select_peer()
}
}
}