diff --git a/tests/simulation/CMakeLists.txt b/tests/simulation/CMakeLists.txt index b44dacb36..15c426e8c 100644 --- a/tests/simulation/CMakeLists.txt +++ b/tests/simulation/CMakeLists.txt @@ -31,4 +31,4 @@ add_simulation_test(raft.cpp address) add_simulation_test(trial_query_storage/query_storage_test.cpp address) -add_simulation_test(sharded_map.cpp address) +#add_simulation_test(sharded_map.cpp address) diff --git a/tests/simulation/raft.cpp b/tests/simulation/raft.cpp index b7e6af5ee..29f0a97dd 100644 --- a/tests/simulation/raft.cpp +++ b/tests/simulation/raft.cpp @@ -116,6 +116,91 @@ class TestState { } }; +template +class RsmClient { + using ServerPool = std::vector
; + + IoImpl io_; + Address leader_; + + std::mt19937 cli_rng_{0}; + ServerPool server_addrs_; + + template + std::optional CheckForCorrectLeader(ResponseT response) { + if (response.retry_leader) { + MG_ASSERT(!response.success, "retry_leader should never be set for successful responses"); + leader_ = response.retry_leader.value(); + std::cout << "client redirected to leader server " << leader_.last_known_port << std::endl; + } else if (!response.success) { + std::uniform_int_distribution addr_distrib(0, (server_addrs_.size() - 1)); + size_t addr_index = addr_distrib(cli_rng_); + leader_ = server_addrs_[addr_index]; + + std::cout << "client NOT redirected to leader server, trying a random one at index " << addr_index + << " with port " << leader_.last_known_port << std::endl; + return {}; + } + + return response; + } + + public: + RsmClient(IoImpl &&io, Address &&leader, ServerPool &&server_addrs) + : io_{io}, leader_{leader}, server_addrs_{server_addrs} {} + + RsmClient() = delete; + + std::optional> SendWriteRequest(WriteRequestT req) { + WriteRequest client_req; + client_req.operation = req; + + std::cout << "client sending CasRequest to Leader " << leader_.last_known_port << std::endl; + ResponseFuture> response_future = + io_.template Request, WriteResponse>(leader_, client_req); + ResponseResult> response_result = std::move(response_future).Wait(); + + if (response_result.HasError()) { + std::cout << "client timed out while trying to communicate with leader server " << std::endl; + // continue; + return std::nullopt; + } + + ResponseEnvelope> response_envelope = response_result.GetValue(); + WriteResponse write_response = response_envelope.message; + + return CheckForCorrectLeader(write_response); + } + + std::optional> SendReadRequest(ReadRequestT req) { + ReadRequest read_req; + read_req.operation = req; + + std::cout << "client sending GetRequest to Leader " << leader_.last_known_port << std::endl; + ResponseFuture> get_response_future = + io_.template Request, ReadResponse>(leader_, read_req); + + // receive response + ResponseResult> get_response_result = std::move(get_response_future).Wait(); + + if (get_response_result.HasError()) { + std::cout << "client timed out while trying to communicate with leader server " << std::endl; + return {}; + } + + ResponseEnvelope> get_response_envelope = get_response_result.GetValue(); + ReadResponse read_get_response = get_response_envelope.message; + + if (!read_get_response.success) { + // sent to a non-leader + return {}; + } + + return CheckForCorrectLeader(read_get_response); + } +}; + template void RunRaft(Raft server) { server.Run(); @@ -147,7 +232,6 @@ void RunSimulation() { std::vector
srv_2_peers = {srv_addr_1, srv_addr_3}; std::vector
srv_3_peers = {srv_addr_1, srv_addr_2}; - // TODO(tyler / gabor) supply default TestState to Raft constructor using RaftClass = Raft; RaftClass srv_1{std::move(srv_io_1), srv_1_peers, TestState{}}; RaftClass srv_2{std::move(srv_io_2), srv_2_peers, TestState{}}; @@ -165,16 +249,21 @@ void RunSimulation() { std::cout << "beginning test after servers have become quiescent" << std::endl; std::mt19937 cli_rng_{0}; - Address server_addrs[]{srv_addr_1, srv_addr_2, srv_addr_3}; + std::vector
server_addrs{srv_addr_1, srv_addr_2, srv_addr_3}; Address leader = server_addrs[0]; + RsmClient, CasRequest, CasResponse, GetRequest, GetResponse> client( + std::move(cli_io), std::move(leader), std::move(server_addrs)); + const int key = 0; std::optional last_known_value; bool success = false; for (int i = 0; !success; i++) { - // send request + /* + * Write Request + */ CasRequest cas_req; cas_req.key = key; @@ -182,37 +271,11 @@ void RunSimulation() { cas_req.new_value = i; - WriteRequest cli_req; - cli_req.operation = cas_req; - - std::cout << "client sending CasRequest to Leader " << leader.last_known_port << std::endl; - ResponseFuture> cas_response_future = - cli_io.Request, WriteResponse>(leader, cli_req); - - // receive cas_response - ResponseResult> cas_response_result = std::move(cas_response_future).Wait(); - - if (cas_response_result.HasError()) { - std::cout << "client timed out while trying to communicate with leader server " << std::endl; - continue; - } - - ResponseEnvelope> cas_response_envelope = cas_response_result.GetValue(); - WriteResponse write_cas_response = cas_response_envelope.message; - - if (write_cas_response.retry_leader) { - MG_ASSERT(!write_cas_response.success, "retry_leader should never be set for successful responses"); - leader = write_cas_response.retry_leader.value(); - std::cout << "client redirected to leader server " << leader.last_known_port << std::endl; - } else if (!write_cas_response.success) { - std::uniform_int_distribution addr_distrib(0, 2); - size_t addr_index = addr_distrib(cli_rng_); - leader = server_addrs[addr_index]; - - std::cout << "client NOT redirected to leader server, trying a random one at index " << addr_index - << " with port " << leader.last_known_port << std::endl; + auto write_cas_response_opt = client.SendWriteRequest(cas_req); + if (!write_cas_response_opt) { continue; } + auto write_cas_response = write_cas_response_opt.value(); CasResponse cas_response = write_cas_response.write_return; @@ -228,44 +291,17 @@ void RunSimulation() { continue; } + /* + * Get Request + */ GetRequest get_req; get_req.key = key; - ReadRequest read_req; - read_req.operation = get_req; - - std::cout << "client sending GetRequest to Leader " << leader.last_known_port << std::endl; - ResponseFuture> get_response_future = - cli_io.Request, ReadResponse>(leader, read_req); - - // receive response - ResponseResult> get_response_result = std::move(get_response_future).Wait(); - - if (get_response_result.HasError()) { - std::cout << "client timed out while trying to communicate with leader server " << std::endl; + auto read_get_response_opt = client.SendReadRequest(get_req); + if (!read_get_response_opt) { continue; } - - ResponseEnvelope> get_response_envelope = get_response_result.GetValue(); - ReadResponse read_get_response = get_response_envelope.message; - - if (!read_get_response.success) { - // sent to a non-leader - continue; - } - - if (read_get_response.retry_leader) { - MG_ASSERT(!read_get_response.success, "retry_leader should never be set for successful responses"); - leader = read_get_response.retry_leader.value(); - std::cout << "client redirected to leader server " << leader.last_known_port << std::endl; - } else if (!read_get_response.success) { - std::uniform_int_distribution addr_distrib(0, 2); - size_t addr_index = addr_distrib(cli_rng_); - leader = server_addrs[addr_index]; - - std::cout << "client NOT redirected to leader server, trying a random one at index " << addr_index - << " with port " << leader.last_known_port << std::endl; - } + auto read_get_response = read_get_response_opt.value(); GetResponse get_response = read_get_response.read_return;