]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mds,messages: quiesce db inter-rank messaging
authorLeonid Usov <leonid.usov@ibm.com>
Thu, 8 Feb 2024 12:07:28 +0000 (14:07 +0200)
committerLeonid Usov <leonid.usov@ibm.com>
Thu, 14 Mar 2024 19:07:52 +0000 (15:07 -0400)
Fixes: https://tracker.ceph.com/issues/63708
Signed-off-by: Leonid Usov <leonid.usov@ibm.com>
(cherry picked from commit 82f3dbc3ef7b577219f8e1cfaeae4009a809029e)

src/mds/MDSRank.cc
src/mds/MDSRank.h
src/mds/MDSRankQuiesce.cc
src/mds/QuiesceDbEncoding.h [new file with mode: 0644]
src/mds/QuiesceDbManager.cc
src/messages/MMDSQuiesceDbAck.h [new file with mode: 0644]
src/messages/MMDSQuiesceDbListing.h [new file with mode: 0644]
src/msg/Message.cc
src/msg/Message.h

index 7d3f9cda9a226ce8d484f2795a24711763543544..12f6865b2bc19d7556fcb0fd1fb9fde8fd360c18 100644 (file)
@@ -1065,6 +1065,10 @@ bool MDSRankDispatcher::ms_dispatch(const cref_t<Message> &m)
 
 bool MDSRank::_dispatch(const cref_t<Message> &m, bool new_msg)
 {
+  if (quiesce_dispatch(m)) {
+    return true;
+  }
+
   if (is_stale_message(m)) {
     return true;
   }
@@ -1216,6 +1220,7 @@ bool MDSRank::is_valid_message(const cref_t<Message> &m) {
     return true;
   }
 
+  dout(10) << "invalid message type: " << std::hex << type << std::dec << dendl;
   return false;
 }
 
@@ -1283,6 +1288,13 @@ void MDSRank::handle_message(const cref_t<Message> &m)
       }
       break;
 
+    case MSG_MDS_QUIESCE_DB_LISTING:
+    case MSG_MDS_QUIESCE_DB_ACK:
+      ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS);
+      quiesce_dispatch(m);
+      break;
+
+
     case MSG_MDS_LOCK:
     case MSG_MDS_INODEFILECAPS:
       ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS);
index 02512be7916b584b11eb43242a6d5b60d7c94162..41c45cd7d391a3785df55ba4ca00021a2ed3d863 100644 (file)
@@ -570,6 +570,7 @@ class MDSRank {
 
     void quiesce_cluster_update();
     void quiesce_agent_setup();
+    bool quiesce_dispatch(const cref_t<Message> &m);
 
     /* Update MDSMap export_targets for this rank. Called on ::tick(). */
     void update_targets();
index 49e6f39522533482606a2acf3599053de5352131..27425497b14c3fa92a0accfafe1ed7ced805b98c 100644 (file)
@@ -3,10 +3,15 @@
 
 #include "QuiesceDbManager.h"
 #include "QuiesceAgent.h"
+
+#include "messages/MMDSQuiesceDbListing.h"
+#include "messages/MMDSQuiesceDbAck.h"
+
 #include <boost/url.hpp>
 #include <chrono>
 #include <ranges>
 #include <algorithm>
+#include <queue>
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_mds_quiesce
@@ -203,46 +208,203 @@ void MDSRank::command_quiesce_db(const cmdmap_t& cmdmap, std::function<void(int,
     }
   });
 
-  dout(20) << "Submitting a quiesce db request " << (set_id ? "for" : "without a") << " setid " << set_id.value_or("") << ", operation: " << ctx->request.op_string() << dendl;
+  dout(20) << "Submitting " << ctx->request << dendl;
   int rc = quiesce_db_manager->submit_request(ctx);
   if (rc != 0) {
     bufferlist bl;
+    // on_finish was moved there, so should only call via the ctx.
+    ctx->on_finish(rc, "Error submitting the command to the local db manager", bl);
     delete ctx;
-    on_finish(rc, "Error submitting the command to the local db manager", bl);
   }
 }
 
