Files
scylladb/test/raft/helpers.hh
Avi Kivity fcb8d040e8 treewide: use Software Package Data Exchange (SPDX) license identifiers
Instead of lengthy blurbs, switch to single-line, machine-readable
standardized (https://spdx.dev) license identifiers. The Linux kernel
switched long ago, so there is strong precedent.

Three cases are handled: AGPL-only, Apache-only, and dual licensed.
For the latter case, I chose (AGPL-3.0-or-later and Apache-2.0),
reasoning that our changes are extensive enough to apply our license.

The changes we applied mechanically with a script, except to
licenses/README.md.

Closes #9937
2022-01-18 12:15:18 +01:00

146 lines
4.1 KiB
C++

/*
* Copyright (C) 2021-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
//
// Helper functions for raft tests
//
#pragma once
#include <boost/test/unit_test.hpp>
#include "test/lib/log.hh"
#include "test/lib/random_utils.hh"
#include "serializer_impl.hh"
#include <limits>
#include "raft/fsm.hh"
using seastar::make_lw_shared;
void election_threshold(raft::fsm& fsm);
void election_timeout(raft::fsm& fsm);
void make_candidate(raft::fsm& fsm);
struct trivial_failure_detector: public raft::failure_detector {
bool is_alive(raft::server_id from) override {
return true;
}
};
extern struct trivial_failure_detector trivial_failure_detector;
class discrete_failure_detector: public raft::failure_detector {
bool _is_alive = true;
std::unordered_set<raft::server_id> _dead;
public:
bool is_alive(raft::server_id id) override {
return _is_alive && !_dead.contains(id);
}
void mark_dead(raft::server_id id) { _dead.emplace(id); }
void mark_alive(raft::server_id id) { _dead.erase(id); }
void mark_all_dead() { _is_alive = false; }
void mark_all_alive() { _is_alive = true; }
};
template <typename T> void add_entry(raft::log& log, T cmd) {
log.emplace_back(make_lw_shared<raft::log_entry>(raft::log_entry{log.last_term(), log.next_idx(), cmd}));
}
raft::snapshot_descriptor log_snapshot(raft::log& log, raft::index_t idx);
template <typename T>
raft::command create_command(T val) {
raft::command command;
ser::serialize(command, val);
return command;
}
extern raft::fsm_config fsm_cfg;
extern raft::fsm_config fsm_cfg_pre;
class fsm_debug : public raft::fsm {
public:
using raft::fsm::fsm;
void become_follower(raft::server_id leader) {
raft::fsm::become_follower(leader);
}
const raft::follower_progress& get_progress(raft::server_id id) {
raft::follower_progress* progress = leader_state().tracker.find(id);
return *progress;
}
raft::log& get_log() {
return raft::fsm::get_log();
}
bool leadership_transfer_active() const {
assert(is_leader());
return bool(leader_state().stepdown);
}
};
// NOTE: it doesn't compare data contents, just the data type
bool compare_log_entry(raft::log_entry_ptr le1, raft::log_entry_ptr le2);
bool compare_log_entries(raft::log& log1, raft::log& log2, size_t from, size_t to);
using raft_routing_map = std::unordered_map<raft::server_id, raft::fsm*>;
bool deliver(raft_routing_map& routes, raft::server_id from,
std::pair<raft::server_id, raft::rpc_message> m);
void deliver(raft_routing_map& routes, raft::server_id from,
std::vector<std::pair<raft::server_id, raft::rpc_message>> msgs);
void
communicate_impl(std::function<bool()> stop_pred, raft_routing_map& map);
template <typename... Args>
void communicate_until(std::function<bool()> stop_pred, Args&&... args) {
raft_routing_map map;
auto add_map_entry = [&map](raft::fsm& fsm) -> void {
map.emplace(fsm.id(), &fsm);
};
(add_map_entry(args), ...);
communicate_impl(stop_pred, map);
}
template <typename... Args>
void communicate(Args&&... args) {
return communicate_until([]() { return false; }, std::forward<Args>(args)...);
}
template <typename... Args>
raft::fsm* select_leader(Args&&... args) {
raft::fsm* leader = nullptr;
auto assign_leader = [&leader](raft::fsm& fsm) {
if (fsm.is_leader()) {
leader = &fsm;
return false;
}
return true;
};
(assign_leader(args) && ...);
BOOST_CHECK(leader);
return leader;
}
raft::server_id id();
raft::server_address_set address_set(std::vector<raft::server_id> ids);
fsm_debug create_follower(raft::server_id id, raft::log log,
raft::failure_detector& fd = trivial_failure_detector);
// Raft uses UUID 0 as special case.
// Convert local 0-based integer id to raft +1 UUID
utils::UUID to_raft_uuid(size_t int_id);
raft::server_id to_raft_id(size_t int_id);
// NOTE: can_vote = true
raft::server_address to_server_address(size_t int_id);
size_t to_int_id(utils::UUID uuid);
// Return true upon a random event with given probability
bool rolladice(float probability = 1.0/2.0);