summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_period.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/rgw_period.cc')
-rw-r--r--src/rgw/rgw_period.cc350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/rgw/rgw_period.cc b/src/rgw/rgw_period.cc
new file mode 100644
index 000000000..1e7de60ea
--- /dev/null
+++ b/src/rgw/rgw_period.cc
@@ -0,0 +1,350 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+#include "rgw_sync.h"
+
+using namespace std;
+using namespace rgw_zone_defaults;
+
+std::string period_latest_epoch_info_oid = ".latest_epoch";
+std::string period_info_oid_prefix = "periods.";
+
+#define FIRST_EPOCH 1
+
+int RGWPeriod::init(const DoutPrefixProvider *dpp,
+ CephContext *_cct, RGWSI_SysObj *_sysobj_svc,
+ optional_yield y, bool setup_obj)
+{
+ cct = _cct;
+ sysobj_svc = _sysobj_svc;
+
+ if (!setup_obj)
+ return 0;
+
+ if (id.empty()) {
+ RGWRealm realm(realm_id, realm_name);
+ int ret = realm.init(dpp, cct, sysobj_svc, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 4) << "RGWPeriod::init failed to init realm " << realm_name << " id " << realm_id << " : " <<
+ cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+ id = realm.get_current_period();
+ realm_id = realm.get_id();
+ }
+
+ if (!epoch) {
+ int ret = use_latest_epoch(dpp, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "failed to use_latest_epoch period id " << id << " realm " << realm_name << " id " << realm_id
+ << " : " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+ }
+
+ return read_info(dpp, y);
+}
+
+int RGWPeriod::init(const DoutPrefixProvider *dpp, CephContext *_cct, RGWSI_SysObj *_sysobj_svc,
+ const string& period_realm_id, optional_yield y,
+ const string& period_realm_name, bool setup_obj)
+{
+ cct = _cct;
+ sysobj_svc = _sysobj_svc;
+
+ realm_id = period_realm_id;
+ realm_name = period_realm_name;
+
+ if (!setup_obj)
+ return 0;
+
+ return init(dpp, _cct, _sysobj_svc, y, setup_obj);
+}
+
+const string& RGWPeriod::get_latest_epoch_oid() const
+{
+ if (cct->_conf->rgw_period_latest_epoch_info_oid.empty()) {
+ return period_latest_epoch_info_oid;
+ }
+ return cct->_conf->rgw_period_latest_epoch_info_oid;
+}
+
+const string& RGWPeriod::get_info_oid_prefix() const
+{
+ return period_info_oid_prefix;
+}
+
+const string RGWPeriod::get_period_oid_prefix() const
+{
+ return get_info_oid_prefix() + id;
+}
+
+const string RGWPeriod::get_period_oid() const
+{
+ std::ostringstream oss;
+ oss << get_period_oid_prefix();
+ // skip the epoch for the staging period
+ if (id != get_staging_id(realm_id))
+ oss << "." << epoch;
+ return oss.str();
+}
+
+bool RGWPeriod::find_zone(const DoutPrefixProvider *dpp,
+ const rgw_zone_id& zid,
+ RGWZoneGroup *pzonegroup,
+ optional_yield y) const
+{
+ RGWZoneGroup zg;
+ RGWZone zone;
+
+ bool found = period_map.find_zone_by_id(zid, &zg, &zone);
+ if (found) {
+ *pzonegroup = zg;
+ }
+
+ return found;
+}
+
+rgw_pool RGWPeriod::get_pool(CephContext *cct) const
+{
+ if (cct->_conf->rgw_period_root_pool.empty()) {
+ return rgw_pool(RGW_DEFAULT_PERIOD_ROOT_POOL);
+ }
+ return rgw_pool(cct->_conf->rgw_period_root_pool);
+}
+
+int RGWPeriod::set_latest_epoch(const DoutPrefixProvider *dpp,
+ optional_yield y,
+ epoch_t epoch, bool exclusive,
+ RGWObjVersionTracker *objv)
+{
+ string oid = get_period_oid_prefix() + get_latest_epoch_oid();
+
+ rgw_pool pool(get_pool(cct));
+ bufferlist bl;
+
+ RGWPeriodLatestEpochInfo info;
+ info.epoch = epoch;
+
+ using ceph::encode;
+ encode(info, bl);
+
+ auto sysobj = sysobj_svc->get_obj(rgw_raw_obj(pool, oid));
+ return sysobj.wop()
+ .set_exclusive(exclusive)
+ .write(dpp, bl, y);
+}
+
+int RGWPeriod::read_info(const DoutPrefixProvider *dpp, optional_yield y)
+{
+ rgw_pool pool(get_pool(cct));
+
+ bufferlist bl;
+
+ auto sysobj = sysobj_svc->get_obj(rgw_raw_obj{pool, get_period_oid()});
+ int ret = sysobj.rop().read(dpp, &bl, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "failed reading obj info from " << pool << ":" << get_period_oid() << ": " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+
+ try {
+ using ceph::decode;
+ auto iter = bl.cbegin();
+ decode(*this, iter);
+ } catch (buffer::error& err) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to decode obj from " << pool << ":" << get_period_oid() << dendl;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int RGWPeriod::store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
+{
+ rgw_pool pool(get_pool(cct));
+
+ string oid = get_period_oid();
+ bufferlist bl;
+ using ceph::encode;
+ encode(*this, bl);
+
+ auto sysobj = sysobj_svc->get_obj(rgw_raw_obj(pool, oid));
+ return sysobj.wop()
+ .set_exclusive(exclusive)
+ .write(dpp, bl, y);
+}
+
+int RGWPeriod::create(const DoutPrefixProvider *dpp, optional_yield y, bool exclusive)
+{
+ int ret;
+
+ /* create unique id */
+ uuid_d new_uuid;
+ char uuid_str[37];
+ new_uuid.generate_random();
+ new_uuid.print(uuid_str);
+ id = uuid_str;
+
+ epoch = FIRST_EPOCH;
+
+ period_map.id = id;
+
+ ret = store_info(dpp, exclusive, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+
+ ret = set_latest_epoch(dpp, y, epoch);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: setting latest epoch " << id << ": " << cpp_strerror(-ret) << dendl;
+ }
+
+ return ret;
+}
+
+int RGWPeriod::reflect(const DoutPrefixProvider *dpp, optional_yield y)
+{
+ for (auto& iter : period_map.zonegroups) {
+ RGWZoneGroup& zg = iter.second;
+ zg.reinit_instance(cct, sysobj_svc);
+ int r = zg.write(dpp, false, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to store zonegroup info for zonegroup=" << iter.first << ": " << cpp_strerror(-r) << dendl;
+ return r;
+ }
+ if (zg.is_master_zonegroup()) {
+ // set master as default if no default exists
+ r = zg.set_as_default(dpp, y, true);
+ if (r == 0) {
+ ldpp_dout(dpp, 1) << "Set the period's master zonegroup " << zg.get_id()
+ << " as the default" << dendl;
+ }
+ }
+ }
+
+ int r = period_config.write(dpp, sysobj_svc, realm_id, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to store period config: "
+ << cpp_strerror(-r) << dendl;
+ return r;
+ }
+ return 0;
+}
+
+void RGWPeriod::dump(Formatter *f) const
+{
+ encode_json("id", id, f);
+ encode_json("epoch", epoch , f);
+ encode_json("predecessor_uuid", predecessor_uuid, f);
+ encode_json("sync_status", sync_status, f);
+ encode_json("period_map", period_map, f);
+ encode_json("master_zonegroup", master_zonegroup, f);
+ encode_json("master_zone", master_zone, f);
+ encode_json("period_config", period_config, f);
+ encode_json("realm_id", realm_id, f);
+ encode_json("realm_name", realm_name, f);
+ encode_json("realm_epoch", realm_epoch, f);
+}
+
+void RGWPeriod::decode_json(JSONObj *obj)
+{
+ JSONDecoder::decode_json("id", id, obj);
+ JSONDecoder::decode_json("epoch", epoch, obj);
+ JSONDecoder::decode_json("predecessor_uuid", predecessor_uuid, obj);
+ JSONDecoder::decode_json("sync_status", sync_status, obj);
+ JSONDecoder::decode_json("period_map", period_map, obj);
+ JSONDecoder::decode_json("master_zonegroup", master_zonegroup, obj);
+ JSONDecoder::decode_json("master_zone", master_zone, obj);
+ JSONDecoder::decode_json("period_config", period_config, obj);
+ JSONDecoder::decode_json("realm_id", realm_id, obj);
+ JSONDecoder::decode_json("realm_name", realm_name, obj);
+ JSONDecoder::decode_json("realm_epoch", realm_epoch, obj);
+}
+
+int RGWPeriod::update_latest_epoch(const DoutPrefixProvider *dpp, epoch_t epoch, optional_yield y)
+{
+ 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(dpp, info, y, &objv);
+ if (r == -ENOENT) {
+ // use an exclusive create to set the epoch atomically
+ exclusive = true;
+ ldpp_dout(dpp, 20) << "creating initial latest_epoch=" << epoch
+ << " for period=" << id << dendl;
+ } else if (r < 0) {
+ ldpp_dout(dpp, 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
+ ldpp_dout(dpp, 10) << "found existing latest_epoch " << info.epoch
+ << " >= given epoch " << epoch << ", returning r=" << r << dendl;
+ return r;
+ } else {
+ ldpp_dout(dpp, 20) << "updating latest_epoch from " << info.epoch
+ << " -> " << epoch << " on period=" << id << dendl;
+ }
+
+ r = set_latest_epoch(dpp, y, 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) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to write latest_epoch" << dendl;
+ return r;
+ }
+ return 0; // return success
+ }
+
+ return -ECANCELED; // fail after max retries
+}
+
+int RGWPeriod::read_latest_epoch(const DoutPrefixProvider *dpp,
+ RGWPeriodLatestEpochInfo& info,
+ optional_yield y,
+ RGWObjVersionTracker *objv)
+{
+ string oid = get_period_oid_prefix() + get_latest_epoch_oid();
+
+ rgw_pool pool(get_pool(cct));
+ bufferlist bl;
+ auto sysobj = sysobj_svc->get_obj(rgw_raw_obj{pool, oid});
+ int ret = sysobj.rop().read(dpp, &bl, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 1) << "error read_lastest_epoch " << pool << ":" << oid << dendl;
+ return ret;
+ }
+ try {
+ auto iter = bl.cbegin();
+ using ceph::decode;
+ decode(info, iter);
+ } catch (buffer::error& err) {
+ ldpp_dout(dpp, 0) << "error decoding data from " << pool << ":" << oid << dendl;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int RGWPeriod::use_latest_epoch(const DoutPrefixProvider *dpp, optional_yield y)
+{
+ RGWPeriodLatestEpochInfo info;
+ int ret = read_latest_epoch(dpp, info, y);
+ if (ret < 0) {
+ return ret;
+ }
+
+ epoch = info.epoch;
+
+ return 0;
+}
+