mirror of
https://github.com/ceph/ceph
synced 2025-01-01 08:32:24 +00:00
rgw: return OK on consecutive complete-multipart reqs
Fixes: https://tracker.ceph.com/issues/50141 Signed-off-by: Mark Kogan <mkogan@redhat.com> fixup! rgw: return OK on consecutive complete-multipart reqs
This commit is contained in:
parent
af19bc2a4c
commit
324c377849
@ -5956,6 +5956,11 @@ void RGWCompleteMultipart::execute(optional_yield y)
|
||||
op_ret = serializer->try_lock(dur, y);
|
||||
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;
|
||||
@ -6139,6 +6144,44 @@ void RGWCompleteMultipart::execute(optional_yield y)
|
||||
}
|
||||
}
|
||||
|
||||
bool RGWCompleteMultipart::check_previously_completed(const DoutPrefixProvider* dpp, const RGWMultiCompleteUpload* parts)
|
||||
{
|
||||
// re-calculate the etag from the parts and compare to the existing object
|
||||
s->object->set_bucket(s->bucket.get());
|
||||
int ret = s->object->get_obj_attrs(s->obj_ctx, s->yield, this);
|
||||
if (ret < 0) {
|
||||
ldpp_dout(dpp, 0) << __func__ << "() ERROR: get_obj_attrs() returned ret=" << ret << dendl;
|
||||
return false;
|
||||
}
|
||||
rgw::sal::Attrs sattrs = s->object->get_attrs();
|
||||
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 */
|
||||
|
@ -1815,6 +1815,7 @@ public:
|
||||
int verify_permission(optional_yield y) override;
|
||||
void pre_exec() override;
|
||||
void execute(optional_yield y) override;
|
||||
bool check_previously_completed(const DoutPrefixProvider* dpp, const RGWMultiCompleteUpload* parts);
|
||||
void complete() override;
|
||||
|
||||
virtual int get_params(optional_yield y) = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user