]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/cloud-restore: Handle versioned objects
authorSoumya Koduri <skoduri@redhat.com>
Fri, 3 Jan 2025 08:20:48 +0000 (13:50 +0530)
committerSoumya Koduri <skoduri@redhat.com>
Fri, 14 Mar 2025 11:08:23 +0000 (16:38 +0530)
While restoring non-current object versions, ensure they remain non-current.

Read `olh_epoch` from the restored object's metadata into a new attr
"RGW_ATTR_RESTORE_VERSIONED_EPOCH". This attr/olh_epoch is used while
updating bi entry and also to reset HEAD object post expiry of temporary
copies.

Signed-off-by: Soumya Koduri <skoduri@redhat.com>
16 files changed:
src/rgw/driver/daos/rgw_sal_daos.cc
src/rgw/driver/daos/rgw_sal_daos.h
src/rgw/driver/posix/rgw_sal_posix.cc
src/rgw/driver/posix/rgw_sal_posix.h
src/rgw/driver/rados/rgw_lc_tier.cc
src/rgw/driver/rados/rgw_putobj_processor.cc
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_common.h
src/rgw/rgw_op.cc
src/rgw/rgw_sal.h
src/rgw/rgw_sal_filter.cc
src/rgw/rgw_sal_filter.h
src/rgw/rgw_sal_store.h

