UpdateSequenceNumber (#2588)
This commit is contained in:
parent
07861a9687
commit
ae112cd8a4
@ -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.
|
||||
*/
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user