From 17992d1e622ea74cfd9a7890a7265b5ab1f8fd7a Mon Sep 17 00:00:00 2001 From: Alex Wojno Date: Mon, 22 May 2023 16:13:06 -0400 Subject: [PATCH] rgw: Pass and check destination zone trace when fetching object Fixes: https://tracker.ceph.com/issues/58911 Signed-off-by: Alex Wojno (cherry picked from commit e70fcf9b0a5c03d10415fb91e76a62229397ef82) Conflicts: src/rgw/rgw_rest_s3.cc --- src/cls/rgw/cls_rgw_types.h | 4 ++++ src/rgw/driver/rados/rgw_rados.cc | 7 ++++--- src/rgw/rgw_op.cc | 17 +++++++++++++++++ src/rgw/rgw_op.h | 1 + src/rgw/rgw_rest_conn.cc | 6 +++++- src/rgw/rgw_rest_conn.h | 3 ++- src/rgw/rgw_rest_s3.cc | 2 ++ 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/cls/rgw/cls_rgw_types.h b/src/cls/rgw/cls_rgw_types.h index 37a06defc31..f94bf114fa1 100644 --- a/src/cls/rgw/cls_rgw_types.h +++ b/src/cls/rgw/cls_rgw_types.h @@ -38,6 +38,10 @@ struct rgw_zone_set_entry { return (location_key < e.location_key); } + bool operator==(const rgw_zone_set_entry& e) const { + return zone == e.zone && location_key == e.location_key; + } + rgw_zone_set_entry() {} rgw_zone_set_entry(const std::string& _zone, std::optional _location_key) : zone(_zone), diff --git a/src/rgw/driver/rados/rgw_rados.cc b/src/rgw/driver/rados/rgw_rados.cc index 84ac1e26624..15065408197 100644 --- a/src/rgw/driver/rados/rgw_rados.cc +++ b/src/rgw/driver/rados/rgw_rados.cc @@ -3783,7 +3783,7 @@ int RGWRados::stat_remote_obj(const DoutPrefixProvider *dpp, int ret = conn->get_obj(dpp, user_id, info, src_obj, pmod, unmod_ptr, dest_mtime_weight.zone_short_id, dest_mtime_weight.pg_ver, prepend_meta, get_op, rgwx_stat, - sync_manifest, skip_decrypt, sync_cloudtiered, + sync_manifest, skip_decrypt, nullptr, sync_cloudtiered, true, &cb, &in_stream_req); if (ret < 0) { return ret; @@ -3978,6 +3978,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, const real_time *pmod = mod_ptr; obj_time_weight dest_mtime_weight; + rgw_zone_set_entry dst_zone_trace(svc.zone->get_zone().id, dest_bucket_info.bucket.get_key()); if (copy_if_newer) { /* need to get mtime for destination */ @@ -4000,8 +4001,8 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, ret = conn->get_obj(dpp, user_id, info, src_obj, pmod, unmod_ptr, dest_mtime_weight.zone_short_id, dest_mtime_weight.pg_ver, prepend_meta, get_op, rgwx_stat, - sync_manifest, skip_decrypt, sync_cloudtiered, - true, + sync_manifest, skip_decrypt, &dst_zone_trace, + sync_cloudtiered, true, &cb, &in_stream_req); if (ret < 0) { goto set_err_state; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index cb8ef5b4988..68444bdb0c5 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -2310,6 +2310,23 @@ void RGWGetObj::execute(optional_yield y) filter = &*decompress; } + attr_iter = attrs.find(RGW_ATTR_OBJ_REPLICATION_TRACE); + if (attr_iter != attrs.end()) { + try { + std::vector zones; + auto p = attr_iter->second.cbegin(); + decode(zones, p); + for (const auto& zone: zones) { + if (zone == dst_zone_trace) { + op_ret = -ERR_NOT_MODIFIED; + ldpp_dout(this, 4) << "Object already has been copied to this destination. Returning " + << op_ret << dendl; + goto done_err; + } + } + } catch (const buffer::error&) {} + } + if (get_type() == RGW_OP_GET_OBJ && get_data) { op_ret = handle_cloudtier_obj(attrs, sync_cloudtiered); if (op_ret < 0) { diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index b1dc8994bd8..f398b5b15ba 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -361,6 +361,7 @@ protected: std::string lo_etag; bool rgwx_stat; /* extended rgw stat operation */ std::string version_id; + rgw_zone_set_entry dst_zone_trace; // compression attrs RGWCompressionInfo cs_info; diff --git a/src/rgw/rgw_rest_conn.cc b/src/rgw/rgw_rest_conn.cc index 21ddf6b718f..ffb536ed977 100644 --- a/src/rgw/rgw_rest_conn.cc +++ b/src/rgw/rgw_rest_conn.cc @@ -203,7 +203,7 @@ int RGWRESTConn::get_obj(const DoutPrefixProvider *dpp, const rgw_user& uid, req uint32_t mod_zone_id, uint64_t mod_pg_ver, bool prepend_metadata, bool get_op, bool rgwx_stat, bool sync_manifest, bool skip_decrypt, - bool sync_cloudtiered, + rgw_zone_set_entry *dst_zone_trace, bool sync_cloudtiered, bool send, RGWHTTPStreamRWRequest::ReceiveCB *cb, RGWRESTStreamRWRequest **req) { get_obj_params params; @@ -217,6 +217,7 @@ int RGWRESTConn::get_obj(const DoutPrefixProvider *dpp, const rgw_user& uid, req params.sync_manifest = sync_manifest; params.skip_decrypt = skip_decrypt; params.sync_cloudtiered = sync_cloudtiered; + params.dst_zone_trace = dst_zone_trace; params.cb = cb; return get_obj(dpp, obj, params, send, req); } @@ -245,6 +246,9 @@ int RGWRESTConn::get_obj(const DoutPrefixProvider *dpp, const rgw_obj& obj, cons if (in_params.skip_decrypt) { params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "skip-decrypt", "")); } + if (in_params.dst_zone_trace) { + params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "if-not-replicated-to", in_params.dst_zone_trace->to_str())); + } if (!obj.key.instance.empty()) { params.push_back(param_pair_t("versionId", obj.key.instance)); } diff --git a/src/rgw/rgw_rest_conn.h b/src/rgw/rgw_rest_conn.h index bb0d5a8bbf8..81f839f49a2 100644 --- a/src/rgw/rgw_rest_conn.h +++ b/src/rgw/rgw_rest_conn.h @@ -162,6 +162,7 @@ public: bool range_is_set{false}; uint64_t range_start{0}; uint64_t range_end{0}; + rgw_zone_set_entry *dst_zone_trace{nullptr}; }; int get_obj(const DoutPrefixProvider *dpp, const rgw_obj& obj, const get_obj_params& params, bool send, RGWRESTStreamRWRequest **req); @@ -170,7 +171,7 @@ public: const ceph::real_time *mod_ptr, const ceph::real_time *unmod_ptr, uint32_t mod_zone_id, uint64_t mod_pg_ver, bool prepend_metadata, bool get_op, bool rgwx_stat, bool sync_manifest, - bool skip_decrypt, bool sync_cloudtiered, + bool skip_decrypt, rgw_zone_set_entry *dst_zone_trace, bool sync_cloudtiered, bool send, RGWHTTPStreamRWRequest::ReceiveCB *cb, RGWRESTStreamRWRequest **req); int complete_request(RGWRESTStreamRWRequest *req, std::string *etag, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index eb68d004af5..56d00dae3ca 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -302,6 +302,8 @@ int RGWGetObj_ObjStore_S3::get_params(optional_yield y) // multisite sync requests should fetch cloudtiered objects sync_cloudtiered = s->info.args.exists(RGW_SYS_PARAM_PREFIX "sync-cloudtiered"); + dst_zone_trace = s->info.args.get(RGW_SYS_PARAM_PREFIX "if-not-replicated-to"); + return RGWGetObj_ObjStore::get_params(y); } -- 2.39.5