]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mon/PaxosMap: add map template for managing Paxos structures
authorPatrick Donnelly <pdonnell@ibm.com>
Tue, 24 Jun 2025 16:14:19 +0000 (12:14 -0400)
committerPatrick Donnelly <pdonnell@ibm.com>
Wed, 1 Oct 2025 18:47:11 +0000 (14:47 -0400)
To protect access and codify protocol. Based loosely on PaxosFSMap which can be
refactored to use this later.

Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
src/mon/PaxosMap.h [new file with mode: 0644]

diff --git a/src/mon/PaxosMap.h b/src/mon/PaxosMap.h
new file mode 100644 (file)
index 0000000..1930fab
--- /dev/null
@@ -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 <chrono>
+#include <ostream>
+
+template<typename T>
+concept HasEpoch = requires(T t) {
+  { t.inc_epoch() } -> std::same_as<void>;
+};
+
+template<typename T>
+concept HasEphemeral = requires {
+  { T::is_ephemeral() } -> std::same_as<bool>;
+};
+
+
+template<typename Mon, typename Service, typename T>
+class PaxosMap {
+  static_assert(!(HasEpoch<T> && HasEphemeral<T>), "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<T>) {
+      pending_map.inc_epoch();
+    } else if constexpr (HasEphemeral<T>) {
+      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 */
+};