diff --git a/include/cloud/aws.hpp b/include/cloud/aws.hpp index 2b68a4e..4d7b159 100644 --- a/include/cloud/aws.hpp +++ b/include/cloud/aws.hpp @@ -117,7 +117,11 @@ class AWS : public Provider { return putRequestGeneric(filePath, object, 0, ""); } // Builds the http request for deleting an objects - [[nodiscard]] std::unique_ptr> deleteRequest(const std::string& filePath) const override; + [[nodiscard]] std::unique_ptr> deleteRequest(const std::string& filePath) const override { + return deleteRequestGeneric(filePath, ""); + } + /// Builds the http request for deleting objects + [[nodiscard]] std::unique_ptr> deleteRequestGeneric(const std::string& filePath, const std::string_view uploadId) const override; /// Builds the http request for creating multipart put objects [[nodiscard]] std::unique_ptr> createMultiPartRequest(const std::string& filePath) const override; /// Builds the http request for completing multipart put objects diff --git a/include/cloud/gcp.hpp b/include/cloud/gcp.hpp index f9b062a..d7c237d 100644 --- a/include/cloud/gcp.hpp +++ b/include/cloud/gcp.hpp @@ -84,8 +84,12 @@ class GCP : public Provider { [[nodiscard]] std::unique_ptr> putRequest(const std::string& filePath, const std::string_view object) const override { return putRequestGeneric(filePath, object, 0, ""); } - // Builds the http request for deleting an objects - [[nodiscard]] std::unique_ptr> deleteRequest(const std::string& filePath) const override; + // Builds the http request for deleting an objects + [[nodiscard]] std::unique_ptr> deleteRequest(const std::string& filePath) const override { + return deleteRequestGeneric(filePath, ""); + } + /// Builds the http request for deleting objects + [[nodiscard]] std::unique_ptr> deleteRequestGeneric(const std::string& filePath, const std::string_view uploadId) const override; /// Builds the http request for creating multipart put objects [[nodiscard]] std::unique_ptr> createMultiPartRequest(const std::string& filePath) const override; /// Builds the http request for completing multipart put objects diff --git a/include/cloud/provider.hpp b/include/cloud/provider.hpp index bbad8a7..a4e3683 100644 --- a/include/cloud/provider.hpp +++ b/include/cloud/provider.hpp @@ -85,6 +85,8 @@ class Provider { [[nodiscard]] virtual uint64_t multipartUploadSize() const { return 0; } /// Builds the http request for putting multipart objects without the object data itself [[nodiscard]] virtual std::unique_ptr> putRequestGeneric(const std::string& /*filePath*/, const std::string_view /*object*/, uint16_t /*part*/, const std::string_view /*uploadId*/) const; + /// Builds the http request for deleting multipart aborted objects + [[nodiscard]] virtual std::unique_ptr> deleteRequestGeneric(const std::string& /*filePath*/, const std::string_view /*uploadId*/) const; /// Builds the http request for creating multipart put objects [[nodiscard]] virtual std::unique_ptr> createMultiPartRequest(const std::string& /*filePath*/) const; /// Builds the http request for completing multipart put objects diff --git a/include/network/transaction.hpp b/include/network/transaction.hpp index 8ee1082..9ad6e47 100644 --- a/include/network/transaction.hpp +++ b/include/network/transaction.hpp @@ -44,6 +44,7 @@ class Transaction { Default = 0, Sending = 1, Validating = 2, + Aborted = 1u << 7 }; /// The uploadId std::string uploadId; @@ -166,22 +167,26 @@ class Transaction { _completedMultiparts++; return; } - _multipartUploads[position].uploadId = _provider->getUploadId(result.getResult()); auto offset = 0ull; for (auto i = 1ull; i <= parts; i++) { auto finishMultipart = [position, remotePath, traceId, i, parts, this](network::MessageResult& result) { - // TODO: requires abort handling - if (!result.success()) - return; - - _multipartUploads[position].eTags[i - 1] = _provider->getETag(std::string_view(reinterpret_cast(result.getData()), result.getOffset())); + if (!result.success()) [[unlikely]] { + _multipartUploads[position].state = MultipartUpload::State::Aborted; + } else { + _multipartUploads[position].eTags[i - 1] = _provider->getETag(std::string_view(reinterpret_cast(result.getData()), result.getOffset())); + } if (_multipartUploads[position].outstanding.fetch_sub(1) == 1) { auto finished = [this](network::MessageResult& /*result*/) { _completedMultiparts++; }; - auto originalMsg = makeCallbackMessage(std::move(finished), _provider->completeMultiPartRequest(remotePath, _multipartUploads[position].uploadId, _multipartUploads[position].eTags), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); - _multipartUploads[position].messages[parts] = std::move(originalMsg); + if (_multipartUploads[position].state != MultipartUpload::State::Aborted) [[likely]] { + auto originalMsg = makeCallbackMessage(std::move(finished), _provider->completeMultiPartRequest(remotePath, _multipartUploads[position].uploadId, _multipartUploads[position].eTags), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); + _multipartUploads[position].messages[parts] = std::move(originalMsg); + } else { + auto originalMsg = makeCallbackMessage(std::move(finished), _provider->deleteRequestGeneric(remotePath, _multipartUploads[position].uploadId), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); + _multipartUploads[position].messages[parts] = std::move(originalMsg); + } _multipartUploads[position].state = MultipartUpload::State::Validating; } }; @@ -217,18 +222,23 @@ class Transaction { auto offset = 0ull; for (auto i = 1ull; i <= parts; i++) { auto finishMultipart = [&callback, position, remotePath, traceId, i, parts, this](network::MessageResult& result) { - // TODO: requires abort handling - if (!result.success()) - return; - - _multipartUploads[position].eTags[i - 1] = _provider->getETag(std::string_view(reinterpret_cast(result.getData()), result.getOffset())); + if (!result.success()) [[unlikely]] { + _multipartUploads[position].state = MultipartUpload::State::Aborted; + } else { + _multipartUploads[position].eTags[i - 1] = _provider->getETag(std::string_view(reinterpret_cast(result.getData()), result.getOffset())); + } if (_multipartUploads[position].outstanding.fetch_sub(1) == 1) { auto finished = [&callback, this](network::MessageResult& result) { _completedMultiparts++; std::forward(callback)(result); }; - auto originalMsg = makeCallbackMessage(std::move(finished), _provider->completeMultiPartRequest(remotePath, _multipartUploads[position].uploadId, _multipartUploads[position].eTags), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); - _multipartUploads[position].messages[parts] = std::move(originalMsg); + if (_multipartUploads[position].state != MultipartUpload::State::Aborted) [[likely]] { + auto originalMsg = makeCallbackMessage(std::move(finished), _provider->completeMultiPartRequest(remotePath, _multipartUploads[position].uploadId, _multipartUploads[position].eTags), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); + _multipartUploads[position].messages[parts] = std::move(originalMsg); + } else { + auto originalMsg = makeCallbackMessage(std::move(finished), _provider->deleteRequestGeneric(remotePath, _multipartUploads[position].uploadId), _provider->getAddress(), _provider->getPort(), nullptr, 0, traceId); + _multipartUploads[position].messages[parts] = std::move(originalMsg); + } _multipartUploads[position].state = MultipartUpload::State::Validating; } }; diff --git a/src/cloud/aws.cpp b/src/cloud/aws.cpp index 1e35043..b1318c1 100644 --- a/src/cloud/aws.cpp +++ b/src/cloud/aws.cpp @@ -270,7 +270,7 @@ unique_ptr> AWS::putRequestGeneric(const string& file return make_unique>(reinterpret_cast(httpHeader.data()), reinterpret_cast(httpHeader.data() + httpHeader.size())); } //--------------------------------------------------------------------------- -unique_ptr> AWS::deleteRequest(const string& filePath) const +unique_ptr> AWS::deleteRequestGeneric(const string& filePath, const string_view uploadId) const // Builds the http request for deleting an objects { if (!validKeys()) @@ -286,6 +286,11 @@ unique_ptr> AWS::deleteRequest(const string& filePath else request.path = "/" + _settings.bucket + "/" + filePath; + // Is it a multipart upload? + if (!uploadId.empty()) { + request.queries.emplace("uploadId", uploadId); + } + request.bodyData = nullptr; request.bodyLength = 0; request.headers.emplace("Host", getAddress()); diff --git a/src/cloud/gcp.cpp b/src/cloud/gcp.cpp index b6dc430..4e13376 100644 --- a/src/cloud/gcp.cpp +++ b/src/cloud/gcp.cpp @@ -139,7 +139,7 @@ unique_ptr> GCP::putRequestGeneric(const string& file return make_unique>(reinterpret_cast(httpHeader.data()), reinterpret_cast(httpHeader.data() + httpHeader.size())); } //--------------------------------------------------------------------------- -unique_ptr> GCP::deleteRequest(const string& filePath) const +unique_ptr> GCP::deleteRequestGeneric(const string& filePath, const string_view uploadId) const // Builds the http request for deleting objects { GCPSigner::Request request; @@ -149,6 +149,11 @@ unique_ptr> GCP::deleteRequest(const string& filePath request.bodyData = nullptr; request.bodyLength = 0; + // Is it a multipart upload? + if (!uploadId.empty()) { + request.queries.emplace("uploadId", uploadId); + } + auto date = testEnviornment ? fakeAMZTimestamp : buildAMZTimestamp(); request.queries.emplace("X-Goog-Date", date); request.headers.emplace("Host", getAddress()); @@ -197,7 +202,7 @@ unique_ptr> GCP::completeMultiPartRequest(const strin string content = "\n"; for (auto i = 0ull; i < etags.size(); i++) { content += "\n"; - content += to_string(i+1); + content += to_string(i + 1); content += "\n\""; content += etags[i]; content += "\"\n\n"; diff --git a/src/cloud/provider.cpp b/src/cloud/provider.cpp index f8610c2..fe14ac3 100644 --- a/src/cloud/provider.cpp +++ b/src/cloud/provider.cpp @@ -123,6 +123,12 @@ unique_ptr> Provider::putRequestGeneric(const string& return nullptr; } //--------------------------------------------------------------------------- +unique_ptr> Provider::deleteRequestGeneric(const string& /*filePath*/, const string_view /*uploadId*/) const +// Builds the http request for delete multipart objects +{ + return nullptr; +} +//--------------------------------------------------------------------------- unique_ptr> Provider::createMultiPartRequest(const string& /*filePath*/) const // Builds the http request for creating multipart put objects {