Blob batch improvement (#3790)

This commit is contained in:
JinmingHu 2022-07-01 15:19:27 +08:00 committed by GitHub
parent e7e7db6d79
commit 9aeefefbbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 269 additions and 141 deletions

View File

@ -3,14 +3,9 @@
#pragma once
#include <cstring>
#include <future>
#include <memory>
#include <string>
#include <utility>
#include <azure/core/nullable.hpp>
#include <azure/core/url.hpp>
#include <vector>
#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<Azure::Core::Http::_internal::HttpPipeline> ConstructBatchRequestPolicy(
const std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>>&
@ -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<DeleteBlobResult> after batch object
* is submitted.
@ -99,7 +94,7 @@ namespace Azure { namespace Storage { namespace Blobs {
* @return A deferred response which can produce a Response<DeleteBlobResult> after batch object
* is submitted.
*/
DeferredResponse<Models::DeleteBlobResult> DeleteBlob(
DeferredResponse<Models::DeleteBlobResult> 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<SetBlobAccessTierResult> after batch
@ -128,27 +123,95 @@ namespace Azure { namespace Storage { namespace Blobs {
* @return A deferred response which can produce a Response<SetBlobAccessTierResult> after batch
* object is submitted.
*/
DeferredResponse<Models::SetBlobAccessTierResult> SetBlobAccessTier(
DeferredResponse<Models::SetBlobAccessTierResult> 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<BlobServiceClient> m_blobServiceClient;
Nullable<BlobContainerClient> m_blobContainerClient;
BlobServiceClient m_blobServiceClient;
std::vector<std::shared_ptr<_detail::BatchSubrequest>> 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<DeleteBlobResult> after batch object
* is submitted.
*/
DeferredResponse<Models::DeleteBlobResult> 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<DeleteBlobResult> after batch object
* is submitted.
*/
DeferredResponse<Models::DeleteBlobResult> 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<SetBlobAccessTierResult> after batch
* object is submitted.
*/
DeferredResponse<Models::SetBlobAccessTierResult> 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<SetBlobAccessTierResult> after batch
* object is submitted.
*/
DeferredResponse<Models::SetBlobAccessTierResult> 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<std::shared_ptr<_detail::BatchSubrequest>> m_subrequests;
friend class BlobContainerClient;
friend struct _detail::BlobBatchAccessHelper;
friend class _detail::BlobBatchAccessHelper;
};
}}} // namespace Azure::Storage::Blobs

View File

@ -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

View File

@ -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<Models::SubmitBlobBatchResult> 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

View File

@ -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<Models::SubmitBlobBatchResult> 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<Azure::Core::Http::_internal::HttpPipeline> m_batchRequestPipeline;
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_batchSubrequestPipeline;
friend class BlobBatch;
friend class BlobServiceBatch;
};
}}} // namespace Azure::Storage::Blobs

View File

@ -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<Response<T>()> m_func;
friend class Blobs::BlobBatch;
friend class Blobs::BlobServiceBatch;
friend class Blobs::BlobContainerBatch;
};
}} // namespace Azure::Storage

View File

