Refactor replication client/server (#1311)
This commit is contained in:
parent
61ac7e1b11
commit
d71b6a5007
@ -238,9 +238,10 @@ class ReplQueryHandler final : public query::ReplicationQueryHandler {
|
|||||||
if (!port || *port < 0 || *port > std::numeric_limits<uint16_t>::max()) {
|
if (!port || *port < 0 || *port > std::numeric_limits<uint16_t>::max()) {
|
||||||
throw QueryRuntimeException("Port number invalid!");
|
throw QueryRuntimeException("Port number invalid!");
|
||||||
}
|
}
|
||||||
if (!db_->SetReplicaRole(
|
if (!db_->SetReplicaRole(storage::replication::ReplicationServerConfig{
|
||||||
io::network::Endpoint(storage::replication::kDefaultReplicationServerIp, static_cast<uint16_t>(*port)),
|
.ip_address = storage::replication::kDefaultReplicationServerIp,
|
||||||
storage::replication::ReplicationServerConfig{})) {
|
.port = static_cast<uint16_t>(*port),
|
||||||
|
})) {
|
||||||
throw QueryRuntimeException("Couldn't set role to replica!");
|
throw QueryRuntimeException("Couldn't set role to replica!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,9 +287,14 @@ class ReplQueryHandler final : public query::ReplicationQueryHandler {
|
|||||||
io::network::Endpoint::ParseSocketOrIpAddress(socket_address, storage::replication::kDefaultReplicationPort);
|
io::network::Endpoint::ParseSocketOrIpAddress(socket_address, storage::replication::kDefaultReplicationPort);
|
||||||
if (maybe_ip_and_port) {
|
if (maybe_ip_and_port) {
|
||||||
auto [ip, port] = *maybe_ip_and_port;
|
auto [ip, port] = *maybe_ip_and_port;
|
||||||
auto ret = db_->RegisterReplica(name, {std::move(ip), port}, repl_mode,
|
auto ret = db_->RegisterReplica(
|
||||||
storage::replication::RegistrationMode::MUST_BE_INSTANTLY_VALID,
|
storage::replication::RegistrationMode::MUST_BE_INSTANTLY_VALID,
|
||||||
{.replica_check_frequency = replica_check_frequency, .ssl = std::nullopt});
|
storage::replication::ReplicationClientConfig{.name = name,
|
||||||
|
.mode = repl_mode,
|
||||||
|
.ip_address = ip,
|
||||||
|
.port = port,
|
||||||
|
.replica_check_frequency = replica_check_frequency,
|
||||||
|
.ssl = std::nullopt});
|
||||||
if (ret.HasError()) {
|
if (ret.HasError()) {
|
||||||
throw QueryRuntimeException(fmt::format("Couldn't register replica '{}'!", name));
|
throw QueryRuntimeException(fmt::format("Couldn't register replica '{}'!", name));
|
||||||
}
|
}
|
||||||
|
@ -375,13 +375,12 @@ class DiskStorage final : public Storage {
|
|||||||
EdgeImportMode edge_import_status_{EdgeImportMode::INACTIVE};
|
EdgeImportMode edge_import_status_{EdgeImportMode::INACTIVE};
|
||||||
std::unique_ptr<EdgeImportModeCache> edge_import_mode_cache_{nullptr};
|
std::unique_ptr<EdgeImportModeCache> edge_import_mode_cache_{nullptr};
|
||||||
|
|
||||||
auto CreateReplicationClient(std::string name, io::network::Endpoint endpoint, replication::ReplicationMode mode,
|
auto CreateReplicationClient(replication::ReplicationClientConfig const &config)
|
||||||
const replication::ReplicationClientConfig &config)
|
|
||||||
-> std::unique_ptr<ReplicationClient> override {
|
-> std::unique_ptr<ReplicationClient> override {
|
||||||
throw utils::BasicException("Disk storage mode does not support replication.");
|
throw utils::BasicException("Disk storage mode does not support replication.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CreateReplicationServer(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config)
|
auto CreateReplicationServer(const replication::ReplicationServerConfig &config)
|
||||||
-> std::unique_ptr<ReplicationServer> override {
|
-> std::unique_ptr<ReplicationServer> override {
|
||||||
throw utils::BasicException("Disk storage mode does not support replication.");
|
throw utils::BasicException("Disk storage mode does not support replication.");
|
||||||
}
|
}
|
||||||
|
@ -102,10 +102,9 @@ uint64_t ReplicateCurrentWal(CurrentWalHandler &stream, durability::WalFile cons
|
|||||||
|
|
||||||
////// ReplicationClient //////
|
////// ReplicationClient //////
|
||||||
|
|
||||||
InMemoryReplicationClient::InMemoryReplicationClient(InMemoryStorage *storage, std::string name,
|
InMemoryReplicationClient::InMemoryReplicationClient(InMemoryStorage *storage,
|
||||||
io::network::Endpoint endpoint, replication::ReplicationMode mode,
|
|
||||||
const replication::ReplicationClientConfig &config)
|
const replication::ReplicationClientConfig &config)
|
||||||
: ReplicationClient{storage, std::move(name), std::move(endpoint), mode, config} {}
|
: ReplicationClient{storage, config} {}
|
||||||
|
|
||||||
void InMemoryReplicationClient::RecoverReplica(uint64_t replica_commit) {
|
void InMemoryReplicationClient::RecoverReplica(uint64_t replica_commit) {
|
||||||
spdlog::debug("Starting replica recover");
|
spdlog::debug("Starting replica recover");
|
||||||
|
@ -18,8 +18,7 @@ class InMemoryStorage;
|
|||||||
|
|
||||||
class InMemoryReplicationClient : public ReplicationClient {
|
class InMemoryReplicationClient : public ReplicationClient {
|
||||||
public:
|
public:
|
||||||
InMemoryReplicationClient(InMemoryStorage *storage, std::string name, io::network::Endpoint endpoint,
|
InMemoryReplicationClient(InMemoryStorage *storage, const replication::ReplicationClientConfig &config);
|
||||||
replication::ReplicationMode mode, const replication::ReplicationClientConfig &config = {});
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void RecoverReplica(uint64_t replica_commit) override;
|
void RecoverReplica(uint64_t replica_commit) override;
|
||||||
|
@ -32,9 +32,9 @@ std::pair<uint64_t, durability::WalDeltaData> ReadDelta(durability::BaseDecoder
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
InMemoryReplicationServer::InMemoryReplicationServer(InMemoryStorage *storage, memgraph::io::network::Endpoint endpoint,
|
InMemoryReplicationServer::InMemoryReplicationServer(InMemoryStorage *storage,
|
||||||
const replication::ReplicationServerConfig &config)
|
const replication::ReplicationServerConfig &config)
|
||||||
: ReplicationServer{std::move(endpoint), config}, storage_(storage) {
|
: ReplicationServer{config}, storage_(storage) {
|
||||||
rpc_server_.Register<replication::HeartbeatRpc>([this](auto *req_reader, auto *res_builder) {
|
rpc_server_.Register<replication::HeartbeatRpc>([this](auto *req_reader, auto *res_builder) {
|
||||||
spdlog::debug("Received HeartbeatRpc");
|
spdlog::debug("Received HeartbeatRpc");
|
||||||
this->HeartbeatHandler(req_reader, res_builder);
|
this->HeartbeatHandler(req_reader, res_builder);
|
||||||
|
@ -20,8 +20,7 @@ class InMemoryStorage;
|
|||||||
|
|
||||||
class InMemoryReplicationServer : public ReplicationServer {
|
class InMemoryReplicationServer : public ReplicationServer {
|
||||||
public:
|
public:
|
||||||
explicit InMemoryReplicationServer(InMemoryStorage *storage, io::network::Endpoint endpoint,
|
explicit InMemoryReplicationServer(InMemoryStorage *storage, const replication::ReplicationServerConfig &config);
|
||||||
const replication::ReplicationServerConfig &config);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// RPC handlers
|
// RPC handlers
|
||||||
|
@ -1832,16 +1832,14 @@ utils::FileRetainer::FileLockerAccessor::ret_type InMemoryStorage::UnlockPath()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto InMemoryStorage::CreateReplicationClient(std::string name, io::network::Endpoint endpoint,
|
auto InMemoryStorage::CreateReplicationClient(replication::ReplicationClientConfig const &config)
|
||||||
replication::ReplicationMode mode,
|
|
||||||
replication::ReplicationClientConfig const &config)
|
|
||||||
-> std::unique_ptr<ReplicationClient> {
|
-> std::unique_ptr<ReplicationClient> {
|
||||||
return std::make_unique<InMemoryReplicationClient>(this, std::move(name), std::move(endpoint), mode, config);
|
return std::make_unique<InMemoryReplicationClient>(this, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ReplicationServer> InMemoryStorage::CreateReplicationServer(
|
std::unique_ptr<ReplicationServer> InMemoryStorage::CreateReplicationServer(
|
||||||
io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config) {
|
const replication::ReplicationServerConfig &config) {
|
||||||
return std::make_unique<InMemoryReplicationServer>(this, std::move(endpoint), config);
|
return std::make_unique<InMemoryReplicationServer>(this, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace memgraph::storage
|
} // namespace memgraph::storage
|
||||||
|
@ -371,11 +371,10 @@ class InMemoryStorage final : public Storage {
|
|||||||
|
|
||||||
Transaction CreateTransaction(IsolationLevel isolation_level, StorageMode storage_mode) override;
|
Transaction CreateTransaction(IsolationLevel isolation_level, StorageMode storage_mode) override;
|
||||||
|
|
||||||
auto CreateReplicationClient(std::string name, io::network::Endpoint endpoint, replication::ReplicationMode mode,
|
auto CreateReplicationClient(replication::ReplicationClientConfig const &config)
|
||||||
replication::ReplicationClientConfig const &config)
|
|
||||||
-> std::unique_ptr<ReplicationClient> override;
|
-> std::unique_ptr<ReplicationClient> override;
|
||||||
|
|
||||||
auto CreateReplicationServer(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config)
|
auto CreateReplicationServer(const replication::ReplicationServerConfig &config)
|
||||||
-> std::unique_ptr<ReplicationServer> override;
|
-> std::unique_ptr<ReplicationServer> override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@ -15,8 +15,15 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "storage/v2/replication/enums.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::replication {
|
namespace memgraph::storage::replication {
|
||||||
struct ReplicationClientConfig {
|
struct ReplicationClientConfig {
|
||||||
|
std::string name;
|
||||||
|
ReplicationMode mode;
|
||||||
|
std::string ip_address;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
// The default delay between main checking/pinging replicas is 1s because
|
// The default delay between main checking/pinging replicas is 1s because
|
||||||
// that seems like a reasonable timeframe in which main should notice a
|
// that seems like a reasonable timeframe in which main should notice a
|
||||||
// replica is down.
|
// replica is down.
|
||||||
@ -33,6 +40,8 @@ struct ReplicationClientConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ReplicationServerConfig {
|
struct ReplicationServerConfig {
|
||||||
|
std::string ip_address;
|
||||||
|
uint16_t port;
|
||||||
struct SSL {
|
struct SSL {
|
||||||
std::string key_file;
|
std::string key_file;
|
||||||
std::string cert_file;
|
std::string cert_file;
|
||||||
|
@ -23,8 +23,8 @@ using OOMExceptionEnabler = utils::MemoryTracker::OutOfMemoryExceptionEnabler;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string RegisterReplicaErrorToString(ReplicationState::RegisterReplicaError error) {
|
std::string RegisterReplicaErrorToString(RegisterReplicaError error) {
|
||||||
using enum ReplicationState::RegisterReplicaError;
|
using enum RegisterReplicaError;
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case NAME_EXISTS:
|
case NAME_EXISTS:
|
||||||
return "NAME_EXISTS";
|
return "NAME_EXISTS";
|
||||||
@ -147,84 +147,75 @@ bool storage::ReplicationState::FinalizeTransaction(uint64_t timestamp) {
|
|||||||
return finalized_on_all_replicas;
|
return finalized_on_all_replicas;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::BasicResult<ReplicationState::RegisterReplicaError> ReplicationState::RegisterReplica(
|
utils::BasicResult<RegisterReplicaError> ReplicationState::RegisterReplica(
|
||||||
std::string name, io::network::Endpoint endpoint, const replication::ReplicationMode replication_mode,
|
|
||||||
const replication::RegistrationMode registration_mode, const replication::ReplicationClientConfig &config,
|
const replication::RegistrationMode registration_mode, const replication::ReplicationClientConfig &config,
|
||||||
Storage *storage) {
|
Storage *storage) {
|
||||||
MG_ASSERT(GetRole() == replication::ReplicationRole::MAIN, "Only main instance can register a replica!");
|
MG_ASSERT(GetRole() == replication::ReplicationRole::MAIN, "Only main instance can register a replica!");
|
||||||
|
|
||||||
const bool name_exists = replication_clients_.WithLock([&](auto &clients) {
|
auto name_check = [&config](auto &clients) {
|
||||||
return std::any_of(clients.begin(), clients.end(), [&name](const auto &client) { return client->Name() == name; });
|
auto name_matches = [&name = config.name](const auto &client) { return client->Name() == name; };
|
||||||
});
|
return std::any_of(clients.begin(), clients.end(), name_matches);
|
||||||
|
};
|
||||||
|
|
||||||
if (name_exists) {
|
auto desired_endpoint = io::network::Endpoint{config.ip_address, config.port};
|
||||||
return RegisterReplicaError::NAME_EXISTS;
|
auto endpoint_check = [&](auto &clients) {
|
||||||
}
|
auto endpoint_matches = [&](const auto &client) { return client->Endpoint() == desired_endpoint; };
|
||||||
|
return std::any_of(clients.begin(), clients.end(), endpoint_matches);
|
||||||
|
};
|
||||||
|
|
||||||
const auto end_point_exists = replication_clients_.WithLock([&endpoint](auto &clients) {
|
auto task = [&](auto &clients) -> utils::BasicResult<RegisterReplicaError> {
|
||||||
return std::any_of(clients.begin(), clients.end(),
|
if (name_check(clients)) {
|
||||||
[&endpoint](const auto &client) { return client->Endpoint() == endpoint; });
|
return RegisterReplicaError::NAME_EXISTS;
|
||||||
});
|
}
|
||||||
|
|
||||||
if (end_point_exists) {
|
if (endpoint_check(clients)) {
|
||||||
return RegisterReplicaError::END_POINT_EXISTS;
|
return RegisterReplicaError::END_POINT_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldStoreAndRestoreReplicationState()) {
|
if (!TryPersistReplicaClient(config)) {
|
||||||
auto data = replication::ReplicationStatusToJSON(
|
|
||||||
replication::ReplicationStatus{.name = name,
|
|
||||||
.ip_address = endpoint.address,
|
|
||||||
.port = endpoint.port,
|
|
||||||
.sync_mode = replication_mode,
|
|
||||||
.replica_check_frequency = config.replica_check_frequency,
|
|
||||||
.ssl = config.ssl,
|
|
||||||
.role = replication::ReplicationRole::REPLICA});
|
|
||||||
if (!durability_->Put(name, data.dump())) {
|
|
||||||
spdlog::error("Error when saving replica {} in settings.", name);
|
|
||||||
return RegisterReplicaError::COULD_NOT_BE_PERSISTED;
|
return RegisterReplicaError::COULD_NOT_BE_PERSISTED;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto client = storage->CreateReplicationClient(std::move(name), std::move(endpoint), replication_mode, config);
|
auto client = storage->CreateReplicationClient(config);
|
||||||
client->Start();
|
client->Start();
|
||||||
|
|
||||||
if (client->State() == replication::ReplicaState::INVALID) {
|
if (client->State() == replication::ReplicaState::INVALID) {
|
||||||
if (replication::RegistrationMode::CAN_BE_INVALID != registration_mode) {
|
if (replication::RegistrationMode::CAN_BE_INVALID != registration_mode) {
|
||||||
return RegisterReplicaError::CONNECTION_FAILED;
|
return RegisterReplicaError::CONNECTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::warn("Connection failed when registering replica {}. Replica will still be registered.", client->Name());
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::warn("Connection failed when registering replica {}. Replica will still be registered.", client->Name());
|
clients.push_back(std::move(client));
|
||||||
}
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
return replication_clients_.WithLock(
|
return replication_clients_.WithLock(task);
|
||||||
[&](auto &clients) -> utils::BasicResult<ReplicationState::RegisterReplicaError> {
|
|
||||||
// Another thread could have added a client with same name while
|
|
||||||
// we were connecting to this client.
|
|
||||||
if (std::any_of(clients.begin(), clients.end(),
|
|
||||||
[&](const auto &other_client) { return client->Name() == other_client->Name(); })) {
|
|
||||||
return RegisterReplicaError::NAME_EXISTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::any_of(clients.begin(), clients.end(), [&client](const auto &other_client) {
|
|
||||||
return client->Endpoint() == other_client->Endpoint();
|
|
||||||
})) {
|
|
||||||
return RegisterReplicaError::END_POINT_EXISTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
clients.push_back(std::move(client));
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplicationState::SetReplicaRole(io::network::Endpoint endpoint,
|
bool ReplicationState::TryPersistReplicaClient(const replication::ReplicationClientConfig &config) {
|
||||||
const replication::ReplicationServerConfig &config, Storage *storage) {
|
if (!ShouldStoreAndRestoreReplicationState()) return true;
|
||||||
|
auto data = replication::ReplicationStatusToJSON(
|
||||||
|
replication::ReplicationStatus{.name = config.name,
|
||||||
|
.ip_address = config.ip_address,
|
||||||
|
.port = config.port,
|
||||||
|
.sync_mode = config.mode,
|
||||||
|
.replica_check_frequency = config.replica_check_frequency,
|
||||||
|
.ssl = config.ssl,
|
||||||
|
.role = replication::ReplicationRole::REPLICA});
|
||||||
|
if (durability_->Put(config.name, data.dump())) return true;
|
||||||
|
spdlog::error("Error when saving replica {} in settings.", config.name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReplicationState::SetReplicaRole(const replication::ReplicationServerConfig &config, Storage *storage) {
|
||||||
// We don't want to restart the server if we're already a REPLICA
|
// We don't want to restart the server if we're already a REPLICA
|
||||||
if (GetRole() == replication::ReplicationRole::REPLICA) {
|
if (GetRole() == replication::ReplicationRole::REPLICA) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto port = endpoint.port; // assigning because we will move the endpoint
|
replication_server_ = storage->CreateReplicationServer(config);
|
||||||
replication_server_ = storage->CreateReplicationServer(std::move(endpoint), config);
|
|
||||||
bool res = replication_server_->Start();
|
bool res = replication_server_->Start();
|
||||||
if (!res) {
|
if (!res) {
|
||||||
spdlog::error("Unable to start the replication server.");
|
spdlog::error("Unable to start the replication server.");
|
||||||
@ -235,8 +226,8 @@ bool ReplicationState::SetReplicaRole(io::network::Endpoint endpoint,
|
|||||||
// Only thing that matters here is the role saved as REPLICA and the listening port
|
// Only thing that matters here is the role saved as REPLICA and the listening port
|
||||||
auto data = replication::ReplicationStatusToJSON(
|
auto data = replication::ReplicationStatusToJSON(
|
||||||
replication::ReplicationStatus{.name = replication::kReservedReplicationRoleName,
|
replication::ReplicationStatus{.name = replication::kReservedReplicationRoleName,
|
||||||
.ip_address = "",
|
.ip_address = config.ip_address,
|
||||||
.port = port,
|
.port = config.port,
|
||||||
.sync_mode = replication::ReplicationMode::SYNC,
|
.sync_mode = replication::ReplicationMode::SYNC,
|
||||||
.replica_check_frequency = std::chrono::seconds(0),
|
.replica_check_frequency = std::chrono::seconds(0),
|
||||||
.ssl = std::nullopt,
|
.ssl = std::nullopt,
|
||||||
@ -318,8 +309,10 @@ void ReplicationState::RestoreReplicationRole(Storage *storage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (GetRole() == replication::ReplicationRole::REPLICA) {
|
if (GetRole() == replication::ReplicationRole::REPLICA) {
|
||||||
io::network::Endpoint endpoint(replication::kDefaultReplicationServerIp, port);
|
replication_server_ = storage->CreateReplicationServer(replication::ReplicationServerConfig{
|
||||||
replication_server_ = storage->CreateReplicationServer(std::move(endpoint), {});
|
.ip_address = replication::kDefaultReplicationServerIp,
|
||||||
|
.port = port,
|
||||||
|
});
|
||||||
bool res = replication_server_->Start();
|
bool res = replication_server_->Start();
|
||||||
if (!res) {
|
if (!res) {
|
||||||
LOG_FATAL("Unable to start the replication server.");
|
LOG_FATAL("Unable to start the replication server.");
|
||||||
@ -352,14 +345,16 @@ void ReplicationState::RestoreReplicas(Storage *storage) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret =
|
auto ret = RegisterReplica(replication::RegistrationMode::CAN_BE_INVALID,
|
||||||
RegisterReplica(std::move(replica_status.name), {std::move(replica_status.ip_address), replica_status.port},
|
replication::ReplicationClientConfig{
|
||||||
replica_status.sync_mode, replication::RegistrationMode::CAN_BE_INVALID,
|
.name = replica_status.name,
|
||||||
{
|
.mode = replica_status.sync_mode,
|
||||||
.replica_check_frequency = replica_status.replica_check_frequency,
|
.ip_address = replica_status.ip_address,
|
||||||
.ssl = replica_status.ssl,
|
.port = replica_status.port,
|
||||||
},
|
.replica_check_frequency = replica_status.replica_check_frequency,
|
||||||
storage);
|
.ssl = replica_status.ssl,
|
||||||
|
},
|
||||||
|
storage);
|
||||||
|
|
||||||
if (ret.HasError()) {
|
if (ret.HasError()) {
|
||||||
MG_ASSERT(RegisterReplicaError::CONNECTION_FAILED != ret.GetError());
|
MG_ASSERT(RegisterReplicaError::CONNECTION_FAILED != ret.GetError());
|
||||||
|
@ -32,14 +32,9 @@ class Storage;
|
|||||||
class ReplicationServer;
|
class ReplicationServer;
|
||||||
class ReplicationClient;
|
class ReplicationClient;
|
||||||
|
|
||||||
struct ReplicationState {
|
enum class RegisterReplicaError : uint8_t { NAME_EXISTS, END_POINT_EXISTS, CONNECTION_FAILED, COULD_NOT_BE_PERSISTED };
|
||||||
enum class RegisterReplicaError : uint8_t {
|
|
||||||
NAME_EXISTS,
|
|
||||||
END_POINT_EXISTS,
|
|
||||||
CONNECTION_FAILED,
|
|
||||||
COULD_NOT_BE_PERSISTED
|
|
||||||
};
|
|
||||||
|
|
||||||
|
struct ReplicationState {
|
||||||
// TODO: This mirrors the logic in InMemoryConstructor; make it independent
|
// TODO: This mirrors the logic in InMemoryConstructor; make it independent
|
||||||
ReplicationState(bool restore, std::filesystem::path durability_dir);
|
ReplicationState(bool restore, std::filesystem::path durability_dir);
|
||||||
|
|
||||||
@ -50,7 +45,7 @@ struct ReplicationState {
|
|||||||
|
|
||||||
bool SetMainReplicationRole(Storage *storage); // Set the instance to MAIN
|
bool SetMainReplicationRole(Storage *storage); // Set the instance to MAIN
|
||||||
// TODO: ReplicationServer/Client uses Storage* for RPC callbacks
|
// TODO: ReplicationServer/Client uses Storage* for RPC callbacks
|
||||||
bool SetReplicaRole(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config,
|
bool SetReplicaRole(const replication::ReplicationServerConfig &config,
|
||||||
Storage *storage); // Sets the instance to REPLICA
|
Storage *storage); // Sets the instance to REPLICA
|
||||||
// Generic restoration
|
// Generic restoration
|
||||||
void RestoreReplicationRole(Storage *storage);
|
void RestoreReplicationRole(Storage *storage);
|
||||||
@ -64,9 +59,7 @@ struct ReplicationState {
|
|||||||
bool FinalizeTransaction(uint64_t timestamp);
|
bool FinalizeTransaction(uint64_t timestamp);
|
||||||
|
|
||||||
// MAIN connecting to replicas
|
// MAIN connecting to replicas
|
||||||
utils::BasicResult<RegisterReplicaError> RegisterReplica(std::string name, io::network::Endpoint endpoint,
|
utils::BasicResult<RegisterReplicaError> RegisterReplica(const replication::RegistrationMode registration_mode,
|
||||||
const replication::ReplicationMode replication_mode,
|
|
||||||
const replication::RegistrationMode registration_mode,
|
|
||||||
const replication::ReplicationClientConfig &config,
|
const replication::ReplicationClientConfig &config,
|
||||||
Storage *storage);
|
Storage *storage);
|
||||||
bool UnregisterReplica(std::string_view name);
|
bool UnregisterReplica(std::string_view name);
|
||||||
@ -97,8 +90,8 @@ struct ReplicationState {
|
|||||||
void AppendEpoch(std::string new_epoch);
|
void AppendEpoch(std::string new_epoch);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool TryPersistReplicaClient(const replication::ReplicationClientConfig &config);
|
||||||
bool ShouldStoreAndRestoreReplicationState() const { return nullptr != durability_; }
|
bool ShouldStoreAndRestoreReplicationState() const { return nullptr != durability_; }
|
||||||
|
|
||||||
void SetRole(replication::ReplicationRole role) { return replication_role_.store(role); }
|
void SetRole(replication::ReplicationRole role) { return replication_role_.store(role); }
|
||||||
|
|
||||||
// NOTE: Server is not in MAIN it is in REPLICA
|
// NOTE: Server is not in MAIN it is in REPLICA
|
||||||
|
@ -30,14 +30,12 @@ static auto CreateClientContext(const replication::ReplicationClientConfig &conf
|
|||||||
: communication::ClientContext{};
|
: communication::ClientContext{};
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplicationClient::ReplicationClient(Storage *storage, std::string name, memgraph::io::network::Endpoint endpoint,
|
ReplicationClient::ReplicationClient(Storage *storage, replication::ReplicationClientConfig const &config)
|
||||||
replication::ReplicationMode mode,
|
: name_{config.name},
|
||||||
replication::ReplicationClientConfig const &config)
|
|
||||||
: name_{std::move(name)},
|
|
||||||
rpc_context_{CreateClientContext(config)},
|
rpc_context_{CreateClientContext(config)},
|
||||||
rpc_client_{std::move(endpoint), &rpc_context_},
|
rpc_client_{io::network::Endpoint(config.ip_address, config.port), &rpc_context_},
|
||||||
replica_check_frequency_{config.replica_check_frequency},
|
replica_check_frequency_{config.replica_check_frequency},
|
||||||
mode_{mode},
|
mode_{config.mode},
|
||||||
storage_{storage} {}
|
storage_{storage} {}
|
||||||
|
|
||||||
ReplicationClient::~ReplicationClient() {
|
ReplicationClient::~ReplicationClient() {
|
||||||
|
@ -66,8 +66,7 @@ class ReplicationClient {
|
|||||||
friend class ReplicaStream;
|
friend class ReplicaStream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReplicationClient(Storage *storage, std::string name, memgraph::io::network::Endpoint endpoint,
|
ReplicationClient(Storage *storage, replication::ReplicationClientConfig const &config);
|
||||||
replication::ReplicationMode mode, const replication::ReplicationClientConfig &config);
|
|
||||||
|
|
||||||
ReplicationClient(ReplicationClient const &) = delete;
|
ReplicationClient(ReplicationClient const &) = delete;
|
||||||
ReplicationClient &operator=(ReplicationClient const &) = delete;
|
ReplicationClient &operator=(ReplicationClient const &) = delete;
|
||||||
|
@ -30,9 +30,10 @@ auto CreateServerContext(const replication::ReplicationServerConfig &config) ->
|
|||||||
constexpr auto kReplictionServerThreads = 1;
|
constexpr auto kReplictionServerThreads = 1;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ReplicationServer::ReplicationServer(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config)
|
ReplicationServer::ReplicationServer(const replication::ReplicationServerConfig &config)
|
||||||
: rpc_server_context_{CreateServerContext(config)},
|
: rpc_server_context_{CreateServerContext(config)},
|
||||||
rpc_server_{std::move(endpoint), &rpc_server_context_, kReplictionServerThreads} {
|
rpc_server_{io::network::Endpoint{config.ip_address, config.port}, &rpc_server_context_,
|
||||||
|
kReplictionServerThreads} {
|
||||||
rpc_server_.Register<replication::FrequentHeartbeatRpc>([](auto *req_reader, auto *res_builder) {
|
rpc_server_.Register<replication::FrequentHeartbeatRpc>([](auto *req_reader, auto *res_builder) {
|
||||||
spdlog::debug("Received FrequentHeartbeatRpc");
|
spdlog::debug("Received FrequentHeartbeatRpc");
|
||||||
FrequentHeartbeatHandler(req_reader, res_builder);
|
FrequentHeartbeatHandler(req_reader, res_builder);
|
||||||
|
@ -20,7 +20,7 @@ namespace memgraph::storage {
|
|||||||
|
|
||||||
class ReplicationServer {
|
class ReplicationServer {
|
||||||
public:
|
public:
|
||||||
explicit ReplicationServer(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config);
|
explicit ReplicationServer(const replication::ReplicationServerConfig &config);
|
||||||
ReplicationServer(const ReplicationServer &) = delete;
|
ReplicationServer(const ReplicationServer &) = delete;
|
||||||
ReplicationServer(ReplicationServer &&) = delete;
|
ReplicationServer(ReplicationServer &&) = delete;
|
||||||
ReplicationServer &operator=(const ReplicationServer &) = delete;
|
ReplicationServer &operator=(const ReplicationServer &) = delete;
|
||||||
|
@ -315,29 +315,23 @@ class Storage {
|
|||||||
|
|
||||||
virtual void EstablishNewEpoch() = 0;
|
virtual void EstablishNewEpoch() = 0;
|
||||||
|
|
||||||
virtual auto CreateReplicationClient(std::string name, io::network::Endpoint endpoint,
|
virtual auto CreateReplicationClient(replication::ReplicationClientConfig const &config)
|
||||||
replication::ReplicationMode mode,
|
|
||||||
replication::ReplicationClientConfig const &config)
|
|
||||||
-> std::unique_ptr<ReplicationClient> = 0;
|
-> std::unique_ptr<ReplicationClient> = 0;
|
||||||
|
|
||||||
virtual auto CreateReplicationServer(io::network::Endpoint endpoint,
|
virtual auto CreateReplicationServer(const replication::ReplicationServerConfig &config)
|
||||||
replication::ReplicationServerConfig const &config)
|
|
||||||
-> std::unique_ptr<ReplicationServer> = 0;
|
-> std::unique_ptr<ReplicationServer> = 0;
|
||||||
|
|
||||||
/// REPLICATION
|
/// REPLICATION
|
||||||
bool SetReplicaRole(io::network::Endpoint endpoint, const replication::ReplicationServerConfig &config) {
|
bool SetReplicaRole(const replication::ReplicationServerConfig &config) {
|
||||||
return replication_state_.SetReplicaRole(std::move(endpoint), config, this);
|
return replication_state_.SetReplicaRole(config, this);
|
||||||
}
|
}
|
||||||
bool SetMainReplicationRole() { return replication_state_.SetMainReplicationRole(this); }
|
bool SetMainReplicationRole() { return replication_state_.SetMainReplicationRole(this); }
|
||||||
|
|
||||||
/// @pre The instance should have a MAIN role
|
/// @pre The instance should have a MAIN role
|
||||||
/// @pre Timeout can only be set for SYNC replication
|
/// @pre Timeout can only be set for SYNC replication
|
||||||
auto RegisterReplica(std::string name, io::network::Endpoint endpoint,
|
auto RegisterReplica(const replication::RegistrationMode registration_mode,
|
||||||
const replication::ReplicationMode replication_mode,
|
|
||||||
const replication::RegistrationMode registration_mode,
|
|
||||||
const replication::ReplicationClientConfig &config) {
|
const replication::ReplicationClientConfig &config) {
|
||||||
return replication_state_.RegisterReplica(std::move(name), std::move(endpoint), replication_mode, registration_mode,
|
return replication_state_.RegisterReplica(registration_mode, config, this);
|
||||||
config, this);
|
|
||||||
}
|
}
|
||||||
/// @pre The instance should have a MAIN role
|
/// @pre The instance should have a MAIN role
|
||||||
bool UnregisterReplica(const std::string &name) { return replication_state_.UnregisterReplica(name); }
|
bool UnregisterReplica(const std::string &name) { return replication_state_.UnregisterReplica(name); }
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user