// 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 "storage/v2/replication/replication_storage_state.hpp" #include "replication/replication_server.hpp" #include "storage/v2/replication/replication_client.hpp" namespace memgraph::storage { void ReplicationStorageState::InitializeTransaction(uint64_t seq_num, Storage *storage, DatabaseAccessProtector db_acc) { replication_clients_.WithLock([=, db_acc = std::move(db_acc)](auto &clients) mutable { for (auto &client : clients) { client->StartTransactionReplication(seq_num, storage, std::move(db_acc)); } }); } void ReplicationStorageState::AppendDelta(const Delta &delta, const Vertex &vertex, uint64_t timestamp) { replication_clients_.WithLock([&](auto &clients) { for (auto &client : clients) { client->IfStreamingTransaction([&](auto &stream) { stream.AppendDelta(delta, vertex, timestamp); }); } }); } void ReplicationStorageState::AppendDelta(const Delta &delta, const Edge &edge, uint64_t timestamp) { replication_clients_.WithLock([&](auto &clients) { for (auto &client : clients) { client->IfStreamingTransaction([&](auto &stream) { stream.AppendDelta(delta, edge, timestamp); }); } }); } void ReplicationStorageState::AppendOperation(durability::StorageMetadataOperation operation, LabelId label, const std::set &properties, const LabelIndexStats &stats, const LabelPropertyIndexStats &property_stats, uint64_t final_commit_timestamp) { replication_clients_.WithLock([&](auto &clients) { for (auto &client : clients) { client->IfStreamingTransaction([&](auto &stream) { stream.AppendOperation(operation, label, properties, stats, property_stats, final_commit_timestamp); }); } }); } bool ReplicationStorageState::FinalizeTransaction(uint64_t timestamp, Storage *storage, DatabaseAccessProtector db_acc) { return replication_clients_.WithLock([=, db_acc = std::move(db_acc)](auto &clients) mutable { bool finalized_on_all_replicas = true; MG_ASSERT(clients.empty() || db_acc.has_value(), "Any clients assumes we are MAIN, we should have gatekeeper_access_wrapper so we can correctly " "handle ASYNC tasks"); for (ReplicationClientPtr &client : clients) { client->IfStreamingTransaction([&](auto &stream) { stream.AppendTransactionEnd(timestamp); }); const auto finalized = client->FinalizeTransactionReplication(storage, std::move(db_acc)); if (client->Mode() == replication_coordination_glue::ReplicationMode::SYNC) { finalized_on_all_replicas = finalized && finalized_on_all_replicas; } } return finalized_on_all_replicas; }); } std::optional ReplicationStorageState::GetReplicaState(std::string_view name) const { return replication_clients_.WithReadLock([&](auto const &clients) -> std::optional { auto const name_matches = [=](ReplicationClientPtr const &client) { return client->Name() == name; }; auto const client_it = std::find_if(clients.cbegin(), clients.cend(), name_matches); if (client_it == clients.cend()) { return std::nullopt; } return (*client_it)->State(); }); } std::vector ReplicationStorageState::ReplicasInfo(const Storage *storage) const { return replication_clients_.WithReadLock([storage](auto const &clients) { std::vector replica_infos; replica_infos.reserve(clients.size()); auto const asReplicaInfo = [storage](ReplicationClientPtr const &client) -> ReplicaInfo { const auto ts = client->GetTimestampInfo(storage); return {client->Name(), client->Mode(), client->Endpoint(), client->State(), ts}; }; std::transform(clients.begin(), clients.end(), std::back_inserter(replica_infos), asReplicaInfo); return replica_infos; }); } void ReplicationStorageState::Reset() { replication_clients_.WithLock([](auto &clients) { clients.clear(); }); } void ReplicationStorageState::TrackLatestHistory() { constexpr uint16_t kEpochHistoryRetention = 1000; // Generate new epoch id and save the last one to the history. if (history.size() == kEpochHistoryRetention) { history.pop_front(); } history.emplace_back(epoch_.id(), last_commit_timestamp_); } void ReplicationStorageState::AddEpochToHistoryForce(std::string prev_epoch) { history.emplace_back(std::move(prev_epoch), last_commit_timestamp_); } } // namespace memgraph::storage