]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add atomic RGWPeriod::update_latest_epoch
authorCasey Bodley <cbodley@redhat.com>
Tue, 2 May 2017 14:44:20 +0000 (10:44 -0400)
committerCasey Bodley <cbodley@redhat.com>
Fri, 16 Jun 2017 17:34:48 +0000 (13:34 -0400)
update_latest_epoch() uses RGWObjVersionTracker to implement atomic
updates to the period's latest_epoch, returning -EEXIST if we already
have an epoch >= the one given

Fixes: http://tracker.ceph.com/issues/19816
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h

index bc06c6b99fdec15540f2b5d597dec97ca30c3d08..d19e7606dc1d38979d3a3b891856ac2d1a19865c 100644 (file)
@@ -1188,6 +1188,51 @@ int RGWPeriod::set_latest_epoch(epoch_t epoch, bool exclusive,
                             exclusive, objv, real_time(), nullptr);
 }
 
+int RGWPeriod::update_latest_epoch(epoch_t epoch)
+{
+  static constexpr int MAX_RETRIES = 20;
+
+  for (int i = 0; i < MAX_RETRIES; i++) {
+    RGWPeriodLatestEpochInfo info;
+    RGWObjVersionTracker objv;
+    bool exclusive = false;
+
+    // read existing epoch
+    int r = read_latest_epoch(info, &objv);
+    if (r == -ENOENT) {
+      // use an exclusive create to set the epoch atomically
+      exclusive = true;
+      ldout(cct, 20) << "creating initial latest_epoch=" << epoch
+          << " for period=" << id << dendl;
+    } else if (r < 0) {
+      ldout(cct, 0) << "ERROR: failed to read latest_epoch" << dendl;
+      return r;
+    } else if (epoch <= info.epoch) {
+      r = -EEXIST; // fail with EEXIST if epoch is not newer
+      ldout(cct, 1) << "found existing latest_epoch " << info.epoch
+          << " >= given epoch " << epoch << ", returning r=" << r << dendl;
+      return r;
+    } else {
+      ldout(cct, 20) << "updating latest_epoch from " << info.epoch
+          << " -> " << epoch << " on period=" << id << dendl;
+    }
+
+    r = set_latest_epoch(epoch, exclusive, &objv);
+    if (r == -EEXIST) {
+      continue; // exclusive create raced with another update, retry
+    } else if (r == -ECANCELED) {
+      continue; // write raced with a conflicting version, retry
+    }
+    if (r < 0) {
+      ldout(cct, 0) << "ERROR: failed to write latest_epoch" << dendl;
+      return r;
+    }
+    return 0; // return success
+  }
+
+  return -ECANCELED; // fail after max retries
+}
+
 int RGWPeriod::delete_obj()
 {
   rgw_pool pool(get_pool(cct));
index 302560885c62ff5467d6e6d7a68892e3f6af7c4f..0ae433257fd069eb9eeca5f519d87f33a0eb77d0 100644 (file)
@@ -1875,6 +1875,8 @@ public:
   int get_latest_epoch(epoch_t& epoch);
   int set_latest_epoch(epoch_t epoch, bool exclusive = false,
                        RGWObjVersionTracker *objv = nullptr);
+  // update latest_epoch if the given epoch is higher, else return -EEXIST
+  int update_latest_epoch(epoch_t epoch);
 
   int init(CephContext *_cct, RGWRados *_store, const string &period_realm_id, const string &period_realm_name = "",
           bool setup_obj = true);