initial code repo
[stor4nfv.git] / src / ceph / src / rgw / rgw_period_puller.cc
diff --git a/src/ceph/src/rgw/rgw_period_puller.cc b/src/ceph/src/rgw/rgw_period_puller.cc
new file mode 100644 (file)
index 0000000..2c811a3
--- /dev/null
@@ -0,0 +1,109 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "rgw_rados.h"
+#include "rgw_rest_conn.h"
+#include "common/ceph_json.h"
+#include "common/errno.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+#undef dout_prefix
+#define dout_prefix (*_dout << "rgw period puller: ")
+
+namespace {
+
+// pull the given period over the connection
+int pull_period(RGWRESTConn* conn, const std::string& period_id,
+                const std::string& realm_id, RGWPeriod& period)
+{
+  rgw_user user;
+  RGWEnv env;
+  req_info info(conn->get_ctx(), &env);
+  info.method = "GET";
+  info.request_uri = "/admin/realm/period";
+
+  auto& params = info.args.get_params();
+  params["realm_id"] = realm_id;
+  params["period_id"] = period_id;
+
+  bufferlist data;
+#define MAX_REST_RESPONSE (128 * 1024)
+  int r = conn->forward(user, info, nullptr, MAX_REST_RESPONSE, nullptr, &data);
+  if (r < 0) {
+    return r;
+  }
+
+  JSONParser parser;
+  r = parser.parse(data.c_str(), data.length());
+  if (r < 0) {
+    lderr(conn->get_ctx()) << "request failed: " << cpp_strerror(-r) << dendl;
+    return r;
+  }
+
+  try {
+    decode_json_obj(period, &parser);
+  } catch (JSONDecoder::err& e) {
+    lderr(conn->get_ctx()) << "failed to decode JSON input: "
+        << e.message << dendl;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+} // anonymous namespace
+
+int RGWPeriodPuller::pull(const std::string& period_id, RGWPeriod& period)
+{
+  // try to read the period from rados
+  period.set_id(period_id);
+  period.set_epoch(0);
+  int r = period.init(store->ctx(), store);
+  if (r < 0) {
+    if (store->is_meta_master()) {
+      // can't pull if we're the master
+      ldout(store->ctx(), 1) << "metadata master failed to read period "
+          << period_id << " from local storage: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+    ldout(store->ctx(), 14) << "pulling period " << period_id
+        << " from master" << dendl;
+    // request the period from the master zone
+    r = pull_period(store->rest_master_conn, period_id,
+                    store->realm.get_id(), period);
+    if (r < 0) {
+      lderr(store->ctx()) << "failed to pull period " << period_id << dendl;
+      return r;
+    }
+    // write the period to rados
+    r = period.store_info(true);
+    if (r == -EEXIST) {
+      r = 0;
+    } else if (r < 0) {
+      lderr(store->ctx()) << "failed to store period " << period_id << dendl;
+      return r;
+    }
+    // update latest epoch
+    r = period.update_latest_epoch(period.get_epoch());
+    if (r == -EEXIST) {
+      // already have this epoch (or a more recent one)
+      return 0;
+    }
+    if (r < 0) {
+      lderr(store->ctx()) << "failed to update latest_epoch for period "
+          << period_id << dendl;
+      return r;
+    }
+    // reflect period objects if this is the latest version
+    r = period.reflect();
+    if (r < 0) {
+      return r;
+    }
+    ldout(store->ctx(), 14) << "period " << period_id
+        << " pulled and written to local storage" << dendl;
+  } else {
+    ldout(store->ctx(), 14) << "found period " << period_id
+        << " in local storage" << dendl;
+  }
+  return 0;
+}