237 lines
11 KiB
C++
237 lines
11 KiB
C++
// Copyright 2024 Memgraph Ltd.
|
|
//
|
|
// 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
|
|
// License, and you may not use this file except in compliance with the Business Source License.
|
|
//
|
|
// As of the Change Date specified in that file, in accordance with
|
|
// the Business Source License, use of this software will be governed
|
|
// by the Apache License, Version 2.0, included in the file
|
|
// licenses/APL.txt.
|
|
|
|
#include <gflags/gflags.h>
|
|
#include <gtest/gtest.h>
|
|
#include "coordination/coordinator_instance.hpp"
|
|
#include "dbms/constants.hpp"
|
|
#include "replication_coordination_glue/common.hpp"
|
|
#include "utils/functional.hpp"
|
|
|
|
class CoordinationUtils : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {}
|
|
|
|
void TearDown() override {}
|
|
|
|
std::filesystem::path test_folder_{std::filesystem::temp_directory_path() / "MG_tests_unit_coordination"};
|
|
};
|
|
|
|
TEST_F(CoordinationUtils, MemgraphDbHistorySimple) {
|
|
// Choose any if everything is same
|
|
// X = dead
|
|
// Main : A(24) B(36) C(48) D(50) E(51) X
|
|
// replica 1: A(24) B(36) C(48) D(50) E(51)
|
|
// replica 2: A(24) B(36) C(48) D(50) E(51)
|
|
// replica 3: A(24) B(36) C(48) D(50) E(51)
|
|
std::vector<std::pair<std::string, memgraph::replication_coordination_glue::DatabaseHistories>>
|
|
instance_database_histories;
|
|
|
|
std::vector<std::pair<memgraph::utils::UUID, uint64_t>> histories;
|
|
histories.emplace_back(memgraph::utils::UUID{}, 24);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 36);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 48);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 50);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 51);
|
|
|
|
memgraph::utils::UUID db_uuid;
|
|
std::string default_name = std::string(memgraph::dbms::kDefaultDB);
|
|
|
|
auto db_histories = memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistory history{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_1_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_1", instance_1_db_histories_);
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_2_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_2", instance_2_db_histories_);
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_3_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_3", instance_3_db_histories_);
|
|
memgraph::coordination::CoordinatorInstance instance;
|
|
|
|
auto [instance_name, latest_epoch, latest_commit_timestamp] =
|
|
instance.ChooseMostUpToDateInstance(instance_database_histories);
|
|
ASSERT_TRUE(instance_name == "instance_1" || instance_name == "instance_2" || instance_name == "instance_3");
|
|
ASSERT_TRUE(latest_epoch == db_histories.back().first);
|
|
ASSERT_TRUE(latest_commit_timestamp == db_histories.back().second);
|
|
}
|
|
|
|
TEST_F(CoordinationUtils, MemgraphDbHistoryLastEpochDifferent) {
|
|
// Prioritize one with the biggest last commit timestamp on last epoch
|
|
// X = dead
|
|
// Main : A(24) B(36) C(48) D(50) E(59) X
|
|
// replica 1: A(24) B(12) C(15) D(17) E(51)
|
|
// replica 2: A(24) B(12) C(15) D(17) E(57)
|
|
// replica 3: A(24) B(12) C(15) D(17) E(59)
|
|
std::vector<std::pair<std::string, memgraph::replication_coordination_glue::DatabaseHistories>>
|
|
instance_database_histories;
|
|
|
|
std::vector<std::pair<memgraph::utils::UUID, uint64_t>> histories;
|
|
histories.emplace_back(memgraph::utils::UUID{}, 24);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 36);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 48);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 50);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 59);
|
|
|
|
memgraph::utils::UUID db_uuid;
|
|
std::string default_name = std::string(memgraph::dbms::kDefaultDB);
|
|
|
|
auto db_histories = memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
db_histories.back().second = 51;
|
|
memgraph::replication_coordination_glue::DatabaseHistory history1{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_1_db_histories_{history1};
|
|
instance_database_histories.emplace_back("instance_1", instance_1_db_histories_);
|
|
|
|
db_histories.back().second = 57;
|
|
memgraph::replication_coordination_glue::DatabaseHistory history2{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_2_db_histories_{history2};
|
|
instance_database_histories.emplace_back("instance_2", instance_2_db_histories_);
|
|
|
|
db_histories.back().second = 59;
|
|
memgraph::replication_coordination_glue::DatabaseHistory history3{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_3_db_histories_{history3};
|
|
instance_database_histories.emplace_back("instance_3", instance_3_db_histories_);
|
|
|
|
memgraph::coordination::CoordinatorInstance instance;
|
|
auto [instance_name, latest_epoch, latest_commit_timestamp] =
|
|
instance.ChooseMostUpToDateInstance(instance_database_histories);
|
|
|
|
ASSERT_TRUE(instance_name == "instance_3");
|
|
ASSERT_TRUE(latest_epoch == db_histories.back().first);
|
|
ASSERT_TRUE(latest_commit_timestamp == db_histories.back().second);
|
|
}
|
|
|
|
TEST_F(CoordinationUtils, MemgraphDbHistoryOneInstanceAheadFewEpochs) {
|
|
// Prioritize one biggest commit timestamp
|
|
// X = dead
|
|
// Main : A(24) B(36) C(48) D(50) E(51) X X X X
|
|
// replica 1: A(24) B(36) C(48) D(50) E(51) F(60) G(65) X up
|
|
// replica 2: A(24) B(36) C(48) D(50) E(51) X X X up
|
|
// replica 3: A(24) B(36) C(48) D(50) E(51) X X X up
|
|
std::vector<std::pair<std::string, memgraph::replication_coordination_glue::DatabaseHistories>>
|
|
instance_database_histories;
|
|
|
|
std::vector<std::pair<memgraph::utils::UUID, uint64_t>> histories;
|
|
histories.emplace_back(memgraph::utils::UUID{}, 24);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 36);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 48);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 50);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 51);
|
|
|
|
memgraph::utils::UUID db_uuid;
|
|
std::string default_name = std::string(memgraph::dbms::kDefaultDB);
|
|
|
|
auto db_histories = memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistory history{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_1_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_1", instance_1_db_histories_);
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_2_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_2", instance_2_db_histories_);
|
|
|
|
histories.emplace_back(memgraph::utils::UUID{}, 60);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 65);
|
|
auto db_histories_longest =
|
|
memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistory history_longest{
|
|
.db_uuid = db_uuid, .history = db_histories_longest, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_3_db_histories_{history_longest};
|
|
instance_database_histories.emplace_back("instance_3", instance_3_db_histories_);
|
|
|
|
memgraph::coordination::CoordinatorInstance instance;
|
|
auto [instance_name, latest_epoch, latest_commit_timestamp] =
|
|
instance.ChooseMostUpToDateInstance(instance_database_histories);
|
|
|
|
ASSERT_TRUE(instance_name == "instance_3");
|
|
ASSERT_TRUE(latest_epoch == db_histories_longest.back().first);
|
|
ASSERT_TRUE(latest_commit_timestamp == db_histories_longest.back().second);
|
|
}
|
|
|
|
TEST_F(CoordinationUtils, MemgraphDbHistoryInstancesHistoryDiverged) {
|
|
// When history diverged, also prioritize one with biggest last commit timestamp
|
|
// Main : A(1) B(2) C(3) X
|
|
// replica 1: A(1) B(2) C(3) X X up
|
|
// replica 2: A(1) B(2) X D(5) X up
|
|
// replica 3: A(1) B(2) X D(4) X up
|
|
std::vector<std::pair<std::string, memgraph::replication_coordination_glue::DatabaseHistories>>
|
|
instance_database_histories;
|
|
|
|
std::vector<std::pair<memgraph::utils::UUID, uint64_t>> histories;
|
|
histories.emplace_back(memgraph::utils::UUID{}, 1);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 2);
|
|
histories.emplace_back(memgraph::utils::UUID{}, 3);
|
|
|
|
memgraph::utils::UUID db_uuid;
|
|
std::string default_name = std::string(memgraph::dbms::kDefaultDB);
|
|
|
|
auto db_histories = memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistory history{
|
|
.db_uuid = db_uuid, .history = db_histories, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_1_db_histories_{history};
|
|
instance_database_histories.emplace_back("instance_1", instance_1_db_histories_);
|
|
|
|
db_histories.pop_back();
|
|
|
|
auto oldest_commit_timestamp{5};
|
|
auto newest_different_epoch = memgraph::utils::UUID{};
|
|
histories.emplace_back(newest_different_epoch, oldest_commit_timestamp);
|
|
auto db_histories_different =
|
|
memgraph::utils::fmap(histories, [](const std::pair<memgraph::utils::UUID, uint64_t> &pair) {
|
|
return std::make_pair(std::string(pair.first), pair.second);
|
|
});
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistory history_3{
|
|
.db_uuid = db_uuid, .history = db_histories_different, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_3_db_histories_{history_3};
|
|
instance_database_histories.emplace_back("instance_3", instance_3_db_histories_);
|
|
|
|
db_histories_different.back().second = 4;
|
|
memgraph::replication_coordination_glue::DatabaseHistory history_2{
|
|
.db_uuid = db_uuid, .history = db_histories_different, .name = default_name};
|
|
|
|
memgraph::replication_coordination_glue::DatabaseHistories instance_2_db_histories_{history_2};
|
|
instance_database_histories.emplace_back("instance_2", instance_2_db_histories_);
|
|
|
|
memgraph::coordination::CoordinatorInstance instance;
|
|
auto [instance_name, latest_epoch, latest_commit_timestamp] =
|
|
instance.ChooseMostUpToDateInstance(instance_database_histories);
|
|
|
|
ASSERT_TRUE(instance_name == "instance_3");
|
|
ASSERT_TRUE(latest_epoch == std::string(newest_different_epoch));
|
|
ASSERT_TRUE(latest_commit_timestamp == oldest_commit_timestamp);
|
|
}
|