From: Casey Bodley Date: Thu, 17 Dec 2015 21:03:43 +0000 (-0500) Subject: rgw: 'period push' handler uses RGWPeriodHistory X-Git-Tag: v10.1.0~354^2~72 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=71dd4085b85498753c39b7679da413a629baddaa;p=ceph.git rgw: 'period push' handler uses RGWPeriodHistory Signed-off-by: Casey Bodley --- diff --git a/src/rgw/rgw_rest_realm.cc b/src/rgw/rgw_rest_realm.cc index 9e466d6960d..2f45db99009 100644 --- a/src/rgw/rgw_rest_realm.cc +++ b/src/rgw/rgw_rest_realm.cc @@ -8,6 +8,9 @@ #define dout_subsys ceph_subsys_rgw +// reject 'period push' if we would have to fetch too many intermediate periods +static const uint32_t PERIOD_HISTORY_FETCH_MAX = 64; + // base period op, shared between Get and Post class RGWOp_Period_Base : public RGWRESTOp { protected: @@ -122,21 +125,48 @@ void RGWOp_Period_Post::execute() return; } + // write the period to rados + http_ret = period.store_info(false); + if (http_ret < 0) { + lderr(cct) << "failed to store period " << period.get_id() << dendl; + return; + } + + // decide whether we can set_current_period() or set_latest_epoch() if (period.get_id() != current_period.get_id()) { - // new period must follow current period - if (period.get_predecessor() != current_period.get_id()) { - ldout(cct, 10) << "current period " << current_period.get_id() - << " is not period " << period.get_id() << "'s predecessor" << dendl; - // XXX: this indicates a race between successive period updates. we should - // fetch this new period's predecessors until we have a full history, then - // set the latest period as the realm's current_period + auto current_epoch = current_period.get_realm_epoch(); + // discard periods in the past + if (period.get_realm_epoch() < current_epoch) { + ldout(cct, 10) << "discarding period " << period.get_id() + << " with realm epoch " << period.get_realm_epoch() + << " older than current epoch " << current_epoch << dendl; + // return success to ack that we have this period + return; + } + // discard periods too far in the future + if (period.get_realm_epoch() > current_epoch + PERIOD_HISTORY_FETCH_MAX) { + lderr(cct) << "discarding period " << period.get_id() + << " with realm epoch " << period.get_realm_epoch() << " too far in " + "the future from current epoch " << current_epoch << dendl; http_ret = -ENOENT; // XXX: error code return; } - // write the period to rados - http_ret = period.store_info(false); - if (http_ret < 0) { - lderr(cct) << "failed to store new period" << dendl; + // attach a copy of the period into the period history + auto cursor = store->period_history->attach(RGWPeriod{period}); + if (!cursor) { + // we're missing some history between the new period and current_period + http_ret = cursor.get_error(); + lderr(cct) << "failed to collect the periods between current period " + << current_period.get_id() << " (realm epoch " << current_epoch + << ") and the new period " << period.get_id() + << " (realm epoch " << period.get_realm_epoch() + << "): " << cpp_strerror(-http_ret) << dendl; + return; + } + if (cursor.has_next()) { + // don't switch if we have a newer period in our history + ldout(cct, 4) << "attached period " << period.get_id() + << " to history, but the history contains newer periods" << dendl; return; } // set as current period @@ -145,9 +175,9 @@ void RGWOp_Period_Post::execute() lderr(cct) << "failed to update realm's current period" << dendl; return; } - ldout(cct, 4) << "current period " << current_period.get_id() - << " is period " << period.get_id() << "'s predecessor, " - "updating current period and notifying zone" << dendl; + ldout(cct, 4) << "period " << period.get_id() + << " is newer than current period " << current_period.get_id() + << ", updating realm's current period and notifying zone" << dendl; realm.notify_new_period(period); return; } @@ -158,13 +188,6 @@ void RGWOp_Period_Post::execute() << ", discarding update" << dendl; return; } - - // write the period to rados - http_ret = period.store_info(false); - if (http_ret < 0) { - lderr(cct) << "failed to store period " << period.get_id() << dendl; - return; - } // set as latest epoch http_ret = period.set_latest_epoch(period.get_epoch()); if (http_ret < 0) { @@ -180,8 +203,10 @@ void RGWOp_Period_Post::execute() } ldout(cct, 4) << "period epoch " << period.get_epoch() << " is newer than current epoch " << current_period.get_epoch() - << ", updating latest epoch and notifying zone" << dendl; + << ", updating period's latest epoch and notifying zone" << dendl; realm.notify_new_period(period); + // update the period history + store->period_history->insert(RGWPeriod{period}); } class RGWHandler_Period : public RGWHandler_Auth_S3 {