From 912f41a6d7bcdfc140e837899dedf37490f1f0b3 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Tue, 24 Jun 2025 12:14:19 -0400 Subject: [PATCH] mon/PaxosMap: add map template for managing Paxos structures To protect access and codify protocol. Based loosely on PaxosFSMap which can be refactored to use this later. Signed-off-by: Patrick Donnelly (cherry picked from commit eed2c1cb205180c3769c69179b7167f65fd320d7) --- src/mon/PaxosMap.h | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/mon/PaxosMap.h diff --git a/src/mon/PaxosMap.h b/src/mon/PaxosMap.h new file mode 100644 index 00000000000..1930fab5be8 --- /dev/null +++ b/src/mon/PaxosMap.h @@ -0,0 +1,89 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright 2025 (C) IBM, Inc. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 2.1, as published by + * the Free Software Foundation. See file COPYING. + * + */ + +#pragma once + +#include "include/ceph_assert.h" + +#include "common/CanHasPrint.h" + +#include +#include + +template +concept HasEpoch = requires(T t) { + { t.inc_epoch() } -> std::same_as; +}; + +template +concept HasEphemeral = requires { + { T::is_ephemeral() } -> std::same_as; +}; + + +template +class PaxosMap { + static_assert(!(HasEpoch && HasEphemeral), "A type cannot satisfy both HasEpoch and HasEphemeral concepts."); + +public: + PaxosMap(Mon const& m, Service const& s) : mon(m), service(s) {} + virtual ~PaxosMap() = default; + + const T& get_pending_map() const { ceph_assert(mon.is_leader()); return pending_map; } + const T& get_map() const { return map; } + + void print(std::ostream& os) const { + os << "PaxosMap@" << typeid(T).name() + << "(current=" << map + << " pending=" << pending_map + << ")"; + } + +protected: + T& get_pending_map_writeable() { ceph_assert(mon.is_leader()); ceph_assert(service.is_writeable()); return pending_map; } + + T& create_pending() { + ceph_assert(mon.is_leader()); + if constexpr (HasEpoch) { + pending_map.inc_epoch(); + } else if constexpr (HasEphemeral) { + if constexpr (T::is_ephemeral()) { + pending_map = T(); + } + } else { + pending_map = map; + } + return pending_map; + } + + void decode(ceph::buffer::list::const_iterator& blp) { + using ceph::decode; + decode(map, blp); + pending_map = T(); /* nuke it to catch invalid access */ + } + + void clear() { + map = T(); + pending_map = T(); /* nuke it to catch invalid access */ + } + + +private: + friend Service; + + /* Keep these PRIVATE to prevent unprotected manipulation. */ + Mon const& mon; + Service const& service; + T map; /* the current epoch */ + T pending_map; /* the next epoch */ +}; -- 2.39.5