From 3e3224f0a248da67250892df10f2f92251424cd6 Mon Sep 17 00:00:00 2001 From: Andi <andi8647@gmail.com> Date: Fri, 16 Feb 2024 12:41:15 +0100 Subject: [PATCH] Forbid having multiple mains in the cluster (#1727) --- src/coordination/coordinator_instance.cpp | 4 ++++ .../register_main_replica_coordinator_status.hpp | 1 + src/query/interpreter.cpp | 2 ++ .../single_coordinator.py | 15 +++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/src/coordination/coordinator_instance.cpp b/src/coordination/coordinator_instance.cpp index b8afbb6a3..1bbcf4f8f 100644 --- a/src/coordination/coordinator_instance.cpp +++ b/src/coordination/coordinator_instance.cpp @@ -206,6 +206,10 @@ auto CoordinatorInstance::SetReplicationInstanceToMain(std::string instance_name -> SetInstanceToMainCoordinatorStatus { auto lock = std::lock_guard{coord_instance_lock_}; + if (std::ranges::any_of(repl_instances_, &ReplicationInstance::IsMain)) { + return SetInstanceToMainCoordinatorStatus::MAIN_ALREADY_EXISTS; + } + auto const is_new_main = [&instance_name](ReplicationInstance const &instance) { return instance.InstanceName() == instance_name; }; diff --git a/src/coordination/include/coordination/register_main_replica_coordinator_status.hpp b/src/coordination/include/coordination/register_main_replica_coordinator_status.hpp index 5fcb93921..3aa7e3ca1 100644 --- a/src/coordination/include/coordination/register_main_replica_coordinator_status.hpp +++ b/src/coordination/include/coordination/register_main_replica_coordinator_status.hpp @@ -39,6 +39,7 @@ enum class UnregisterInstanceCoordinatorStatus : uint8_t { enum class SetInstanceToMainCoordinatorStatus : uint8_t { NO_INSTANCE_WITH_NAME, + MAIN_ALREADY_EXISTS, NOT_COORDINATOR, SUCCESS, COULD_NOT_PROMOTE_TO_MAIN, diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index f0fed2357..c7ccbb1ef 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -563,6 +563,8 @@ class CoordQueryHandler final : public query::CoordinatorQueryHandler { using enum memgraph::coordination::SetInstanceToMainCoordinatorStatus; case NO_INSTANCE_WITH_NAME: throw QueryRuntimeException("No instance with such name!"); + case MAIN_ALREADY_EXISTS: + throw QueryRuntimeException("Couldn't set instance to main since there is already a main instance in cluster!"); case NOT_COORDINATOR: throw QueryRuntimeException("SET INSTANCE TO MAIN query can only be run on a coordinator!"); case COULD_NOT_PROMOTE_TO_MAIN: diff --git a/tests/e2e/high_availability_experimental/single_coordinator.py b/tests/e2e/high_availability_experimental/single_coordinator.py index d1df05b4f..8e620e7e4 100644 --- a/tests/e2e/high_availability_experimental/single_coordinator.py +++ b/tests/e2e/high_availability_experimental/single_coordinator.py @@ -515,5 +515,20 @@ def test_automatic_failover_main_back_as_main(): mg_sleep_and_assert([("main",)], retrieve_data_show_repl_role_instance3) +def test_disable_multiple_mains(): + safe_execute(shutil.rmtree, TEMP_DIR) + interactive_mg_runner.start_all(MEMGRAPH_INSTANCES_DESCRIPTION) + + coord_cursor = connect(host="localhost", port=7690).cursor() + + try: + execute_and_fetch_all( + coord_cursor, + "SET INSTANCE instance_1 TO MAIN;", + ) + except Exception as e: + assert str(e) == "Couldn't set instance to main since there is already a main instance in cluster!" + + if __name__ == "__main__": sys.exit(pytest.main([__file__, "-rA"]))