Support poll operations in blob service (#1461)
* operation<T> * add test cases * changelog * fix build error * add virtual destructor * fix build error * use Azure::Core::RequestFailedException
This commit is contained in:
parent
a850513e28
commit
ae53a38c7a
@ -34,6 +34,8 @@ namespace Azure { namespace Core {
|
||||
OperationStatus m_status = OperationStatus::NotStarted;
|
||||
|
||||
public:
|
||||
virtual ~Operation() {}
|
||||
|
||||
/**
|
||||
* @brief Final reuslt of the long-running operation.
|
||||
*
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
- Type for lease duration in requests was changed to `std::chrono::seconds`, in response was changed to enum.
|
||||
- `PublicAccessType::Private` was renamed to `PublicAccessType::None`.
|
||||
- `startsOn` parameter for `GetUserDelegationKey` was changed to optional.
|
||||
- Return types of `BlobClient::StartCopyFromUri` and `PageBlobClient::StartCopyIncremental` were changed to `StartCopyBlobResult`, supporting poll operations.
|
||||
|
||||
## 12.0.0-beta.6 (2020-01-14)
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ set(
|
||||
src/blob_client.cpp
|
||||
src/blob_container_client.cpp
|
||||
src/blob_lease_client.cpp
|
||||
src/blob_responses.cpp
|
||||
src/blob_rest_client.cpp
|
||||
src/blob_sas_builder.cpp
|
||||
src/blob_service_client.cpp
|
||||
|
||||
@ -199,9 +199,9 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* public or must be authenticated via a shared access signature. If the source blob is public,
|
||||
* no authentication is required to perform the copy operation.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return A StartCopyBlobFromUriResult describing the state of the copy operation.
|
||||
* @return A StartCopyBlobResult describing the state of the copy operation.
|
||||
*/
|
||||
Azure::Core::Response<Models::StartCopyBlobFromUriResult> StartCopyFromUri(
|
||||
Azure::Core::Response<Models::StartCopyBlobResult> StartCopyFromUri(
|
||||
const std::string& sourceUri,
|
||||
const StartCopyBlobFromUriOptions& options = StartCopyBlobFromUriOptions()) const;
|
||||
|
||||
|
||||
@ -5,63 +5,107 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <azure/core/operation.hpp>
|
||||
|
||||
#include "azure/storage/blobs/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs { namespace Models {
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
struct DownloadBlobToResult
|
||||
{
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int64_t ContentLength = 0;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
Models::BlobType BlobType;
|
||||
bool IsServerEncrypted = false;
|
||||
Azure::Core::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
};
|
||||
class BlobClient;
|
||||
class PageBlobClient;
|
||||
|
||||
using UploadBlockBlobFromResult = UploadBlockBlobResult;
|
||||
namespace Models {
|
||||
|
||||
struct AcquireBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
struct DownloadBlobToResult
|
||||
{
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int64_t ContentLength = 0;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
Models::BlobType BlobType;
|
||||
bool IsServerEncrypted = false;
|
||||
Azure::Core::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
};
|
||||
|
||||
struct BreakBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int32_t LeaseTime = 0;
|
||||
};
|
||||
using UploadBlockBlobFromResult = UploadBlockBlobResult;
|
||||
|
||||
struct ChangeBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
struct AcquireBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
|
||||
struct ReleaseBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
};
|
||||
struct BreakBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int32_t LeaseTime = 0;
|
||||
};
|
||||
|
||||
struct RenewBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
struct ChangeBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
|
||||
}}}} // namespace Azure::Storage::Blobs::Models
|
||||
struct ReleaseBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
};
|
||||
|
||||
struct RenewBlobLeaseResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string LeaseId;
|
||||
};
|
||||
|
||||
class StartCopyBlobResult : public Azure::Core::Operation<GetBlobPropertiesResult> {
|
||||
public:
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string CopyId;
|
||||
Models::CopyStatus CopyStatus;
|
||||
Azure::Core::Nullable<std::string> VersionId;
|
||||
|
||||
public:
|
||||
GetBlobPropertiesResult Value() const override { return m_pollResult; }
|
||||
|
||||
~StartCopyBlobResult() override {}
|
||||
|
||||
private:
|
||||
std::string GetResumeToken() const override
|
||||
{
|
||||
// Not supported
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> PollInternal(
|
||||
Azure::Core::Context& context) override;
|
||||
|
||||
Azure::Core::Response<GetBlobPropertiesResult> PollUntilDoneInternal(
|
||||
Azure::Core::Context& context,
|
||||
std::chrono::milliseconds period) override;
|
||||
|
||||
std::shared_ptr<BlobClient> m_blobClient;
|
||||
Models::GetBlobPropertiesResult m_pollResult;
|
||||
|
||||
friend class Blobs::BlobClient;
|
||||
friend class Blobs::PageBlobClient;
|
||||
};
|
||||
|
||||
} // namespace Models
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
|
||||
@ -248,9 +248,9 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* @param sourceUri Specifies the to the source page blob as a uri up to 2 KB in length. The
|
||||
* source blob must either be public or must be authenticated via a shared access signature.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return A StartCopyPageBlobIncrementalResult describing the state of the copy operation.
|
||||
* @return A StartCopyBlobResult describing the state of the copy operation.
|
||||
*/
|
||||
Azure::Core::Response<Models::StartCopyPageBlobIncrementalResult> StartCopyIncremental(
|
||||
Azure::Core::Response<Models::StartCopyBlobResult> StartCopyIncremental(
|
||||
const std::string& sourceUri,
|
||||
const StartCopyPageBlobIncrementalOptions& options
|
||||
= StartCopyPageBlobIncrementalOptions()) const;
|
||||
|
||||
@ -844,25 +844,29 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
ObjectReplicationStatus ReplicationStatus;
|
||||
}; // struct ObjectReplicationRule
|
||||
|
||||
struct StartCopyBlobFromUriResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string CopyId;
|
||||
Models::CopyStatus CopyStatus;
|
||||
Azure::Core::Nullable<std::string> VersionId;
|
||||
}; // struct StartCopyBlobFromUriResult
|
||||
namespace Details {
|
||||
struct StartCopyBlobFromUriResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string CopyId;
|
||||
Models::CopyStatus CopyStatus;
|
||||
Azure::Core::Nullable<std::string> VersionId;
|
||||
}; // struct StartCopyBlobFromUriResult
|
||||
} // namespace Details
|
||||
|
||||
struct StartCopyPageBlobIncrementalResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string CopyId;
|
||||
Models::CopyStatus CopyStatus;
|
||||
Azure::Core::Nullable<std::string> VersionId;
|
||||
}; // struct StartCopyPageBlobIncrementalResult
|
||||
namespace Details {
|
||||
struct StartCopyPageBlobIncrementalResult
|
||||
{
|
||||
std::string RequestId;
|
||||
std::string ETag;
|
||||
Azure::Core::DateTime LastModified;
|
||||
std::string CopyId;
|
||||
Models::CopyStatus CopyStatus;
|
||||
Azure::Core::Nullable<std::string> VersionId;
|
||||
}; // struct StartCopyPageBlobIncrementalResult
|
||||
} // namespace Details
|
||||
|
||||
struct AppendBlockFromUriResult
|
||||
{
|
||||
@ -5975,7 +5979,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Core::Nullable<bool> ShouldSealDestination;
|
||||
}; // struct StartCopyBlobFromUriOptions
|
||||
|
||||
static Azure::Core::Response<StartCopyBlobFromUriResult> StartCopyFromUri(
|
||||
static Azure::Core::Response<Models::Details::StartCopyBlobFromUriResult> StartCopyFromUri(
|
||||
const Azure::Core::Context& context,
|
||||
Azure::Core::Http::HttpPipeline& pipeline,
|
||||
const Azure::Core::Http::Url& url,
|
||||
@ -6071,7 +6075,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
auto pHttpResponse = pipeline.Send(context, request);
|
||||
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
|
||||
StartCopyBlobFromUriResult response;
|
||||
Models::Details::StartCopyBlobFromUriResult response;
|
||||
auto http_status_code
|
||||
= static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||
httpResponse.GetStatusCode());
|
||||
@ -6091,7 +6095,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
response.VersionId = x_ms_version_id__iterator->second;
|
||||
}
|
||||
return Azure::Core::Response<StartCopyBlobFromUriResult>(
|
||||
return Azure::Core::Response<Models::Details::StartCopyBlobFromUriResult>(
|
||||
std::move(response), std::move(pHttpResponse));
|
||||
}
|
||||
|
||||
@ -8661,7 +8665,8 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Core::Nullable<std::string> IfTags;
|
||||
}; // struct StartCopyPageBlobIncrementalOptions
|
||||
|
||||
static Azure::Core::Response<StartCopyPageBlobIncrementalResult> StartCopyIncremental(
|
||||
static Azure::Core::Response<Models::Details::StartCopyPageBlobIncrementalResult>
|
||||
StartCopyIncremental(
|
||||
const Azure::Core::Context& context,
|
||||
Azure::Core::Http::HttpPipeline& pipeline,
|
||||
const Azure::Core::Http::Url& url,
|
||||
@ -8706,7 +8711,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
auto pHttpResponse = pipeline.Send(context, request);
|
||||
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
|
||||
StartCopyPageBlobIncrementalResult response;
|
||||
Models::Details::StartCopyPageBlobIncrementalResult response;
|
||||
auto http_status_code
|
||||
= static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||
httpResponse.GetStatusCode());
|
||||
@ -8726,7 +8731,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
response.VersionId = x_ms_version_id__iterator->second;
|
||||
}
|
||||
return Azure::Core::Response<StartCopyPageBlobIncrementalResult>(
|
||||
return Azure::Core::Response<Models::Details::StartCopyPageBlobIncrementalResult>(
|
||||
std::move(response), std::move(pHttpResponse));
|
||||
}
|
||||
|
||||
|
||||
@ -545,7 +545,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
options.Context, *m_pipeline, m_blobUrl, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<Models::StartCopyBlobFromUriResult> BlobClient::StartCopyFromUri(
|
||||
Azure::Core::Response<Models::StartCopyBlobResult> BlobClient::StartCopyFromUri(
|
||||
const std::string& sourceUri,
|
||||
const StartCopyBlobFromUriOptions& options) const
|
||||
{
|
||||
@ -567,8 +567,19 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch;
|
||||
protocolLayerOptions.ShouldSealDestination = options.ShouldSealDestination;
|
||||
protocolLayerOptions.SourceIfTags = options.SourceAccessConditions.TagConditions;
|
||||
return Details::BlobRestClient::Blob::StartCopyFromUri(
|
||||
|
||||
auto response = Details::BlobRestClient::Blob::StartCopyFromUri(
|
||||
options.Context, *m_pipeline, m_blobUrl, protocolLayerOptions);
|
||||
Models::StartCopyBlobResult res;
|
||||
res.RequestId = std::move(response->RequestId);
|
||||
res.ETag = std::move(response->ETag);
|
||||
res.LastModified = std::move(response->LastModified);
|
||||
res.CopyId = std::move(response->CopyId);
|
||||
res.CopyStatus = std::move(response->CopyStatus);
|
||||
res.VersionId = std::move(response->VersionId);
|
||||
res.m_blobClient = std::make_shared<BlobClient>(*this);
|
||||
return Azure::Core::Response<Models::StartCopyBlobResult>(
|
||||
std::move(res), response.ExtractRawResponse());
|
||||
}
|
||||
|
||||
Azure::Core::Response<Models::AbortCopyBlobFromUriResult> BlobClient::AbortCopyFromUri(
|
||||
|
||||
61
sdk/storage/azure-storage-blobs/src/blob_responses.cpp
Normal file
61
sdk/storage/azure-storage-blobs/src/blob_responses.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/storage/blobs/blob_responses.hpp"
|
||||
|
||||
#include "azure/storage/blobs/blob_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs { namespace Models {
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> StartCopyBlobResult::PollInternal(
|
||||
Azure::Core::Context& context)
|
||||
{
|
||||
unused(context);
|
||||
|
||||
auto response = m_blobClient->GetProperties();
|
||||
if (!response->CopyStatus.HasValue())
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Failed;
|
||||
}
|
||||
else if (response->CopyStatus.GetValue() == CopyStatus::Pending)
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Running;
|
||||
}
|
||||
else if (response->CopyStatus.GetValue() == CopyStatus::Success)
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Succeeded;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Failed;
|
||||
}
|
||||
m_pollResult = *response;
|
||||
return response.ExtractRawResponse();
|
||||
}
|
||||
|
||||
Azure::Core::Response<GetBlobPropertiesResult> StartCopyBlobResult::PollUntilDoneInternal(
|
||||
Azure::Core::Context& context,
|
||||
std::chrono::milliseconds period)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
auto rawResponse = PollInternal(context);
|
||||
|
||||
if (m_status == Azure::Core::OperationStatus::Succeeded)
|
||||
{
|
||||
return Azure::Core::Response<GetBlobPropertiesResult>(m_pollResult, std::move(rawResponse));
|
||||
}
|
||||
else if (m_status == Azure::Core::OperationStatus::Failed)
|
||||
{
|
||||
throw Azure::Core::RequestFailedException("Operation failed");
|
||||
}
|
||||
else if (m_status == Azure::Core::OperationStatus::Cancelled)
|
||||
{
|
||||
throw Azure::Core::RequestFailedException("Operation was cancelled");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(period);
|
||||
};
|
||||
}
|
||||
|
||||
}}}} // namespace Azure::Storage::Blobs::Models
|
||||
@ -279,8 +279,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
options.Context, *m_pipeline, m_blobUrl, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<Models::StartCopyPageBlobIncrementalResult>
|
||||
PageBlobClient::StartCopyIncremental(
|
||||
Azure::Core::Response<Models::StartCopyBlobResult> PageBlobClient::StartCopyIncremental(
|
||||
const std::string& sourceUri,
|
||||
const StartCopyPageBlobIncrementalOptions& options) const
|
||||
{
|
||||
@ -291,8 +290,19 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
|
||||
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
|
||||
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
|
||||
return Details::BlobRestClient::PageBlob::StartCopyIncremental(
|
||||
|
||||
auto response = Details::BlobRestClient::PageBlob::StartCopyIncremental(
|
||||
options.Context, *m_pipeline, m_blobUrl, protocolLayerOptions);
|
||||
Models::StartCopyBlobResult res;
|
||||
res.RequestId = std::move(response->RequestId);
|
||||
res.ETag = std::move(response->ETag);
|
||||
res.LastModified = std::move(response->LastModified);
|
||||
res.CopyId = std::move(response->CopyId);
|
||||
res.CopyStatus = std::move(response->CopyStatus);
|
||||
res.VersionId = std::move(response->VersionId);
|
||||
res.m_blobClient = std::make_shared<BlobClient>(*this);
|
||||
return Azure::Core::Response<Models::StartCopyBlobResult>(
|
||||
std::move(res), response.ExtractRawResponse());
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
|
||||
@ -327,8 +327,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
Blobs::StartCopyBlobFromUriOptions copyOptions;
|
||||
copyOptions.ShouldSealDestination = false;
|
||||
auto copyResult = blobClient2.StartCopyFromUri(blobClient.GetUrl() + GetSas(), copyOptions);
|
||||
// TODO: poller wait here
|
||||
getPropertiesResult = blobClient2.GetProperties();
|
||||
getPropertiesResult = copyResult->PollUntilDone(std::chrono::seconds(1));
|
||||
ASSERT_TRUE(getPropertiesResult->CopyStatus.HasValue());
|
||||
EXPECT_EQ(getPropertiesResult->CopyStatus.GetValue(), Blobs::Models::CopyStatus::Success);
|
||||
if (getPropertiesResult->IsSealed.HasValue())
|
||||
{
|
||||
EXPECT_FALSE(getPropertiesResult->IsSealed.GetValue());
|
||||
@ -336,10 +337,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
copyOptions.ShouldSealDestination = true;
|
||||
copyResult = blobClient2.StartCopyFromUri(blobClient.GetUrl() + GetSas(), copyOptions);
|
||||
// TODO: poller wait here
|
||||
getPropertiesResult = blobClient2.GetProperties();
|
||||
getPropertiesResult = copyResult->PollUntilDone(std::chrono::seconds(1));
|
||||
EXPECT_TRUE(getPropertiesResult->IsSealed.HasValue());
|
||||
EXPECT_TRUE(getPropertiesResult->IsSealed.GetValue());
|
||||
ASSERT_TRUE(getPropertiesResult->CopyStatus.HasValue());
|
||||
EXPECT_EQ(getPropertiesResult->CopyStatus.GetValue(), Blobs::Models::CopyStatus::Success);
|
||||
}
|
||||
|
||||
TEST_F(AppendBlobClientTest, CreateIfNotExists)
|
||||
|
||||
@ -157,6 +157,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(copyInfo->CopyStatus.Get().empty());
|
||||
EXPECT_TRUE(copyInfo->VersionId.HasValue());
|
||||
EXPECT_FALSE(copyInfo->VersionId.GetValue().empty());
|
||||
auto getPropertiesResult = copyInfo->PollUntilDone(std::chrono::seconds(1));
|
||||
ASSERT_TRUE(getPropertiesResult->CopyStatus.HasValue());
|
||||
EXPECT_EQ(getPropertiesResult->CopyStatus.GetValue(), Blobs::Models::CopyStatus::Success);
|
||||
}
|
||||
|
||||
TEST_F(PageBlobClientTest, Lease)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user