+static void rebind_agent_callback(std::shared_ptr<QuiesceAgent> agt, std::shared_ptr<QuiesceDbManager> mgr) {
+  if (!agt || !mgr) {
+    return;
+  }
+  std::weak_ptr<QuiesceAgent> weak_agent = agt;
+  mgr->reset_agent_callback([weak_agent](QuiesceMap& update) {
+    if (auto agent = weak_agent.lock()) {
+      return agent->db_update(update);
+    } else {
+      return false;
+    }
+  });
+}
+
 void MDSRank::quiesce_cluster_update() {
+  // the quiesce leader is the lowest rank with the highest state up to ACTIVE
+  auto less_leader = [](MDSMap::mds_info_t const* l, MDSMap::mds_info_t const* r) {
+    ceph_assert(l->rank != MDS_RANK_NONE);
+    ceph_assert(r->rank != MDS_RANK_NONE);
+    ceph_assert(l->state <= MDSMap::STATE_ACTIVE);
+    ceph_assert(r->state <= MDSMap::STATE_ACTIVE);
+    if (l->rank == r->rank) {
+      return l->state < r->state;
+    } else {
+      return l->rank > r->rank;
+    }
+  };
+
+  std::priority_queue<MDSMap::mds_info_t const*, std::vector<MDSMap::mds_info_t const*>, decltype(less_leader)> member_info(less_leader);
   QuiesceClusterMembership membership;
 
-  mds_rank_t leader = 0; // MAYBE LATER: initialize this from the map
+  QuiesceInterface::PeerId me = mds_gid_t(monc->get_global_id());
+
+  for (auto&& [gid, info] : mdsmap->get_mds_info()) {
+    // if it has a rank and state <= ACTIVE, it's good enough
+    if (info.rank != MDS_RANK_NONE && info.state <= MDSMap::STATE_ACTIVE) {
+      member_info.push(&info);
+      membership.members.insert(info.global_id);
+    }
+  }
+
+  QuiesceInterface::PeerId leader = 
+    member_info.empty() 
+    ? QuiesceClusterMembership::INVALID_MEMBER 
+    : member_info.top()->global_id;
 
   membership.epoch = mdsmap->get_epoch();
   membership.leader = leader;
-  membership.me = whoami;
-  membership.fs_id = mdsmap->get_info(whoami).join_fscid;
+  membership.me = me;
   membership.fs_name = mdsmap->get_fs_name();
-  mdsmap->get_mds_set(membership.members);
 
-  dout(5) << "epoch:" << membership.epoch << " leader:" << membership.leader << " members:" << membership.members << dendl;
+  dout(5) << "epoch:" << membership.epoch << " me:" << me << " leader:" << leader << " members:" << membership.members 
+    << (mdsmap->is_degraded() ? " (degraded)" : "") << dendl;
 
-  membership.send_ack = [=,this](QuiesceMap&& ack) {
-    if (whoami == leader) {
-      // loopback
-      quiesce_db_manager->submit_ack_from(whoami, std::move(ack));
-      return 0;
-    } else {
-      // TODO: implement messaging
-      return -ENOTSUP;
+  if (leader != QuiesceClusterMembership::INVALID_MEMBER) {
+    membership.send_ack = [=, this](QuiesceMap&& ack) {
+      if (me == leader) {
+        // loopback
+        quiesce_db_manager->submit_ack_from(me, std::move(ack));
+        return 0;
+      } else {
+        std::lock_guard guard(mds_lock);
+
+        if (mdsmap->get_state_gid(leader) == MDSMap::STATE_NULL) {
+          dout(5) << "couldn't find the leader " << leader << " in the map" << dendl;
+          return -ENOENT;
+        }
+        auto addrs = mdsmap->get_info_gid(leader).addrs;
+
+        auto ack_msg = make_message<MMDSQuiesceDbAck>(me);
+        dout(10) << "sending ack " << ack << " to the leader " << leader << dendl;
+        ack_msg->diff_map = std::move(ack);
+        return send_message_mds(ack_msg, addrs);
+      }
+    };
+
+    membership.send_listing_to = [=, this](QuiesceInterface::PeerId to, QuiesceDbListing&& db) {
+      std::lock_guard guard(mds_lock);
+      if (mdsmap->get_state_gid(to) == MDSMap::STATE_NULL) {
+        dout(5) << "couldn't find the peer " << to << " in the map" << dendl;
+        return -ENOENT;
+      }
+      auto addrs = mdsmap->get_info_gid(to).addrs;
+      auto listing_msg = make_message<MMDSQuiesceDbListing>(me);
+      dout(10) << "sending listing " << db << " to the peer " << to << dendl;
+      listing_msg->db_listing = std::move(db);
+      return send_message_mds(listing_msg, addrs);
+    };
+  }
+
+  QuiesceDbManager::RequestContext* inject_request = nullptr;
+
+  bool degraded = mdsmap->is_degraded();
+
+  if (degraded && membership.is_leader()) {
+    dout(5) << "WARNING: injecting a cancel all request"
+      << " members: " << membership.members
+      << " in: " << mdsmap->get_num_in_mds() 
+      << " up: " << mdsmap->get_num_up_mds() 
+      << " sr: " << mdsmap->get_num_standby_replay_mds()
+      << dendl;
+    
+    struct CancelAll: public QuiesceDbManager::RequestContext {
+      mds_rank_t whoami;
+      CancelAll(mds_rank_t whoami) : whoami(whoami) {
+        request.cancel_roots();
+      }
+      void finish(int rc) override {
+        dout(rc == 0 ? 15 : 3) << "injected cancel all completed with rc: " << rc << dendl;
+      }
+    };
+
+    inject_request = new CancelAll(whoami);
+  }
+
+  if (!is_active()) {
+    quiesce_db_manager->reset_agent_callback([whoami = whoami, degraded, is_sr = is_standby_replay()](QuiesceMap& quiesce_map) {
+      for (auto it = quiesce_map.roots.begin(); it != quiesce_map.roots.end();) {
+        switch (it->second.state) {
+        case QS_QUIESCING:
+          if (degraded) {
+            it->second.state = QS_FAILED;
+            dout(3) << "DEGRADED RESPONDER: reporting '" << it->first << "' as " << it->second.state << dendl;
+            ++it;
+          } else if (is_sr) {
+            it->second.state = QS_QUIESCED;
+            dout(15) << "STANDBY REPLAY RESPONDER: reporting '" << it->first << "' as " << it->second.state << dendl;
+            ++it;
+          } else {
+            // just ack.
+            dout(20) << "INTACTIVE RESPONDER: reporting '" << it->first << "' as " << it->second.state << dendl;
+            it = quiesce_map.roots.erase(it);
+          }
+          break;
+        default:
+          it = quiesce_map.roots.erase(it);
+          break;
+        }
+      }
+      return true;
+    });
+
+    if (quiesce_agent) {
+      // reset the agent if it's present
+      // because it won't receive any more callbacks
+      quiesce_agent->reset_async();
     }
-  };
+  } else {
+    rebind_agent_callback(quiesce_agent, quiesce_db_manager);
+  }
 
-  membership.send_listing_to = [=](mds_rank_t to, QuiesceDbListing&& db) {
-    // TODO: implement messaging
-    return -ENOTSUP;
-  };
+  quiesce_db_manager->update_membership(membership, inject_request);
+}
 
-  quiesce_db_manager->update_membership(membership);
+bool MDSRank::quiesce_dispatch(const cref_t<Message> &m) {
+  switch(m->get_type()) {
+    case MSG_MDS_QUIESCE_DB_LISTING:
+    {
+      const auto& req = ref_cast<MMDSQuiesceDbListing>(m);
+      if (quiesce_db_manager) {
+        dout(10) << "got " << req->db_listing << " from peer " << req->gid << dendl;
+        int result = quiesce_db_manager->submit_listing_from(req->gid, std::move(req->db_listing));
+        if (result != 0) {
+          dout(3) << "error (" << result << ") submitting " << req->db_listing << " from peer " << req->gid << dendl;
+        }
+      } else {
+        dout(5) << "no db manager to process " << req->db_listing << dendl;
+      }
+      return true;
+    }
+    case MSG_MDS_QUIESCE_DB_ACK:
+    {
+      const auto& req = ref_cast<MMDSQuiesceDbAck>(m);
+      if (quiesce_db_manager) {
+        dout(10) << "got ack " << req->diff_map << " from peer " << req->gid << dendl;
+        int result = quiesce_db_manager->submit_ack_from(req->gid, std::move(req->diff_map));
+        if (result != 0) {
+          dout(3) << "error (" << result << ") submitting an ack from peer " << req->gid << dendl;
+        }
+      } else {
+        dout(5) << "no db manager to process an ack: " << req->diff_map << dendl;
+      }
+      return true;
+    }
+    default:
+      return false;
+  }
 }
 
 void MDSRank::quiesce_agent_setup() {
@@ -278,29 +440,62 @@ void MDSRank::quiesce_agent_setup() {
         return std::nullopt;
       }
     }
-    std::optional<double> dummy_quiesce_after;
+    std::optional<double> debug_quiesce_after;
     if (auto pit = uri->params().find("q"); pit != uri->params().end()) {
       try {
-        dummy_quiesce_after = (*pit).has_value ? std::stod((*pit).value) : 1 /*second*/;
+        debug_quiesce_after = (*pit).has_value ? std::stod((*pit).value) : 1 /*second*/;
       } catch (...) {
         dout(5) << "error parsing the time for debug quiesce for query: " << uri->query() << dendl;
         c->complete(-EINVAL);
         return std::nullopt;
       }
     }
+    std::optional<double> debug_fail_after;
+    if (auto pit = uri->params().find("f"); pit != uri->params().end()) {
+      try {
+        debug_fail_after = (*pit).has_value ? std::stod((*pit).value) : 1 /*second*/;
+      } catch (...) {
+        dout(5) << "error parsing the time for debug fail for query: " << uri->query() << dendl;
+        c->complete(-EINVAL);
+        return std::nullopt;
+      }
+    }
+    std::optional<mds_rank_t> debug_rank;
+    if (auto pit = uri->params().find("r"); pit != uri->params().end()) {
+      try {
+        if ((*pit).has_value) {
+          debug_rank = (mds_rank_t)std::stoul((*pit).value);
+        }
+      } catch (...) {
+        dout(5) << "error parsing the rank for debug pin for query: " << uri->query() << dendl;
+        c->complete(-EINVAL);
+        return std::nullopt;
+      }
+    }
+
+    if (debug_rank && (debug_rank >= mdsmap->get_max_mds())) {
+        dout(5) << "invalid rank: " << uri->query() << dendl;
+        c->complete(-EINVAL);
+        return std::nullopt;
+    }
 
     auto path = uri->path();
     dout(20) << "got request to quiesce '" << path << "'" << dendl;
 
     std::lock_guard l(mds_lock);
 
-    if (!dummy_quiesce_after) {
+    if (!debug_quiesce_after && !debug_fail_after && !debug_rank) {
       // the real deal!
+      if (mdsmap->is_degraded()) {
+        dout(3) << "DEGRADED: refusing to quiesce" << dendl;
+        c->complete(EPERM);
+        return std::nullopt;
+      }
       auto qc = new MDCache::C_MDS_QuiescePath(mdcache, c);
       auto mdr = mdcache->quiesce_path(filepath(path), qc, nullptr, quiesce_delay_ms);
       return mdr ? mdr->reqid : std::optional<RequestHandle>();
     } else {
-      /* dummy quiesce */
+      /* dummy quiesce/fail */
       // always create a new request id
       auto req_id = metareqid_t(entity_name_t::MDS(whoami), issue_tid());
       auto [it, inserted] = quiesce_requests->try_emplace(path, req_id, c);
@@ -317,25 +512,44 @@ void MDSRank::quiesce_agent_setup() {
           // since we weren't inserted, we must have successfully quiesced
           c->complete(0);
         }
+      } else if (debug_rank && (debug_rank != whoami)) {
+        // the root was pinned to a different rank
+        // we should acknowledge the quiesce regardless of the other flags
+        it->second.second->complete(0);
+        it->second.second = nullptr;
       } else {
-        // do quiesce if needed
+        // do quiesce or fail
+
+        bool do_fail = false;
+        double delay;
+        if (debug_quiesce_after.has_value() && debug_fail_after.has_value()) {
+          do_fail = debug_fail_after < debug_quiesce_after;
+        } else {
+          do_fail = debug_fail_after.has_value();
+        }
+
+        if (do_fail) {
+          delay = debug_fail_after.value();
+        } else {
+          delay = debug_quiesce_after.value();
+        }
 
-        auto quiesce_task = new LambdaContext([quiesce_requests, req_id, this](int) {
+        auto quiesce_task = new LambdaContext([quiesce_requests, req_id, do_fail, this](int) {
           // the mds lock should be held by the timer
           dout(20) << "quiesce_task: callback by the timer" << dendl;
           auto it = std::ranges::find(*quiesce_requests, req_id, [](auto x) { return x.second.first; });
           if (it != quiesce_requests->end() && it->second.second != nullptr) {
-            dout(20) << "quiesce_task: completing the root '" << it->first << "'" << dendl;
-            it->second.second->complete(0);
+            dout(20) << "quiesce_task: completing the root '" << it->first << "' as failed: " << do_fail << dendl;
+            it->second.second->complete(do_fail ? -EBADF : 0);
             it->second.second = nullptr;
           }
           dout(20) << "quiesce_task: done" << dendl;
         });
 
         dout(20) << "scheduling a quiesce_task (" << quiesce_task
-                 << ") to fire after " << *dummy_quiesce_after
+                 << ") to fire after " << delay
                  << " seconds on timer " << &timer << dendl;
-        timer.add_event_after(*dummy_quiesce_after, quiesce_task);
+        timer.add_event_after(delay, quiesce_task);
       }
       return it->second.first;
     }
@@ -373,13 +587,5 @@ void MDSRank::quiesce_agent_setup() {
   };
 
   quiesce_agent.reset(new QuiesceAgent(ci));
-
-  std::weak_ptr<QuiesceAgent> weak_agent = quiesce_agent;
-  quiesce_db_manager->reset_agent_callback([weak_agent](QuiesceMap& update) {
-    if (auto agent = weak_agent.lock()) {
-      return agent->db_update(update);
-    } else {
-      return false;
-    }
-  });
+  rebind_agent_callback(quiesce_agent, quiesce_db_manager);
 };
diff --git a/src/mds/QuiesceDbEncoding.h b/src/mds/QuiesceDbEncoding.h
new file mode 100644 (file)
index 0000000..756e63c
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2023 IBM, Red Hat
+ *
+ * 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 "QuiesceDb.h"
+#include "include/encoding.h"
+#include <stdint.h>
+
+void encode(QuiesceDbVersion const& v, bufferlist& bl, uint64_t features = 0)
+{
+  encode(v.epoch, bl, features);
+  encode(v.set_version, bl, features);
+}
+
+void decode(QuiesceDbVersion& v, bufferlist::const_iterator& p)
+{
+  decode(v.epoch, p);
+  decode(v.set_version, p);
+}
+
+void encode(QuiesceState const & state, bufferlist& bl, uint64_t features=0)
+{
+  static_assert(QuiesceState::QS__MAX <= UINT8_MAX);
+  uint8_t v = (uint8_t)state;
+  encode(v, bl, features);
+}
+
+void decode(QuiesceState & state, bufferlist::const_iterator& p)
+{
+  uint8_t v = 0;
+  decode(v, p);
+  state = (QuiesceState)v;
+}
+
+void encode(QuiesceTimeInterval const & interval, bufferlist& bl, uint64_t features=0)
+{
+  encode(interval.count(), bl, features);
+}
+
+void decode(QuiesceTimeInterval & interval, bufferlist::const_iterator& p)
+{
+  QuiesceClock::rep count;
+  decode(count, p);
+  interval = QuiesceTimeInterval { count };
+}
+
+void encode(RecordedQuiesceState const& rstate, bufferlist& bl, uint64_t features = 0)
+{
+  encode(rstate.state, bl, features);
+  encode(rstate.at_age.count(), bl, features);
+}
+
+void decode(RecordedQuiesceState& rstate, bufferlist::const_iterator& p)
+{
+  decode(rstate.state, p);
+  decode(rstate.at_age, p);
+}
+
+void encode(QuiesceSet::MemberInfo const& member, bufferlist& bl, uint64_t features = 0)
+{
+  encode(member.rstate, bl, features);
+  encode(member.excluded, bl, features);
+}
+
+void decode(QuiesceSet::MemberInfo& member, bufferlist::const_iterator& p)
+{
+  decode(member.rstate, p);
+  decode(member.excluded, p);
+}
+
+void encode(QuiesceSet const& set, bufferlist& bl, uint64_t features = 0)
+{
+  encode(set.version, bl, features);
+  encode(set.rstate, bl, features);
+  encode(set.timeout, bl, features);
+  encode(set.expiration, bl, features);
+  encode(set.members, bl, features);
+}
+
+void decode(QuiesceSet& set, bufferlist::const_iterator& p)
+{
+  decode(set.version, p);
+  decode(set.rstate, p);
+  decode(set.timeout, p);
+  decode(set.expiration, p);
+  decode(set.members, p);
+}
+
+void encode(QuiesceDbRequest const& req, bufferlist& bl, uint64_t features = 0)
+{
+  encode(req.control.raw, bl, features);
+  encode(req.set_id, bl);
+  encode(req.if_version, bl);
+  encode(req.timeout, bl);
+  encode(req.expiration, bl);
+  encode(req.await, bl);
+  encode(req.roots, bl);
+}
+
+void decode(QuiesceDbRequest& req, bufferlist::const_iterator& p)
+{
+  decode(req.control.raw, p);
+  decode(req.set_id, p);
+  decode(req.if_version, p);
+  decode(req.timeout, p);
+  decode(req.expiration, p);
+  decode(req.await, p);
+  decode(req.roots, p);
+}
+
+void encode(QuiesceDbListing const& listing, bufferlist& bl, uint64_t features = 0)
+{
+  encode(listing.db_version, bl, features);
+  encode(listing.db_age, bl, features);
+  encode(listing.sets, bl, features);
+}
+
+void decode(QuiesceDbListing& listing, bufferlist::const_iterator& p)
+{
+  decode(listing.db_version, p);
+  decode(listing.db_age, p);
+  decode(listing.sets, p);
+}
+
+void encode(QuiesceMap::RootInfo const& root, bufferlist& bl, uint64_t features = 0)
+{
+  encode(root.state, bl, features);
+  encode(root.ttl, bl, features);
+}
+
+void decode(QuiesceMap::RootInfo& root, bufferlist::const_iterator& p)
+{
+  decode(root.state, p);
+  decode(root.ttl, p);
+}
+
+void encode(QuiesceMap const& map, bufferlist& bl, uint64_t features = 0)
+{
+  encode(map.db_version, bl, features);
+  encode(map.roots, bl, features);
+}
+
+void decode(QuiesceMap& map, bufferlist::const_iterator& p)
+{
+  decode(map.db_version, p);
+  decode(map.roots, p);
+}
+
index 3eb9009f86b0be4eaf062f2eb765bc62c7631a86..1ff998f606868fde6f9df9f0a84f7ceaa5cfba17 100644 (file)
@@ -202,7 +202,9 @@ bool QuiesceDbManager::membership_upkeep()
   bool was_leader = membership.epoch > 0 && membership.leader == membership.me;
   bool is_leader = cluster_membership && cluster_membership->leader == cluster_membership->me;
   if (cluster_membership) {
-    dout(10) << "epoch: " << cluster_membership->epoch << " is_leader: " << is_leader << " was_leader: " << was_leader << dendl;
+    dout(10) << "epoch:" << cluster_membership->epoch << " leader:" 
+      << std::boolalpha << was_leader << "->" << is_leader << std::noboolalpha
+      << " members:" << cluster_membership->members << dendl;
   } else {
     dout(10) << "shutdown! was_leader: " << was_leader << dendl;
   }
diff --git a/src/messages/MMDSQuiesceDbAck.h b/src/messages/MMDSQuiesceDbAck.h
new file mode 100644 (file)
index 0000000..907db23
--- /dev/null
@@ -0,0 +1,63 @@
+// -*- 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 (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * 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 "messages/MMDSOp.h"
+#include "mds/QuiesceDbEncoding.h"
+
+class MMDSQuiesceDbAck final : public MMDSOp {
+public:
+  mds_gid_t gid;
+  mutable QuiesceMap diff_map;
+
+protected:
+  MMDSQuiesceDbAck(mds_gid_t gid) : MMDSOp{MSG_MDS_QUIESCE_DB_ACK}, gid(gid) {}
+  MMDSQuiesceDbAck() : MMDSQuiesceDbAck(MDS_GID_NONE) {}
+  ~MMDSQuiesceDbAck() final {}
+
+public:
+  std::string_view get_type_name() const override { return "mds_quiesce_db_ack"; }
+  void print(std::ostream& o) const override {
+
+  }
+
+  void encode_payload(uint64_t features) override
+  {
+    using ceph::encode;
+
+    ceph_assert(gid != MDS_GID_NONE);
+
+    ENCODE_START(1, 1, payload);
+    encode(gid, payload);
+    encode(diff_map, payload);
+    ENCODE_FINISH(payload);
+  }
+
+  void decode_payload() override {
+    using ceph::decode;
+    auto p = payload.cbegin();
+    DECODE_START(1, p);
+    decode(gid, p);
+    decode(diff_map, p);
+    DECODE_FINISH(p);
+  }
+
+private:
+  template<class T, typename... Args>
+  friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args);
+  template<class T, typename... Args>
+  friend MURef<T> crimson::make_message(Args&&... args);
+};
diff --git a/src/messages/MMDSQuiesceDbListing.h b/src/messages/MMDSQuiesceDbListing.h
new file mode 100644 (file)
index 0000000..9d3ce20
--- /dev/null
@@ -0,0 +1,63 @@
+// -*- 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 (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * 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 "messages/MMDSOp.h"
+#include "mds/QuiesceDbEncoding.h"
+
+class MMDSQuiesceDbListing final : public MMDSOp {
+public:
+  mds_gid_t gid;
+  mutable QuiesceDbListing db_listing;
+
+protected:
+  MMDSQuiesceDbListing(mds_gid_t gid) : MMDSOp{MSG_MDS_QUIESCE_DB_LISTING}, gid(gid) {}
+  MMDSQuiesceDbListing() : MMDSQuiesceDbListing(MDS_GID_NONE) {}
+  ~MMDSQuiesceDbListing() final {}
+
+public:
+  std::string_view get_type_name() const override { return "mds_quiesce_db_listing"; }
+  void print(std::ostream& o) const override {
+
+  }
+
+  void encode_payload(uint64_t features) override
+  {
+    using ceph::encode;
+
+    ceph_assert(gid != MDS_GID_NONE);
+
+    ENCODE_START(1, 1, payload);
+    encode(gid, payload);
+    encode(db_listing, payload);
+    ENCODE_FINISH(payload);
+  }
+
+  void decode_payload() override {
+    using ceph::decode;
+    auto p = payload.cbegin();
+    DECODE_START(1, p);
+    decode(gid, p);
+    decode(db_listing, p);
+    DECODE_FINISH(p);
+  }
+
+private:
+  template<class T, typename... Args>
+  friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args);
+  template<class T, typename... Args>
+  friend MURef<T> crimson::make_message(Args&&... args);
+};
index 70ac4ad133894b03f5d5a352ed19ffdba88f49b3..7f209f9022348cbe2b826909fd95f5dd6a56d558 100644 (file)
 #include "messages/MClientMetrics.h"
 
 #include "messages/MMDSPeerRequest.h"
