]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: return OK on consecutive complete-multipart reqs 45488/head
authorMark Kogan <mkogan@redhat.com>
Mon, 5 Apr 2021 12:49:42 +0000 (15:49 +0300)
committerCory Snyder <csnyder@iland.com>
Fri, 22 Apr 2022 08:09:09 +0000 (04:09 -0400)
Fixes: https://tracker.ceph.com/issues/50141
Signed-off-by: Mark Kogan <mkogan@redhat.com>
fixup! rgw: return OK on consecutive complete-multipart reqs

(cherry picked from commit 324c377849a5d246f689f6e7a2862f42f1504d2c)

Conflicts: src/rgw/rgw_op.h src/rgw/rgw_op.cc

Cherry-pick notes:
- Conflicts due in rgw_op.h due to execute method adjacent to change not having optional_yield arg
- Conflicts in rgw_op.cc due to lack of rgw::sal::Object encapsulation in Octopus

src/rgw/rgw_op.cc
src/rgw/rgw_op.h

index 2339dccb7fd0e092f2677cf5d8847fdf5390b548..9d0b45f76f4c716429956c89f867a5f800d80fdb 100644 (file)
@@ -6127,6 +6127,11 @@ void RGWCompleteMultipart::execute()
   op_ret = serializer.try_lock(raw_obj.oid, dur);
   if (op_ret < 0) {
     ldpp_dout(this, 0) << "failed to acquire lock" << dendl;
+    if (op_ret == -ENOENT && check_previously_completed(this, parts)) {
+      ldpp_dout(this, 1) << "NOTICE: This multipart completion is already completed" << dendl;
+      op_ret = 0;
+      return;
+    }
     op_ret = -ERR_INTERNAL_ERROR;
     s->err.message = "This multipart completion is already in progress";
     return;
@@ -6324,6 +6329,43 @@ int RGWCompleteMultipart::MPSerializer::try_lock(
   return ret;
 }
 
+bool RGWCompleteMultipart::check_previously_completed(const DoutPrefixProvider* dpp, const RGWMultiCompleteUpload* parts)
+{
+  // re-calculate the etag from the parts and compare to the existing object
+  map<string, bufferlist> sattrs;
+  int ret = get_obj_attrs(store, s, {s->bucket, s->object}, sattrs);
+  if (ret < 0) {
+    ldpp_dout(dpp, 0) << __func__ << "() ERROR: get_obj_attrs() returned ret=" << ret << dendl;
+    return false;
+  }
+  string oetag = sattrs[RGW_ATTR_ETAG].to_str();
+
+  MD5 hash;
+  for (const auto& [index, part] : parts->parts) {
+    std::string partetag = rgw_string_unquote(part);
+    char petag[CEPH_CRYPTO_MD5_DIGESTSIZE];
+    hex_to_buf(partetag.c_str(), petag, CEPH_CRYPTO_MD5_DIGESTSIZE);
+    hash.Update((const unsigned char *)petag, sizeof(petag));
+    ldpp_dout(dpp, 20) << __func__ << "() re-calculating multipart etag: part: "
+                                   << index << ", etag: " << partetag << dendl;
+  }
+
+  unsigned char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE];
+  char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16];
+  hash.Final(final_etag);
+  buf_to_hex(final_etag, 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)parts->parts.size());
+
+  if (oetag.compare(final_etag_str) != 0) {
+    ldpp_dout(dpp, 1) << __func__ << "() NOTICE: etag mismatch: object etag:"
+                                  << oetag << ", re-calculated etag:" << final_etag_str << dendl;
+    return false;
+  }
+  ldpp_dout(dpp, 5) << __func__ << "() object etag and re-calculated etag match, etag: " << oetag << dendl;
+  return true;
+}
+
 void RGWCompleteMultipart::complete()
 {
   /* release exclusive lock iff not already */
index 8074607d3fbf2d91ae734faab5638a383326771f..2eb37ebbdbc31a9863028d8d830a8cc15d0a4354 100644 (file)
@@ -1773,6 +1773,7 @@ public:
   int verify_permission() override;
   void pre_exec() override;
   void execute() override;
+  bool check_previously_completed(const DoutPrefixProvider* dpp, const RGWMultiCompleteUpload* parts);
   void complete() override;
 
   virtual int get_params() = 0;