]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
[RGW][Multisite] Add multisite verifier support for MPU objects
authorPrasad Krishnan <prasad.krishnan@flipkart.com>
Fri, 6 Mar 2020 05:08:05 +0000 (05:08 +0000)
committerNathan Cutler <ncutler@suse.com>
Thu, 28 Jan 2021 15:45:32 +0000 (16:45 +0100)
The Etag for MPU objects is calculated using a method different from how
it is done for atomic objects. This patch makes use of the RGWObjManifest
to determine the parts in the source cluster and re-computes the ETag in
a similar fashion at the destination cluster during multisite sync for
verification.

Signed-off-by: Prasad Krishnan <prasad.krishnan@flipkart.com>
(cherry picked from commit 6f085bb9cb6cffddcf2eed18a7295a3dd59f755f)

src/rgw/rgw_obj_manifest.h
src/rgw/rgw_rados.cc

index 4b3e66e9fd649bcbb6754f8a175d7c72f626eb64..227eaff50f200078c733b97e0e623f21464b429b 100644 (file)
@@ -466,6 +466,10 @@ public:
       return location;
     }
 
+    int get_cur_part_id() const {
+      return cur_part_id;
+    }
+
     /* start of current stripe */
     uint64_t get_stripe_ofs() {
       if (manifest->explicit_objs) {
index 9784971219107073b5307a69a3c8184312f3e731..b46c2e24eb207f15551baf56a6bbd7f681a9be34 100644 (file)
@@ -3261,7 +3261,7 @@ class RGWRadosPutObj : public RGWHTTPStreamRWRequest::ReceiveCB
   rgw::putobj::ObjectProcessor *processor;
   void (*progress_cb)(off_t, void *);
   void *progress_data;
-  bufferlist extra_data_bl, full_obj;
+  bufferlist extra_data_bl, full_obj, manifest_bl;
   uint64_t extra_data_left{0};
   bool need_to_process_attrs{true};
   uint64_t data_len{0};
@@ -3298,7 +3298,8 @@ public:
       JSONDecoder::decode_json("attrs", src_attrs, &jp);
 
       src_attrs.erase(RGW_ATTR_COMPRESSION);
-      src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout
+      /* We need the manifest to recompute the ETag for verification */
+      manifest_bl = src_attrs[RGW_ATTR_MANIFEST];
 
       // filter out olh attributes
       auto iter = src_attrs.lower_bound(RGW_ATTR_OLH_PREFIX);
@@ -3396,15 +3397,84 @@ public:
   }
 
   string get_calculated_etag() {
-    MD5 hash;
-    unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
+    MD5 hash, mpu_etag_hash;
+    unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE], mpu_m[CEPH_CRYPTO_MD5_DIGESTSIZE];
     char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
+    char calc_md5_part[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
+    char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16];
+    RGWObjManifest manifest;
+    std::string calculated_etag_part;
+    int prev_part_id = 1, cur_part_id = 1;
+
+    auto miter = manifest_bl.cbegin();
+    try {
+      decode(manifest, miter);
+    } catch (buffer::error& err) {
+      ldout(cct, 0) << "ERROR: couldn't decode manifest" << dendl;
+      return std::string();
+    }
+    RGWObjManifest::obj_iterator mi;
+
+    RGWObjManifestRule rule;
+    bool found = manifest.get_rule(0, &rule);
+    if (!found) {
+      lderr(cct) << "ERROR: manifest->get_rule() could not find rule" << dendl;
+      return std::string();
+    }
+
+    /*
+     * Check if the object was created using multipart upload. This check is
+     * required as MPU objects' ETag != MD5sum.
+     */
+    if (rule.part_size == 0) {
+      hash.Update((const unsigned char *)full_obj.c_str(), data_len);
+      hash.Final(m);
+      buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
+      calculated_etag = calc_md5;
+      ldout(cct, 20) << "Single part object: " << manifest.get_obj().get_oid() <<
+             " size:" << manifest.get_obj_size() << " etag:" <<
+             calculated_etag << dendl;
+      return calculated_etag;
+    }
+
+    for (mi = manifest.obj_begin(); mi != manifest.obj_end(); ++mi) {
+      bufferlist obj_stripe;
+
+      cur_part_id = mi.get_cur_part_id();
+      if (cur_part_id != prev_part_id) {
+        hash.Final(m);
+        mpu_etag_hash.Update((const unsigned char *)m, sizeof(m));
+       hash.Restart();
+        buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5_part);
+        calculated_etag_part = calc_md5_part;
+        ldout(cct, 20) << "Part " << prev_part_id << " etag: " <<
+              calculated_etag_part << dendl;
+       prev_part_id = cur_part_id;
+      }
+      full_obj.splice(0, mi.get_stripe_size(), &obj_stripe);
+      hash.Update((const unsigned char *)obj_stripe.c_str(), mi.get_stripe_size());
+    }
 
-    hash.Update((const unsigned char *)full_obj.c_str(), data_len);
     hash.Final(m);
-    buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
-    calculated_etag = calc_md5;
+    mpu_etag_hash.Update((const unsigned char *)m, sizeof(m));
+
+    buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5_part);
+    calculated_etag_part = calc_md5_part;
+    ldout(cct, 20) << "Part " << prev_part_id << " etag: " << calculated_etag_part << dendl;
+
+    /* Refer RGWCompleteMultipart::execute() for ETag calculation for MPU object */
+    mpu_etag_hash.Final(mpu_m);
+    buf_to_hex(mpu_m, CEPH_CRYPTO_MD5_DIGESTSIZE, final_etag_str);
+    snprintf(&final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2],
+            sizeof(final_etag_str) - CEPH_CRYPTO_MD5_DIGESTSIZE * 2,
+             "-%lld", (long long)(mi.get_cur_part_id() - 1));
+    calculated_etag = final_etag_str;
+
+    ldout(cct, 20) << "MPU calculated ETag:"<< calculated_etag << " Object:" <<
+          manifest.get_obj().get_oid() <<
+          " size:" << manifest.get_obj_size() << dendl;
     return calculated_etag;
+
   }
 };