UpdateSequenceNumber (#2588)

This commit is contained in:
JinmingHu 2021-07-10 10:11:04 +08:00 committed by GitHub
parent 07861a9687
commit ae112cd8a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 257 additions and 0 deletions

View File

@ -1059,6 +1059,22 @@ namespace Azure { namespace Storage { namespace Blobs {
BlobAccessConditions AccessConditions;
};
/**
* @brief Optional parameters for #Azure::Storage::Blobs::PageBlobClient::UpdateSequenceNumber.
*/
struct UpdatePageBlobSequenceNumberOptions final
{
/**
* @brief An updated sequence number of your choosing, if Action is Max or Update.
*/
Azure::Nullable<int64_t> SequenceNumber;
/**
* @brief Optional conditions that must be met to perform this operation.
*/
BlobAccessConditions AccessConditions;
};
/**
* @brief Optional parameters for #Azure::Storage::Blobs::PageBlobClient::GetPageRanges.
*/

View File

@ -208,6 +208,19 @@ namespace Azure { namespace Storage { namespace Blobs {
const ResizePageBlobOptions& options = ResizePageBlobOptions(),
const Azure::Core::Context& context = Azure::Core::Context()) const;
/**
* @brief Changes the sequence number for this page blob.
*
* @param action Specifies how the service should modify the blob's sequence number.
* @param options Optional parameters to execute this function.
* @param context Context for cancelling long running operations.
* @return An UpdateSequenceNumberResult describing the updated page blob.
*/
Azure::Response<Models::UpdateSequenceNumberResult> UpdateSequenceNumber(
Models::SequenceNumberAction action,
const UpdatePageBlobSequenceNumberOptions& options = UpdatePageBlobSequenceNumberOptions(),
const Azure::Core::Context& context = Azure::Core::Context()) const;
/**
* @brief Returns the list of valid page ranges for a page blob or snapshot of a page blob.
*

View File

@ -2100,6 +2100,34 @@ namespace Azure { namespace Storage { namespace Blobs {
bool IsSealed = true;
}; // struct SealAppendBlobResult
/**
* @brief Indicates how the service should modify the blob's sequence number.
*/
class SequenceNumberAction final {
public:
SequenceNumberAction() = default;
explicit SequenceNumberAction(std::string value) : m_value(std::move(value)) {}
bool operator==(const SequenceNumberAction& other) const { return m_value == other.m_value; }
bool operator!=(const SequenceNumberAction& other) const { return !(*this == other); }
const std::string& ToString() const { return m_value; }
/**
* Sets the sequence number to be the higher of the value included with the request and the
* value currently stored for the blob.
*/
AZ_STORAGE_BLOBS_DLLEXPORT const static SequenceNumberAction Max;
/**
* Sets the sequence number to the value included with the request.
*/
AZ_STORAGE_BLOBS_DLLEXPORT const static SequenceNumberAction Update;
/**
* Increments the value of the sequence number by 1.
*/
AZ_STORAGE_BLOBS_DLLEXPORT const static SequenceNumberAction Increment;
private:
std::string m_value;
}; // extensible enum SequenceNumberAction
/**
* @brief Statistics for the storage service.
*/
@ -2298,6 +2326,28 @@ namespace Azure { namespace Storage { namespace Blobs {
{
}; // struct UndeleteBlobResult
/**
* @brief Response type for Azure::Storage::Blobs::PageBlobClient::UpdateSequenceNumber.
*/
struct UpdateSequenceNumberResult final
{
/**
* The ETag contains a value that you can use to perform operations conditionally.
*/
Azure::ETag ETag;
/**
* The date and time the container was last modified. Any operation that modifies the blob,
* including an update of the metadata or properties, changes the last-modified time of the
* blob.
*/
Azure::DateTime LastModified;
/**
* The current sequence number for a page blob. This value is null for block blobs or append
* blobs.
*/
int64_t SequenceNumber = 0;
}; // struct UpdateSequenceNumberResult
/**
* @brief Response type for #Azure::Storage::Blobs::BlockBlobClient::Upload.
*/
@ -10335,6 +10385,109 @@ namespace Azure { namespace Storage { namespace Blobs {
std::move(response), std::move(pHttpResponse));
}
struct UpdatePageBlobSequenceNumberOptions final
{
Azure::Nullable<int32_t> Timeout;
SequenceNumberAction Action;
Azure::Nullable<int64_t> SequenceNumber;
Azure::Nullable<std::string> LeaseId;
Azure::Nullable<int64_t> IfSequenceNumberLessThanOrEqualTo;
Azure::Nullable<int64_t> IfSequenceNumberLessThan;
Azure::Nullable<int64_t> IfSequenceNumberEqualTo;
Azure::Nullable<Azure::DateTime> IfModifiedSince;
Azure::Nullable<Azure::DateTime> IfUnmodifiedSince;
Azure::ETag IfMatch;
Azure::ETag IfNoneMatch;
Azure::Nullable<std::string> IfTags;
}; // struct UpdatePageBlobSequenceNumberOptions
static Azure::Response<UpdateSequenceNumberResult> UpdateSequenceNumber(
Azure::Core::Http::_internal::HttpPipeline& pipeline,
const Azure::Core::Url& url,
const UpdatePageBlobSequenceNumberOptions& options,
const Azure::Core::Context& context)
{
(void)options;
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
request.SetHeader("Content-Length", "0");
request.GetUrl().AppendQueryParameter("comp", "properties");
request.SetHeader("x-ms-version", "2020-02-10");
if (options.Timeout.HasValue())
{
request.GetUrl().AppendQueryParameter(
"timeout", std::to_string(options.Timeout.Value()));
}
if (options.LeaseId.HasValue())
{
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
}
if (options.IfSequenceNumberLessThanOrEqualTo.HasValue())
{
request.SetHeader(
"x-ms-if-sequence-number-le",
std::to_string(options.IfSequenceNumberLessThanOrEqualTo.Value()));
}
if (options.IfSequenceNumberLessThan.HasValue())
{
request.SetHeader(
"x-ms-if-sequence-number-lt",
std::to_string(options.IfSequenceNumberLessThan.Value()));
}
if (options.IfSequenceNumberEqualTo.HasValue())
{
request.SetHeader(
"x-ms-if-sequence-number-eq",
std::to_string(options.IfSequenceNumberEqualTo.Value()));
}
if (options.IfModifiedSince.HasValue())
{
request.SetHeader(
"If-Modified-Since",
options.IfModifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123));
}
if (options.IfUnmodifiedSince.HasValue())
{
request.SetHeader(
"If-Unmodified-Since",
options.IfUnmodifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123));
}
if (options.IfMatch.HasValue() && !options.IfMatch.ToString().empty())
{
request.SetHeader("If-Match", options.IfMatch.ToString());
}
if (options.IfNoneMatch.HasValue() && !options.IfNoneMatch.ToString().empty())
{
request.SetHeader("If-None-Match", options.IfNoneMatch.ToString());
}
if (options.IfTags.HasValue())
{
request.SetHeader("x-ms-if-tags", options.IfTags.Value());
}
request.SetHeader("x-ms-sequence-number-action", options.Action.ToString());
if (options.SequenceNumber.HasValue())
{
request.SetHeader(
"x-ms-blob-sequence-number", std::to_string(options.SequenceNumber.Value()));
}
auto pHttpResponse = pipeline.Send(request, context);
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
UpdateSequenceNumberResult response;
auto http_status_code
= static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
httpResponse.GetStatusCode());
if (!(http_status_code == 200))
{
throw StorageException::CreateFromResponse(std::move(pHttpResponse));
}
response.ETag = Azure::ETag(httpResponse.GetHeaders().at("etag"));
response.LastModified = Azure::DateTime::Parse(
httpResponse.GetHeaders().at("last-modified"), Azure::DateTime::DateFormat::Rfc1123);
response.SequenceNumber
= std::stoll(httpResponse.GetHeaders().at("x-ms-blob-sequence-number"));
return Azure::Response<UpdateSequenceNumberResult>(
std::move(response), std::move(pHttpResponse));
}
struct GetPageBlobPageRangesOptions final
{
Azure::Nullable<int32_t> Timeout;

View File

@ -93,4 +93,8 @@ namespace Azure { namespace Storage { namespace Blobs { namespace Models {
const ScheduleBlobExpiryOriginType ScheduleBlobExpiryOriginType::RelativeToNow("RelativeToNow");
const ScheduleBlobExpiryOriginType ScheduleBlobExpiryOriginType::Absolute("Absolute");
const SequenceNumberAction SequenceNumberAction::Max("max");
const SequenceNumberAction SequenceNumberAction::Update("update");
const SequenceNumberAction SequenceNumberAction::Increment("increment");
}}}} // namespace Azure::Storage::Blobs::Models

View File

@ -238,6 +238,24 @@ namespace Azure { namespace Storage { namespace Blobs {
*m_pipeline, m_blobUrl, protocolLayerOptions, context);
}
Azure::Response<Models::UpdateSequenceNumberResult> PageBlobClient::UpdateSequenceNumber(
Models::SequenceNumberAction action,
const UpdatePageBlobSequenceNumberOptions& options,
const Azure::Core::Context& context) const
{
_detail::BlobRestClient::PageBlob::UpdatePageBlobSequenceNumberOptions protocolLayerOptions;
protocolLayerOptions.Action = action;
protocolLayerOptions.SequenceNumber = options.SequenceNumber;
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince;
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
return _detail::BlobRestClient::PageBlob::UpdateSequenceNumber(
*m_pipeline, m_blobUrl, protocolLayerOptions, context);
}
GetPageRangesPagedResponse PageBlobClient::GetPageRanges(
const GetPageRangesOptions& options,
const Azure::Core::Context& context) const

View File

@ -1037,6 +1037,18 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_NO_THROW(pageBlobClient.Resize(contentSize, options));
}
{
Blobs::UpdatePageBlobSequenceNumberOptions options;
options.AccessConditions.TagConditions = failWhereExpression;
EXPECT_THROW(
pageBlobClient.UpdateSequenceNumber(
Blobs::Models::SequenceNumberAction::Increment, options),
StorageException);
options.AccessConditions.TagConditions = successWhereExpression;
EXPECT_NO_THROW(pageBlobClient.UpdateSequenceNumber(
Blobs::Models::SequenceNumberAction::Increment, options));
}
{
Blobs::GetPageRangesOptions options;
options.AccessConditions.TagConditions = failWhereExpression;

View File

@ -401,4 +401,45 @@ namespace Azure { namespace Storage { namespace Test {
}
}
TEST_F(PageBlobClientTest, UpdateSequenceNumber)
{
auto blobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
blobClient.Create(512);
Blobs::Models::BlobHttpHeaders headers;
headers.ContentType = "text/plain";
blobClient.SetHttpHeaders(headers);
Blobs::UpdatePageBlobSequenceNumberOptions options;
options.SequenceNumber = 100;
auto res
= blobClient.UpdateSequenceNumber(Blobs::Models::SequenceNumberAction::Update, options);
EXPECT_TRUE(res.Value.ETag.HasValue());
EXPECT_TRUE(IsValidTime(res.Value.LastModified));
EXPECT_EQ(res.Value.SequenceNumber, 100);
EXPECT_EQ(blobClient.GetProperties().Value.SequenceNumber.Value(), 100);
options.SequenceNumber = 200;
res = blobClient.UpdateSequenceNumber(Blobs::Models::SequenceNumberAction::Update, options);
EXPECT_EQ(res.Value.SequenceNumber, 200);
EXPECT_EQ(blobClient.GetProperties().Value.SequenceNumber.Value(), 200);
options.SequenceNumber = 50;
res = blobClient.UpdateSequenceNumber(Blobs::Models::SequenceNumberAction::Max, options);
EXPECT_EQ(res.Value.SequenceNumber, 200);
EXPECT_EQ(blobClient.GetProperties().Value.SequenceNumber.Value(), 200);
options.SequenceNumber = 300;
res = blobClient.UpdateSequenceNumber(Blobs::Models::SequenceNumberAction::Max, options);
EXPECT_EQ(res.Value.SequenceNumber, 300);
EXPECT_EQ(blobClient.GetProperties().Value.SequenceNumber.Value(), 300);
options.SequenceNumber.Reset();
res = blobClient.UpdateSequenceNumber(Blobs::Models::SequenceNumberAction::Increment, options);
EXPECT_EQ(res.Value.SequenceNumber, 301);
EXPECT_EQ(blobClient.GetProperties().Value.SequenceNumber.Value(), 301);
EXPECT_EQ(blobClient.GetProperties().Value.HttpHeaders.ContentType, headers.ContentType);
}
}}} // namespace Azure::Storage::Test