]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: copy_obj_data() record uncompressed size for a compressed source 70006/head
authorOguzhan Ozmen <oozmen@bloomberg.net>
Tue, 7 Jul 2026 12:27:14 +0000 (12:27 +0000)
committerOguzhan Ozmen <oozmen@bloomberg.net>
Tue, 7 Jul 2026 13:00:17 +0000 (13:00 +0000)
When copying an object and a compressor/encryption processor is configured
for the destination, the bucket-index accounted_size was set from `ofs`. If
the source is compressed but the destination is not (re-)compressed (e.g.
compression is off, or rgw_compression_type=random rolled no-compression),
then `ofs` is the compressed size, not the logical size.

In multisite this diverges from the peer zone, which recomputes its own
accounted_size via fetch_remote_obj() (already corrected in #63306).
ListObjectVersions then reports different sizes per zone.

Pass along the source's logical size (astate->accounted_size, derived from the
object's own attrs and correct for plain/compressed/encrypted) into
copy_obj_data() and use it when the destination is not compressed. The
rewrite_obj() and transition_obj() callers pass 0 and keep the prior
ofs-based behaviour. This is the copy_obj analog of the fetch_remote_obj
fix in #63306.

No on-disk/encoding change; corrects newly copied objects only (existing
index entries are unaffected) and is safe across a mixed-version upgrade.

Fixes: https://tracker.ceph.com/issues/75716
Fixes: https://tracker.ceph.com/issues/75715
Signed-off-by: Oguzhan Ozmen <oozmen@bloomberg.net>
src/rgw/driver/rados/rgw_rados.cc
src/rgw/driver/rados/rgw_rados.h

index 5907e9075349508242207b701ec0491e86b47b51..b46975b38919bc4bcfd927c91906921051207c41 100644 (file)
@@ -5304,7 +5304,8 @@ int RGWRados::copy_obj(RGWObjectCtx& src_obj_ctx,
     attrs.erase(RGW_ATTR_CRYPT_PART_NUMS);
     attrs.erase(RGW_ATTR_CRYPT_PREFETCH_ALIGN);
     return copy_obj_data(dest_obj_ctx, owner, dest_bucket_info, dest_placement, read_op, obj_size - 1, dest_obj,
-                         mtime, real_time(), attrs, olh_epoch, delete_at, petag, dp_factory, dpp, y);
+                         mtime, real_time(), attrs, olh_epoch, delete_at, petag, dp_factory, dpp, y,
+                         astate->accounted_size);
   }
 
   /* This has been in for 2 years, so we can safely assume amanifest is not NULL */
@@ -5475,6 +5476,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
                rgw::sal::DataProcessorFactory *dp_factory,
                const DoutPrefixProvider *dpp,
                optional_yield y,
+               uint64_t src_accounted_size,
                bool log_op)
 {
   string tag;
@@ -5543,8 +5545,13 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
       ldpp_dout(dpp, 0) << "ERROR: failed to read compression info" << dendl;
       return ret;
     }
-    // pass original size if compressed
-    accounted_size = compressed ? cs_info.orig_size : ofs;
+    // The bucket index accounted_size must be the object's logical (uncompressed)
+    // size. When the destination is compressed we take it from the compression info.
+    // Otherwise `ofs` is the number of RAW bytes read from the source: but if the source
+    // itself is compressed, the ofs is the *compressed* size, not the logical
+    // size. So, prefer the source's known logical size.
+    accounted_size = compressed ? cs_info.orig_size
+                                : (src_accounted_size ? src_accounted_size : ofs);
   }
 
   const req_context rctx{dpp, y, nullptr};
@@ -5650,6 +5657,7 @@ int RGWRados::transition_obj(RGWObjectCtx& obj_ctx,
                       nullptr, /* dp_factory */
                       dpp,
                       y,
+                      0, /* src_accounted_size: unknown here, keep ofs-based size */
                       log_op);
   if (ret < 0) {
     return ret;
index e7ccb0175aff7a506730f811ea13fe81fddb7d90..57215ec812df83b2546bfe430177aa66a84399f8 100644 (file)
@@ -1273,6 +1273,7 @@ public:
                rgw::sal::DataProcessorFactory *dp_factory,
                const DoutPrefixProvider *dpp,
                optional_yield y,
+               uint64_t src_accounted_size = 0,
                bool log_op = true);
 
   int transition_obj(RGWObjectCtx& obj_ctx,