]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Update obj_mtime only when replication log is added
authorAlex Wojno <awojno@bloomberg.net>
Mon, 10 Jun 2024 15:45:06 +0000 (11:45 -0400)
committerAlex Wojno <awojno@bloomberg.net>
Fri, 21 Jun 2024 19:50:35 +0000 (15:50 -0400)
Signed-off-by: Alex Wojno <awojno@bloomberg.net>
21 files changed:
1  2 
src/rgw/driver/d4n/rgw_sal_d4n.cc
src/rgw/driver/daos/rgw_sal_daos.cc
src/rgw/driver/daos/rgw_sal_daos.h
src/rgw/driver/motr/rgw_sal_motr.cc
src/rgw/driver/motr/rgw_sal_motr.h
src/rgw/driver/posix/rgw_sal_posix.cc
src/rgw/driver/posix/rgw_sal_posix.h
src/rgw/driver/rados/rgw_bucket_sync.cc
src/rgw/driver/rados/rgw_bucket_sync.h
src/rgw/driver/rados/rgw_rados.cc
src/rgw/driver/rados/rgw_rados.h
src/rgw/driver/rados/rgw_sal_rados.cc
src/rgw/driver/rados/rgw_sal_rados.h
src/rgw/rgw_op.cc
src/rgw/rgw_sal.h
src/rgw/rgw_sal_dbstore.cc
src/rgw/rgw_sal_dbstore.h
src/rgw/rgw_sal_filter.cc
src/rgw/rgw_sal_filter.h
src/rgw/rgw_sal_store.h
src/test/rgw/rgw_multi/tests.py

Simple merge
Simple merge
index 8c72fa68fa6723247bd5377e753081beeabf0a94,8b40c645caf51011078f113508df47d8b19e4fff..39749a0d33ceb2e28b93e88e9b0ba60ff9dd4a72
@@@ -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,
Simple merge
index 233e99e8f59ed0a5088459bfa8b1b76fe36d708c,caf7c8667f71192706e7430af42e0e540ed6e126..ac1af5376f32e3834d5a3029f0475c9f87082855
@@@ -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;
Simple merge
index 22445d066672af64ed5954984459c1d1e447aa83,ac83173a00d0862cd3166991d50414aa358caac0..d2ea90b01093d84b3b61d9ae8c7be0288686d483
@@@ -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,
index d59d79a008580faa46f77b6d49c0d1b2d74d061a,dafbb6df46f4ce107ce876372947905c9a5ff260..28e35d4bb47cb280c67ba4c21e769e839bbc3dfa
@@@ -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) {
index db542833792a0c38e6021173741cf1596463c5f7,d425ecf1732f59c5d070cff107bf1ef27a0d5f34..ba578c8371c0646183f8ce8e108a172808a52156
@@@ -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;
  
Simple merge
Simple merge
index aa1e5c902b68d7eb2e8ae79a09c6e4f6824df9a0,9057bc7af4489791acdab8001fd7be20923ae257..2e8a23a6742c81e9e19545a2b3f350979c78637f
@@@ -2240,43 -2254,11 +2256,45 @@@ RadosObject::~RadosObject(
      delete rados_ctx;
  }
  
- int RadosObject::get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **pstate, optional_yield y, bool follow_olh)
 +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<rgw_bi_log_entry> 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::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 auto mtime = state.mtime + std::chrono::nanoseconds(1);
++  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 = 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)
index a056b08a832bc0463c32a5de8c0c10581867d113,f880319b56e0e288989cf5615fcf00eb30ca7e4b..ff36c2edfd8e92dd1ec730641c28db43787947d8
@@@ -585,10 -591,10 +591,13 @@@ class RadosObject : public StoreObject 
        StoreObject::set_compressed();
      }
  
-     virtual int get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **state, optional_yield y, bool follow_olh = true) override;
++
 +    virtual bool is_sync_completed(const DoutPrefixProvider* dpp,
 +      const ceph::real_time& obj_mtime) override;
 -    virtual int set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y) 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, 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;
index 6045a9a60f3cd9cad1e91bc88b472ac08f848346,c2a8d05bb061af91bac9bbcc1b6225f89f67663e..c0821e78c5baa76080b8259167385585a8cda1f5
@@@ -909,27 -910,6 +911,27 @@@ void rgw_build_iam_environment(rgw::sal
    }
  }
  
-         setattrs[RGW_ATTR_OBJ_REPLICATION_STATUS] = bl;
 +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] = 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 
      }
    }
  
-   if (policy_handler && policy_handler->bucket_exports_object(s->object->get_name(), *obj_tags)) {
 +  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.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);
index eab0ad13e08e5991af63f79d264fab367bb524ea,5fd20fda692ea39444e5fe11a8af26aa8cb8f86d..3eaae189a151179179c1520c7da3e727e2ff4ccc
@@@ -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. */
index b6bbcf7a0300e86b20e9fc4163fecfb51f1fb74c,8c415feddc992d50439bed92efa0d1506c8f63b0..4b27bd35f99ab24e03d02f61abc1728fd6b845dd
@@@ -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)
  
      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() {
index 516ab47393a1a72bff157f2f4e9c94b844a0c508,b542028e53ef68fd96949247c6bb2aa05627fbb0..defa5c2c50d82fef3eb1732883af4ca5a7beeea7
@@@ -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;
Simple merge
index 2e9a08ed0b55e4fcfdde75d3f2d508409a6b7f55,7d26a466efe7197f5663060ca820e5a275110a5e..6ff3004189540f89f9e520b76c4a66c23ae45871
@@@ -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,
Simple merge
index cb3f2bf8ed437a5eced19aa253c1db2acf3b1095,df9c70a47810a16ca67cb28b5248e31e41fabbe1..a392588c58e89a1fe4df2f9949ffbc179fe68573
@@@ -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()