From 20d3577f92b597b79ce9fc330a93a96601432142 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 20 Jan 2025 11:22:52 +0100 Subject: [PATCH] GH-45304: [C++][S3] Workaround compatibility issue between AWS SDK and Minio --- cpp/src/arrow/filesystem/s3fs.cc | 28 +++++++++++++++------------ cpp/src/arrow/filesystem/s3fs_test.cc | 1 - 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/cpp/src/arrow/filesystem/s3fs.cc b/cpp/src/arrow/filesystem/s3fs.cc index b6a928ecdd344..1d44d8ebc04e6 100644 --- a/cpp/src/arrow/filesystem/s3fs.cc +++ b/cpp/src/arrow/filesystem/s3fs.cc @@ -1983,27 +1983,32 @@ class ObjectOutputStream final : public io::OutputStream { const void* data, int64_t nbytes, std::shared_ptr owned_buffer = nullptr) { req.SetBucket(ToAwsString(path_.bucket)); req.SetKey(ToAwsString(path_.key)); - req.SetBody(std::make_shared(data, nbytes)); req.SetContentLength(nbytes); RETURN_NOT_OK(SetSSECustomerKey(&req, sse_customer_key_)); if (!background_writes_) { - req.SetBody(std::make_shared(data, nbytes)); + // (GH-45304: avoid setting a body stream if length is 0) + if (nbytes != 0) { + req.SetBody(std::make_shared(data, nbytes)); + } ARROW_ASSIGN_OR_RAISE(auto outcome, TriggerUploadRequest(req, holder_)); RETURN_NOT_OK(sync_result_callback(req, upload_state_, part_number_, outcome)); } else { - // If the data isn't owned, make an immutable copy for the lifetime of the closure - if (owned_buffer == nullptr) { - ARROW_ASSIGN_OR_RAISE(owned_buffer, AllocateBuffer(nbytes, io_context_.pool())); - memcpy(owned_buffer->mutable_data(), data, nbytes); - } else { - DCHECK_EQ(data, owned_buffer->data()); - DCHECK_EQ(nbytes, owned_buffer->size()); + // (GH-45304: avoid setting a body stream if length is 0) + if (nbytes != 0) { + // If the data isn't owned, make an immutable copy for the lifetime of the closure + if (owned_buffer == nullptr) { + ARROW_ASSIGN_OR_RAISE(owned_buffer, AllocateBuffer(nbytes, io_context_.pool())); + memcpy(owned_buffer->mutable_data(), data, nbytes); + } else { + DCHECK_EQ(data, owned_buffer->data()); + DCHECK_EQ(nbytes, owned_buffer->size()); + } + req.SetBody(std::make_shared(owned_buffer->data(), + owned_buffer->size())); } - req.SetBody( - std::make_shared(owned_buffer->data(), owned_buffer->size())); { std::unique_lock lock(upload_state_->mutex); @@ -2345,7 +2350,6 @@ class S3FileSystem::Impl : public std::enable_shared_from_this("")); return OutcomeToStatus( std::forward_as_tuple("When creating key '", key, "' in bucket '", bucket, "': "), "PutObject", client_lock.Move()->PutObject(req)); diff --git a/cpp/src/arrow/filesystem/s3fs_test.cc b/cpp/src/arrow/filesystem/s3fs_test.cc index 3082ecb7843b8..370f3b26852aa 100644 --- a/cpp/src/arrow/filesystem/s3fs_test.cc +++ b/cpp/src/arrow/filesystem/s3fs_test.cc @@ -526,7 +526,6 @@ class TestS3FS : public S3TestMixin { Aws::S3::Model::PutObjectRequest req; req.SetBucket(ToAwsString("bucket")); req.SetKey(ToAwsString("emptydir/")); - req.SetBody(std::make_shared("")); RETURN_NOT_OK(OutcomeToStatus("PutObject", client_->PutObject(req))); // NOTE: no need to create intermediate "directories" somedir/ and // somedir/subdir/