]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/lc: Fix issues with non-current objects with instance empty 63031/head
authorSoumya Koduri <skoduri@redhat.com>
Mon, 7 Oct 2024 11:24:02 +0000 (16:54 +0530)
committerSoumya Koduri <skoduri@redhat.com>
Tue, 29 Apr 2025 06:22:56 +0000 (11:52 +0530)
When the bucket versioning is enabled, old plain object entry is converted
to versioned by updating its instance as "null" in its raw head/old object.
However its instance remains empty in the bi list entry. Same is the case for
the entries created after versioning is suspended and re-enabled.

So to access such objects which are non-current, we need to set rgw_obj_key.instance as
1) "null" to read the actual raw obj and
2) empty while accessing/updating their bi entry.

Fixes: https://tracker.ceph.com/issues/71119
Signed-off-by: Soumya Koduri <skoduri@redhat.com>
(cherry picked from commit 60149ade9d5193a78fa5fd83e28919f8f36fe05d)

src/rgw/driver/rados/rgw_lc_tier.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/rgw_lc.cc

index 1b7de42b3757871d1b72e8aea362ec7ad8586b91..0509b32bf89b2bd214dd7c2923b796456bc8ceee 100644 (file)
@@ -76,8 +76,9 @@ WRITE_CLASS_ENCODER(rgw_lc_multipart_upload_info)
 
 static inline string get_key_instance(const rgw_obj_key& key)
 {
-  if (!key.instance.empty() &&
-      !key.have_null_instance()) {
+  // if non-current entry, add versionID to the
+  // transitioned object name including "null".
+  if (!key.instance.empty()) {
     return "-" + key.instance;
   }
   return "";
index 31918add52dfb88c8338ef5b633b508d896fbbe7..9272f9649e808e1e46021c0c2115add15e6a736b 100644 (file)
@@ -4752,7 +4752,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
 
 int RGWRados::transition_obj(RGWObjectCtx& obj_ctx,
                              RGWBucketInfo& bucket_info,
-                             const rgw_obj& obj,
+                             rgw_obj obj,
                              const rgw_placement_rule& placement_rule,
                              const real_time& mtime,
                              uint64_t olh_epoch,
@@ -4783,6 +4783,11 @@ int RGWRados::transition_obj(RGWObjectCtx& obj_ctx,
     return -ECANCELED;
   }
 
+  // bi expects empty instance for the entries created when bucket versioning
+  // is not enabled or suspended.
+  if (obj.key.instance == "null") {
+    obj.key.instance.clear();
+  }
   attrs.erase(RGW_ATTR_ID_TAG);
   attrs.erase(RGW_ATTR_TAIL_TAG);
 
index e04208604274bd9e0398bf34098804211c60e4c3..e89fa1330b4badb7b382d197aaecabc584b1fba8 100644 (file)
@@ -1207,7 +1207,7 @@ public:
 
   int transition_obj(RGWObjectCtx& obj_ctx,
                      RGWBucketInfo& bucket_info,
-                     const rgw_obj& obj,
+                     rgw_obj obj,
                      const rgw_placement_rule& placement_rule,
                      const real_time& mtime,
                      uint64_t olh_epoch,
index 647d311e6ef2ecd886a4b81ed005b301997f8f86..2f81a5bca6952323d1b6625b5178a71ff2bd8ac2 100644 (file)
@@ -2069,6 +2069,13 @@ int RadosObject::write_cloud_tier(const DoutPrefixProvider* dpp,
 {
   rgw::sal::RadosPlacementTier* rtier = static_cast<rgw::sal::RadosPlacementTier*>(tier);
   map<string, bufferlist> attrs = get_attrs();
+  rgw_obj_key& obj_key = get_key();
+  // bi expects empty instance for the entries created when bucket versioning
+  // is not enabled or suspended.
+  if (obj_key.instance == "null") {
+      obj_key.instance.clear();
+  }
+
   RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj());
   RGWRados::Object::Write obj_op(&op_target);
 
index cdc17109735524b016a13e4e06abd96a4f94585c..1fa14db3f6db1eaff12045e750b6ad0c4f9a25e2 100644 (file)
@@ -499,6 +499,14 @@ struct lc_op_ctx {
       rctx(env.driver), dpp(dpp), wq(wq)
     {
       obj = bucket->get_object(o.key);
+      /* once bucket versioning is enabled, the non-current entries with
+       * instance empty should have instance set to "null" to be able
+       * to correctly read its olh version entry.
+       */
+      if (o.key.instance.empty() && bucket->versioned() && !o.is_current()) {
+        rgw_obj_key& obj_key = obj->get_key();
+        obj_key.instance = "null";
+      }
     }
 
   bool next_has_same_name(const std::string& key_name) {
@@ -1303,9 +1311,9 @@ public:
   int delete_tier_obj(lc_op_ctx& oc) {
     int ret = 0;
 
-    /* If bucket is versioned, create delete_marker for current version
+    /* If bucket has versioning enabled, create delete_marker for current version
      */
-    if (oc.bucket->versioned() && oc.o.is_current() && !oc.o.is_delete_marker()) {
+    if (oc.bucket->versioning_enabled() && oc.o.is_current() && !oc.o.is_delete_marker()) {
       ret = remove_expired_obj(oc.dpp, oc, false, rgw::notify::ObjectExpiration);
       ldpp_dout(oc.dpp, 20) << "delete_tier_obj Object(key:" << oc.o.key << ") current & not delete_marker" << " versioned_epoch:  " << oc.o.versioned_epoch << "flags: " << oc.o.flags << dendl;
     } else {
@@ -1316,9 +1324,10 @@ public:
   }
 
   int transition_obj_to_cloud(lc_op_ctx& oc) {
-    /* If CurrentVersion object, remove it & create delete marker */
+    /* If CurrentVersion object & bucket has versioning enabled, remove it &
+     * create delete marker */
     bool delete_object = (!oc.tier->retain_head_object() ||
-                     (oc.o.is_current() && oc.bucket->versioned()));
+                     (oc.o.is_current() && oc.bucket->versioning_enabled()));
 
     int ret = oc.obj->transition_to_cloud(oc.bucket, oc.tier.get(), oc.o,
                                          oc.env.worker->get_cloud_targets(), oc.cct,