refactor: refactoring into async first
This commit is contained in:
parent
e64f16dd95
commit
cec2eeda62
105
Cargo.lock
generated
105
Cargo.lock
generated
|
@ -80,12 +80,102 @@ name = "distributed-systems-flyio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dashmap",
|
"dashmap",
|
||||||
|
"futures",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
|
@ -217,6 +307,12 @@ version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -338,6 +434,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dashmap = "5.5.3"
|
dashmap = "5.5.3"
|
||||||
|
futures = "0.3.30"
|
||||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||||
serde = { version = "1.0.193", features = ["serde_derive"] }
|
serde = { version = "1.0.193", features = ["serde_derive"] }
|
||||||
serde_json = "1.0.109"
|
serde_json = "1.0.109"
|
||||||
|
|
255
src/lib.rs
255
src/lib.rs
|
@ -2,59 +2,73 @@
|
||||||
#![feature(hash_set_entry)]
|
#![feature(hash_set_entry)]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
pub mod seq_kv;
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
use crate::{seq_kv::MonotonicCounter, types::Message};
|
use crate::types::{Message, MessageBody, SeqKvInput};
|
||||||
use rand::{rngs::SmallRng, Rng, SeedableRng};
|
use futures::future::BoxFuture;
|
||||||
|
use rand::{rngs::SmallRng, SeedableRng};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::{stdin, stdout, BufRead, Error as IoError, Stdin, Stdout, Write},
|
future::Future,
|
||||||
|
io::{stdin, stdout, BufRead, Error as IoError, Stdout, Write},
|
||||||
|
pin::Pin,
|
||||||
sync::{Arc, Mutex, RwLock},
|
sync::{Arc, Mutex, RwLock},
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
use tokio::{
|
||||||
|
runtime::Handle,
|
||||||
|
sync::oneshot::{self, Receiver, Sender},
|
||||||
};
|
};
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
|
|
||||||
pub trait Handler = Fn(Message, Arc<RwLock<Malestorm>>, Arc<Mutex<MalestormIo>>) -> Result<(), String>
|
trait Callback = FnOnce(Message) -> Result<(), String> + Send + Sync + 'static;
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static;
|
|
||||||
|
|
||||||
pub struct Malestorm {
|
type Handler = Arc<
|
||||||
|
dyn Fn(
|
||||||
|
Message,
|
||||||
|
Arc<RwLock<Maelstorm>>,
|
||||||
|
Arc<Mutex<MaelstormIo>>,
|
||||||
|
) -> BoxFuture<'static, Result<(), String>>
|
||||||
|
+ Send
|
||||||
|
+ Sync,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct Maelstorm {
|
||||||
|
mutex: Mutex<()>,
|
||||||
pub node: Node,
|
pub node: Node,
|
||||||
pub handlers: HashMap<String, Arc<dyn Handler>>,
|
pub handlers: HashMap<String, Handler>,
|
||||||
|
callbacks: HashMap<i64, Box<dyn Callback>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
id: String,
|
pub id: String,
|
||||||
nodes: Vec<String>,
|
pub nodes: Vec<String>,
|
||||||
counter: MonotonicCounter,
|
|
||||||
rng: SmallRng,
|
rng: SmallRng,
|
||||||
}
|
}
|
||||||
pub struct MalestormIo {
|
pub struct MaelstormIo {
|
||||||
stdout: Stdout,
|
stdout: Stdout,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Malestorm {
|
impl Default for Maelstorm {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let seed = SystemTime::now()
|
let seed = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.expect("time went backwards??");
|
.expect("time went backwards??");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
mutex: Mutex::new(()),
|
||||||
node: Node {
|
node: Node {
|
||||||
id: String::new(),
|
id: String::new(),
|
||||||
nodes: Vec::new(),
|
nodes: Vec::new(),
|
||||||
counter: MonotonicCounter::new(),
|
|
||||||
rng: SmallRng::seed_from_u64(seed.as_secs()),
|
rng: SmallRng::seed_from_u64(seed.as_secs()),
|
||||||
},
|
},
|
||||||
handlers: HashMap::new(),
|
handlers: HashMap::new(),
|
||||||
|
callbacks: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MalestormIo {
|
impl MaelstormIo {
|
||||||
fn write(&self, buf: &[u8]) -> Result<(), IoError> {
|
fn write(&self, buf: &[u8]) -> Result<(), IoError> {
|
||||||
let mut writer = self.stdout.lock();
|
let mut writer = self.stdout.lock();
|
||||||
writer.write_all(buf)?;
|
writer.write_all(buf)?;
|
||||||
|
@ -63,14 +77,14 @@ impl MalestormIo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MalestormIo {
|
impl Default for MaelstormIo {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { stdout: stdout() }
|
Self { stdout: stdout() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Malestorm {
|
impl Maelstorm {
|
||||||
pub fn run(self, runtime: Runtime, io: MalestormIo) {
|
pub async fn run(self, io: MaelstormIo) {
|
||||||
let program = Arc::new(RwLock::new(self));
|
let program = Arc::new(RwLock::new(self));
|
||||||
let io = Arc::new(Mutex::new(io));
|
let io = Arc::new(Mutex::new(io));
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
|
@ -101,12 +115,29 @@ impl Malestorm {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mtype = message.body.message_type.clone();
|
if let Some(reply_msg_id) = message.body.in_reply_to {
|
||||||
|
let mut program = program.write().unwrap();
|
||||||
|
|
||||||
let handler: Arc<dyn Handler> = {
|
let callback = match program.callbacks.remove(&reply_msg_id) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
eprintln!("no callback for msg with reply id {}", reply_msg_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = callback(message)
|
||||||
|
/* add await*/
|
||||||
|
{
|
||||||
|
eprintln!("error in callback: {e}");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = {
|
||||||
let program = program.read().unwrap();
|
let program = program.read().unwrap();
|
||||||
|
|
||||||
match program.handlers.get(&mtype) {
|
match program.handlers.get(&message.body.message_type) {
|
||||||
Some(v) => v.clone(),
|
Some(v) => v.clone(),
|
||||||
None => {
|
None => {
|
||||||
//eprintln!("no handler found for {}", message.body.message_type);
|
//eprintln!("no handler found for {}", message.body.message_type);
|
||||||
|
@ -117,42 +148,24 @@ impl Malestorm {
|
||||||
|
|
||||||
let pc = program.clone();
|
let pc = program.clone();
|
||||||
let io = io.clone();
|
let io = io.clone();
|
||||||
runtime.spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = handler(message, pc, io) {
|
if let Err(e) = handler(message, pc, io).await {
|
||||||
eprintln!("error in serving request: {}", e);
|
eprintln!("error in serving request: {}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_node_id(&mut self, node_id: String) {
|
pub fn init(&mut self, node_id: String, nodes: Vec<String>) {
|
||||||
self.node.id = node_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_nodes(&mut self, nodes: Vec<String>) {
|
|
||||||
self.node.nodes = nodes;
|
self.node.nodes = nodes;
|
||||||
}
|
self.node.id = node_id;
|
||||||
|
|
||||||
pub fn get_nodes(&self) -> Vec<String> {
|
|
||||||
self.node.nodes.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_counter(&self, src: &str) -> u64 {
|
|
||||||
self.node.counter.read(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_counter(&mut self, src: &str, v: u64) {
|
|
||||||
self.node.counter.write(src, v);
|
|
||||||
}
|
|
||||||
pub fn add_counter(&mut self, src: &str, v: u64) {
|
|
||||||
self.node.counter.add(src, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync(
|
pub fn sync(
|
||||||
&self,
|
&self,
|
||||||
dest: &str,
|
dest: &str,
|
||||||
prev_msg: Message,
|
prev_msg: Message,
|
||||||
io: Arc<Mutex<MalestormIo>>,
|
io: Arc<Mutex<MaelstormIo>>,
|
||||||
) -> Result<(), IoError> {
|
) -> Result<(), IoError> {
|
||||||
let msg = Message {
|
let msg = Message {
|
||||||
id: Some(prev_msg.id.unwrap_or(0) + 1),
|
id: Some(prev_msg.id.unwrap_or(0) + 1),
|
||||||
|
@ -167,32 +180,91 @@ impl Malestorm {
|
||||||
};
|
};
|
||||||
|
|
||||||
let out = serde_json::to_vec(&msg)?;
|
let out = serde_json::to_vec(&msg)?;
|
||||||
eprintln!("wrote = {:?}", String::from_utf8_lossy(&out));
|
|
||||||
let io = io.lock().unwrap();
|
let io = io.lock().unwrap();
|
||||||
io.write(&out)?;
|
io.write(&out)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_client_id(&mut self) -> String {
|
pub fn register<F, Fut>(&mut self, name: &str, func: F)
|
||||||
let s2: u64 = self.node.rng.gen();
|
where
|
||||||
let s1 = &self.node.id;
|
F: Fn(Message, Arc<RwLock<Maelstorm>>, Arc<Mutex<MaelstormIo>>) -> Fut
|
||||||
format!("{}_{}", s1, s2)
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
Fut: Future<Output = Result<(), String>> + Send + 'static,
|
||||||
|
{
|
||||||
|
self.handlers.insert(
|
||||||
|
name.to_string(),
|
||||||
|
Arc::new(move |a, b, c| Box::pin(func(a, b, c))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(&mut self, name: &str, func: impl Handler) {
|
pub async fn sync_rpc(
|
||||||
self.handlers.insert(name.to_string(), Arc::new(func));
|
&mut self,
|
||||||
|
io: Arc<Mutex<MaelstormIo>>,
|
||||||
|
msg: Message,
|
||||||
|
) -> Result<Message, String> {
|
||||||
|
let (tx, rx): (Sender<Message>, Receiver<Message>) = oneshot::channel();
|
||||||
|
|
||||||
|
self.rpc(
|
||||||
|
io,
|
||||||
|
msg,
|
||||||
|
Box::new(|msg| {
|
||||||
|
tx.send(msg)
|
||||||
|
.map_err(|e| format!("error in sending to tx chan: {:?}", e))?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
match tokio::time::timeout(Duration::from_secs(2), rx).await {
|
||||||
|
Ok(result) => match result {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("sync callback error: {}", e);
|
||||||
|
Err(e.to_string())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("sync callback timeout: {}", e);
|
||||||
|
Err(e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, io: Arc<Mutex<MalestormIo>>, mut msg: Message) -> Result<(), IoError> {
|
fn rpc(
|
||||||
|
&mut self,
|
||||||
|
io: Arc<Mutex<MaelstormIo>>,
|
||||||
|
mut msg: Message,
|
||||||
|
handler: impl Callback,
|
||||||
|
) -> Result<(), IoError> {
|
||||||
|
let next_msg_id = msg.body.msg_id.unwrap() + 1;
|
||||||
|
self.callbacks.insert(next_msg_id, Box::new(handler));
|
||||||
|
|
||||||
|
msg.body.msg_id = Some(next_msg_id);
|
||||||
|
|
||||||
|
self.send(io, msg.clone(), &msg.src)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply(&mut self, io: Arc<Mutex<MaelstormIo>>, mut msg: Message) -> Result<(), IoError> {
|
||||||
|
msg.body.in_reply_to = msg.body.msg_id;
|
||||||
|
msg.body.msg_id = None;
|
||||||
|
self.send(io, msg.clone(), &msg.src)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(
|
||||||
|
&self,
|
||||||
|
io: Arc<Mutex<MaelstormIo>>,
|
||||||
|
mut msg: Message,
|
||||||
|
dst: &str,
|
||||||
|
) -> Result<(), IoError> {
|
||||||
// Before replying, Swap src / dst in original message
|
// Before replying, Swap src / dst in original message
|
||||||
// Add the correct value for in_reply_to
|
// Add the correct value for in_reply_to
|
||||||
|
|
||||||
std::mem::swap(&mut msg.src, &mut msg.dest);
|
msg.dest = dst.to_string();
|
||||||
msg.src = self.node.id.clone();
|
msg.src = self.node.id.clone();
|
||||||
|
|
||||||
msg.body.in_reply_to = msg.body.msg_id;
|
|
||||||
|
|
||||||
let out = serde_json::to_vec(&msg)?;
|
let out = serde_json::to_vec(&msg)?;
|
||||||
let io = io.lock().unwrap();
|
let io = io.lock().unwrap();
|
||||||
|
|
||||||
|
@ -204,9 +276,62 @@ impl Malestorm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_request_and_handle(
|
//impl Maelstorm {
|
||||||
program: Arc<RwLock<Malestorm>>,
|
// pub fn read_counter(
|
||||||
io: Arc<Mutex<MalestormIo>>,
|
// &mut self,
|
||||||
buf: &[u8],
|
// io: Arc<Mutex<MaelstormIo>>,
|
||||||
) {
|
// store: &str,
|
||||||
}
|
// node_to_read: String,
|
||||||
|
// ) -> Result<u64, String> {
|
||||||
|
// let msg = Message {
|
||||||
|
// id: None,
|
||||||
|
// src: self.node.id.clone(),
|
||||||
|
// dest: store.to_string(),
|
||||||
|
// body: MessageBody {
|
||||||
|
// msg_id: Some(0),
|
||||||
|
// in_reply_to: None,
|
||||||
|
// message_type: "read".to_string(),
|
||||||
|
// message_body: serde_json::to_value(SeqKvInput {
|
||||||
|
// key: node_to_read,
|
||||||
|
// value: None,
|
||||||
|
// })
|
||||||
|
// .unwrap(),
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// let mut result = self.sync_rpc(io, msg)?;
|
||||||
|
//
|
||||||
|
// let body: SeqKvInput = serde_json::from_value(result.body.message_body.take())
|
||||||
|
// .map_err(|e| format!("error in parsing response body: {}", e))?;
|
||||||
|
//
|
||||||
|
// Ok(body.value.unwrap())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn write_counter(
|
||||||
|
// &mut self,
|
||||||
|
// io: Arc<Mutex<MaelstormIo>>,
|
||||||
|
// store: &str,
|
||||||
|
// val: u64,
|
||||||
|
// ) -> Result<(), String> {
|
||||||
|
// let msg = Message {
|
||||||
|
// id: None,
|
||||||
|
// src: self.node.id.clone(),
|
||||||
|
// dest: store.to_string(),
|
||||||
|
// body: MessageBody {
|
||||||
|
// msg_id: Some(0),
|
||||||
|
// in_reply_to: None,
|
||||||
|
// message_type: "write".to_string(),
|
||||||
|
// message_body: serde_json::to_value(SeqKvInput {
|
||||||
|
// key: self.node.id.clone(),
|
||||||
|
// value: Some(val),
|
||||||
|
// })
|
||||||
|
// .unwrap(),
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// let mut result = self.sync_rpc(io, msg)?;
|
||||||
|
//
|
||||||
|
// let body: SeqKvInput = serde_json::from_value(result.body.message_body.take())
|
||||||
|
// .map_err(|e| format!("error in parsing response body: {}", e))?;
|
||||||
|
//
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
138
src/main.rs
138
src/main.rs
|
@ -2,108 +2,100 @@
|
||||||
|
|
||||||
use distributed_systems_flyio::{
|
use distributed_systems_flyio::{
|
||||||
types::{GrowCounterReadMessage, GrowCounterUpdateMessage, InitMessage, Message},
|
types::{GrowCounterReadMessage, GrowCounterUpdateMessage, InitMessage, Message},
|
||||||
Malestorm, MalestormIo,
|
Maelstorm, MaelstormIo,
|
||||||
};
|
};
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
|
|
||||||
fn main() {
|
async fn test(
|
||||||
let mut program = Malestorm::default();
|
msg: Message,
|
||||||
|
program: Arc<RwLock<Maelstorm>>,
|
||||||
|
io: Arc<Mutex<MaelstormIo>>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let mut program = Maelstorm::default();
|
||||||
|
|
||||||
program.register(
|
program.register(
|
||||||
"init",
|
"init",
|
||||||
// TODO: Replace error string with a type
|
// TODO: Replace error string with a type
|
||||||
|mut msg: Message,
|
async |mut msg: Message,
|
||||||
program: Arc<RwLock<Malestorm>>,
|
program: Arc<RwLock<Maelstorm>>,
|
||||||
io: Arc<Mutex<MalestormIo>>|
|
io: Arc<Mutex<MaelstormIo>>|
|
||||||
-> Result<(), String> {
|
-> Result<(), String> {
|
||||||
let message_body: InitMessage = serde_json::from_value(msg.body.message_body.take())
|
let message_body: InitMessage = serde_json::from_value(msg.body.message_body.take())
|
||||||
.map_err(|e| format!("error in parsing response body: {}", e))?;
|
.map_err(|e| format!("error in parsing response body: {}", e))?;
|
||||||
|
|
||||||
let mut program = program.write().unwrap();
|
let mut program = program.write().unwrap();
|
||||||
program.set_node_id(message_body.node_id);
|
program.init(message_body.node_id, message_body.nodes);
|
||||||
program.set_nodes(message_body.nodes);
|
|
||||||
msg.body.message_type = "init_ok".into();
|
msg.body.message_type = "init_ok".into();
|
||||||
|
|
||||||
program
|
program
|
||||||
.send(io, msg)
|
.reply(io, msg)
|
||||||
.map_err(|e| format!("init: error in writing response: {}", e))
|
.map_err(|e| format!("init: error in writing response: {}", e))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
program.register(
|
// program.register(
|
||||||
"add",
|
// "add",
|
||||||
|mut msg: Message,
|
// async |mut msg: Message,
|
||||||
program: Arc<RwLock<Malestorm>>,
|
// program: Arc<RwLock<Maelstorm>>,
|
||||||
io: Arc<Mutex<MalestormIo>>|
|
// io: Arc<Mutex<MaelstormIo>>|
|
||||||
-> Result<(), String> {
|
// -> Result<(), String> {
|
||||||
let body: GrowCounterUpdateMessage =
|
// let body: GrowCounterUpdateMessage =
|
||||||
serde_json::from_value(msg.body.message_body.take())
|
// serde_json::from_value(msg.body.message_body.take())
|
||||||
.map_err(|e| format!("error in parsing response body: {}", e))?;
|
// .map_err(|e| format!("error in parsing response body: {}", e))?;
|
||||||
msg.body.message_type = "add_ok".into();
|
|
||||||
|
|
||||||
let mut program = program.write().unwrap();
|
// msg.body.message_type = "add_ok".into();
|
||||||
program.add_counter(&msg.src, body.delta);
|
|
||||||
|
|
||||||
program
|
// let mut program = program.write().unwrap();
|
||||||
.send(io, msg.clone())
|
|
||||||
.map_err(|e| format!("add: error in writing response: {}", e))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
program.register(
|
// let id = program.node.id.clone();
|
||||||
"read",
|
|
||||||
|mut msg: Message,
|
|
||||||
program: Arc<RwLock<Malestorm>>,
|
|
||||||
io: Arc<Mutex<MalestormIo>>|
|
|
||||||
-> Result<(), String> {
|
|
||||||
msg.body.message_type = "read_ok".into();
|
|
||||||
|
|
||||||
let program = program.read().unwrap();
|
// // let current = program
|
||||||
let mut sum = 0;
|
// // .read_counter(io.clone(), "seq-kv", id)
|
||||||
for node in program.get_nodes() {
|
// // .expect("error in reading value");
|
||||||
if node == msg.src {
|
|
||||||
sum += program.read_counter(&node);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Sync first then add
|
|
||||||
|
|
||||||
program.sync(&node, msg.clone(), io.clone());
|
// // program.write_counter(io.clone(), "seq-kv", current + body.delta)?;
|
||||||
|
|
||||||
sum += program.read_counter(&msg.src);
|
// program
|
||||||
}
|
// .reply(io, msg)
|
||||||
|
// .map_err(|e| format!("add: error in writing response: {}", e))
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
msg.body.message_body =
|
// program.register(
|
||||||
serde_json::to_value(GrowCounterReadMessage { value: sum }).unwrap();
|
// "read",
|
||||||
|
// async |mut msg: Message,
|
||||||
|
// program: Arc<RwLock<Maelstorm>>,
|
||||||
|
// io: Arc<Mutex<MaelstormIo>>|
|
||||||
|
// -> Result<(), String> {
|
||||||
|
// msg.body.message_type = "read_ok".into();
|
||||||
|
|
||||||
program
|
// let mut program = program.write().unwrap();
|
||||||
.send(io, msg.clone())
|
// let mut sum = 0;
|
||||||
.map_err(|e| format!("read: error in writing response: {}", e))
|
// for node in program.node.nodes.clone() {
|
||||||
},
|
// if *node == msg.src {
|
||||||
);
|
// sum += program.read_counter(io.clone(), "seq-kv", node)?;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// // Sync first then add
|
||||||
|
|
||||||
program.register(
|
// sum += program.read_counter(io.clone(), "seq-kv", node)?;
|
||||||
"counter_sync",
|
// }
|
||||||
|mut msg: Message,
|
|
||||||
program: Arc<RwLock<Malestorm>>,
|
|
||||||
io: Arc<Mutex<MalestormIo>>|
|
|
||||||
-> Result<(), String> {
|
|
||||||
msg.body.message_type = "counter_sync_ok".into();
|
|
||||||
|
|
||||||
let program = program.read().unwrap();
|
// msg.body.message_body =
|
||||||
msg.body.message_body = serde_json::to_value(GrowCounterReadMessage {
|
// serde_json::to_value(GrowCounterReadMessage { value: sum }).unwrap();
|
||||||
value: program.read_counter(&msg.src),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
program
|
// program
|
||||||
.send(io, msg.clone())
|
// .reply(io, msg.clone())
|
||||||
.map_err(|e| format!("read: error in writing response: {}", e))
|
// .map_err(|e| format!("read: error in writing response: {}", e))
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
|
|
||||||
let io = MalestormIo::default();
|
let io = MaelstormIo::default();
|
||||||
let runtime = Runtime::new().unwrap();
|
|
||||||
|
|
||||||
program.run(runtime, io);
|
program.run(io).await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MonotonicCounter {
|
|
||||||
counter: HashMap<String, u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MonotonicCounter {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
counter: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&self, node: &str) -> u64 {
|
|
||||||
*self.counter.get(node).unwrap_or(&0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&mut self, node: &str, v: u64) {
|
|
||||||
*self.counter.entry(node.to_string()).or_insert(0) = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, node: &str, v: u64) {
|
|
||||||
eprintln!("{:?}", self.counter);
|
|
||||||
|
|
||||||
*self.counter.entry(node.to_string()).or_insert(0) += v;
|
|
||||||
}
|
|
||||||
}
|
|
55
src/types.rs
55
src/types.rs
|
@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
#[derive(Debug, Serialize, Clone, Deserialize)]
|
#[derive(Debug, Serialize, Clone, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub id: Option<i64>,
|
pub id: Option<i64>,
|
||||||
pub src: String,
|
pub src: String,
|
||||||
pub dest: String,
|
pub dest: String,
|
||||||
|
@ -11,7 +12,9 @@ pub struct Message {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone, Deserialize)]
|
#[derive(Debug, Serialize, Clone, Deserialize)]
|
||||||
pub struct MessageBody {
|
pub struct MessageBody {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub msg_id: Option<i64>,
|
pub msg_id: Option<i64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub in_reply_to: Option<i64>,
|
pub in_reply_to: Option<i64>,
|
||||||
|
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -41,50 +44,10 @@ pub struct GrowCounterReadMessage {
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
mod test {
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct SeqKvInput {
|
||||||
use super::*;
|
pub key: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub fn extraneous_fields_fail() {
|
pub value: Option<u64>,
|
||||||
let body = "{
|
|
||||||
\"src\": \"c1\",
|
|
||||||
\"dest\": \"n1\",
|
|
||||||
\"body\": {
|
|
||||||
\"type\": \"echo\",
|
|
||||||
\"msg_id\": 1,
|
|
||||||
\"echo\": \"Please echo 35\",
|
|
||||||
\"extraneous\": \"hi\"
|
|
||||||
}
|
|
||||||
}";
|
|
||||||
|
|
||||||
let resp: Result<Message, serde_json::Error> = serde_json::from_str(body);
|
|
||||||
|
|
||||||
if resp.is_ok() {
|
|
||||||
eprintln!("successfully parsed into Message {:#?}", resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(resp.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn parse_echo() {
|
|
||||||
let body = "{
|
|
||||||
\"src\": \"c1\",
|
|
||||||
\"dest\": \"n1\",
|
|
||||||
\"body\": {
|
|
||||||
\"type\": \"echo\",
|
|
||||||
\"msg_id\": 1,
|
|
||||||
\"echo\": \"Please echo 35\"
|
|
||||||
}
|
|
||||||
}";
|
|
||||||
|
|
||||||
let resp: Result<Message, serde_json::Error> = serde_json::from_str(body);
|
|
||||||
|
|
||||||
if resp.is_err() {
|
|
||||||
eprintln!("failed to parsed into Echo Message {:#?}", resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(resp.is_ok());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user