@ -7,8 +7,7 @@
#include <cstring>
#include <functional>
#include <future>
#include <type_traits>
#include <vector>
#include <stdexcept>
#include <azure/core/azure_assert.hpp>
#include <azure/core/http/policies/policy.hpp>
@ -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<std::shared_ptr<BatchSubrequest>>& 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<Blobs::BlobClient> Client;
Blobs::BlobClient Client;
DeleteBlobOptions Options;
std::promise<Nullable<Response<Models::DeleteBlobResult>>> 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<Blobs::BlobClient> Client;
Blobs::BlobClient Client;
Models::AccessTier Tier;
SetBlobAccessTierOptions Options;
std::promise<Nullable<Response<Models::SetBlobAccessTierResult>>> 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<DeleteBlobSubrequest*>(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<DeleteBlobSubrequest*>(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<SetBlobAccessTierSubrequest*>(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<Models::DeleteBlobResult> 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<DeleteBlobSubrequest>(
GetBlobClientForSubrequest(std::move(blobUrl)), options);
DeferredResponse<Models::DeleteBlobResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::DeleteBlobResult> BlobServiceBatch::DeleteBlobUrl(
const std::string& blobUrl,
const DeleteBlobOptions& options)
{
auto op = std::make_shared<DeleteBlobSubrequest>(
GetBlobClientForSubrequest(Core::Url(blobUrl)), options);
DeferredResponse<Models::DeleteBlobResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::SetBlobAccessTierResult> 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<SetBlobAccessTierSubrequest>(
GetBlobClientForSubrequest(std::move(blobUrl)), std::move(accessTier), options);
DeferredResponse<Models::SetBlobAccessTierResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::SetBlobAccessTierResult> BlobServiceBatch::SetBlobAccessTierUrl(
const std::string& blobUrl,
Models::AccessTier accessTier,
const SetBlobAccessTierOptions& options)
{
auto op = std::make_shared<SetBlobAccessTierSubrequest>(
GetBlobClientForSubrequest(Core::Url(blobUrl)), std::move(accessTier), options);
DeferredResponse<Models::SetBlobAccessTierResult> 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<Models::DeleteBlobResult> BlobBatch::DeleteBlob(
const std::string& blobContainerName,
DeferredResponse<Models::DeleteBlobResult> BlobContainerBatch::DeleteBlob(
const std::string& blobName,
const DeleteBlobOptions& options)
{
auto blobUrl = m_url;
blobUrl.AppendPath(blobContainerName);
blobUrl.AppendPath(blobName);
auto op = std::make_shared<DeleteBlobSubrequest>();
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<DeleteBlobSubrequest>(
GetBlobClientForSubrequest(std::move(blobUrl)), options);
DeferredResponse<Models::DeleteBlobResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::DeleteBlobResult> BlobBatch::DeleteBlob(
DeferredResponse<Models::DeleteBlobResult> BlobContainerBatch::DeleteBlobUrl(
const std::string& blobUrl,
const DeleteBlobOptions& options)
{
auto op = std::make_shared<DeleteBlobSubrequest>();
op->Client = GetBlobClientForSubrequest(Core::Url(blobUrl));
op->Options = options;
auto op = std::make_shared<DeleteBlobSubrequest>(
GetBlobClientForSubrequest(Core::Url(blobUrl)), options);
DeferredResponse<Models::DeleteBlobResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::SetBlobAccessTierResult> BlobBatch::SetBlobAccessTier(
const std::string& blobContainerName,
DeferredResponse<Models::SetBlobAccessTierResult> 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<SetBlobAccessTierSubrequest>();
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<SetBlobAccessTierSubrequest>(
GetBlobClientForSubrequest(std::move(blobUrl)), std::move(accessTier), options);
DeferredResponse<Models::SetBlobAccessTierResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
DeferredResponse<Models::SetBlobAccessTierResult> BlobBatch::SetBlobAccessTier(
DeferredResponse<Models::SetBlobAccessTierResult> BlobContainerBatch::SetBlobAccessTierUrl(
const std::string& blobUrl,
Models::AccessTier accessTier,
const SetBlobAccessTierOptions& options)
{
auto op = std::make_shared<SetBlobAccessTierSubrequest>();
op->Client = GetBlobClientForSubrequest(Core::Url(blobUrl));
op->Tier = accessTier;
op->Options = options;
auto op = std::make_shared<SetBlobAccessTierSubrequest>(
GetBlobClientForSubrequest(Core::Url(blobUrl)), std::move(accessTier), options);
DeferredResponse<Models::SetBlobAccessTierResult> deferredResponse(
CreateDeferredResponseFunc(op->Promise));
m_subrequests.push_back(std::move(op));
return deferredResponse;
}
}}} // namespace Azure::Storage::Blobs

View File

@ -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<Models::SubmitBlobBatchResult> 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>(
Models::SubmitBlobBatchResult(), std::move(response.RawResponse));
}

View File

@ -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<Models::SubmitBlobBatchResult> 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>(
Models::SubmitBlobBatchResult(), std::move(response.RawResponse));
}

View File

@ -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);