From 0f690117439384827cdfffaf662b71a99f73b34a Mon Sep 17 00:00:00 2001 From: Soumya Koduri Date: Tue, 25 Apr 2023 23:34:28 +0530 Subject: [PATCH] rgw/cloud-transition: New attrs to detect cloudtiered objects Add new attrs "RGW_ATTR_CLOUD_TIER_TYPE" and "RGW_ATTR_CLOUD_TIER_CONFIG" to store details about cloud-tiered objects so that they get synced accordingly in a multisite environment. Signed-off-by: Soumya Koduri --- src/rgw/driver/rados/rgw_putobj_processor.cc | 37 +++++++++++++ src/rgw/rgw_common.h | 6 ++ src/rgw/rgw_op.cc | 58 ++++++++++++++------ 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/rgw/driver/rados/rgw_putobj_processor.cc b/src/rgw/driver/rados/rgw_putobj_processor.cc index d52e303291d..11ba9d713aa 100644 --- a/src/rgw/driver/rados/rgw_putobj_processor.cc +++ b/src/rgw/driver/rados/rgw_putobj_processor.cc @@ -28,6 +28,41 @@ using namespace std; namespace rgw::putobj { +/* + * For the cloudtiered objects, update the object manifest with the + * cloudtier config info read from the attrs. + * Since these attrs are used internally for only replication, do not store them + * in the head object. + */ +void read_cloudtier_info_from_attrs(rgw::sal::Attrs& attrs, RGWObjCategory& category, + RGWObjManifest& manifest) { + auto attr_iter = attrs.find(RGW_ATTR_CLOUD_TIER_TYPE); + if (attr_iter != attrs.end()) { + auto i = attr_iter->second; + string m = i.to_str(); + + if (m == "cloud-s3") { + category = RGWObjCategory::CloudTiered; + manifest.set_tier_type("cloud-s3"); + + auto config_iter = attrs.find(RGW_ATTR_CLOUD_TIER_CONFIG); + if (config_iter != attrs.end()) { + auto i = config_iter->second.cbegin(); + RGWObjTier tier_config; + + try { + using ceph::decode; + decode(tier_config, i); + manifest.set_tier_config(tier_config); + attrs.erase(config_iter); + } catch (buffer::error& err) { + } + } + } + attrs.erase(attr_iter); + } +} + int HeadObjectProcessor::process(bufferlist&& data, uint64_t logical_offset) { const bool flush = (data.length() == 0); @@ -341,6 +376,8 @@ int AtomicObjectProcessor::complete(size_t accounted_size, obj_op.meta.zones_trace = zones_trace; obj_op.meta.modify_tail = true; + read_cloudtier_info_from_attrs(attrs, obj_op.meta.category, manifest); + r = obj_op.write_meta(dpp, actual_size, accounted_size, attrs, y); if (r < 0) { if (r == -ETIMEDOUT) { diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 7cabd8e4ca6..7d649f3c1f4 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -137,6 +137,12 @@ using ceph::crypto::MD5; #define RGW_ATTR_APPEND_PART_NUM RGW_ATTR_PREFIX "append_part_num" +/* Attrs to store cloudtier config information. These are used internally + * for the replication of cloudtiered objects but not stored as xattrs in + * the head object. */ +#define RGW_ATTR_CLOUD_TIER_TYPE RGW_ATTR_PREFIX "cloud_tier_type" +#define RGW_ATTR_CLOUD_TIER_CONFIG RGW_ATTR_PREFIX "cloud_tier_config" + #define RGW_ATTR_OBJ_REPLICATION_STATUS RGW_ATTR_PREFIX "amz-replication-status" /* IAM Policy */ diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 731dc101d4d..8b23c1c2da9 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -914,6 +914,41 @@ void rgw_build_iam_environment(rgw::sal::Driver* driver, } } +/* + * GET on CloudTiered objects is processed only when sent from the sync client. + * In all other cases, fail with `ERR_INVALID_OBJECT_STATE`. + */ +int handle_cloudtier_obj(rgw::sal::Attrs& attrs, bool sync_cloudtiered) { + int op_ret = 0; + auto attr_iter = attrs.find(RGW_ATTR_MANIFEST); + if (attr_iter != attrs.end()) { + RGWObjManifest m; + try { + decode(m, attr_iter->second); + if (m.get_tier_type() == "cloud-s3") { + if (!sync_cloudtiered) { + /* XXX: Instead send presigned redirect or read-through */ + op_ret = -ERR_INVALID_OBJECT_STATE; + } else { // fetch object for sync and set cloud_tier attrs + bufferlist t, t_tier; + RGWObjTier tier_config; + m.get_tier_config(&tier_config); + + t.append("cloud-s3"); + attrs[RGW_ATTR_CLOUD_TIER_TYPE] = t; + encode(tier_config, t_tier); + attrs[RGW_ATTR_CLOUD_TIER_CONFIG] = t_tier; + } + } + } catch (const buffer::end_of_buffer&) { + // ignore empty manifest; it's not cloud-tiered + } catch (const std::exception& e) { + } + } + + return op_ret; +} + void rgw_bucket_object_pre_exec(req_state *s) { if (s->expect_cont) @@ -2257,24 +2292,15 @@ void RGWGetObj::execute(optional_yield y) filter = &*decompress; } - attr_iter = attrs.find(RGW_ATTR_MANIFEST); - if (attr_iter != attrs.end() && get_type() == RGW_OP_GET_OBJ && get_data) { - RGWObjManifest m; - try { - decode(m, attr_iter->second); - if (m.get_tier_type() == "cloud-s3" && !sync_cloudtiered) { - /* XXX: Instead send presigned redirect or read-through */ - op_ret = -ERR_INVALID_OBJECT_STATE; + if (get_type() == RGW_OP_GET_OBJ && get_data) { + op_ret = handle_cloudtier_obj(attrs, sync_cloudtiered); + if (op_ret < 0) { + ldpp_dout(this, 4) << "Cannot get cloud tiered object: " << *s->object + <<". Failing with " << op_ret << dendl; + if (op_ret == -ERR_INVALID_OBJECT_STATE) { s->err.message = "This object was transitioned to cloud-s3"; - ldpp_dout(this, 4) << "Cannot get cloud tiered object. Failing with " - << op_ret << dendl; - goto done_err; } - } catch (const buffer::end_of_buffer&) { - // ignore empty manifest; it's not cloud-tiered - } catch (const std::exception& e) { - ldpp_dout(this, 1) << "WARNING: failed to decode object manifest for " - << *s->object << ": " << e.what() << dendl; + goto done_err; } } -- 2.39.5