Commit 09213be9 authored by Ramon Nou's avatar Ramon Nou
Browse files

Record repair journal owner identity

parent 6532a9a0
Loading
Loading
Loading
Loading
Loading
+43 −0
Changes for include/client/rpc/repair_journal_lock.hpp: 43 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -17,12 +17,21 @@
#include <unistd.h>

#include <cerrno>
#include <chrono>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
#include <sys/types.h>

namespace gkfs::rpc {

struct repair_journal_owner {
    std::string hostname;
    pid_t pid{};
    uint64_t acquired_at{};
};

/**
 * @brief Owns the advisory process lock for a client-local repair journal.
 *
@@ -68,7 +77,34 @@ public:
                                     journal_path + "': " + ::strerror(error));
        }

        repair_journal_owner owner;
        owner.hostname.resize(255);
        if(::gethostname(owner.hostname.data(), owner.hostname.size()) != 0) {
            owner.hostname = "unknown";
        } else {
            owner.hostname.resize(std::strlen(owner.hostname.c_str()));
        }
        owner.pid = ::getpid();
        owner.acquired_at = static_cast<uint64_t>(
                std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count());

        const auto record = "hostname=" + owner.hostname + "\n" +
                            "pid=" + std::to_string(owner.pid) + "\n" +
                            "acquired_at=" + std::to_string(owner.acquired_at) +
                            "\n";
        if(::ftruncate(candidate.get(), 0) != 0 ||
           ::write(candidate.get(), record.data(), record.size()) !=
                   static_cast<ssize_t>(record.size())) {
            const auto error = errno;
            throw std::runtime_error(
                    "Unable to write replica repair journal owner record '" +
                    journal_path + "': " + ::strerror(error));
        }

        fd_ = std::move(candidate);
        owner_ = std::move(owner);
    }

    void
@@ -78,6 +114,7 @@ public:
            fd_.reset();
        }
        lock_path_.clear();
        owner_ = {};
    }

    [[nodiscard]] bool
@@ -90,9 +127,15 @@ public:
        return lock_path_;
    }

    [[nodiscard]] const repair_journal_owner&
    owner() const noexcept {
        return owner_;
    }

private:
    gkfs::utils::unique_fd fd_;
    std::string lock_path_;
    repair_journal_owner owner_;
};

} // namespace gkfs::rpc
+12 −0
Changes for tests/unit/test_repair_journal_lock.cpp: 12 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include <catch2/catch_all.hpp>

#include <filesystem>
#include <fstream>
#include <sstream>
#include <unistd.h>

namespace {
@@ -35,6 +37,15 @@ TEST_CASE("repair journal lock has exclusive process ownership",
        first.acquire(journal.string());
        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);

        std::ifstream owner_record(lock_path);
        std::stringstream contents;
        contents << owner_record.rdbuf();
        REQUIRE(contents.str().find("pid=" + std::to_string(::getpid())) !=
                std::string::npos);

        gkfs::rpc::repair_journal_lock second;
        REQUIRE_THROWS_WITH(second.acquire(journal.string()),
@@ -55,4 +66,5 @@ TEST_CASE("empty repair journal path does not create a lock",
    gkfs::rpc::repair_journal_lock lock;
    REQUIRE_NOTHROW(lock.acquire(""));
    REQUIRE_FALSE(lock.owns_lock());
    REQUIRE(lock.owner().hostname.empty());
}