From: Alex Wojno Date: Mon, 10 Jun 2024 15:45:06 +0000 (-0400) Subject: rgw: Update obj_mtime only when replication log is added X-Git-Tag: v20.0.0~1605^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3c1041a2df9a8eba1e1319a48da521eacc222858;p=ceph.git rgw: Update obj_mtime only when replication log is added Signed-off-by: Alex Wojno --- 3c1041a2df9a8eba1e1319a48da521eacc222858 diff --cc src/rgw/driver/daos/rgw_sal_daos.h index 8c72fa68fa6,8b40c645caf..39749a0d33c --- a/src/rgw/driver/daos/rgw_sal_daos.h +++ b/src/rgw/driver/daos/rgw_sal_daos.h @@@ -617,10 -617,10 +617,10 @@@ class DaosObject : public StoreObject return 0; } - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState** state, - optional_yield y, bool follow_olh = true) override; + virtual int load_obj_state(const DoutPrefixProvider *dpp, optional_yield y, + bool follow_olh = true) override; virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, - Attrs* delattrs, optional_yield y) override; + Attrs* delattrs, optional_yield y, uint32_t flags) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, diff --cc src/rgw/driver/motr/rgw_sal_motr.h index 233e99e8f59,caf7c8667f7..ac1af5376f3 --- a/src/rgw/driver/motr/rgw_sal_motr.h +++ b/src/rgw/driver/motr/rgw_sal_motr.h @@@ -676,8 -676,8 +676,8 @@@ class MotrObject : public StoreObject const DoutPrefixProvider* dpp, optional_yield y) override; virtual RGWAccessControlPolicy& get_acl(void) override { return acls; } virtual int set_acl(const RGWAccessControlPolicy& acl) override { acls = acl; return 0; } - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) override; + virtual int load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh = true) override; - virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) override; + virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y, uint32_t flags) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, optional_yield y, const DoutPrefixProvider* dpp) override; virtual int delete_obj_attrs(const DoutPrefixProvider* dpp, const char* attr_name, optional_yield y) override; diff --cc src/rgw/driver/posix/rgw_sal_posix.h index 22445d06667,ac83173a00d..d2ea90b0109 --- a/src/rgw/driver/posix/rgw_sal_posix.h +++ b/src/rgw/driver/posix/rgw_sal_posix.h @@@ -339,9 -339,9 +339,9 @@@ public const DoutPrefixProvider* dpp, optional_yield y) override; virtual RGWAccessControlPolicy& get_acl(void) override { return acls; } virtual int set_acl(const RGWAccessControlPolicy& acl) override { acls = acl; return 0; } - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) override; + virtual int load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh = true) override; virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, - Attrs* delattrs, optional_yield y) override; + Attrs* delattrs, optional_yield y, uint32_t flags) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, diff --cc src/rgw/driver/rados/rgw_bucket_sync.cc index d59d79a0085,dafbb6df46f..28e35d4bb47 --- a/src/rgw/driver/rados/rgw_bucket_sync.cc +++ b/src/rgw/driver/rados/rgw_bucket_sync.cc @@@ -984,19 -984,6 +984,20 @@@ void RGWBucketSyncPolicyHandler::get_pi } } - bool RGWBucketSyncPolicyHandler::bucket_exports_object(const std::string& obj_name, const RGWObjTags& tags) { ++bool RGWBucketSyncPolicyHandler::bucket_exports_object(const std::string& obj_name, const RGWObjTags* tags) const { + if (bucket_exports_data()) { + for (auto& entry : target_pipes.pipe_map) { + auto& filter = entry.second.params.source.filter; - if (filter.check_prefix(obj_name) && filter.check_tags(tags.get_tags())) { ++ if (filter.check_prefix(obj_name) && ++ (tags == nullptr || filter.check_tags(tags->get_tags()))) { + return true; + } + } + } + + return false; +} + bool RGWBucketSyncPolicyHandler::bucket_exports_data() const { if (!bucket) { diff --cc src/rgw/driver/rados/rgw_bucket_sync.h index db542833792,d425ecf1732..ba578c8371c --- a/src/rgw/driver/rados/rgw_bucket_sync.h +++ b/src/rgw/driver/rados/rgw_bucket_sync.h @@@ -402,7 -402,6 +402,7 @@@ public return target_hints; } - bool bucket_exports_object(const std::string& obj_name, const RGWObjTags& tags); ++ bool bucket_exports_object(const std::string& obj_name, const RGWObjTags* tags) const; bool bucket_exports_data() const; bool bucket_imports_data() const; diff --cc src/rgw/driver/rados/rgw_sal_rados.cc index aa1e5c902b6,9057bc7af44..2e8a23a6742 --- a/src/rgw/driver/rados/rgw_sal_rados.cc +++ b/src/rgw/driver/rados/rgw_sal_rados.cc @@@ -2240,43 -2254,11 +2256,45 @@@ RadosObject::~RadosObject( delete rados_ctx; } +bool RadosObject::is_sync_completed(const DoutPrefixProvider* dpp, + const ceph::real_time& obj_mtime) +{ + const auto& bucket_info = get_bucket()->get_info(); + if (bucket_info.is_indexless()) { + ldpp_dout(dpp, 0) << "ERROR: Trying to check object replication status for object in an indexless bucket. obj=" << get_key() << dendl; + return false; + } + + const auto& log_layout = bucket_info.layout.logs.front(); + const uint32_t shard_count = num_shards(log_to_index_layout(log_layout)); + + std::string marker; + bool truncated; + list entries; + + const int shard_id = RGWSI_BucketIndex_RADOS::bucket_shard_index(get_key(), shard_count); + + int ret = store->svc()->bilog_rados->log_list(dpp, bucket_info, log_layout, shard_id, + marker, 1, entries, &truncated); + + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: Failed to retrieve bilog info for obj=" << get_key() << dendl; + return false; + } + + if (entries.empty()) { + return true; + } + + const rgw_bi_log_entry& earliest_marker = entries.front(); + return earliest_marker.timestamp > obj_mtime; +} + - int RadosObject::get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **pstate, optional_yield y, bool follow_olh) + int RadosObject::load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh) { - int ret = store->getRados()->get_obj_state(dpp, rados_ctx, bucket->get_info(), get_obj(), pstate, &manifest, follow_olh, y); + RGWObjState *pstate{nullptr}; + + int ret = store->getRados()->get_obj_state(dpp, rados_ctx, bucket->get_info(), get_obj(), &pstate, &manifest, follow_olh, y); if (ret < 0) { return ret; } @@@ -2304,15 -2286,18 +2322,19 @@@ int RadosObject::read_attrs(const DoutP return read_op.prepare(y, dpp); } -int RadosObject::set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) +int RadosObject::set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y, uint32_t flags) { Attrs empty; ++ const bool log_op = flags & rgw::sal::FLAG_LOG_OP; + // make a tiny adjustment to the existing mtime so that fetch_remote_obj() + // won't return ERR_NOT_MODIFIED when syncing the modified object - const auto mtime = state.mtime + std::chrono::nanoseconds(1); ++ const auto mtime = log_op ? state.mtime + std::chrono::nanoseconds(1) : state.mtime; return store->getRados()->set_attrs(dpp, rados_ctx, bucket->get_info(), get_obj(), setattrs ? *setattrs : empty, delattrs ? delattrs : nullptr, - y, flags & rgw::sal::FLAG_LOG_OP); - y, mtime); ++ y, log_op, mtime); } int RadosObject::get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj) diff --cc src/rgw/driver/rados/rgw_sal_rados.h index a056b08a832,f880319b56e..ff36c2edfd8 --- a/src/rgw/driver/rados/rgw_sal_rados.h +++ b/src/rgw/driver/rados/rgw_sal_rados.h @@@ -585,10 -591,10 +591,13 @@@ class RadosObject : public StoreObject StoreObject::set_compressed(); } ++ + virtual bool is_sync_completed(const DoutPrefixProvider* dpp, + const ceph::real_time& obj_mtime) override; - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) override; + /* For rgw_admin.cc */ + RGWObjState& get_state() { return state; } + virtual int load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh = true) override; - virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) override; + virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y, uint32_t flags) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, optional_yield y, const DoutPrefixProvider* dpp) override; virtual int delete_obj_attrs(const DoutPrefixProvider* dpp, const char* attr_name, optional_yield y) override; diff --cc src/rgw/rgw_op.cc index 6045a9a60f3,c2a8d05bb06..c0821e78c5b --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@@ -909,27 -910,6 +911,27 @@@ void rgw_build_iam_environment(rgw::sal } } +void handle_replication_status_header( + const DoutPrefixProvider *dpp, + rgw::sal::Attrs& attrs, + req_state* s, + const ceph::real_time &obj_mtime) { + auto attr_iter = attrs.find(RGW_ATTR_OBJ_REPLICATION_STATUS); + if (attr_iter != attrs.end() && attr_iter->second.to_str() == "PENDING") { + if (s->object->is_sync_completed(dpp, obj_mtime)) { + s->object->set_atomic(); + rgw::sal::Attrs setattrs, rmattrs; + bufferlist bl; + bl.append("COMPLETED"); - setattrs[RGW_ATTR_OBJ_REPLICATION_STATUS] = bl; ++ setattrs[RGW_ATTR_OBJ_REPLICATION_STATUS] = std::move(bl); + int ret = s->object->set_obj_attrs(dpp, &setattrs, &rmattrs, s->yield, 0); + if (ret == 0) { + ldpp_dout(dpp, 20) << *s->object << " has amz-replication-status header set to COMPLETED" << dendl; + } + } + } +} + /* * GET on CloudTiered objects is processed only when sent from the sync client. * In all other cases, fail with `ERR_INVALID_OBJECT_STATE`. @@@ -4506,19 -4451,6 +4477,19 @@@ void RGWPutObj::execute(optional_yield } } + RGWBucketSyncPolicyHandlerRef policy_handler; + op_ret = driver->get_sync_policy_handler(this, std::nullopt, s->bucket->get_key(), &policy_handler, s->yield); + + if (op_ret < 0) { + ldpp_dout(this, 0) << "failed to read sync policy for bucket: " << s->bucket << dendl; + return; + } - if (policy_handler && policy_handler->bucket_exports_object(s->object->get_name(), *obj_tags)) { ++ if (policy_handler && policy_handler->bucket_exports_object(s->object->get_name(), obj_tags.get())) { + bufferlist repl_bl; + repl_bl.append("PENDING"); + emplace_attr(RGW_ATTR_OBJ_REPLICATION_STATUS, std::move(repl_bl)); + } + if (slo_info) { bufferlist manifest_bl; encode(*slo_info, manifest_bl); diff --cc src/rgw/rgw_sal.h index eab0ad13e08,5fd20fda692..3eaae189a15 --- a/src/rgw/rgw_sal.h +++ b/src/rgw/rgw_sal.h @@@ -1190,13 -1153,11 +1156,11 @@@ class Object /** Get the name of this object */ virtual const std::string &get_name() const = 0; - /** Get the object state for this object. Will be removed in the future */ - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) = 0; - /** Set the object state for this object */ - virtual void set_obj_state(RGWObjState& _state) = 0; + /** Load the object state for this object. */ + virtual int load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh = true) = 0; /** Set attributes for this object from the backing store. Attrs can be set or * deleted. @note the attribute APIs may be revisited in the future. */ - virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) = 0; + virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y, uint32_t flags) = 0; /** Get attributes for this object */ virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) = 0; /** Modify attributes for this object. */ diff --cc src/rgw/rgw_sal_dbstore.cc index b6bbcf7a030,8c415feddc9..4b27bd35f99 --- a/src/rgw/rgw_sal_dbstore.cc +++ b/src/rgw/rgw_sal_dbstore.cc @@@ -552,7 -551,7 +551,7 @@@ namespace rgw::sal } set_atomic(); state.attrset[attr_name] = attr_val; - return set_obj_attrs(dpp, &state.attrset, nullptr, y, 0); - return set_obj_attrs(dpp, &state.attrset, nullptr, y); ++ return set_obj_attrs(dpp, &state.attrset, nullptr, y, rgw::sal::FLAG_LOG_OP); } int DBObject::delete_obj_attrs(const DoutPrefixProvider* dpp, const char* attr_name, optional_yield y) @@@ -562,7 -561,7 +561,7 @@@ set_atomic(); rmattr[attr_name] = bl; - return set_obj_attrs(dpp, nullptr, &rmattr, y, 0); - return set_obj_attrs(dpp, nullptr, &rmattr, y); ++ return set_obj_attrs(dpp, nullptr, &rmattr, y, rgw::sal::FLAG_LOG_OP); } bool DBObject::is_expired() { diff --cc src/rgw/rgw_sal_dbstore.h index 516ab47393a,b542028e53e..defa5c2c50d --- a/src/rgw/rgw_sal_dbstore.h +++ b/src/rgw/rgw_sal_dbstore.h @@@ -541,8 -541,8 +541,8 @@@ protected virtual RGWAccessControlPolicy& get_acl(void) override { return acls; } virtual int set_acl(const RGWAccessControlPolicy& acl) override { acls = acl; return 0; } - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) override; + virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y, uint32_t flags) override; + virtual int load_obj_state(const DoutPrefixProvider* dpp, optional_yield y, bool follow_olh = true) override; - virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, optional_yield y, const DoutPrefixProvider* dpp) override; virtual int delete_obj_attrs(const DoutPrefixProvider* dpp, const char* attr_name, optional_yield y) override; diff --cc src/rgw/rgw_sal_filter.h index 2e9a08ed0b5,7d26a466efe..6ff30041895 --- a/src/rgw/rgw_sal_filter.h +++ b/src/rgw/rgw_sal_filter.h @@@ -752,11 -756,10 +758,10 @@@ public virtual bool empty() const override { return next->empty(); } virtual const std::string &get_name() const override { return next->get_name(); } - virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, - optional_yield y, bool follow_olh = true) override; - virtual void set_obj_state(RGWObjState& _state) override { return next->set_obj_state(_state); } + virtual int load_obj_state(const DoutPrefixProvider *dpp, optional_yield y, + bool follow_olh = true) override; virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, - Attrs* delattrs, optional_yield y) override; + Attrs* delattrs, optional_yield y, uint32_t flags) override; virtual int get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj = NULL) override; virtual int modify_obj_attrs(const char* attr_name, bufferlist& attr_val, diff --cc src/test/rgw/rgw_multi/tests.py index cb3f2bf8ed4,df9c70a4781..a392588c58e --- a/src/test/rgw/rgw_multi/tests.py +++ b/src/test/rgw/rgw_multi/tests.py @@@ -1921,34 -1928,38 +1928,68 @@@ def test_role_delete_sync() zone.iam_conn.get_role, RoleName=role_name) log.info(f'success, zone: {zone.name} does not have role: {role_name}') ++ +def test_replication_status(): + zonegroup = realm.master_zonegroup() + zonegroup_conns = ZonegroupConns(zonegroup) + zone = zonegroup_conns.rw_zones[0] + + bucket = zone.conn.create_bucket(gen_bucket_name()) + obj_name = "a" + k = new_key(zone, bucket.name, obj_name) + k.set_contents_from_string('foo') + zonegroup_meta_checkpoint(zonegroup) + zonegroup_bucket_checkpoint(zonegroup_conns, bucket.name) + + head_res = zone.head_object(bucket.name, obj_name) + log.info("checking if object has PENDING ReplicationStatus") + assert(head_res["ReplicationStatus"] == "PENDING") + + bilog_autotrim(zone.zone) + zonegroup_data_checkpoint(zonegroup_conns) + zonegroup_bucket_checkpoint(zonegroup_conns, bucket.name) + + head_res = zone.head_object(bucket.name, obj_name) + log.info("checking if object has COMPLETED ReplicationStatus") + assert(head_res["ReplicationStatus"] == "COMPLETED") + + log.info("checking that ReplicationStatus update did not write a bilog") + bilog = bilog_list(zone.zone, bucket.name) + assert(len(bilog) == 0) + + def test_object_acl(): + zonegroup = realm.master_zonegroup() + zonegroup_conns = ZonegroupConns(zonegroup) + primary = zonegroup_conns.rw_zones[0] + secondary = zonegroup_conns.rw_zones[1] + + bucket = primary.create_bucket(gen_bucket_name()) + log.debug('created bucket=%s', bucket.name) + + # upload a dummy object and wait for sync. + k = new_key(primary, bucket, 'dummy') + k.set_contents_from_string('foo') + zonegroup_meta_checkpoint(zonegroup) + zonegroup_data_checkpoint(zonegroup_conns) + + #check object on secondary before setacl + bucket2 = get_bucket(secondary, bucket.name) + before_set_acl = bucket2.get_acl(k) + assert(len(before_set_acl.acl.grants) == 1) + + #set object acl on primary and wait for sync. + bucket.set_canned_acl('public-read', key_name=k) + log.debug('set acl=%s', bucket.name) + zonegroup_data_checkpoint(zonegroup_conns) + zonegroup_bucket_checkpoint(zonegroup_conns, bucket.name) + + #check object secondary after setacl + bucket2 = get_bucket(secondary, bucket.name) + after_set_acl = bucket2.get_acl(k) + assert(len(after_set_acl.acl.grants) == 2) # read grant added on AllUsers + ++ + @attr('fails_with_rgw') @attr('data_sync_init') def test_bucket_full_sync_after_data_sync_init(): zonegroup = realm.master_zonegroup()