use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use bincode::options;
use bytes::{BufMut, Bytes, BytesMut};
use futures::Stream;
use hydroflow::compiled::pull::HalfMultisetJoinState;
use hydroflow::hydroflow_syntax;
use hydroflow::scheduled::ticks::TickInstant;
use hydroflow_lang::graph::{WriteConfig, WriteGraphType};
use lattices::map_union::{MapUnionHashMap, MapUnionSingletonMap};
use lattices::set_union::SetUnionSingletonSet;
use lattices::{Max, Point, WithBot};
use rand::{Rng, SeedableRng};
use serde::de::DeserializeSeed;
use serde::Serialize;
use tokio::task;
use tokio_stream::StreamExt;
use crate::buffer_pool::BufferPool;
use crate::protocol::{
KvsRequest, KvsRequestDeserializer, KvsResponse, MyLastWriteWins, MySetUnion, NodeId,
};
use crate::Topology;
pub fn run_server<RX>(
server_id: usize,
topology: Topology<RX>,
dist: f64,
throughput: Arc<AtomicUsize>,
write_graph: Option<WriteGraphType>,
write_config: Option<WriteConfig>,
) where
RX: Stream<Item = (usize, Bytes)> + StreamExt + Unpin + Send + 'static,
{
std::thread::spawn(move || {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async {
const BUFFER_SIZE: usize = 1024;
let buffer_pool = BufferPool::<BUFFER_SIZE>::create_buffer_pool();
let (transducer_to_peers_tx, mut transducer_to_peers_rx) =
hydroflow::util::unsync_channel::<(Bytes, NodeId)>(None);
let (client_to_transducer_tx, client_to_transducer_rx) =
hydroflow::util::unsync_channel::<(KvsRequest<BUFFER_SIZE>, NodeId)>(None);
let (transducer_to_client_tx, mut _transducer_to_client_rx) =
hydroflow::util::unsync_channel::<(KvsResponse<BUFFER_SIZE>, NodeId)>(None);
let localset = task::LocalSet::new();
let inbound_networking_task = localset.run_until({
let buffer_pool = buffer_pool.clone();
async {
task::spawn_local({
async move {
let mut joined_streams = futures::stream::select_all(topology.rx);
while let Some((node_id, req)) = joined_streams.next().await {
let mut deserializer = bincode::Deserializer::from_slice(&req, options());
let req = KvsRequestDeserializer {
collector: Rc::clone(&buffer_pool),
}.deserialize(&mut deserializer).unwrap();
client_to_transducer_tx.try_send((req, node_id)).unwrap();
}
}
})
.await
.unwrap()
}});
let outbound_networking_task = localset.run_until({
let lookup = topology.lookup.clone();
async move {
loop {
while let Some((serialized_req, node_id)) = transducer_to_peers_rx.next().await {
let index = lookup.binary_search(&node_id).unwrap();
topology.tx[index].send(serialized_req).unwrap();
}
}
}
});
let relatively_recent_timestamp: &'static _ = &*Box::leak(Box::new(std::sync::atomic::AtomicU64::new(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64)));
let f3 = localset.run_until({
async move {
let mut interval = tokio::time::interval(
Duration::from_millis(100),
);
loop {
interval.tick().await;
relatively_recent_timestamp.store(std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64,
Ordering::Relaxed);
}
}
});
let mut rng = rand::rngs::SmallRng::from_entropy();
let dist = rand_distr::Zipf::new(1_000_000, dist).unwrap();
let mut pre_gen_index = 0;
let pre_gen_random_numbers: Vec<u64> = (0..(128*1024)).map(|_| rng.sample(dist) as u64).collect();
let create_unique_id = move |server_id: u128, tick: TickInstant, e: u128| -> u128 {
assert!(tick < TickInstant(1_000_000_000));
assert!(e < 1_000_000_000);
(relatively_recent_timestamp.load(Ordering::Relaxed) as u128)
.checked_mul(100).unwrap()
.checked_add(server_id).unwrap()
.checked_mul(1_000_000_000).unwrap()
.checked_add(tick.0 as u128).unwrap()
.checked_mul(1_000_000_000).unwrap()
.checked_add(e).unwrap()
};
let mut throughput_internal = 0usize;
let mut df = hydroflow_syntax! {
simulated_put_requests = spin() -> flat_map(|_| {
let buffer_pool = buffer_pool.clone();
let pre_gen_random_numbers = &pre_gen_random_numbers;
std::iter::repeat_with(move || {
let value = BufferPool::get_from_buffer_pool(&buffer_pool);
// Did the original C++ benchmark do anything with the data..?
// Can uncomment this to modify the buffers then.
//
// let mut borrow = buff.borrow_mut().unwrap();
// let mut r = rng.sample(dist_uniform) as u64;
// for i in 0..8 {
// borrow[i] = (r % 256) as u8;
// r /= 256;
// }
let key = pre_gen_random_numbers[pre_gen_index % pre_gen_random_numbers.len()];
pre_gen_index += 1;
(KvsRequest::Put {
key,
value,
}, 99999999)
})
});
union_puts_and_gossip_requests = union();
simulated_put_requests -> union_puts_and_gossip_requests;
source_stream(client_to_transducer_rx)
-> union_puts_and_gossip_requests;
client_input = union_puts_and_gossip_requests
-> enumerate::<'tick>()
-> demux(|(e, (req, addr)): (usize, (KvsRequest<BUFFER_SIZE>, NodeId)), var_args!(gets, store, broadcast)| {
match req {
KvsRequest::Put {key, value} => {
throughput_internal += 1;
const GATE: usize = 2 * 1024;
if throughput_internal % GATE == 0 {
throughput.fetch_add(GATE, Ordering::SeqCst);
}
let marker = create_unique_id(server_id as u128, context.current_tick(), e as u128);
broadcast.give((key, MyLastWriteWins::new(
Max::new(marker),
WithBot::new_from(Point::new(value.clone())),
)));
store.give((key, MyLastWriteWins::new(
Max::new(marker),
WithBot::new_from(Point::new(value)),
)));
},
KvsRequest::Gossip {map} => {
for (key, reg) in map.into_reveal() {
store.give((key, reg));
}
},
KvsRequest::Get {key} => gets.give((key, addr)),
KvsRequest::Delete {key} => {
let marker = create_unique_id(server_id as u128, context.current_tick(), e as u128);
broadcast.give((key, MyLastWriteWins::new(
Max::new(marker),
WithBot::default(),
)));
store.give((key, MyLastWriteWins::new(
Max::new(marker),
WithBot::default(),
)));
}
}
});
peers = cross_join::<'static, 'tick, HalfMultisetJoinState>();
source_iter(topology.lookup) -> [0]peers;
ticker = source_interval(Duration::from_millis(100))
-> [signal]batcher;
client_input[broadcast]
-> map(|(key, reg)| MapUnionSingletonMap::new_from((key, reg)))
-> [input]batcher;
batcher = _lattice_fold_batch::<MapUnionHashMap<_, _>>()
-> map(|lattice| {
use bincode::Options;
let serialization_options = options();
let req = KvsRequest::Gossip { map: lattice };
let mut serialized = BytesMut::with_capacity(serialization_options.serialized_size(&req).unwrap() as usize);
let mut serializer = bincode::Serializer::new((&mut serialized).writer(), options());
Serialize::serialize(&req, &mut serializer).unwrap();
serialized.freeze()
})
-> [1]peers;
peers
-> for_each(|(node_id, serialized_req)| transducer_to_peers_tx.try_send((serialized_req, node_id)).unwrap());
lookup = _lattice_join_fused_join::<'static, 'tick, MyLastWriteWins<BUFFER_SIZE>, MySetUnion>();
client_input[store]
-> [0]lookup;
client_input[gets]
-> enumerate() -> map(|(id, (key, addr))| {
(key, SetUnionSingletonSet::new_from((addr, id)))
})
-> [1]lookup;
lookup
-> map(|singleton_map: lattices::map_union::MapUnionSingletonMap<_, lattices::Pair::<MyLastWriteWins<BUFFER_SIZE>, MySetUnion>>| {
let lattices::collections::SingletonMap(k, v) = singleton_map.into_reveal();
(k, (v.into_reveal()))
})
-> map(|(key, (reg, gets))| {
gets.0.into_iter().map(move |(dest, _seq_num)| {
(KvsResponse::GetResponse { key, reg: reg.clone() }, dest)
})
})
-> flatten()
-> for_each(|x| transducer_to_client_tx.try_send(x).unwrap());
};
if let Some(graph) = write_graph {
let meta_graph = df
.meta_graph()
.expect("No graph found, maybe failed to parse.");
meta_graph.open_graph(graph, write_config).unwrap();
}
let hydroflow_task = df.run_async();
futures::join!(inbound_networking_task, outbound_networking_task, hydroflow_task, f3);
});
});
}