index c27cf19703c38a5074586841447700e17f597413..808a0a5f993a277768c19a4764a3269d0a31148a 100644 (file)
@@ -1032,7 +1032,6 @@ int DaosObject::restore_obj_from_cloud(Bucket* bucket,
           rgw_bucket_dir_entry& o,
          CephContext* cct,
           RGWObjTier& tier_config,
-          real_time& mtime,
           uint64_t olh_epoch,
           std::optional<uint64_t> days,
           const DoutPrefixProvider* dpp, 
index 84aaf5a60f332bdf3db6bb7521b65ee8a9d4eee2..fac26b548811c7c8d86cb5c7953440f34b082564 100644 (file)
@@ -655,7 +655,6 @@ class DaosObject : public StoreObject {
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,
index 985f7244a1a519ecbfed20cb1792e5f03bbc98cd..69e9d36321d804ff6b7577ae925eb38fd2940a5d 100644 (file)
@@ -3059,7 +3059,6 @@ int POSIXObject::restore_obj_from_cloud(Bucket* bucket,
           rgw_bucket_dir_entry& o,
          CephContext* cct,
           RGWObjTier& tier_config,
-          real_time& mtime,
           uint64_t olh_epoch,
           std::optional<uint64_t> days,
           const DoutPrefixProvider* dpp, 
index 06943814574662a221784d4e52eb6ca31cc11294..45968193566a1932d8f3a043684dd857f7ba3433 100644 (file)
@@ -697,7 +697,6 @@ public:
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,
index 4954b943b5ab1f55041b0e23d34d1f7f116ae5a9..1b576a31849527b82ff538230736d9b02bedee48 100644 (file)
@@ -319,8 +319,15 @@ int rgw_cloud_tier_get_object(RGWLCCloudTierCtx& tier_ctx, bool head,
 
     const auto aiter = generic_attrs_map.find(name);
     if (aiter != std::end(generic_attrs_map)) {
-      ldpp_dout(tier_ctx.dpp, 20) << __func__ << " Received attrs aiter->first = " << aiter->first << ", aiter->second = " << aiter->second << ret << dendl;
-     attrs[aiter->second] = bl;
+      attrs[aiter->second] = bl;
+    } else {
+      std::string s1 = boost::algorithm::to_lower_copy(header.first);
+      std::replace(s1.begin(), s1.end(), '_', '-');
+
+      // copy versioned epoch
+      if (s1 == "x-amz-meta-rgwx-versioned-epoch") {
+        attrs[s1] = bl;
+      }
     }
     
     if (header.first == "CONTENT_LENGTH") {
index 2c9d6fac7a6031f72fd8905568afc29dcdac7513..d0f5a45d9bd2e76ac5d07c6af1b33e10e914b94a 100644 (file)
@@ -35,9 +35,11 @@ namespace rgw::putobj {
  * cloudtier config info read from the attrs.
  * Since these attrs are used internally for only replication, do not store them
  * in the head object.
+ * 
+ * Update versioned epoch incase the object is being restored.
  */
-void read_cloudtier_info_from_attrs(rgw::sal::Attrs& attrs, RGWObjCategory& category,
-                          RGWObjManifest& manifest) {
+int read_cloudtier_info_from_attrs(rgw::sal::Attrs& attrs, RGWObjCategory& category,
+                          std::optional<uint64_t>& olh_epoch, RGWObjManifest& manifest) {
   auto attr_iter = attrs.find(RGW_ATTR_CLOUD_TIER_TYPE);
   if (attr_iter != attrs.end()) {
     auto i = attr_iter->second;
@@ -58,11 +60,37 @@ void read_cloudtier_info_from_attrs(rgw::sal::Attrs& attrs, RGWObjCategory& cate
           manifest.set_tier_config(tier_config);
           attrs.erase(config_iter);
         } catch (buffer::error& err) {
+          return -EIO;
         }
       }
     }
     attrs.erase(attr_iter);
   }
+  attr_iter = attrs.find(RGW_ATTR_RESTORE_VERSIONED_EPOCH);
+  if (attr_iter != attrs.end()) {
+    try {
+      using ceph::decode;
+      uint64_t v_epoch = 0;
+      decode(v_epoch, attr_iter->second);
+      olh_epoch = v_epoch;
+      /*
+       * Keep this attr only for Temp restored copies as its needed while
+       * resetting head object post expiry.
+       */
+      auto r_iter = attrs.find(RGW_ATTR_RESTORE_TYPE);
+      if (r_iter != attrs.end()) {
+        rgw::sal::RGWRestoreType restore_type;
+        using ceph::decode;
+        decode(restore_type, r_iter->second);
+        if (restore_type != rgw::sal::RGWRestoreType::Temporary) {
+               attrs.erase(attr_iter);
+        }
+      }
+    } catch (buffer::error& err) {
+      return -EIO;
+    }
+  }
+  return 0;
 }
 
 int HeadObjectProcessor::process(bufferlist&& data, uint64_t logical_offset)
@@ -390,7 +418,11 @@ int AtomicObjectProcessor::complete(
   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 = read_cloudtier_info_from_attrs(attrs, obj_op.meta.category, obj_op.meta.olh_epoch, manifest);
+
+  if (r < 0) { // incase of any errors while decoding tier_config/restore attrs
+    return r;
+  }
 
   r = obj_op.write_meta(actual_size, accounted_size, attrs, rctx,
                         writer.get_trace(), flags & rgw::sal::FLAG_LOG_OP);
index 9dff93ca06f10ec711a1b7500629da24fe39dd38..4cfd3f3590495cbde093c5c77923eaf20fc5abe0 100644 (file)
@@ -5248,7 +5248,6 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
                              const rgw_obj& dest_obj,
                              rgw_placement_rule& dest_placement,
                              RGWObjTier& tier_config,
-                             real_time& mtime,
                              uint64_t olh_epoch,
                              std::optional<uint64_t> days,
                              const DoutPrefixProvider *dpp,
@@ -5258,6 +5257,7 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
   //XXX: read below from attrs .. check transition_obj()
   ACLOwner owner;
   rgw::sal::Attrs attrs;
+  real_time mtime;
   const req_context rctx{dpp, y, nullptr};
   int ret = 0;
   bufferlist t, t_tier;
@@ -5299,6 +5299,19 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
                       return 0;
                     });
 
+  // fetch mtime of the object and other attrs of the object
+  // to check for restore_status
+  RGWRados::Object op_target(this, dest_bucket_info, obj_ctx, dest_obj);
+  RGWRados::Object::Read read_op(&op_target);
+  read_op.params.lastmod = &mtime;
+  read_op.params.attrs = &attrs;
+
+  ret = read_op.prepare(y, dpp);
+  if (ret < 0) {
+    ldpp_dout(dpp, 0) << "Restoring object(" << dest_obj << ") , read_op failed ret=" << ret << dendl;
+    return ret;
+  }
+
   uint64_t accounted_size = 0;
   string etag;
   real_time set_mtime;
@@ -5331,6 +5344,24 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
     return ret;
   }
 
+  {
+    if (!olh_epoch) {
+      const auto aiter = attrs.find("x-amz-meta-rgwx-versioned-epoch");
+      if (aiter != std::end(attrs)) {
+        std::optional<uint64_t> olh_ep = ceph::parse<uint64_t>(rgw_bl_str(aiter->second));
+        if (olh_ep) {
+          olh_epoch = *olh_ep;
+        }
+        attrs.erase(aiter);
+      }
+    }
+    if (olh_epoch) { // needed for only versioned objects
+      bufferlist bl;
+      encode(olh_epoch, bl);
+      attrs[RGW_ATTR_RESTORE_VERSIONED_EPOCH] = std::move(bl);
+    }
+  }
+
   {
     bufferlist bl;
     encode(rgw::sal::RGWRestoreStatus::CloudRestored, bl);
@@ -5409,6 +5440,9 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
     attrs[RGW_ATTR_STORAGE_CLASS] = std::move(bl);
   }
 
+  for (auto& iter: attrs) {
+    ldpp_dout(dpp, 30) << "Restore attrs set: " << iter.first << dendl;
+  }
   // XXX: handle COMPLETE_RETRY like in fetch_remote_obj
   bool canceled = false;
   rgw_zone_set zone_set{};
@@ -5419,7 +5453,6 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
     return ret;
   }
 
-  // XXX: handle olh_epoch for versioned objects like in fetch_remote_obj
   return ret; 
 }
 
index e7272c5b375fad02b42f2ab12a74cc77f60cddc5..ea8b6916e837ed85e69bec1e48a6e97d1d0e8e6d 100644 (file)
@@ -1255,7 +1255,6 @@ int restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
                              const rgw_obj& dest_obj,
                              rgw_placement_rule& dest_placement,
                              RGWObjTier& tier_config,
-                             real_time& mtime,
                              uint64_t olh_epoch,
                              std::optional<uint64_t> days,
                              const DoutPrefixProvider *dpp,
index 864f599887aa3c128b35717a316ae2cfee56967e..387a3febaeb5ea5eee275858a7717b7a005e958e 100644 (file)
@@ -2899,7 +2899,6 @@ int RadosObject::restore_obj_from_cloud(Bucket* bucket,
                                  rgw_bucket_dir_entry& o,
                                  CephContext* cct,
                                   RGWObjTier& tier_config,
-                                  real_time& mtime,
                                   uint64_t olh_epoch,
                                   std::optional<uint64_t> days,
                                   const DoutPrefixProvider* dpp, 
@@ -2918,16 +2917,6 @@ int RadosObject::restore_obj_from_cloud(Bucket* bucket,
   int ret = 0;
   string src_storage_class = o.meta.storage_class; // or take src_placement also as input
 
-  // fetch mtime of the object
-  std::unique_ptr<rgw::sal::Object::ReadOp> read_op(get_read_op());
-  read_op->params.lastmod = &mtime;
-
-  ret = read_op->prepare(y, dpp);
-  if (ret < 0) {
-    ldpp_dout(dpp, 0) << "Restoring object(" << o.key << "): read_op failed ret=" << ret << dendl;
-    return ret;
-  }
-
   if (bucket_name.empty()) {
     bucket_name = "rgwx-" + zonegroup.get_name() + "-" + tier->get_storage_class() +
                     "-cloud-bucket";
@@ -2968,7 +2957,7 @@ int RadosObject::restore_obj_from_cloud(Bucket* bucket,
   ret = store->getRados()->restore_obj_from_cloud(tier_ctx, *rados_ctx,
                                 bucket->get_info(), get_obj(), placement_rule,
                                 tier_config,
-                                mtime, olh_epoch, days, dpp, y, flags & FLAG_LOG_OP);
+                                olh_epoch, days, dpp, y, flags & FLAG_LOG_OP);
 
   if (ret < 0) { //failed to restore
     ldpp_dout(dpp, 0) << "Restoring object(" << o.key << ") from the cloud endpoint(" << endpoint << ") failed, ret=" << ret << dendl;
@@ -3140,7 +3129,7 @@ int RadosObject::handle_obj_expiry(const DoutPrefixProvider* dpp, optional_yield
           RGWObjManifest *pmanifest;
           pmanifest = &m;
 
-               Object* head_obj = (Object*)this;
+          Object* head_obj = (Object*)this;
           RGWObjTier tier_config;
           m.get_tier_config(&tier_config);
        
@@ -3151,12 +3140,21 @@ int RadosObject::handle_obj_expiry(const DoutPrefixProvider* dpp, optional_yield
           pmanifest->set_obj_size(0);
           obj_op.meta.manifest = pmanifest;
 
+          auto v_iter = attrs.find(RGW_ATTR_RESTORE_VERSIONED_EPOCH);
+          if (v_iter != attrs.end()) {
+            uint64_t versioned_epoch;
+            using ceph::decode;
+            decode(versioned_epoch, v_iter->second);
+            obj_op.meta.olh_epoch = versioned_epoch;
+          }
+
           // erase restore attrs
           attrs.erase(RGW_ATTR_RESTORE_STATUS);
           attrs.erase(RGW_ATTR_RESTORE_TYPE);
           attrs.erase(RGW_ATTR_RESTORE_TIME);
           attrs.erase(RGW_ATTR_RESTORE_EXPIRY_DATE);
           attrs.erase(RGW_ATTR_CLOUDTIER_STORAGE_CLASS);
+         attrs.erase(RGW_ATTR_RESTORE_VERSIONED_EPOCH);
 
           bufferlist bl;
           bl.append(tier_config.name);
index 23e469d4c6cc69ff92111c4340a1d3b0d9de579f..5072e1e5753ae614afdf3d4c15b952d112aff398 100644 (file)
@@ -639,7 +639,6 @@ class RadosObject : public StoreObject {
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,
index 73f4923b84036bb22318b1e791eea4c2efe3c4fe..ab261d173fa2756993d1af014dbfec5f39fbc621 100644 (file)
@@ -126,6 +126,7 @@ using ceph::crypto::MD5;
 #define RGW_ATTR_RESTORE_TIME   RGW_ATTR_PREFIX "restored-at"
 #define RGW_ATTR_RESTORE_EXPIRY_DATE   RGW_ATTR_PREFIX "restore-expiry-date"
 #define RGW_ATTR_TRANSITION_TIME RGW_ATTR_PREFIX "transition-at"
+#define RGW_ATTR_RESTORE_VERSIONED_EPOCH RGW_ATTR_PREFIX "restore-versioned-epoch"
 
 #define RGW_ATTR_TEMPURL_KEY1   RGW_ATTR_META_PREFIX "temp-url-key"
 #define RGW_ATTR_TEMPURL_KEY2   RGW_ATTR_META_PREFIX "temp-url-key-2"
index e6771948e1e57747d3982c98017fd4c3d7583966..a96eb3ef6024fdcfd976a73f939a6daae619b509 100644 (file)
@@ -1029,19 +1029,23 @@ int handle_cloudtier_obj(req_state* s, const DoutPrefixProvider *dpp, rgw::sal::
       // fill in the entry. XXX: Maybe we can avoid it by passing only necessary params
       rgw_bucket_dir_entry ent;
       ent.key.name = s->object->get_key().name;
+      ent.key.instance = s->object->get_key().instance;
       ent.meta.accounted_size = ent.meta.size = s->obj_size;
       ent.meta.etag = "" ;
-      ceph::real_time mtime = s->object->get_mtime();
       uint64_t epoch = 0;
       op_ret = get_system_versioning_params(s, &epoch, NULL);
+      if (!ent.key.instance.empty()) { // non-current versioned object
+        ent.flags |= rgw_bucket_dir_entry::FLAG_VER;
+      }
       ldpp_dout(dpp, 20) << "getting versioning params tier placement handle cloud tier" << op_ret << dendl;
       if (op_ret < 0) {
         ldpp_dout(dpp, 20) << "failed to get versioning params, op_ret = " << op_ret << dendl;
         s->err.message = "failed to restore object";
         return op_ret;
       }
-      op_ret = s->object->restore_obj_from_cloud(pbucket, tier.get(), target_placement, ent, s->cct, tier_config,
-                                                   mtime, epoch, days, dpp, y, s->bucket->get_info().flags);
+      op_ret = s->object->restore_obj_from_cloud(pbucket, tier.get(), target_placement, ent,
+                                                 s->cct, tier_config, epoch,
+                                                 days, dpp, y, s->bucket->get_info().flags);
       if (op_ret < 0) {
         ldpp_dout(dpp, 0) << "object " << ent.key.name << " fetching failed" << op_ret << dendl;
         s->err.message = "failed to restore object";
index 91d6aa6f77be55896f93892debc6abf6911ab1aa..8af0d863342566fa939865e9d8d6d68b2486fe1e 100644 (file)
@@ -1257,7 +1257,6 @@ class Object {
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,
index d20af0dca608e0591bcc05ce8d0d122662402b52..70fb306c7b3a4cc8434c9a47f7c7a46df5b5ae69 100644 (file)
@@ -1139,7 +1139,6 @@ int FilterObject::restore_obj_from_cloud(Bucket* bucket,
                          rgw_bucket_dir_entry& o,
                          CephContext* cct,
                          RGWObjTier& tier_config,
-                         real_time& mtime,
                          uint64_t olh_epoch,
                          std::optional<uint64_t> days,
                          const DoutPrefixProvider* dpp, 
@@ -1147,7 +1146,7 @@ int FilterObject::restore_obj_from_cloud(Bucket* bucket,
                          uint32_t flags)
 {
   return next->restore_obj_from_cloud(nextBucket(bucket), nextPlacementTier(tier),
-           placement_rule, o, cct, tier_config, mtime, olh_epoch, days, dpp, y, flags);
+           placement_rule, o, cct, tier_config, olh_epoch, days, dpp, y, flags);
 }
 
 bool FilterObject::placement_rules_match(rgw_placement_rule& r1, rgw_placement_rule& r2)
index c9e7cc21f14b78ee7d1bf24dcb7ac337be7d9b50..38f7b3413c848c98012596601aff493cf7fc85b3 100644 (file)
@@ -830,7 +830,6 @@ public:
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,
index 99b905649977246497c19f0f07d00bcb2f6d19f5..a44f3bc189d7658e7b84793d306b03ea459f8fdd 100644 (file)
@@ -378,7 +378,6 @@ class StoreObject : public Object {
                           rgw_bucket_dir_entry& o,
                           CephContext* cct,
                           RGWObjTier& tier_config,
-                          real_time& mtime,
                           uint64_t olh_epoch,
                           std::optional<uint64_t> days,
                           const DoutPrefixProvider* dpp,