diff --git a/.gitignore b/.gitignore index 546ca5e01..25fc88643 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # will have compiled files and executables debug/ target/ +dom_top/ # These are backup files generated by rustfmt diff --git a/.gitmodules b/.gitmodules index 75cdd085c..9efeaae70 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,7 @@ [submodule "curp/proto/common"] path = crates/curp/proto/common url = https://github.com/xline-kv/curp-proto.git +[submodule "crates/jepsen-rs"] + path = crates/jepsen-rs + url = https://github.com/lxl66566/jepsen-rs.git + branch = main diff --git a/Cargo.lock b/Cargo.lock index aa2e95cb9..a4bca2787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "assert_cmd" @@ -176,6 +176,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "async-scoped" version = "0.9.0" @@ -217,9 +228,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", @@ -447,6 +458,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -806,6 +823,18 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "default-struct-builder" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fa90da96b8fd491f5754d1f7a731f73921e3b7aa0ce333c821a0e43666ac14" +dependencies = [ + "darling 0.20.8", + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "der" version = "0.7.9" @@ -891,6 +920,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.13.0" @@ -925,6 +960,19 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -950,7 +998,7 @@ dependencies = [ "http", "prost", "tokio", - "tokio-stream 0.1.15", + "tokio-stream 0.1.16", "tonic", "tonic-build", "tower", @@ -1033,6 +1081,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.30" @@ -1212,6 +1266,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1273,6 +1333,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "1.4.1" @@ -1414,6 +1480,17 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -1444,6 +1521,75 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "j4rs" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "689ae4f2bd4eba82601592f3d22b7e7147b1df52d3b525223f5218990501b4eb" +dependencies = [ + "cesu8", + "dunce", + "fs_extra", + "futures", + "glob", + "java-locator", + "jni-sys", + "lazy_static", + "libc", + "libloading", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "java-locator" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2abecabd9961c5e01405a6426687fcf1bd94a269927137e4c3cc1a7419b93fd" +dependencies = [ + "glob", + "lazy_static", +] + +[[package]] +name = "jepsen-rs" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-recursion", + "async-trait", + "default-struct-builder", + "futures-util", + "j4rs", + "log", + "madsim", + "madsim-tokio", + "pretty_env_logger", + "serde", + "serde_json", + "tokio-stream 0.1.16", +] + +[[package]] +name = "jni-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c30a312d782b8d56a1e0897d45c1af33f31f9b4a4d13d31207a8675e0223b818" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c199962dfd5610ced8eca382606e349f7940a4ac7d867b58a046123411cbb4" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "jobserver" version = "0.1.31" @@ -1825,7 +1971,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -1978,7 +2124,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tokio-stream 0.1.15", + "tokio-stream 0.1.16", ] [[package]] @@ -2154,6 +2300,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -2552,18 +2708,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -2572,9 +2728,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -2680,6 +2836,8 @@ dependencies = [ "engine", "futures", "itertools 0.13.0", + "j4rs", + "jepsen-rs", "madsim", "madsim-tokio", "madsim-tonic", @@ -2688,6 +2846,7 @@ dependencies = [ "prost", "tempfile", "tracing", + "tracing-subscriber", "utils", "workspace-hack", "xline", @@ -2822,6 +2981,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "termtree" version = "0.4.1" @@ -2967,9 +3135,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -3048,7 +3216,7 @@ dependencies = [ "socket2", "tokio", "tokio-rustls", - "tokio-stream 0.1.15", + "tokio-stream 0.1.16", "tower", "tower-layer", "tower-service", @@ -3077,7 +3245,7 @@ dependencies = [ "async-stream", "prost", "tokio", - "tokio-stream 0.1.15", + "tokio-stream 0.1.16", "tonic", ] @@ -3476,6 +3644,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3681,7 +3858,7 @@ dependencies = [ "syn 2.0.65", "time", "tokio", - "tokio-stream 0.1.15", + "tokio-stream 0.1.16", "tokio-util", "tonic", "tower", diff --git a/crates/jepsen-rs b/crates/jepsen-rs new file mode 160000 index 000000000..ce07e5769 --- /dev/null +++ b/crates/jepsen-rs @@ -0,0 +1 @@ +Subproject commit ce07e5769cee731a87b89781882e8ae977c88893 diff --git a/crates/simulation/Cargo.toml b/crates/simulation/Cargo.toml index bbc988f05..5176698fb 100644 --- a/crates/simulation/Cargo.toml +++ b/crates/simulation/Cargo.toml @@ -18,26 +18,29 @@ curp-test-utils = { path = "../curp-test-utils" } engine = { path = "../engine" } futures = "0.3.29" itertools = "0.13" +j4rs = "0.20.0" madsim = "0.2.27" parking_lot = "0.12.3" prost = "0.13" tempfile = "3" tokio = { version = "0.2.25", package = "madsim-tokio", features = [ - "rt", - "rt-multi-thread", - "fs", - "sync", - "macros", - "time", - "signal", + "rt", + "rt-multi-thread", + "fs", + "sync", + "macros", + "time", + "signal", ] } tonic = { version = "0.5.0", package = "madsim-tonic" } tracing = { version = "0.1.34", features = ["std", "log", "attributes"] } +tracing-subscriber = "0.3.1" utils = { path = "../utils", version = "0.1.0", features = ["parking_lot"] } workspace-hack = { version = "0.1", path = "../../workspace-hack" } xline = { path = "../xline" } xline-client = { path = "../xline-client" } xlineapi = { path = "../xlineapi" } +jepsen-rs = { path = "../jepsen-rs" } [build-dependencies] tonic-build = { version = "0.5.0", package = "madsim-tonic-build" } diff --git a/crates/simulation/src/xline_group.rs b/crates/simulation/src/xline_group.rs index d3a0c41ae..9016c76b5 100644 --- a/crates/simulation/src/xline_group.rs +++ b/crates/simulation/src/xline_group.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; use itertools::Itertools; +use jepsen_rs::client::ElleRwClusterClient; use madsim::runtime::NodeHandle; use tonic::transport::Channel; use tracing::debug; @@ -213,6 +214,28 @@ impl SimClient { } } +#[async_trait::async_trait] +impl ElleRwClusterClient for SimClient { + async fn get(&self, key: u64) -> Result, String> { + Ok(self + .range(key.to_be_bytes(), None) + .await + .map_err(|err| err.to_string())? + .kvs + .into_iter() + .next() + .map(|kv: xlineapi::KeyValue| { + u64::from_be_bytes(kv.value.try_into().expect("key should be 8 bytes")) + })) + } + async fn put(&self, key: u64, value: u64) -> Result<(), String> { + self.put(key.to_be_bytes(), value.to_be_bytes(), None) + .await + .map_err(|err| err.to_string())?; + Ok(()) + } +} + impl Drop for XlineGroup { fn drop(&mut self) { let handle = madsim::runtime::Handle::current(); diff --git a/crates/simulation/tests/it/jepsen/basic.rs b/crates/simulation/tests/it/jepsen/basic.rs new file mode 100644 index 000000000..de05f23ba --- /dev/null +++ b/crates/simulation/tests/it/jepsen/basic.rs @@ -0,0 +1,39 @@ +use jepsen_rs::{ + client::{Client, JepsenClient}, + generator::{controller::GeneratorGroupStrategy, elle_rw::ElleRwGenerator, GeneratorGroup}, + op::Op, +}; +use tracing::info; + +use simulation::xline_group::XlineGroup; + +#[test] +fn basic_test() { + let mut rt = madsim::runtime::Runtime::new(); + rt.set_allow_system_thread(true); + + rt.block_on(async move { + let group = XlineGroup::new(5).await; + let sim_client = group.client().await; + let jepsen_client = JepsenClient::new(sim_client, ElleRwGenerator::new().unwrap()); + let jepsen_client = Box::leak(jepsen_client.into()); + info!("basic_test: client created"); + + // get generators, transform and merge them + let g1 = jepsen_client + .new_generator(100) + .filter(|o| matches!(o, Op::Txn(txn) if txn.len() == 1)) + .await; + let g2 = jepsen_client.new_generator(50); + let g3 = jepsen_client.new_generator(50); + info!("intergration_test: generators created"); + let gen_g = GeneratorGroup::new([g1, g2, g3]) + .with_strategy(GeneratorGroupStrategy::RoundRobin(usize::MAX)); + info!("generator group created"); + let res = jepsen_client + .run(gen_g) + .await + .unwrap_or_else(|e| panic!("{}", e)); + println!("history checked result: {:?}", res); + }) +} diff --git a/crates/simulation/tests/it/jepsen/mod.rs b/crates/simulation/tests/it/jepsen/mod.rs new file mode 100644 index 000000000..1bca5f8cb --- /dev/null +++ b/crates/simulation/tests/it/jepsen/mod.rs @@ -0,0 +1 @@ +mod basic; diff --git a/crates/simulation/tests/it/main.rs b/crates/simulation/tests/it/main.rs index 4003739ef..fda7990e0 100644 --- a/crates/simulation/tests/it/main.rs +++ b/crates/simulation/tests/it/main.rs @@ -1,4 +1,5 @@ #![cfg(madsim)] mod curp; +mod jepsen; mod xline;