From: Casey Bodley Date: Tue, 2 May 2017 14:44:20 +0000 (-0400) Subject: rgw: add atomic RGWPeriod::update_latest_epoch X-Git-Tag: v12.1.1~21^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=55000d7fb3d4ab1ba4c19f3b3730823b5b056b67;p=ceph.git rgw: add atomic RGWPeriod::update_latest_epoch 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 --- diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index bc06c6b99fde..d19e7606dc1d 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -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)); diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index 302560885c62..0ae433257fd0 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -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);