]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: implement find_oldest_log_period for RGWMetadataManager
authorCasey Bodley <cbodley@redhat.com>
Thu, 25 Feb 2016 15:40:09 +0000 (10:40 -0500)
committerCasey Bodley <cbodley@redhat.com>
Fri, 4 Mar 2016 22:04:09 +0000 (17:04 -0500)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/rgw_metadata.cc
src/rgw/rgw_rados.cc

index 2f0d1e98174c99bdb38247f3f295575d0cb998d8..027781bb1e983408b82c9d7e59e1ee53f72dbc24 100644 (file)
@@ -1,6 +1,7 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include <boost/intrusive_ptr.hpp>
 #include "common/ceph_json.h"
 #include "rgw_metadata.h"
 #include "rgw_coroutine.h"
@@ -9,6 +10,9 @@
 #include "rgw_rados.h"
 #include "rgw_tools.h"
 
+#include "rgw_cr_rados.h"
+#include "rgw_boost_asio_yield.h"
+
 #define dout_subsys ceph_subsys_rgw
 
 void LogStatusDump::dump(Formatter *f) const {
@@ -357,19 +361,126 @@ RGWMetadataManager::~RGWMetadataManager()
   handlers.clear();
 }
 
-static RGWPeriodHistory::Cursor find_oldest_log_period(RGWRados* store)
+namespace {
+
+class FindAnyShardCR : public RGWCoroutine {
+  RGWRados *const store;
+  const RGWMetadataLog& mdlog;
+  const int num_shards;
+  int ret = 0;
+ public:
+  FindAnyShardCR(RGWRados *store, const RGWMetadataLog& mdlog, int num_shards)
+    : RGWCoroutine(store->ctx()), store(store), mdlog(mdlog),
+      num_shards(num_shards) {}
+
+  int operate() {
+    reenter(this) {
+      // send stat requests for each shard in parallel
+      yield {
+        auto async_rados = store->get_async_rados();
+        auto& pool = store->get_zone_params().log_pool;
+        auto oid = std::string{};
+
+        for (int i = 0; i < num_shards; i++) {
+          mdlog.get_shard_oid(i, oid);
+          auto obj = rgw_obj{pool, oid};
+          spawn(new RGWStatObjCR(async_rados, store, obj), true);
+        }
+      }
+      drain_all();
+      // if any shards were found, return success
+      while (collect_next(&ret)) {
+        if (ret == 0) {
+          // TODO: cancel instead of waiting for the rest
+          return set_cr_done();
+        }
+        ret = 0; // collect_next() won't modify &ret unless it's a failure
+      }
+      // no shards found
+      set_retcode(-ENOENT);
+      return set_cr_error(-ENOENT);
+    }
+    return 0;
+  }
+};
+
+// return true if any log shards exist for the given period
+int find_shards_for_period(RGWRados *store, const std::string& period_id)
 {
-  // TODO: search backwards through the period history for the first period with
-  // no log shard objects, and return its successor (some shards may be missing
+  auto cct = store->ctx();
+  RGWMetadataLog mdlog(cct, store, period_id);
+  auto num_shards = cct->_conf->rgw_md_log_max_shards;
+
+  using FindAnyShardCRRef = boost::intrusive_ptr<FindAnyShardCR>;
+  auto cr = FindAnyShardCRRef{new FindAnyShardCR(store, mdlog, num_shards)};
+
+  RGWCoroutinesManager mgr(cct, nullptr);
+  int r = mgr.run(cr.get());
+  if (r < 0) {
+    return r;
+  }
+  return cr->get_ret_status();
+}
+
+RGWPeriodHistory::Cursor find_oldest_log_period(RGWRados *store)
+{
+  // search backwards through the period history for the first period with no
+  // log shard objects, and return its successor (some shards may be missing
   // if they contain no metadata yet, so we need to check all shards)
-  return store->period_history->get_current();
+  auto cursor = store->period_history->get_current();
+  auto oldest_log = cursor;
+
+  while (cursor) {
+    // search for an existing log shard object for this period
+    int r = find_shards_for_period(store, cursor.get_period().get_id());
+    if (r == -ENOENT) {
+      ldout(store->ctx(), 10) << "find_oldest_log_period found no log shards "
+          "for period " << cursor.get_period().get_id() << "; returning "
+          "period " << oldest_log.get_period().get_id() << dendl;
+      return oldest_log;
+    }
+    if (r < 0) {
+      return RGWPeriodHistory::Cursor{r};
+    }
+    oldest_log = cursor;
+
+    // advance to the period's predecessor
+    if (!cursor.has_prev()) {
+      auto& predecessor = cursor.get_period().get_predecessor();
+      if (predecessor.empty()) {
+        // this is the first period, so our logs must start here
+        ldout(store->ctx(), 10) << "find_oldest_log_period returning first "
+            "period " << cursor.get_period().get_id() << dendl;
+        return cursor;
+      }
+      // pull the predecessor and add it to our history
+      RGWPeriod period;
+      int r = store->period_puller->pull(predecessor, period);
+      if (r < 0) {
+        return RGWPeriodHistory::Cursor{r};
+      }
+      auto prev = store->period_history->insert(std::move(period));
+      if (!prev) {
+        return prev;
+      }
+      ldout(store->ctx(), 10) << "find_oldest_log_period advancing to "
+          "predecessor period " << predecessor << dendl;
+      assert(cursor.has_prev());
+    }
+    cursor.prev();
+  }
+  ldout(store->ctx(), 10) << "find_oldest_log_period returning empty cursor" << dendl;
+  return cursor;
 }
 
+} // anonymous namespace
+
 int RGWMetadataManager::init(const std::string& current_period)
 {
-  // find our oldest log so we can tell other zones where to start their sync
-  oldest_log_period = find_oldest_log_period(store);
-
+  if (store->is_meta_master()) {
+    // find our oldest log so we can tell other zones where to start their sync
+    oldest_log_period = find_oldest_log_period(store);
+  }
   // open a log for the current period
   current_log = get_log(current_period);
   return 0;
index 58d44a506db424926c91944c509fa4060fd1d2a9..820cd6770789f840236f3445f2a0cc3a5c060ded 100644 (file)
@@ -3680,10 +3680,10 @@ int RGWRados::init_complete()
         << cpp_strerror(-ret) << dendl;
     return ret;
   }
-  auto md_log = meta_mgr->get_log(current_period.get_id());
 
-  meta_notifier = new RGWMetaNotifier(this, md_log);
   if (is_meta_master()) {
+    auto md_log = meta_mgr->get_log(current_period.get_id());
+    meta_notifier = new RGWMetaNotifier(this, md_log);
     meta_notifier->start();
   }