Commit 9ed87b56 authored by Ramon Nou's avatar Ramon Nou
Browse files

Record repair journal topology identity

parent 95d78166
Loading
Loading
Loading
Loading
Loading
+30 −2
Changes for include/client/rpc/repair_journal_lock.hpp: 30 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <chrono>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <string>
#include <sys/types.h>
@@ -29,8 +32,31 @@ struct repair_journal_owner {
    std::string hostname;
    pid_t pid{};
    uint64_t acquired_at{};
    std::string topology_identity;
};

inline std::string
repair_journal_topology_identity(const std::string& hostfile_path) {
    std::ifstream input(hostfile_path, std::ios::binary);
    if(!input.is_open()) {
        return "unavailable";
    }

    constexpr uint64_t fnv_offset = 14695981039346656037ULL;
    constexpr uint64_t fnv_prime = 1099511628211ULL;
    uint64_t hash = fnv_offset;
    char byte{};
    while(input.get(byte)) {
        hash ^= static_cast<uint64_t>(static_cast<unsigned char>(byte));
        hash *= fnv_prime;
    }

    std::ostringstream result;
    result << "fnv1a-64:" << std::hex << std::setw(16) << std::setfill('0')
           << hash;
    return result.str();
}

/**
 * @brief Owns the advisory process lock for a client-local repair journal.
 *
@@ -50,7 +76,8 @@ public:
    }

    void
    acquire(const std::string& journal_path) {
    acquire(const std::string& journal_path,
            const std::string& topology_identity = "unknown") {
        if(journal_path.empty() || fd_) {
            return;
        }
@@ -93,11 +120,12 @@ public:
                std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count());
        owner.topology_identity = topology_identity;

        const auto record = "hostname=" + owner.hostname + "\n" +
                            "pid=" + std::to_string(owner.pid) + "\n" +
                            "acquired_at=" + std::to_string(owner.acquired_at) +
                            "\n";
                            "\n" + "topology=" + owner.topology_identity + "\n";
        if(::ftruncate(candidate.get(), 0) != 0 ||
           ::write(candidate.get(), record.data(), record.size()) !=
                   static_cast<ssize_t>(record.size())) {
+5 −1
Changes for src/client/preload_context.cpp: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -106,7 +106,11 @@ PreloadContext::PreloadContext()
    PreloadContext::set_replicas(replicas);
    repair_status_path_ = gkfs::env::get_var(gkfs::env::REPAIR_STATUS_PATH);
    repair_journal_path_ = gkfs::env::get_var(gkfs::env::REPAIR_JOURNAL_PATH);
    repair_journal_lock_.acquire(repair_journal_path_);
    const auto hostfile_path = gkfs::env::get_var(gkfs::env::HOSTS_FILE,
                                                  gkfs::config::hostfile_path);
    repair_journal_lock_.acquire(
            repair_journal_path_,
            gkfs::rpc::repair_journal_topology_identity(hostfile_path));

    const std::string env_dirents_buff_size =
            gkfs::env::get_var(gkfs::env::DIRENTS_BUFF_SIZE);
+11 −1
Changes for tests/unit/test_repair_journal_lock.cpp: 11 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -29,17 +29,26 @@ test_journal_path() {
TEST_CASE("repair journal lock has exclusive process ownership",
          "[replication][repair][journal]") {
    const auto journal = test_journal_path();
    const auto hostfile = journal.string() + ".hosts";
    const auto lock_path = journal.string() + ".lock";
    std::filesystem::remove(lock_path);
    {
        std::ofstream output(hostfile);
        output << "host-a fi+sockets://127.0.0.1:1234\n";
    }
    const auto topology =
            gkfs::rpc::repair_journal_topology_identity(hostfile);
    REQUIRE(topology.rfind("fnv1a-64:", 0) == 0);

    {
        gkfs::rpc::repair_journal_lock first;
        first.acquire(journal.string());
        first.acquire(journal.string(), topology);
        REQUIRE(first.owns_lock());
        REQUIRE(first.path() == lock_path);
        REQUIRE(first.owner().pid == ::getpid());
        REQUIRE_FALSE(first.owner().hostname.empty());
        REQUIRE(first.owner().acquired_at > 0);
        REQUIRE(first.owner().topology_identity == topology);

        std::ifstream owner_record(lock_path);
        std::stringstream contents;
@@ -59,6 +68,7 @@ TEST_CASE("repair journal lock has exclusive process ownership",
    REQUIRE(after_release.owns_lock());
    after_release.release();
    std::filesystem::remove(lock_path);
    std::filesystem::remove(hostfile);
}

TEST_CASE("empty repair journal path does not create a lock",