From 9aeefefbbce58b6f16fdb9c0835390a43836673b Mon Sep 17 00:00:00 2001 From: JinmingHu Date: Fri, 1 Jul 2022 15:19:27 +0800 Subject: [PATCH] Blob batch improvement (#3790) --- .../inc/azure/storage/blobs/blob_batch.hpp | 105 ++++++-- .../inc/azure/storage/blobs/blob_client.hpp | 3 +- .../storage/blobs/blob_container_client.hpp | 8 +- .../storage/blobs/blob_service_client.hpp | 8 +- .../azure/storage/blobs/deferred_response.hpp | 8 +- .../azure-storage-blobs/src/blob_batch.cpp | 233 ++++++++++++------ .../src/blob_container_client.cpp | 11 +- .../src/blob_service_client.cpp | 11 +- .../test/ut/blob_batch_client_test.cpp | 23 +- 9 files changed, 269 insertions(+), 141 deletions(-) diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch.hpp index 09a24d642..3655cab17 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch.hpp @@ -3,14 +3,9 @@ #pragma once -#include -#include #include #include -#include - -#include -#include +#include #include "azure/storage/blobs/blob_client.hpp" #include "azure/storage/blobs/blob_container_client.hpp" @@ -20,7 +15,8 @@ namespace Azure { namespace Storage { namespace Blobs { namespace _detail { - extern const Core::Context::Key s_batchKey; + extern const Core::Context::Key s_serviceBatchKey; + extern const Core::Context::Key s_containerBatchKey; class StringBodyStream final : public Core::IO::BodyStream { public: @@ -55,7 +51,7 @@ namespace Azure { namespace Storage { namespace Blobs { BatchSubrequestType Type; }; - struct BlobBatchAccessHelper; + class BlobBatchAccessHelper; std::shared_ptr ConstructBatchRequestPolicy( const std::vector>& @@ -72,16 +68,15 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief A batch object allows you to batch multiple operations in a single request via - * #Azure::Storage::Blobs::BlobServiceClient::SubmitBatch or - * #Azure::Storage::Blobs::BlobContainerClient::SubmitBatch. + * #Azure::Storage::Blobs::BlobServiceClient::SubmitBatch. */ - class BlobBatch final { + class BlobServiceBatch final { public: /** * @brief Adds a delete subrequest into batch object. * * @param blobContainerName Container name of the blob to delete. - * @param blobName Blob name of the blob to delete. + * @param blobName Name of the blob to delete. * @param options Optional parameters to execute the delete operation. * @return A deferred response which can produce a Response after batch object * is submitted. @@ -99,7 +94,7 @@ namespace Azure { namespace Storage { namespace Blobs { * @return A deferred response which can produce a Response after batch object * is submitted. */ - DeferredResponse DeleteBlob( + DeferredResponse DeleteBlobUrl( const std::string& blobUrl, const DeleteBlobOptions& options = DeleteBlobOptions()); @@ -107,7 +102,7 @@ namespace Azure { namespace Storage { namespace Blobs { * @brief Adds a change tier subrequest into batch object. * * @param blobContainerName Container name of the blob to delete. - * @param blobName Blob name of the blob to delete. + * @param blobName Name of the blob to delete. * @param accessTier Indicates the tier to be set on the blob. * @param options Optional parameters to execute the delete operation. * @return A deferred response which can produce a Response after batch @@ -128,27 +123,95 @@ namespace Azure { namespace Storage { namespace Blobs { * @return A deferred response which can produce a Response after batch * object is submitted. */ - DeferredResponse SetBlobAccessTier( + DeferredResponse SetBlobAccessTierUrl( const std::string& blobUrl, Models::AccessTier accessTier, const SetBlobAccessTierOptions& options = SetBlobAccessTierOptions()); private: - explicit BlobBatch(BlobServiceClient blobServiceClient); - explicit BlobBatch(BlobContainerClient blobContainerClient); + explicit BlobServiceBatch(BlobServiceClient blobServiceClient); BlobClient GetBlobClientForSubrequest(Core::Url url) const; private: - Core::Url m_url; - Nullable m_blobServiceClient; - Nullable m_blobContainerClient; + BlobServiceClient m_blobServiceClient; std::vector> m_subrequests; friend class BlobServiceClient; + friend class _detail::BlobBatchAccessHelper; + }; + + /** + * @brief A batch object allows you to batch multiple operations in a single request via + * #Azure::Storage::Blobs::BlobContainerClient::SubmitBatch. + */ + class BlobContainerBatch final { + public: + /** + * @brief Adds a delete subrequest into batch object. + * + * @param blobName Name of the blob to delete. + * @param options Optional parameters to execute the delete operation. + * @return A deferred response which can produce a Response after batch object + * is submitted. + */ + DeferredResponse DeleteBlob( + const std::string& blobName, + const DeleteBlobOptions& options = DeleteBlobOptions()); + + /** + * @brief Adds a delete subrequest into batch object. + * + * @param blobUrl Url of the blob to delete. + * @param options Optional parameters to execute the delete operation. + * @return A deferred response which can produce a Response after batch object + * is submitted. + */ + DeferredResponse DeleteBlobUrl( + const std::string& blobUrl, + const DeleteBlobOptions& options = DeleteBlobOptions()); + + /** + * @brief Adds a change tier subrequest into batch object. + * + * @param blobName Name of the blob to delete. + * @param accessTier Indicates the tier to be set on the blob. + * @param options Optional parameters to execute the delete operation. + * @return A deferred response which can produce a Response after batch + * object is submitted. + */ + DeferredResponse SetBlobAccessTier( + const std::string& blobName, + Models::AccessTier accessTier, + const SetBlobAccessTierOptions& options = SetBlobAccessTierOptions()); + + /** + * @brief Adds a change tier subrequest into batch object. + * + * @param blobUrl Url of the blob to delete. + * @param accessTier Indicates the tier to be set on the blob. + * @param options Optional parameters to execute the delete operation. + * @return A deferred response which can produce a Response after batch + * object is submitted. + */ + DeferredResponse SetBlobAccessTierUrl( + const std::string& blobUrl, + Models::AccessTier accessTier, + const SetBlobAccessTierOptions& options = SetBlobAccessTierOptions()); + + private: + explicit BlobContainerBatch(BlobContainerClient blobContainerClient); + + BlobClient GetBlobClientForSubrequest(Core::Url url) const; + + private: + BlobContainerClient m_blobContainerClient; + + std::vector> m_subrequests; + friend class BlobContainerClient; - friend struct _detail::BlobBatchAccessHelper; + friend class _detail::BlobBatchAccessHelper; }; }}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp index b3034f3f7..a704d034e 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp @@ -431,6 +431,7 @@ namespace Azure { namespace Storage { namespace Blobs { friend class Files::DataLake::DataLakeDirectoryClient; friend class Files::DataLake::DataLakeFileClient; friend class BlobLeaseClient; - friend class BlobBatch; + friend class BlobServiceBatch; + friend class BlobContainerBatch; }; }}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_container_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_container_client.hpp index acd4e485d..53ff7006d 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_container_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_container_client.hpp @@ -12,7 +12,7 @@ namespace Azure { namespace Storage { namespace Blobs { class BlobLeaseClient; - class BlobBatch; + class BlobContainerBatch; /** * The BlobContainerClient allows you to manipulate Azure Storage containers and their @@ -291,7 +291,7 @@ namespace Azure { namespace Storage { namespace Blobs { * * @return A new batch object. */ - BlobBatch CreateBatch(); + BlobContainerBatch CreateBatch(); /** * @brief Submits a batch of subrequests. @@ -304,7 +304,7 @@ namespace Azure { namespace Storage { namespace Blobs { * (parent request). */ Response SubmitBatch( - const BlobBatch& batch, + const BlobContainerBatch& batch, const SubmitBlobBatchOptions& options = SubmitBlobBatchOptions(), const Core::Context& context = Core::Context()) const; @@ -319,7 +319,7 @@ namespace Azure { namespace Storage { namespace Blobs { friend class BlobServiceClient; friend class BlobLeaseClient; - friend class BlobBatch; + friend class BlobContainerBatch; }; }}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_service_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_service_client.hpp index dc677d31f..2ea2d7cc4 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_service_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_service_client.hpp @@ -13,7 +13,7 @@ namespace Azure { namespace Storage { namespace Blobs { - class BlobBatch; + class BlobServiceBatch; /** * The BlobServiceClient allows you to manipulate Azure Storage service resources and blob @@ -251,7 +251,7 @@ namespace Azure { namespace Storage { namespace Blobs { * * @return A new batch object. */ - BlobBatch CreateBatch(); + BlobServiceBatch CreateBatch(); /** * @brief Submits a batch of subrequests. @@ -264,7 +264,7 @@ namespace Azure { namespace Storage { namespace Blobs { * (parent request). */ Response SubmitBatch( - const BlobBatch& batch, + const BlobServiceBatch& batch, const SubmitBlobBatchOptions& options = SubmitBlobBatchOptions(), const Core::Context& context = Core::Context()) const; @@ -277,6 +277,6 @@ namespace Azure { namespace Storage { namespace Blobs { std::shared_ptr m_batchRequestPipeline; std::shared_ptr m_batchSubrequestPipeline; - friend class BlobBatch; + friend class BlobServiceBatch; }; }}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/deferred_response.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/deferred_response.hpp index ba6e4f63a..bcce2f37e 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/deferred_response.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/deferred_response.hpp @@ -9,8 +9,9 @@ namespace Azure { namespace Storage { namespace Blobs { - class BlobBatch; - } + class BlobServiceBatch; + class BlobContainerBatch; + } // namespace Blobs /** * @brief Base type for a deferred response. */ @@ -37,6 +38,7 @@ namespace Azure { namespace Storage { private: std::function()> m_func; - friend class Blobs::BlobBatch; + friend class Blobs::BlobServiceBatch; + friend class Blobs::BlobContainerBatch; }; }} // namespace Azure::Storage diff --git a/sdk/storage/azure-storage-blobs/src/blob_batch.cpp b/sdk/storage/azure-storage-blobs/src/blob_batch.cpp index 3bcee5b8c..40dcbc76c 100644 --- a/sdk/storage/azure-storage-blobs/src/blob_batch.cpp +++ b/sdk/storage/azure-storage-blobs/src/blob_batch.cpp @@ -7,8 +7,7 @@ #include #include #include -#include -#include +#include #include #include @@ -22,19 +21,24 @@ namespace Azure { namespace Storage { namespace Blobs { - const Core::Context::Key _detail::s_batchKey; + const Core::Context::Key _detail::s_serviceBatchKey; + const Core::Context::Key _detail::s_containerBatchKey; namespace _detail { - struct BlobBatchAccessHelper - { - explicit BlobBatchAccessHelper(const BlobBatch& batch) : m_batch(&batch) {} + class BlobBatchAccessHelper final { + public: + explicit BlobBatchAccessHelper(const BlobServiceBatch& batch) : m_serviceBatch(&batch) {} + explicit BlobBatchAccessHelper(const BlobContainerBatch& batch) : m_containerBatch(&batch) {} const std::vector>& Subrequests() const { - return m_batch->m_subrequests; + return m_serviceBatch ? m_serviceBatch->m_subrequests : m_containerBatch->m_subrequests; } - const BlobBatch* m_batch; + + private: + const BlobServiceBatch* m_serviceBatch = nullptr; + const BlobContainerBatch* m_containerBatch = nullptr; }; } // namespace _detail @@ -263,21 +267,29 @@ namespace Azure { namespace Storage { namespace Blobs { struct DeleteBlobSubrequest final : public _detail::BatchSubrequest { - DeleteBlobSubrequest() : BatchSubrequest(_detail::BatchSubrequestType::DeleteBlob) {} + DeleteBlobSubrequest(Blobs::BlobClient blobClient, DeleteBlobOptions options) + : BatchSubrequest(_detail::BatchSubrequestType::DeleteBlob), + Client(std::move(blobClient)), Options(std::move(options)) + { + } - Nullable Client; + Blobs::BlobClient Client; DeleteBlobOptions Options; std::promise>> Promise; }; struct SetBlobAccessTierSubrequest final : public _detail::BatchSubrequest { - SetBlobAccessTierSubrequest() - : BatchSubrequest(_detail::BatchSubrequestType::SetBlobAccessTier) + SetBlobAccessTierSubrequest( + Blobs::BlobClient blobClient, + Models::AccessTier tier, + SetBlobAccessTierOptions options) + : BatchSubrequest(_detail::BatchSubrequestType::SetBlobAccessTier), + Client(std::move(blobClient)), Tier(std::move(tier)), Options(std::move(options)) { } - Nullable Client; + Blobs::BlobClient Client; Models::AccessTier Tier; SetBlobAccessTierOptions Options; std::promise>> Promise; @@ -298,17 +310,32 @@ namespace Azure { namespace Storage { namespace Blobs { std::string requestBody; - const BlobBatch* batch = nullptr; - context.TryGetValue(_detail::s_batchKey, batch); + std::unique_ptr<_detail::BlobBatchAccessHelper> batchAccessHelper; + { + const BlobServiceBatch* batch = nullptr; + context.TryGetValue(_detail::s_serviceBatchKey, batch); + if (batch) + { + batchAccessHelper = std::make_unique<_detail::BlobBatchAccessHelper>(*batch); + } + } + { + const BlobContainerBatch* batch = nullptr; + context.TryGetValue(_detail::s_containerBatchKey, batch); + if (batch) + { + batchAccessHelper = std::make_unique<_detail::BlobBatchAccessHelper>(*batch); + } + } - for (const auto& subrequestPtr : _detail::BlobBatchAccessHelper(*batch).Subrequests()) + for (const auto& subrequestPtr : batchAccessHelper->Subrequests()) { if (subrequestPtr->Type == _detail::BatchSubrequestType::DeleteBlob) { auto& subrequest = *static_cast(subrequestPtr.get()); requestBody += getBatchBoundary(); std::string subrequestText; - subrequest.Client.Value().Delete( + subrequest.Client.Delete( subrequest.Options, Core::Context().WithValue(s_subrequestKey, &subrequestText)); requestBody += subrequestText; } @@ -318,7 +345,7 @@ namespace Azure { namespace Storage { namespace Blobs { requestBody += getBatchBoundary(); std::string subrequestText; - subrequest.Client.Value().SetAccessTier( + subrequest.Client.SetAccessTier( subrequest.Tier, subrequest.Options, Core::Context().WithValue(s_subrequestKey, &subrequestText)); @@ -391,18 +418,33 @@ namespace Azure { namespace Storage { namespace Blobs { } } - const BlobBatch* batch = nullptr; - context.TryGetValue(_detail::s_batchKey, batch); + std::unique_ptr<_detail::BlobBatchAccessHelper> batchAccessHelper; + { + const BlobServiceBatch* batch = nullptr; + context.TryGetValue(_detail::s_serviceBatchKey, batch); + if (batch) + { + batchAccessHelper = std::make_unique<_detail::BlobBatchAccessHelper>(*batch); + } + } + { + const BlobContainerBatch* batch = nullptr; + context.TryGetValue(_detail::s_containerBatchKey, batch); + if (batch) + { + batchAccessHelper = std::make_unique<_detail::BlobBatchAccessHelper>(*batch); + } + } size_t subresponseCounter = 0; - for (const auto& subrequestPtr : _detail::BlobBatchAccessHelper(*batch).Subrequests()) + for (const auto& subrequestPtr : batchAccessHelper->Subrequests()) { if (subrequestPtr->Type == _detail::BatchSubrequestType::DeleteBlob) { auto& subrequest = *static_cast(subrequestPtr.get()); try { - auto response = subrequest.Client.Value().Delete( + auto response = subrequest.Client.Delete( subrequest.Options, Core::Context().WithValue(s_subresponseKey, &subresponses[subresponseCounter++])); subrequest.Promise.set_value(std::move(response)); @@ -417,7 +459,7 @@ namespace Azure { namespace Storage { namespace Blobs { auto& subrequest = *static_cast(subrequestPtr.get()); try { - auto response = subrequest.Client.Value().SetAccessTier( + auto response = subrequest.Client.SetAccessTier( subrequest.Tier, subrequest.Options, Core::Context().WithValue(s_subresponseKey, &subresponses[subresponseCounter++])); @@ -518,108 +560,141 @@ namespace Azure { namespace Storage { namespace Blobs { } } // namespace _detail - BlobBatch::BlobBatch(BlobServiceClient blobServiceClient) + BlobServiceBatch::BlobServiceBatch(BlobServiceClient blobServiceClient) : m_blobServiceClient(std::move(blobServiceClient)) { - m_url = m_blobServiceClient.Value().m_serviceUrl; } - BlobBatch::BlobBatch(BlobContainerClient blobContainerClient) + BlobClient BlobServiceBatch::GetBlobClientForSubrequest(Core::Url url) const + { + auto blobClient = m_blobServiceClient.GetBlobContainerClient("$").GetBlobClient("$"); + blobClient.m_blobUrl = std::move(url); + blobClient.m_pipeline = m_blobServiceClient.m_batchSubrequestPipeline; + return blobClient; + } + + DeferredResponse BlobServiceBatch::DeleteBlob( + const std::string& blobContainerName, + const std::string& blobName, + const DeleteBlobOptions& options) + { + auto blobUrl = m_blobServiceClient.m_serviceUrl; + blobUrl.AppendPath(_internal::UrlEncodePath(blobContainerName)); + blobUrl.AppendPath(_internal::UrlEncodePath(blobName)); + auto op = std::make_shared( + GetBlobClientForSubrequest(std::move(blobUrl)), options); + DeferredResponse deferredResponse( + CreateDeferredResponseFunc(op->Promise)); + m_subrequests.push_back(std::move(op)); + return deferredResponse; + } + + DeferredResponse BlobServiceBatch::DeleteBlobUrl( + const std::string& blobUrl, + const DeleteBlobOptions& options) + { + auto op = std::make_shared( + GetBlobClientForSubrequest(Core::Url(blobUrl)), options); + DeferredResponse deferredResponse( + CreateDeferredResponseFunc(op->Promise)); + m_subrequests.push_back(std::move(op)); + return deferredResponse; + } + + DeferredResponse BlobServiceBatch::SetBlobAccessTier( + const std::string& blobContainerName, + const std::string& blobName, + Models::AccessTier accessTier, + const SetBlobAccessTierOptions& options) + { + auto blobUrl = m_blobServiceClient.m_serviceUrl; + blobUrl.AppendPath(_internal::UrlEncodePath(blobContainerName)); + blobUrl.AppendPath(_internal::UrlEncodePath(blobName)); + auto op = std::make_shared( + GetBlobClientForSubrequest(std::move(blobUrl)), std::move(accessTier), options); + DeferredResponse deferredResponse( + CreateDeferredResponseFunc(op->Promise)); + m_subrequests.push_back(std::move(op)); + return deferredResponse; + } + + DeferredResponse BlobServiceBatch::SetBlobAccessTierUrl( + const std::string& blobUrl, + Models::AccessTier accessTier, + const SetBlobAccessTierOptions& options) + { + auto op = std::make_shared( + GetBlobClientForSubrequest(Core::Url(blobUrl)), std::move(accessTier), options); + DeferredResponse deferredResponse( + CreateDeferredResponseFunc(op->Promise)); + m_subrequests.push_back(std::move(op)); + return deferredResponse; + } + + BlobContainerBatch::BlobContainerBatch(BlobContainerClient blobContainerClient) : m_blobContainerClient(std::move(blobContainerClient)) { - auto serviceUrl = m_blobContainerClient.Value().m_blobContainerUrl; - auto path = serviceUrl.GetPath(); - if (!path.empty() && path.back() == '/') - { - path.pop_back(); - } - auto slash_pos = path.rfind('/'); - path = path.substr(0, slash_pos == std::string::npos ? 0 : (slash_pos + 1)); - serviceUrl.SetPath(path); - m_url = std::move(serviceUrl); } - BlobClient BlobBatch::GetBlobClientForSubrequest(Core::Url url) const + BlobClient BlobContainerBatch::GetBlobClientForSubrequest(Core::Url url) const { - if (m_blobServiceClient.HasValue()) - { - auto blobClient = m_blobServiceClient.Value().GetBlobContainerClient("$").GetBlobClient("$"); - blobClient.m_blobUrl = std::move(url); - blobClient.m_pipeline = m_blobServiceClient.Value().m_batchSubrequestPipeline; - return blobClient; - } - else if (m_blobContainerClient.HasValue()) - { - auto blobClient = m_blobContainerClient->GetBlobClient("$"); - blobClient.m_blobUrl = std::move(url); - blobClient.m_pipeline = m_blobContainerClient.Value().m_batchSubrequestPipeline; - return blobClient; - } - AZURE_UNREACHABLE_CODE(); + auto blobClient = m_blobContainerClient.GetBlobClient("$"); + blobClient.m_blobUrl = std::move(url); + blobClient.m_pipeline = m_blobContainerClient.m_batchSubrequestPipeline; + return blobClient; } - DeferredResponse BlobBatch::DeleteBlob( - const std::string& blobContainerName, + DeferredResponse BlobContainerBatch::DeleteBlob( const std::string& blobName, const DeleteBlobOptions& options) { - auto blobUrl = m_url; - blobUrl.AppendPath(blobContainerName); - blobUrl.AppendPath(blobName); - auto op = std::make_shared(); - op->Client = GetBlobClientForSubrequest(std::move(blobUrl)); - op->Options = options; + auto blobUrl = m_blobContainerClient.m_blobContainerUrl; + blobUrl.AppendPath(_internal::UrlEncodePath(blobName)); + auto op = std::make_shared( + GetBlobClientForSubrequest(std::move(blobUrl)), options); DeferredResponse deferredResponse( CreateDeferredResponseFunc(op->Promise)); m_subrequests.push_back(std::move(op)); return deferredResponse; } - DeferredResponse BlobBatch::DeleteBlob( + DeferredResponse BlobContainerBatch::DeleteBlobUrl( const std::string& blobUrl, const DeleteBlobOptions& options) { - auto op = std::make_shared(); - op->Client = GetBlobClientForSubrequest(Core::Url(blobUrl)); - op->Options = options; + auto op = std::make_shared( + GetBlobClientForSubrequest(Core::Url(blobUrl)), options); DeferredResponse deferredResponse( CreateDeferredResponseFunc(op->Promise)); m_subrequests.push_back(std::move(op)); return deferredResponse; } - DeferredResponse BlobBatch::SetBlobAccessTier( - const std::string& blobContainerName, + DeferredResponse BlobContainerBatch::SetBlobAccessTier( const std::string& blobName, Models::AccessTier accessTier, const SetBlobAccessTierOptions& options) { - auto blobUrl = m_url; - blobUrl.AppendPath(blobContainerName); - blobUrl.AppendPath(blobName); - auto op = std::make_shared(); - op->Client = GetBlobClientForSubrequest(std::move(blobUrl)); - op->Tier = accessTier; - op->Options = options; + auto blobUrl = m_blobContainerClient.m_blobContainerUrl; + blobUrl.AppendPath(_internal::UrlEncodePath(blobName)); + auto op = std::make_shared( + GetBlobClientForSubrequest(std::move(blobUrl)), std::move(accessTier), options); DeferredResponse deferredResponse( CreateDeferredResponseFunc(op->Promise)); m_subrequests.push_back(std::move(op)); return deferredResponse; } - DeferredResponse BlobBatch::SetBlobAccessTier( + DeferredResponse BlobContainerBatch::SetBlobAccessTierUrl( const std::string& blobUrl, Models::AccessTier accessTier, const SetBlobAccessTierOptions& options) { - auto op = std::make_shared(); - op->Client = GetBlobClientForSubrequest(Core::Url(blobUrl)); - op->Tier = accessTier; - op->Options = options; + auto op = std::make_shared( + GetBlobClientForSubrequest(Core::Url(blobUrl)), std::move(accessTier), options); DeferredResponse deferredResponse( CreateDeferredResponseFunc(op->Promise)); m_subrequests.push_back(std::move(op)); return deferredResponse; } - }}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/src/blob_container_client.cpp b/sdk/storage/azure-storage-blobs/src/blob_container_client.cpp index d1b4bfac8..7b02522be 100644 --- a/sdk/storage/azure-storage-blobs/src/blob_container_client.cpp +++ b/sdk/storage/azure-storage-blobs/src/blob_container_client.cpp @@ -467,20 +467,15 @@ namespace Azure { namespace Storage { namespace Blobs { std::move(blockBlobClient), std::move(response.RawResponse)); } - BlobBatch BlobContainerClient::CreateBatch() { return BlobBatch(*this); } + BlobContainerBatch BlobContainerClient::CreateBatch() { return BlobContainerBatch(*this); } Response BlobContainerClient::SubmitBatch( - const BlobBatch& batch, + const BlobContainerBatch& batch, const SubmitBlobBatchOptions& options, const Core::Context& context) const { (void)options; - if (!batch.m_blobContainerClient.HasValue()) - { - throw std::runtime_error("Batch is not container-scoped."); - } - _detail::BlobContainerClient::SubmitBlobContainerBatchOptions protocolLayerOptions; _detail::StringBodyStream bodyStream(std::string{}); auto response = _detail::BlobContainerClient::SubmitBatch( @@ -488,7 +483,7 @@ namespace Azure { namespace Storage { namespace Blobs { m_blobContainerUrl, bodyStream, protocolLayerOptions, - context.WithValue(_detail::s_batchKey, &batch)); + context.WithValue(_detail::s_containerBatchKey, &batch)); return Azure::Response( Models::SubmitBlobBatchResult(), std::move(response.RawResponse)); } diff --git a/sdk/storage/azure-storage-blobs/src/blob_service_client.cpp b/sdk/storage/azure-storage-blobs/src/blob_service_client.cpp index d4b580061..518712335 100644 --- a/sdk/storage/azure-storage-blobs/src/blob_service_client.cpp +++ b/sdk/storage/azure-storage-blobs/src/blob_service_client.cpp @@ -310,20 +310,15 @@ namespace Azure { namespace Storage { namespace Blobs { std::move(blobContainerClient), std::move(response.RawResponse)); } - BlobBatch BlobServiceClient::CreateBatch() { return BlobBatch(*this); } + BlobServiceBatch BlobServiceClient::CreateBatch() { return BlobServiceBatch(*this); } Response BlobServiceClient::SubmitBatch( - const BlobBatch& batch, + const BlobServiceBatch& batch, const SubmitBlobBatchOptions& options, const Core::Context& context) const { (void)options; - if (!batch.m_blobServiceClient.HasValue()) - { - throw std::runtime_error("Batch is container-scoped."); - } - _detail::ServiceClient::SubmitServiceBatchOptions protocolLayerOptions; _detail::StringBodyStream bodyStream(std::string{}); auto response = _detail::ServiceClient::SubmitBatch( @@ -331,7 +326,7 @@ namespace Azure { namespace Storage { namespace Blobs { m_serviceUrl, bodyStream, protocolLayerOptions, - context.WithValue(_detail::s_batchKey, &batch)); + context.WithValue(_detail::s_serviceBatchKey, &batch)); return Azure::Response( Models::SubmitBlobBatchResult(), std::move(response.RawResponse)); } diff --git a/sdk/storage/azure-storage-blobs/test/ut/blob_batch_client_test.cpp b/sdk/storage/azure-storage-blobs/test/ut/blob_batch_client_test.cpp index afd561ac4..85953ecb7 100644 --- a/sdk/storage/azure-storage-blobs/test/ut/blob_batch_client_test.cpp +++ b/sdk/storage/azure-storage-blobs/test/ut/blob_batch_client_test.cpp @@ -56,11 +56,11 @@ namespace Azure { namespace Storage { namespace Test { blob3Client.CreateSnapshot(); auto batch = serviceClient.CreateBatch(); - auto delete1Response = batch.DeleteBlob(blob1Client.GetUrl()); + auto delete1Response = batch.DeleteBlobUrl(blob1Client.GetUrl()); auto delete2Response = batch.DeleteBlob(containerName1, blob2Name); Blobs::DeleteBlobOptions deleteOptions; deleteOptions.DeleteSnapshots = Blobs::Models::DeleteSnapshotsOption::OnlySnapshots; - auto delete3Response = batch.DeleteBlob(blob3Client.GetUrl(), deleteOptions); + auto delete3Response = batch.DeleteBlobUrl(blob3Client.GetUrl(), deleteOptions); auto submitBatchResponse = serviceClient.SubmitBatch(batch); EXPECT_TRUE(delete1Response.GetResponse().Value.Deleted); @@ -104,10 +104,8 @@ namespace Azure { namespace Storage { namespace Test { blob2Client.UploadFrom(nullptr, 0); auto batch = containerClient.CreateBatch(); - auto setTier1Response - = batch.SetBlobAccessTier(containerName, blob1Name, Blobs::Models::AccessTier::Cool); - auto setTier2Response - = batch.SetBlobAccessTier(blob2Client.GetUrl(), Blobs::Models::AccessTier::Archive); + auto setTier1Response = batch.SetBlobAccessTier(blob1Name, Blobs::Models::AccessTier::Cool); + auto setTier2Response = batch.SetBlobAccessTier(blob2Name, Blobs::Models::AccessTier::Archive); auto submitBatchResponse = containerClient.SubmitBatch(batch); EXPECT_NO_THROW(setTier1Response.GetResponse()); @@ -141,7 +139,7 @@ namespace Azure { namespace Storage { namespace Test { blobClient.Create(); auto batch = containerClient.CreateBatch(); - auto delete1Response = batch.DeleteBlob(blobClient.GetUrl()); + auto delete1Response = batch.DeleteBlobUrl(blobClient.GetUrl()); auto submitBatchResponse = containerClient.SubmitBatch(batch); EXPECT_TRUE(delete1Response.GetResponse().Value.Deleted); @@ -185,9 +183,8 @@ namespace Azure { namespace Storage { namespace Test { // Partial failure { - auto r1 = batch.SetBlobAccessTier(blobClient.GetUrl(), Blobs::Models::AccessTier::Hot); - auto r2 = batch.SetBlobAccessTier( - containerName, "BlobNameNotExists", Blobs::Models::AccessTier::Hot); + auto r1 = batch.SetBlobAccessTierUrl(blobClient.GetUrl(), Blobs::Models::AccessTier::Hot); + auto r2 = batch.SetBlobAccessTier("BlobNameNotExists", Blobs::Models::AccessTier::Hot); EXPECT_NO_THROW(containerClient.SubmitBatch(batch)); EXPECT_NO_THROW(r1.GetResponse()); EXPECT_THROW(r2.GetResponse(), StorageException); @@ -195,8 +192,8 @@ namespace Azure { namespace Storage { namespace Test { // Mixed operations auto batch2 = containerClient.CreateBatch(); - batch2.SetBlobAccessTier(blobClient.GetUrl(), Blobs::Models::AccessTier::Cool); - batch2.DeleteBlob(blobClient.GetUrl()); + batch2.SetBlobAccessTierUrl(blobClient.GetUrl(), Blobs::Models::AccessTier::Cool); + batch2.DeleteBlobUrl(blobClient.GetUrl()); try { @@ -239,7 +236,7 @@ namespace Azure { namespace Storage { namespace Test { auto containerSasClient = Blobs::BlobContainerClient( serviceClient.GetBlobContainerClient(containerName).GetUrl() + containerExpiredSasToken); auto batch3 = containerSasClient.CreateBatch(); - batch3.DeleteBlob(blobClient.GetUrl() + containerSasToken); + batch3.DeleteBlobUrl(blobClient.GetUrl() + containerSasToken); try { containerSasClient.SubmitBatch(batch3);