+#include "messages/MMDSQuiesceDbListing.h"
+#include "messages/MMDSQuiesceDbAck.h"
 
 #include "messages/MMDSMap.h"
 #include "messages/MFSMap.h"
@@ -848,6 +850,14 @@ Message *decode_message(CephContext *cct,
 
   case MSG_MDS_TABLE_REQUEST:
     m = make_message<MMDSTableRequest>();
+    break;
+
+  case MSG_MDS_QUIESCE_DB_LISTING:
+    m = make_message<MMDSQuiesceDbListing>();
+    break;
+
+  case MSG_MDS_QUIESCE_DB_ACK:
+    m = make_message<MMDSQuiesceDbAck>();
     break;
 
        /*  case MSG_MDS_INODEUPDATE:
index 40833744b67d1c337fd37e52f97a78e48112e043..cabefe6556b53839deefdb5819c9038931e96ed5 100644 (file)
 #define MSG_MDS_METRICS            0x501  // for mds metric aggregator
 #define MSG_MDS_PING               0x502  // for mds pinger
 #define MSG_MDS_SCRUB_STATS        0x503  // for mds scrub stack
+#define MSG_MDS_QUIESCE_DB_LISTING 0x505  // quiesce db replication
+#define MSG_MDS_QUIESCE_DB_ACK     0x506  // quiesce agent ack back to the db
 
 // *** generic ***
 #define MSG_TIMECHECK             0x600