diff --git a/Cargo.lock b/Cargo.lock index cd9ab02eeb..46aefe4262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4655,6 +4655,7 @@ dependencies = [ "postgres", "rand", "regex", + "safekeeper", "serde", "thiserror", "utils", diff --git a/Cargo.toml b/Cargo.toml index 188f663971..02777f2240 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,6 +138,7 @@ postgres_ffi = { version = "0.1", path = "./libs/postgres_ffi/" } pq_proto = { version = "0.1", path = "./libs/pq_proto/" } remote_storage = { version = "0.1", path = "./libs/remote_storage/" } safekeeper_api = { version = "0.1", path = "./libs/safekeeper_api" } +safekeeper = { path = "./safekeeper/" } storage_broker = { version = "0.1", path = "./storage_broker/" } # Note: main broker code is inside the binary crate, so linking with the library shouldn't be heavy. tenant_size_model = { version = "0.1", path = "./libs/tenant_size_model/" } tracing-utils = { version = "0.1", path = "./libs/tracing-utils/" } diff --git a/libs/walproposer/.gitignore b/libs/walproposer/.gitignore index 9eca6c88cf..8800186e5f 100644 --- a/libs/walproposer/.gitignore +++ b/libs/walproposer/.gitignore @@ -1,2 +1,3 @@ *.a *.o +*.tmp diff --git a/libs/walproposer/Cargo.toml b/libs/walproposer/Cargo.toml index 62e8cb6c64..9fcd252386 100644 --- a/libs/walproposer/Cargo.toml +++ b/libs/walproposer/Cargo.toml @@ -18,6 +18,7 @@ memoffset.workspace = true thiserror.workspace = true serde.workspace = true utils.workspace = true +safekeeper.workspace = true workspace_hack.workspace = true diff --git a/libs/walproposer/bindgen_deps.h b/libs/walproposer/bindgen_deps.h index 8d5c956bca..a10ca230e4 100644 --- a/libs/walproposer/bindgen_deps.h +++ b/libs/walproposer/bindgen_deps.h @@ -8,3 +8,4 @@ // #include "walproposer.h" int TestFunc(int a, int b); +void RunClientC(); diff --git a/libs/walproposer/build.rs b/libs/walproposer/build.rs index 794ea5ad5e..65f3db460f 100644 --- a/libs/walproposer/build.rs +++ b/libs/walproposer/build.rs @@ -125,6 +125,7 @@ fn main() -> anyhow::Result<()> { // included header files changed. .parse_callbacks(Box::new(CargoCallbacks)) .allowlist_function("TestFunc") + .allowlist_function("RunClientC") // .allowlist_function("WalProposerRust") // .clang_arg(format!("-I{inc_server_path}")) // .clang_arg(format!("-I{inc_pgxn_path}")) diff --git a/libs/walproposer/rust_bindings.h b/libs/walproposer/rust_bindings.h index 358731c5cf..2f8611a03e 100644 --- a/libs/walproposer/rust_bindings.h +++ b/libs/walproposer/rust_bindings.h @@ -4,3 +4,5 @@ #include void rust_function(uint32_t a); + +void sim_sleep(uint64_t ms); diff --git a/libs/walproposer/src/lib.rs b/libs/walproposer/src/lib.rs index 2815de1e65..cb900005a3 100644 --- a/libs/walproposer/src/lib.rs +++ b/libs/walproposer/src/lib.rs @@ -6,23 +6,16 @@ pub mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } -pub use bindings::{TestFunc}; - -use std::cell::RefCell; - -thread_local! { - pub static TMP_TEST: RefCell> = RefCell::new(vec![]); -} - #[no_mangle] pub extern "C" fn rust_function(a: u32) { println!("Hello from Rust!"); println!("a: {}", a); - TMP_TEST.with(|f| { - f.borrow_mut().push(a); - println!("TMP_TEST: {:?}", f.borrow()); - }); } +pub mod sim; + #[cfg(test)] mod test; + +#[cfg(test)] +pub mod simtest; diff --git a/libs/walproposer/src/sim.rs b/libs/walproposer/src/sim.rs new file mode 100644 index 0000000000..be5eacec33 --- /dev/null +++ b/libs/walproposer/src/sim.rs @@ -0,0 +1,27 @@ +use std::cell::RefCell; + +use safekeeper::simlib::node_os::NodeOs; + +thread_local! { + pub static CURRENT_NODE_OS: RefCell> = RefCell::new(None); +} + +/// Get the current node os. +fn os() -> NodeOs { + CURRENT_NODE_OS.with(|cell| { + cell.borrow().clone().expect("no node os set") + }) +} + +/// Should be called before calling any of the C functions. +pub fn c_attach_node_os(os: NodeOs) { + CURRENT_NODE_OS.with(|cell| { + *cell.borrow_mut() = Some(os); + }); +} + +#[no_mangle] +pub extern "C" fn sim_sleep(ms: u64) { + println!("got a call to sleep for {} ms", ms); + os().sleep(ms); +} diff --git a/libs/walproposer/src/simtest/mod.rs b/libs/walproposer/src/simtest/mod.rs new file mode 100644 index 0000000000..c9c0f39aef --- /dev/null +++ b/libs/walproposer/src/simtest/mod.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use safekeeper::simlib::{network::{NetworkOptions, Delay}, world::World}; + +use crate::{bindings::RunClientC, sim::c_attach_node_os}; + +#[test] +fn run_rust_c_test() { + let delay = Delay { + min: 1, + max: 60, + fail_prob: 0.4, + }; + + let network = NetworkOptions { + timeout: Some(50), + connect_delay: delay.clone(), + send_delay: delay.clone(), + }; + let seed = 1337; + + start_simulation_2(seed, network.clone(), 1_000_000); +} + +fn start_simulation_2(seed: u64, network: NetworkOptions, time_limit: u64) { + let network = Arc::new(network); + let world = Arc::new(World::new(seed, network)); + world.register_world(); + + let client_node = world.new_node(); + client_node.launch(move |os| { + c_attach_node_os(os); + unsafe { RunClientC() } + }); + + world.await_all(); + + while world.step() && world.now() < time_limit { + println!("made a step"); + } +} diff --git a/libs/walproposer/src/test.rs b/libs/walproposer/src/test.rs index bda40356c1..9e70c928d8 100644 --- a/libs/walproposer/src/test.rs +++ b/libs/walproposer/src/test.rs @@ -1,8 +1,12 @@ -use crate::{TestFunc, TMP_TEST}; +use crate::bindings::{TestFunc, RunClientC}; #[test] -fn run_test() { +fn test_rust_c_calls() { let res = unsafe { TestFunc(1, 2) }; - // unsafe { WalProposerRust(); } println!("res: {}", res); } + +#[test] +fn test_sim_bindings() { + unsafe { RunClientC(); } +} diff --git a/libs/walproposer/test.c b/libs/walproposer/test.c index 20086604de..61f8c7945b 100644 --- a/libs/walproposer/test.c +++ b/libs/walproposer/test.c @@ -16,3 +16,14 @@ int TestFunc(int a, int b) { printf("After rust_function\n"); return a + b; } + +// This is a quick experiment with rewriting existing Rust code in C. +void RunClientC() { + MemoryContextInit(); + + elog(LOG, "started client"); + + for (int i = 0; i < 10; i++) { + sim_sleep(100); + } +} diff --git a/safekeeper/src/simlib/node_os.rs b/safekeeper/src/simlib/node_os.rs index 3344e2bb39..b582aa0c7e 100644 --- a/safekeeper/src/simlib/node_os.rs +++ b/safekeeper/src/simlib/node_os.rs @@ -10,6 +10,7 @@ use super::{ }; /// Abstraction with all functions (aka syscalls) available to the node. +#[derive(Clone)] pub struct NodeOs { world: Arc, internal: Arc, diff --git a/safekeeper/src/simtest/mod.rs b/safekeeper/src/simtest/mod.rs index 6ec9f9157e..22e8d5e2af 100644 --- a/safekeeper/src/simtest/mod.rs +++ b/safekeeper/src/simtest/mod.rs @@ -14,7 +14,7 @@ use crate::{ }; #[test] -fn run_test() { +fn run_pure_rust_test() { let delay = Delay { min: 1, max: 60,