memgraph/src/raft/coordination.cpp
Matej Ferencevic 1e79313538 Make HA heartbeat independent of other RPCs
Reviewers: msantl, ipaljak

Reviewed By: msantl, ipaljak

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2073
2019-05-20 15:04:15 +02:00

138 lines
4.1 KiB
C++

#include "raft/coordination.hpp"
#include <gflags/gflags.h>
#include <json/json.hpp>
#include "utils/file.hpp"
#include "utils/string.hpp"
DEFINE_string(rpc_cert_file, "", "Certificate file to use (RPC).");
DEFINE_string(rpc_key_file, "", "Key file to use (RPC).");
namespace raft {
namespace fs = std::filesystem;
std::unordered_map<uint16_t, io::network::Endpoint> LoadNodesFromFile(
const std::string &coordination_config_file) {
if (!fs::exists(coordination_config_file))
throw RaftCoordinationConfigException("file (" + coordination_config_file +
") doesn't exist");
std::unordered_map<uint16_t, io::network::Endpoint> nodes;
nlohmann::json data;
try {
data = nlohmann::json::parse(
utils::Join(utils::ReadLines(coordination_config_file), ""));
} catch (const nlohmann::json::parse_error &e) {
throw RaftCoordinationConfigException("invalid json");
}
if (!data.is_array()) throw RaftCoordinationConfigException("not an array");
for (auto &it : data) {
if (!it.is_array())
throw RaftCoordinationConfigException("element not an array");
if (it.size() != 3)
throw RaftCoordinationConfigException("invalid number of subelements");
if (!it[0].is_number_unsigned() || !it[1].is_string() ||
!it[2].is_number_unsigned())
throw RaftCoordinationConfigException("subelement data is invalid");
nodes[it[0]] = io::network::Endpoint{it[1], it[2]};
}
return nodes;
}
Coordination::Coordination(
uint16_t node_id,
std::unordered_map<uint16_t, io::network::Endpoint> all_nodes)
: node_id_(node_id), cluster_size_(all_nodes.size()) {
// Create and initialize all server elements.
if (!FLAGS_rpc_cert_file.empty() && !FLAGS_rpc_key_file.empty()) {
server_context_.emplace(FLAGS_rpc_key_file, FLAGS_rpc_cert_file);
} else {
server_context_.emplace();
}
server_.emplace(all_nodes[node_id_], &server_context_.value(),
all_nodes.size() * 2);
// Create all client elements.
endpoints_.resize(cluster_size_);
clients_.resize(cluster_size_);
client_locks_.resize(cluster_size_);
// Initialize all client elements.
client_context_.emplace(server_context_->use_ssl());
for (uint16_t i = 1; i <= cluster_size_; ++i) {
auto it = all_nodes.find(i);
if (it == all_nodes.end()) {
throw RaftCoordinationConfigException("missing endpoint for node " +
std::to_string(i));
}
endpoints_[i - 1] = it->second;
client_locks_[i - 1] = std::make_unique<std::mutex>();
}
}
Coordination::~Coordination() {
CHECK(!alive_) << "You must call Shutdown and AwaitShutdown on Coordination!";
}
std::vector<uint16_t> Coordination::GetAllNodeIds() {
std::vector<uint16_t> ret;
ret.reserve(cluster_size_);
for (uint16_t i = 1; i <= cluster_size_; ++i) {
ret.push_back(i);
}
return ret;
}
std::vector<uint16_t> Coordination::GetOtherNodeIds() {
std::vector<uint16_t> ret;
ret.reserve(cluster_size_ - 1);
for (uint16_t i = 1; i <= cluster_size_; ++i) {
if (i == node_id_) continue;
ret.push_back(i);
}
return ret;
}
uint16_t Coordination::GetAllNodeCount() { return cluster_size_; }
uint16_t Coordination::GetOtherNodeCount() { return cluster_size_ - 1; }
io::network::Endpoint Coordination::GetOtherNodeEndpoint(uint16_t other_id) {
CHECK(other_id != node_id_) << "Trying to execute RPC on self!";
CHECK(other_id >= 1 && other_id <= cluster_size_) << "Invalid node id!";
return endpoints_[other_id - 1];
}
communication::ClientContext *Coordination::GetRpcClientContext() {
return &client_context_.value();
}
bool Coordination::Start() { return server_->Start(); }
void Coordination::AwaitShutdown(
std::function<void(void)> call_before_shutdown) {
// Wait for a shutdown notification.
while (alive_) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// Call the before shutdown callback.
call_before_shutdown();
// Shutdown our RPC server.
server_->Shutdown();
server_->AwaitShutdown();
}
void Coordination::Shutdown() { alive_.store(false); }
} // namespace raft