From 88228527ac0c8788cc0d3a837b56e1cac5acb56d Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Wed, 8 Apr 2020 18:24:58 -0700 Subject: [PATCH 01/15] Adding autopilot support --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 75 +++++++++++ .../src/Handler/RequestMessage.cs | 13 ++ .../src/Microsoft.Azure.Cosmos.csproj | 2 +- .../src/Resource/Container/Container.cs | 27 ++++ .../src/Resource/Container/ContainerCore.cs | 37 ++++++ .../Resource/Container/ContainerInlineCore.cs | 21 ++++ .../src/Resource/CosmosResponseFactory.cs | 15 +++ .../src/Resource/Database/Database.cs | 101 +++++++++++++++ .../src/Resource/Database/DatabaseCore.cs | 81 ++++++++++++ .../Resource/Database/DatabaseInlineCore.cs | 30 +++++ .../Offer/AutopilotThroughputProperties.cs | 50 ++++++++ .../Offer/AutopilotThroughputResponse.cs | 105 ++++++++++++++++ .../src/Resource/Offer/CosmosOffers.cs | 70 +++++++++-- .../Offer/OfferAutopilotProperties.cs | 36 ++++++ .../Resource/Offer/OfferContentProperties.cs | 56 +++++++++ .../ThroughputProperties.cs | 11 +- .../ThroughputResponse.cs | 0 .../src/Serializer/CosmosSerializerCore.cs | 3 +- .../CosmosContainerTests.cs | 2 +- .../CosmosThroughputTests.cs | 117 ++++++++++++++++++ .../CosmosThroughputTests.cs | 83 +++++++++++++ 21 files changed, 923 insertions(+), 12 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs create mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs create mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs create mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs rename Microsoft.Azure.Cosmos/src/Resource/{Settings => Offer}/ThroughputProperties.cs (87%) rename Microsoft.Azure.Cosmos/src/Resource/{Throughput => Offer}/ThroughputResponse.cs (100%) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index bb361793cb..ff2a7a68bb 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -375,6 +375,47 @@ public virtual Task CreateDatabaseAsync( cancellationToken: cancellationToken)); } + /// + /// Sends a request for creating a database. + /// + /// A database manages users, permissions and a set of containers. + /// Each Azure Cosmos DB Database Account is able to support multiple independent named databases, + /// with the database being the logical container for data. + /// + /// Each Database consists of one or more containers, each of which in turn contain one or more + /// documents. Since databases are an administrative resource, the Service Master Key will be + /// required in order to access and successfully complete any action using the User APIs. + /// + /// The database id. + /// (Optional) The throughput provisioned for a database in measurement of Request Units per second in the Azure Cosmos DB service. + /// (Optional) A set of options that can be set. + /// (Optional) representing request cancellation. + /// A containing a which wraps a containing the resource record. + /// Request Units +#if INTERNAL + public +#else + internal +#endif + virtual Task CreateDatabaseAsync( + string id, + AutopilotThroughputProperties autopilotThroughput, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); + return TaskHelper.RunInlineIfNeededAsync(() => this.CreateAutopilotDatabaseAsync( + databaseProperties: databaseProperties, + autopilotThroughput: autopilotThroughput, + requestOptions: requestOptions, + cancellationToken: cancellationToken)); + } + /// /// Check if a database exists, and if it doesn't, create it. /// Only the database id is used to verify if there is an existing database. Other database properties @@ -709,6 +750,21 @@ internal DatabaseProperties PrepareDatabaseProperties(string id) return databaseProperties; } + internal Task CreateAutopilotDatabaseAsync( + DatabaseProperties databaseProperties, + AutopilotThroughputProperties autopilotThroughput, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Task response = this.CreateAutopilotDatabaseStreamInternalAsync( + streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), + autopilotThroughput: autopilotThroughput, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + + return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); + } + internal Task CreateDatabaseAsync( DatabaseProperties databaseProperties, int? throughput = null, @@ -724,6 +780,25 @@ internal Task CreateDatabaseAsync( return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); } + private Task CreateAutopilotDatabaseStreamInternalAsync( + Stream streamPayload, + AutopilotThroughputProperties autopilotThroughput, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + return this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: this.DatabaseRootUri, + resourceType: ResourceType.Database, + operationType: OperationType.Create, + requestOptions: requestOptions, + cosmosContainerCore: null, + partitionKey: null, + streamPayload: streamPayload, + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddAutoPilotThroughputHeader(autopilotThroughput?.Content?.OfferAutopilotSettings), + diagnosticsContext: null, + cancellationToken: cancellationToken); + } + private Task CreateDatabaseStreamInternalAsync( Stream streamPayload, int? throughput = null, diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs index 29ed55b541..1f005ad665 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs @@ -169,6 +169,19 @@ internal void AddThroughputHeader(int? throughputValue) } } + internal void AddAutoPilotThroughputHeader(OfferAutopilotProperties offerAutopilotProperties) + { + if (this.Headers.OfferThroughput != null) + { + throw new InvalidOperationException("Autopilot can not be configured with fixed offer"); + } + + if (offerAutopilotProperties != null) + { + this.Headers.Add(HttpConstants.HttpHeaders.OfferAutopilotSettings, offerAutopilotProperties.GetJsonString()); + } + } + internal async Task AssertPartitioningDetailsAsync(CosmosClient client, CancellationToken cancellationToken) { if (this.IsMasterOperation()) diff --git a/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj b/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj index d26aa0c7ab..7050db09cc 100644 --- a/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj +++ b/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj @@ -71,7 +71,7 @@ - + diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs index d190ac77cc..1496b37d9b 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs @@ -293,6 +293,33 @@ public abstract Task ReplaceThroughputAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); +#if INTERNAL + /// + /// Gets container throughput in measurement of request units per second in the Azure Cosmos service. + /// + /// The options for the throughput request. + /// (Optional) representing request cancellation. + /// The throughput response. + public abstract Task ReadAutopilotThroughputAsync( + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Sets throughput provisioned for a container in measurement of request units per second in the Azure Cosmos service. + /// + /// The Cosmos container throughput expressed in Request Units per second. + /// (Optional) The options for the throughput request. + /// (Optional) representing request cancellation. + /// The throughput response. + /// + /// Request Units + /// + public abstract Task ReplaceAutopilotThroughputAsync( + AutopilotThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); +#endif + /// /// Creates a Item as an asynchronous operation in the Azure Cosmos service. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs index 4f472a3ece..794283357a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs @@ -162,6 +162,43 @@ internal async Task ReplaceThroughputIfExistsAsync( cancellationToken: cancellationToken); } +#if INTERNAL + public override +#else + internal +#endif + async Task ReadAutopilotThroughputAsync( + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + string rid = await this.GetRIDAsync(cancellationToken); + + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReadAutopilotThroughputAsync( + targetRID: rid, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + +#if INTERNAL + public override +#else + internal +#endif + async Task ReplaceAutopilotThroughputAsync( + AutopilotThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + string rid = await this.GetRIDAsync(cancellationToken); + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReplaceAutoPilotThroughputAsync( + rid, + throughputProperties, + requestOptions, + cancellationToken); + } + public override Task DeleteContainerStreamAsync( ContainerRequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs index f4fedb7cd8..7a872eb69e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs @@ -100,6 +100,26 @@ public override Task ReplaceThroughputAsync( return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReplaceThroughputAsync(throughput, requestOptions, cancellationToken)); } +#if INTERNAL + public override +#else + internal +#endif + Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReadAutopilotThroughputAsync(requestOptions, cancellationToken)); + } + +#if INTERNAL + public override +#else + internal +#endif + Task ReplaceAutopilotThroughputAsync(AutopilotThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReplaceAutopilotThroughputAsync(throughputProperties, requestOptions, cancellationToken)); + } + public override Task CreateItemStreamAsync( Stream streamPayload, PartitionKey partitionKey, @@ -262,6 +282,7 @@ public override TransactionalBatch CreateTransactionalBatch(PartitionKey partiti { return this.container.CreateTransactionalBatch(partitionKey); } + #if PREVIEW public override Task> GetFeedTokensAsync(CancellationToken cancellationToken = default(CancellationToken)) { diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs index 204153bd2d..7846dca0ca 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs @@ -196,6 +196,21 @@ internal Task CreateThroughputResponseAsync( }); } + internal Task CreateAutopilotThroughputResponseAsync( + Task cosmosResponseMessageTask) + { + return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => + { + cosmosResponseMessage.Content.Position = 0; + AutopilotThroughputProperties throughputProperties = this.ToObjectInternal(cosmosResponseMessage); + return new AutopilotThroughputResponse( + cosmosResponseMessage.StatusCode, + cosmosResponseMessage.Headers, + throughputProperties, + cosmosResponseMessage.Diagnostics); + }); + } + internal Task> CreateStoredProcedureExecuteResponseAsync(Task cosmosResponseMessageTask) { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index 7f6e98f592..4a5d0b7a64 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -158,6 +158,107 @@ public abstract Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)); +#if INTERNAL + /// + /// Gets database throughput in measurement of request units per second in the Azure Cosmos service. + /// + /// The options for the throughput request. + /// (Optional) representing request cancellation. + /// The throughput response. + /// + /// The provisioned throughput for this database. + /// + /// + /// Null value indicates a database with no throughput provisioned. + /// + /// Request Units + /// Set throughput on a database + /// + /// The following example shows how to get the throughput + /// + /// + /// + /// + /// + /// The following example shows how to get throughput, MinThroughput and is replace in progress + /// + /// + /// + /// + public abstract Task ReadAutopilotThroughputAsync( + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Sets throughput provisioned for a database in measurement of request units per second in the Azure Cosmos service. + /// + /// The Cosmos database throughput expressed in Request Units per second. + /// (Optional) The options for the throughput request. + /// (Optional) representing request cancellation. + /// The throughput response. + /// + /// The provisioned throughput for this database. + /// + /// + /// The following example shows how to get the throughput. + /// + /// + /// + /// + /// + /// Request Units + /// + public abstract Task ReplaceAutopilotThroughputAsync( + AutopilotThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Creates a container as an asynchronous operation in the Azure Cosmos service. + /// + /// The object. + /// (Optional) The throughput provisioned for a container in measurement of Requests Units per second in the Azure Cosmos DB service. + /// (Optional) The options for the request. + /// (Optional) representing request cancellation. + /// A containing a which wraps a containing the read resource record. + /// If is not set. + /// Represents a consolidation of failures that occurred during async processing. Look within InnerExceptions to find the actual exception(s). + /// This exception can encapsulate many different types of errors. To determine the specific error always look at the StatusCode property. Some common codes you may get when creating a container are: + /// + /// + /// StatusCodeReason for exception + /// + /// + /// 400BadRequest - This means something was wrong with the request supplied. It is likely that an id was not supplied for the new container. + /// + /// + /// 403Forbidden - This means you attempted to exceed your quota for containers. Contact support to have this quota increased. + /// + /// + /// 409Conflict - This means a with an id matching the id you supplied already existed. + /// + /// + /// + /// Request Units + public abstract Task CreateContainerAsync( + ContainerProperties containerProperties, + AutopilotThroughputProperties autopilotThroughput, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); +#endif + /// /// Sets throughput provisioned for a database in measurement of request units per second in the Azure Cosmos service. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index 674c133c65..5f54e6a1d1 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -122,6 +122,68 @@ internal async Task ReplaceThroughputIfExistsAsync( requestOptions: requestOptions, cancellationToken: cancellationToken); } +#if INTERNAL + public override +#else + internal +#endif + Task CreateContainerAsync( + ContainerProperties containerProperties, + AutopilotThroughputProperties autopilotThroughput, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + if (containerProperties == null) + { + throw new ArgumentNullException(nameof(containerProperties)); + } + + this.ValidateContainerProperties(containerProperties); + + Task response = this.ProcessCollectionCreateAsync( + streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), + autoPilotThroughput: autopilotThroughput, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + + return this.ClientContext.ResponseFactory.CreateContainerResponseAsync(this.GetContainer(containerProperties.Id), response); + } + +#if INTERNAL + public override +#else + internal +#endif + async Task ReadAutopilotThroughputAsync( + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + string rid = await this.GetRIDAsync(cancellationToken); + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReadAutopilotThroughputAsync( + targetRID: rid, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + +#if INTERNAL + public override +#else + internal +#endif + async Task ReplaceAutopilotThroughputAsync( + AutopilotThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + string rid = await this.GetRIDAsync(cancellationToken); + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReplaceAutoPilotThroughputAsync( + targetRID: rid, + userAutopilotProperties: throughputProperties, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } public override Task ReadStreamAsync( RequestOptions requestOptions = null, @@ -675,6 +737,25 @@ internal void ValidateContainerProperties(ContainerProperties containerPropertie this.ClientContext.ValidateResource(containerProperties.Id); } + internal Task ProcessCollectionCreateAsync( + Stream streamPayload, + AutopilotThroughputProperties autoPilotThroughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) + { + return this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: this.LinkUri, + resourceType: ResourceType.Collection, + operationType: OperationType.Create, + cosmosContainerCore: null, + partitionKey: null, + streamPayload: streamPayload, + requestOptions: requestOptions, + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddAutoPilotThroughputHeader(autoPilotThroughput?.Content?.OfferAutopilotSettings), + diagnosticsContext: null, + cancellationToken: cancellationToken); + } + internal Task ProcessCollectionCreateAsync( Stream streamPayload, int? throughput, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index 82d9535a38..2fe0656f18 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -208,6 +208,36 @@ public override Task ReplaceThroughputAsync( return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReplaceThroughputAsync(throughput, requestOptions, cancellationToken)); } +#if INTERNAL + public override +#else + internal +#endif + Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReadAutopilotThroughputAsync(requestOptions, cancellationToken)); + } + +#if INTERNAL + public override +#else + internal +#endif + Task ReplaceAutopilotThroughputAsync(AutopilotThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReplaceAutopilotThroughputAsync(throughputProperties, requestOptions, cancellationToken)); + } + +#if INTERNAL + public override +#else + internal +#endif + Task CreateContainerAsync(ContainerProperties containerProperties, AutopilotThroughputProperties autopilotThroughput, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.database.CreateContainerAsync(containerProperties, autopilotThroughput, requestOptions, cancellationToken)); + } + public override Task UpsertUserAsync( string id, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs new file mode 100644 index 0000000000..3afed8c5d2 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos +{ + using Newtonsoft.Json; + + /// + /// Represents a throughput of the resources in the Azure Cosmos DB service. + /// It is the standard pricing for the resource in the Azure Cosmos DB service. + /// + /// + /// It contains provisioned container throughput in measurement of request units per second in the Azure Cosmos service. + /// Refer to http://azure.microsoft.com/documentation/articles/documentdb-performance-levels/ for details on provision offer throughput. + /// +#if INTERNAL + public +#else + internal +#endif + class AutopilotThroughputProperties : ThroughputProperties + { + /// + /// Default constructor for serialization + /// + [JsonConstructor] + private AutopilotThroughputProperties() + { + } + + /// + /// The AutopilotThroughputProperties constructor + /// + /// The maximum throughput the resource can scale to. + public AutopilotThroughputProperties(int maxThroughput) + { + this.MaxThroughput = maxThroughput; + } + + /// + /// The maximum throughput the autopilot will scale to. + /// + [JsonIgnore] + public int? MaxThroughput + { + get => this.Content?.OfferAutopilotSettings?.MaxThroughput; + private set => this.Content = OfferContentProperties.CreateAutoPilotOfferConent(value.Value); + } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs new file mode 100644 index 0000000000..d4215f049b --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs @@ -0,0 +1,105 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Net; + using Microsoft.Azure.Documents; + + /// + /// The cosmos throughput response + /// + #if INTERNAL + public +#else + internal +#endif + class AutopilotThroughputResponse : Response + { + /// + /// Create a as a no-op for mock testing + /// + protected AutopilotThroughputResponse() + : base() + { + } + + /// + /// A private constructor to ensure the factory is used to create the object. + /// This will prevent memory leaks when handling the HttpResponseMessage + /// + internal AutopilotThroughputResponse( + HttpStatusCode httpStatusCode, + Headers headers, + AutopilotThroughputProperties throughputProperties, + CosmosDiagnostics diagnostics) + { + this.StatusCode = httpStatusCode; + this.Headers = headers; + this.Resource = throughputProperties; + this.Diagnostics = diagnostics; + } + + /// + public override Headers Headers { get; } + + /// + public override AutopilotThroughputProperties Resource { get; } + + /// + public override HttpStatusCode StatusCode { get; } + + /// + public override CosmosDiagnostics Diagnostics { get; } + + /// + public override double RequestCharge => this.Headers?.RequestCharge ?? 0; + + /// + public override string ActivityId => this.Headers?.ActivityId; + + /// + public override string ETag => this.Headers?.ETag; + + /// + /// Gets minimum throughput in measurement of request units per second in the Azure Cosmos service. + /// + public int? MinThroughput + { + get + { + if (this.Headers?.GetHeaderValue(WFConstants.BackendHeaders.MinimumRUsForOffer) != null) + { + return int.Parse(this.Headers.GetHeaderValue(WFConstants.BackendHeaders.MinimumRUsForOffer)); + } + return null; + } + } + + /// + /// Gets the status whether offer replace is successful or pending. + /// + public bool? IsReplacePending + { + get + { + if (this.Headers.GetHeaderValue(WFConstants.BackendHeaders.OfferReplacePending) != null) + { + return Boolean.Parse(this.Headers.GetHeaderValue(WFConstants.BackendHeaders.OfferReplacePending)); + } + return null; + } + } + + /// + /// Get implicitly from + /// + /// Throughput response + public static implicit operator AutopilotThroughputProperties(AutopilotThroughputResponse response) + { + return response.Resource; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index d0698e5ad3..39a1c0ea4f 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -30,7 +30,7 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); return await this.GetThroughputResponseAsync( streamPayload: null, @@ -41,12 +41,28 @@ internal async Task ReadThroughputAsync( cancellationToken: cancellationToken); } + internal async Task ReadAutopilotThroughputAsync( + string targetRID, + RequestOptions requestOptions, + CancellationToken cancellationToken = default(CancellationToken)) + { + OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + + return await this.GetAutopilotThroughputResponseAsync( + streamPayload: null, + operationType: OperationType.Read, + linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), + resourceType: ResourceType.Offer, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + internal async Task ReadThroughputIfExistsAsync( string targetRID, RequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); + OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); if (offerV2 == null) { @@ -72,7 +88,7 @@ internal async Task ReplaceThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); OfferV2 newOffer = new OfferV2(offerV2, throughput); return await this.GetThroughputResponseAsync( @@ -84,6 +100,24 @@ internal async Task ReplaceThroughputAsync( cancellationToken: cancellationToken); } + internal async Task ReplaceAutoPilotThroughputAsync( + string targetRID, + AutopilotThroughputProperties userAutopilotProperties, + RequestOptions requestOptions, + CancellationToken cancellationToken) + { + AutopilotThroughputProperties currentProperty = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + currentProperty.Content = userAutopilotProperties.Content; + + return await this.GetAutopilotThroughputResponseAsync( + streamPayload: this.ClientContext.SerializerCore.ToStream(currentProperty), + operationType: OperationType.Replace, + linkUri: new Uri(currentProperty.SelfLink, UriKind.Relative), + resourceType: ResourceType.Offer, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + internal async Task ReplaceThroughputIfExistsAsync( string targetRID, int throughput, @@ -92,7 +126,7 @@ internal async Task ReplaceThroughputIfExistsAsync( { try { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); OfferV2 newOffer = new OfferV2(offerV2, throughput); return await this.GetThroughputResponseAsync( @@ -123,7 +157,7 @@ internal async Task ReplaceThroughputIfExistsAsync( } } - private async Task GetOfferV2Async( + private async Task GetOfferV2Async( string targetRID, bool failIfNotConfigured, CancellationToken cancellationToken) @@ -136,12 +170,12 @@ private async Task GetOfferV2Async( QueryDefinition queryDefinition = new QueryDefinition("select * from root r where r.offerResourceId= @targetRID"); queryDefinition.WithParameter("@targetRID", targetRID); - FeedIterator databaseStreamIterator = this.GetOfferQueryIterator( + FeedIterator databaseStreamIterator = this.GetOfferQueryIterator( queryDefinition: queryDefinition, continuationToken: null, requestOptions: null, cancellationToken: cancellationToken); - OfferV2 offerV2 = await this.SingleOrDefaultAsync(databaseStreamIterator); + T offerV2 = await this.SingleOrDefaultAsync(databaseStreamIterator); if (offerV2 == null && failIfNotConfigured) @@ -228,5 +262,27 @@ private async Task GetThroughputResponseAsync( return await this.ClientContext.ResponseFactory.CreateThroughputResponseAsync(responseMessage); } + private async Task GetAutopilotThroughputResponseAsync( + Stream streamPayload, + OperationType operationType, + Uri linkUri, + ResourceType resourceType, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Task responseMessage = this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: linkUri, + resourceType: resourceType, + operationType: operationType, + cosmosContainerCore: null, + partitionKey: null, + streamPayload: streamPayload, + requestOptions: requestOptions, + requestEnricher: null, + diagnosticsContext: null, + cancellationToken: cancellationToken); + + return await this.ClientContext.ResponseFactory.CreateAutopilotThroughputResponseAsync(responseMessage); + } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs new file mode 100644 index 0000000000..aa3b5a0f0d --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs @@ -0,0 +1,36 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using Microsoft.Azure.Documents; + using Newtonsoft.Json; + + internal sealed class OfferAutopilotProperties + { + /// + /// Default constructor for serialization + /// + [JsonConstructor] + private OfferAutopilotProperties() + { + } + + internal OfferAutopilotProperties(int maxThroughput) + { + this.MaxThroughput = maxThroughput; + } + + /// + /// The maximum throughput the autopilot will scale to. + /// + [JsonProperty(PropertyName = Constants.Properties.AutopilotMaxThroughput, NullValueHandling = NullValueHandling.Ignore)] + public int? MaxThroughput { get; private set; } + + internal string GetJsonString() + { + return JsonConvert.SerializeObject(this, Formatting.None); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs new file mode 100644 index 0000000000..7c6622e0e2 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + using Microsoft.Azure.Documents; + using Newtonsoft.Json; + + internal sealed class OfferContentProperties + { + /// + /// Default constructor for serialization + /// + [JsonConstructor] + private OfferContentProperties() + { + } + + private OfferContentProperties(int fixedThroughput) + { + this.OfferThroughput = fixedThroughput; + this.OfferAutopilotSettings = null; + } + + private OfferContentProperties(OfferAutopilotProperties autopilotProperties) + { + this.OfferThroughput = null; + this.OfferAutopilotSettings = autopilotProperties ?? throw new ArgumentNullException(nameof(autopilotProperties)); + } + + /// + /// Represents customizable throughput chosen by user for his collection in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferThroughput, DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? OfferThroughput { get; private set; } + + /// + /// Represents customizable throughput chosen by user for his collection in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.AutopilotSettings, DefaultValueHandling = DefaultValueHandling.Ignore)] + public OfferAutopilotProperties OfferAutopilotSettings { get; private set; } + + public static OfferContentProperties CreateFixedOfferConent(int throughput) + { + return new OfferContentProperties(fixedThroughput: throughput); + } + + public static OfferContentProperties CreateAutoPilotOfferConent(int maxThroughput) + { + OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties(maxThroughput); + return new OfferContentProperties(autopilotProperties); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs similarity index 87% rename from Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs rename to Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs index 9c0ecf7680..64d4d36a74 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs @@ -49,10 +49,11 @@ public class ThroughputProperties /// /// Gets the provisioned throughput for a resource in measurement of request units per second in the Azure Cosmos service. /// + [JsonIgnore] public int? Throughput { get => this.Content?.OfferThroughput; - private set => this.Content = new OfferContentV2(value.Value); + private set => this.Content = OfferContentProperties.CreateFixedOfferConent(value.Value); } /// @@ -79,6 +80,12 @@ public int? Throughput internal string ResourceRID { get; private set; } [JsonProperty(PropertyName = "content", DefaultValueHandling = DefaultValueHandling.Ignore)] - private OfferContentV2 Content { get; set; } + internal OfferContentProperties Content { get; set; } + + /// + /// Gets the version of this offer resource in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] + internal string OfferVersion { get; private set; } = Constants.Offers.OfferVersion_V2; } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Throughput/ThroughputResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputResponse.cs similarity index 100% rename from Microsoft.Azure.Cosmos/src/Resource/Throughput/ThroughputResponse.cs rename to Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputResponse.cs diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs index 8bad357710..4484a83de5 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs @@ -125,7 +125,8 @@ private CosmosSerializer GetSerializer() inputType == typeof(ConflictProperties) || inputType == typeof(ThroughputProperties) || inputType == typeof(OfferV2) || - inputType == typeof(PartitionedQueryExecutionInfo)) + inputType == typeof(PartitionedQueryExecutionInfo) || + inputType == typeof(AutopilotThroughputProperties)) { return CosmosSerializerCore.propertiesSerializer; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosContainerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosContainerTests.cs index 4b32bba569..f15e6c99db 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosContainerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosContainerTests.cs @@ -854,7 +854,7 @@ public async Task ReadReplaceThroughputResponseTests() (cosmosClientBuilder) => cosmosClientBuilder.WithCustomSerializer(mockJsonSerializer)); int databaseThroughput = 10000; - Cosmos.Database databaseNoThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), null); + Cosmos.Database databaseNoThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), throughput: null); Cosmos.Database databaseWithThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), databaseThroughput, null); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs new file mode 100644 index 0000000000..528cec0c6d --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests +{ + using System; + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class CosmosThroughputTests + { + private CosmosClient cosmosClient = null; + + [TestInitialize] + public void TestInit() + { + this.cosmosClient = TestCommon.CreateCosmosClient(); + } + + [TestCleanup] + public void TestCleanup() + { + if (this.cosmosClient == null) + { + return; + } + + this.cosmosClient.Dispose(); + } + + [TestMethod] + public async Task CreateDropAutopilotDatabase() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString(), + new AutopilotThroughputProperties(5000)); + + AutopilotThroughputResponse autopilot = await database.ReadAutopilotThroughputAsync(); + Assert.IsNotNull(autopilot); + Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); + + AutopilotThroughputResponse autopilotReplaced = await database.ReplaceAutopilotThroughputAsync( + new AutopilotThroughputProperties(10000)); + Assert.IsNotNull(autopilotReplaced); + Assert.AreEqual(10000, autopilotReplaced.Resource.MaxThroughput); + + await database.DeleteAsync(); + } + + [TestMethod] + public async Task CreateDropAutopilotContainer() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString()); + + ContainerCore container = (ContainerInlineCore)await database.CreateContainerAsync( + new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), + new AutopilotThroughputProperties(5000)); + Assert.IsNotNull(container); + + AutopilotThroughputResponse autopilot = await container.ReadAutopilotThroughputAsync(); + Assert.IsNotNull(autopilot); + Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); + + AutopilotThroughputResponse autopilotReplaced = await container.ReplaceAutopilotThroughputAsync( + new AutopilotThroughputProperties(10000)); + Assert.IsNotNull(autopilotReplaced); + Assert.AreEqual(10000, autopilotReplaced.Resource.MaxThroughput); + + await database.DeleteAsync(); + } + + [TestMethod] + public async Task ReadFixedWithAutopilotTests() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString()); + + ContainerCore autopilotContainer = (ContainerInlineCore)await database.CreateContainerAsync( + new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), + new AutopilotThroughputProperties(5000)); + Assert.IsNotNull(autopilotContainer); + + // Reading a autopilot container with fixed results + int? throughput = await autopilotContainer.ReadThroughputAsync(); + Assert.IsNotNull(throughput); + + await database.DeleteAsync(); + } + + [TestMethod] + public async Task ReadAutoPilotWithFixedTests() + { + Database database = await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString()); + + ContainerCore fixedContainer = (ContainerInlineCore)await database.CreateContainerAsync( + new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), + throughput: 1000); + Assert.IsNotNull(fixedContainer); + + int? throughput = await fixedContainer.ReadThroughputAsync(); + Assert.AreEqual(1000, throughput); + + // Reading a fixed container with autopilot results in max throughput being null + AutopilotThroughputResponse autopilot = await fixedContainer.ReadAutopilotThroughputAsync(); + Assert.IsNotNull(autopilot); + Assert.IsNotNull(autopilot.Resource.Throughput); + Assert.AreEqual(1000, autopilot.Resource.Throughput); + Assert.IsNull(autopilot.Resource.MaxThroughput); + + await database.DeleteAsync(); + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs new file mode 100644 index 0000000000..9108fbb40f --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Azure.Documents; + using Microsoft.Azure.Cosmos.Handlers; + using Microsoft.Azure.Cosmos.Routing; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using System.IO; + + [TestClass] + public class CosmosThroughputTests + { + [TestMethod] + public async Task AutopilotThroughputSerializationTest() + { + AutopilotThroughputProperties autopilotThroughputProperties = new AutopilotThroughputProperties(1000); + Assert.AreEqual(1000, autopilotThroughputProperties.MaxThroughput); + Assert.IsNull(autopilotThroughputProperties.Throughput); + + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotThroughputProperties)) + { + using(StreamReader reader = new StreamReader(stream)) + { + string output = await reader.ReadToEndAsync(); + Assert.IsNotNull(output); + Assert.AreEqual("{\"content\":{\"offerAutopilotSettings\":{\"maxThroughput\":1000}},\"offerVersion\":\"V2\"}", output); + } + } + + OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties(1000); + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotProperties)) + { + using (StreamReader reader = new StreamReader(stream)) + { + string output = await reader.ReadToEndAsync(); + Assert.IsNotNull(output); + Assert.AreEqual("{\"maxThroughput\":1000}", output); + } + } + + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotProperties)) + { + OfferAutopilotProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); + Assert.IsNotNull(fromStream); + Assert.AreEqual(1000, fromStream.MaxThroughput); + } + + OfferContentProperties content = OfferContentProperties.CreateAutoPilotOfferConent(1000); + using (Stream stream = MockCosmosUtil.Serializer.ToStream(content)) + { + using (StreamReader reader = new StreamReader(stream)) + { + string output = await reader.ReadToEndAsync(); + Assert.IsNotNull(output); + Assert.AreEqual("{\"offerAutopilotSettings\":{\"maxThroughput\":1000}}", output); + } + } + + using (Stream stream = MockCosmosUtil.Serializer.ToStream(content)) + { + OfferContentProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); + Assert.IsNotNull(fromStream.OfferAutopilotSettings); + Assert.AreEqual(1000, fromStream.OfferAutopilotSettings.MaxThroughput); + Assert.IsNull(fromStream.OfferThroughput); + } + + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotThroughputProperties)) + { + AutopilotThroughputProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); + Assert.AreEqual(1000, fromStream.MaxThroughput); + Assert.IsNull(fromStream.Throughput); ; + } + } + } +} From 2fa539dc6ce8f6ff76c040902023274d2add750b Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 04:48:00 -0700 Subject: [PATCH 02/15] Fixed contract changes --- .../src/Resource/Offer/AutopilotThroughputProperties.cs | 3 +++ .../src/Resource/Offer/ThroughputProperties.cs | 3 +-- .../CosmosThroughputTests.cs | 2 ++ .../Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs index 3afed8c5d2..2c49a0e253 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs @@ -37,6 +37,9 @@ public AutopilotThroughputProperties(int maxThroughput) this.MaxThroughput = maxThroughput; } + [JsonIgnore] + public override int? Throughput => base.Throughput; + /// /// The maximum throughput the autopilot will scale to. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs index 64d4d36a74..ba829339d4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs @@ -49,8 +49,7 @@ public class ThroughputProperties /// /// Gets the provisioned throughput for a resource in measurement of request units per second in the Azure Cosmos service. /// - [JsonIgnore] - public int? Throughput + public virtual int? Throughput { get => this.Content?.OfferThroughput; private set => this.Content = OfferContentProperties.CreateFixedOfferConent(value.Value); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 528cec0c6d..effbc364f0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -50,6 +50,7 @@ public async Task CreateDropAutopilotDatabase() } [TestMethod] + [Ignore] // Not currently working with emulator public async Task CreateDropAutopilotContainer() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( @@ -73,6 +74,7 @@ public async Task CreateDropAutopilotContainer() } [TestMethod] + [Ignore] // Not currently working with emulator public async Task ReadFixedWithAutopilotTests() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs index 05d9b87327..5489f16830 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs @@ -146,7 +146,7 @@ public void ValidateCustomSerializerNotUsedForInternalTypes() $@"{{""id"":""{id}"",""operationType"":""Invalid"",""resourceType"":null,""resourceId"":null,""content"":null,""conflict_lsn"":0}}"); // Throughput doesn't have an id. - string defaultThroughputJson = @"{""Throughput"":null}"; + string defaultThroughputJson = @"{""Throughput"":null,""offerVersion"":""V2""}"; ThroughputProperties property = JsonConvert.DeserializeObject(defaultThroughputJson); Assert.IsNull(property.Throughput); string propertyJson = JsonConvert.SerializeObject(property); From c10123eda10ba1e543f45522009de052778f810d Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 06:20:21 -0700 Subject: [PATCH 03/15] Adding auto upgrade policy --- .../Offer/AutopilotThroughputProperties.cs | 26 ++++++++++- .../OfferAutopilotAutoUpgradeProperties.cs | 44 +++++++++++++++++++ .../Offer/OfferAutopilotProperties.cs | 15 +++++++ .../Resource/Offer/OfferContentProperties.cs | 10 +++++ .../CosmosThroughputTests.cs | 36 ++++++++++++++- 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs index 2c49a0e253..4e682da999 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs @@ -34,7 +34,21 @@ private AutopilotThroughputProperties() /// The maximum throughput the resource can scale to. public AutopilotThroughputProperties(int maxThroughput) { - this.MaxThroughput = maxThroughput; + this.Content = OfferContentProperties.CreateAutoPilotOfferConent(maxThroughput); + } + + /// + /// The AutopilotThroughputProperties constructor + /// + /// The maximum throughput the resource can scale to. + /// This scales the maximum throughput by the percentage if maximum throughput is not enough + public AutopilotThroughputProperties( + int startingMaxThroughput, + int autoUpgradeMaxThroughputIncrementPercentage) + { + this.Content = OfferContentProperties.CreateAutoPilotOfferConent( + startingMaxThroughput, + autoUpgradeMaxThroughputIncrementPercentage); } [JsonIgnore] @@ -47,7 +61,15 @@ public AutopilotThroughputProperties(int maxThroughput) public int? MaxThroughput { get => this.Content?.OfferAutopilotSettings?.MaxThroughput; - private set => this.Content = OfferContentProperties.CreateAutoPilotOfferConent(value.Value); + } + + /// + /// The amount to increment if the maximum RUs is getting throttled. + /// + [JsonIgnore] + public int? AutoUpgradeMaxThroughputIncrementPercentage + { + get => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs new file mode 100644 index 0000000000..0e1555c35d --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs @@ -0,0 +1,44 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using Microsoft.Azure.Documents; + using Newtonsoft.Json; + + internal sealed class OfferAutopilotAutoUpgradeProperties + { + /// + /// Default constructor for serialization + /// + [JsonConstructor] + private OfferAutopilotAutoUpgradeProperties() + { + } + + internal OfferAutopilotAutoUpgradeProperties(int incrementPercent) + { + this.ThroughputProperties = new AutoPilotThroughputProperties(incrementPercent); + } + + [JsonProperty(PropertyName = Constants.Properties.AutopilotThroughputPolicy, NullValueHandling = NullValueHandling.Ignore)] + public AutoPilotThroughputProperties ThroughputProperties { get; private set; } + + internal string GetJsonString() + { + return JsonConvert.SerializeObject(this, Formatting.None); + } + + public class AutoPilotThroughputProperties + { + public AutoPilotThroughputProperties(int incrementPercent) + { + this.IncrementPercent = incrementPercent; + } + + [JsonProperty(PropertyName = Constants.Properties.AutopilotThroughputPolicyIncrementPercent, NullValueHandling = NullValueHandling.Ignore)] + public int IncrementPercent { get; private set; } + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs index aa3b5a0f0d..bd11a12bd1 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs @@ -20,6 +20,15 @@ private OfferAutopilotProperties() internal OfferAutopilotProperties(int maxThroughput) { this.MaxThroughput = maxThroughput; + this.AutopilotAutoUpgradeProperties = null; + } + + internal OfferAutopilotProperties( + int startingMaxThroughput, + int autoUpgradeMaxThroughputIncrementPercentage) + { + this.MaxThroughput = startingMaxThroughput; + this.AutopilotAutoUpgradeProperties = new OfferAutopilotAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage); } /// @@ -28,6 +37,12 @@ internal OfferAutopilotProperties(int maxThroughput) [JsonProperty(PropertyName = Constants.Properties.AutopilotMaxThroughput, NullValueHandling = NullValueHandling.Ignore)] public int? MaxThroughput { get; private set; } + /// + /// Scales the maximum through put automatically + /// + [JsonProperty(PropertyName = Constants.Properties.AutopilotAutoUpgradePolicy, NullValueHandling = NullValueHandling.Ignore)] + public OfferAutopilotAutoUpgradeProperties AutopilotAutoUpgradeProperties { get; private set; } + internal string GetJsonString() { return JsonConvert.SerializeObject(this, Formatting.None); diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs index 7c6622e0e2..ea57713079 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs @@ -52,5 +52,15 @@ public static OfferContentProperties CreateAutoPilotOfferConent(int maxThroughpu OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties(maxThroughput); return new OfferContentProperties(autopilotProperties); } + + public static OfferContentProperties CreateAutoPilotOfferConent( + int startingMaxThroughput, + int autoUpgradeMaxThroughputIncrementPercentage) + { + OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties( + startingMaxThroughput, + autoUpgradeMaxThroughputIncrementPercentage); + return new OfferContentProperties(autopilotProperties); + } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index effbc364f0..7a3329aa80 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -34,7 +34,7 @@ public void TestCleanup() public async Task CreateDropAutopilotDatabase() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( - Guid.NewGuid().ToString(), + nameof(CreateDropAutopilotDatabase) + Guid.NewGuid().ToString(), new AutopilotThroughputProperties(5000)); AutopilotThroughputResponse autopilot = await database.ReadAutopilotThroughputAsync(); @@ -49,6 +49,40 @@ public async Task CreateDropAutopilotDatabase() await database.DeleteAsync(); } + [TestMethod] + public async Task CreateDropAutopilotAutoUpgradeDatabase() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + nameof(CreateDropAutopilotAutoUpgradeDatabase) + Guid.NewGuid(), + new AutopilotThroughputProperties( + startingMaxThroughput: 5000, + autoUpgradeMaxThroughputIncrementPercentage: 10)); + + // Container is required to validate database throughput upgrade scenarios + Container container = await database.CreateContainerAsync("Test", "/id"); + + AutopilotThroughputResponse autopilot = await database.ReadAutopilotThroughputAsync(); + Assert.IsNotNull(autopilot); + Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); + Assert.AreEqual(10, autopilot.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + AutopilotThroughputResponse autopilotReplaced = await database.ReplaceAutopilotThroughputAsync( + new AutopilotThroughputProperties(6000)); + Assert.IsNotNull(autopilotReplaced); + Assert.AreEqual(6000, autopilotReplaced.Resource.MaxThroughput); + Assert.IsNull(autopilotReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + AutopilotThroughputResponse autoUpgradeReplace = await database.ReplaceAutopilotThroughputAsync( + new AutopilotThroughputProperties( + startingMaxThroughput: 7000, + autoUpgradeMaxThroughputIncrementPercentage: 20)); + Assert.IsNotNull(autoUpgradeReplace); + Assert.AreEqual(7000, autoUpgradeReplace.Resource.MaxThroughput); + Assert.AreEqual(20, autoUpgradeReplace.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + await database.DeleteAsync(); + } + [TestMethod] [Ignore] // Not currently working with emulator public async Task CreateDropAutopilotContainer() From 9670f814c68b311b907fed0193ff4f51d5a72e4a Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 06:24:20 -0700 Subject: [PATCH 04/15] Fixed tests --- .../src/Resource/Offer/AutopilotThroughputProperties.cs | 8 ++++++++ .../src/Resource/Offer/ThroughputProperties.cs | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs index 4e682da999..88e368ab6f 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs @@ -3,6 +3,7 @@ // ------------------------------------------------------------ namespace Microsoft.Azure.Cosmos { + using Microsoft.Azure.Documents; using Newtonsoft.Json; /// @@ -51,6 +52,7 @@ public AutopilotThroughputProperties( autoUpgradeMaxThroughputIncrementPercentage); } + /// [JsonIgnore] public override int? Throughput => base.Throughput; @@ -71,5 +73,11 @@ public int? AutoUpgradeMaxThroughputIncrementPercentage { get => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; } + + /// + /// Gets the version of this offer resource in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] + internal string OfferVersion { get; private set; } = Constants.Offers.OfferVersion_V2; } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs index ba829339d4..3d5973d9d9 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs @@ -80,11 +80,5 @@ public virtual int? Throughput [JsonProperty(PropertyName = "content", DefaultValueHandling = DefaultValueHandling.Ignore)] internal OfferContentProperties Content { get; set; } - - /// - /// Gets the version of this offer resource in the Azure Cosmos DB service. - /// - [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] - internal string OfferVersion { get; private set; } = Constants.Offers.OfferVersion_V2; } } From 3d5b16f32434b902113a89ceaf10fe18263b9612 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 09:33:23 -0700 Subject: [PATCH 05/15] Fixed unit test --- .../Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs index 5489f16830..05d9b87327 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs @@ -146,7 +146,7 @@ public void ValidateCustomSerializerNotUsedForInternalTypes() $@"{{""id"":""{id}"",""operationType"":""Invalid"",""resourceType"":null,""resourceId"":null,""content"":null,""conflict_lsn"":0}}"); // Throughput doesn't have an id. - string defaultThroughputJson = @"{""Throughput"":null,""offerVersion"":""V2""}"; + string defaultThroughputJson = @"{""Throughput"":null}"; ThroughputProperties property = JsonConvert.DeserializeObject(defaultThroughputJson); Assert.IsNull(property.Throughput); string propertyJson = JsonConvert.SerializeObject(property); From 3d43e78728b38ed571f2a65360f3e8bc78b48de2 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 09:57:09 -0700 Subject: [PATCH 06/15] Updated unit test --- .../tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs index 9108fbb40f..c264011498 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs @@ -31,7 +31,7 @@ public async Task AutopilotThroughputSerializationTest() { string output = await reader.ReadToEndAsync(); Assert.IsNotNull(output); - Assert.AreEqual("{\"content\":{\"offerAutopilotSettings\":{\"maxThroughput\":1000}},\"offerVersion\":\"V2\"}", output); + Assert.AreEqual("{\"offerVersion\":\"V2\",\"content\":{\"offerAutopilotSettings\":{\"maxThroughput\":1000}}}", output); } } From d3c84bd1874e84ab96d7e1848109cf2788dd08c6 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 13:17:42 -0700 Subject: [PATCH 07/15] Converted to use ThroughputProperties as a UnionType --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 18 +-- .../src/Handler/RequestMessage.cs | 15 +- .../src/Resource/Container/Container.cs | 6 +- .../src/Resource/Container/ContainerCore.cs | 24 +--- .../Resource/Container/ContainerInlineCore.cs | 8 +- .../src/Resource/CosmosResponseFactory.cs | 15 -- .../src/Resource/Database/Database.cs | 46 +------ .../src/Resource/Database/DatabaseCore.cs | 29 ++-- .../Resource/Database/DatabaseInlineCore.cs | 18 +-- .../Offer/AutopilotThroughputProperties.cs | 83 ----------- .../Offer/AutopilotThroughputResponse.cs | 105 -------------- .../src/Resource/Offer/CosmosOffers.cs | 105 +++++--------- ...=> OfferAutoscaleAutoUpgradeProperties.cs} | 6 +- ...perties.cs => OfferAutoscaleProperties.cs} | 12 +- .../Resource/Offer/OfferContentProperties.cs | 22 ++- .../Resource/Offer/ThroughputProperties.cs | 115 +++++++++++++++- .../src/Serializer/CosmosSerializerCore.cs | 3 +- .../CosmosThroughputTests.cs | 129 ++++++++++++------ .../CosmosSerializerCoreTests.cs | 2 +- .../CosmosThroughputTests.cs | 37 ++--- .../DotNetSDKAPI.json | 6 +- 21 files changed, 331 insertions(+), 473 deletions(-) delete mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs delete mode 100644 Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs rename Microsoft.Azure.Cosmos/src/Resource/Offer/{OfferAutopilotAutoUpgradeProperties.cs => OfferAutoscaleAutoUpgradeProperties.cs} (88%) rename Microsoft.Azure.Cosmos/src/Resource/Offer/{OfferAutopilotProperties.cs => OfferAutoscaleProperties.cs} (78%) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index ff2a7a68bb..e5ee901e2c 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -387,7 +387,7 @@ public virtual Task CreateDatabaseAsync( /// required in order to access and successfully complete any action using the User APIs. /// /// The database id. - /// (Optional) The throughput provisioned for a database in measurement of Request Units per second in the Azure Cosmos DB service. + /// (Optional) The throughput provisioned for a database in measurement of Request Units per second in the Azure Cosmos DB service. /// (Optional) A set of options that can be set. /// (Optional) representing request cancellation. /// A containing a which wraps a containing the resource record. @@ -399,7 +399,7 @@ public virtual Task CreateDatabaseAsync( #endif virtual Task CreateDatabaseAsync( string id, - AutopilotThroughputProperties autopilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { @@ -409,9 +409,9 @@ virtual Task CreateDatabaseAsync( } DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); - return TaskHelper.RunInlineIfNeededAsync(() => this.CreateAutopilotDatabaseAsync( + return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseAsync( databaseProperties: databaseProperties, - autopilotThroughput: autopilotThroughput, + throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken)); } @@ -750,15 +750,15 @@ internal DatabaseProperties PrepareDatabaseProperties(string id) return databaseProperties; } - internal Task CreateAutopilotDatabaseAsync( + internal Task CreateDatabaseAsync( DatabaseProperties databaseProperties, - AutopilotThroughputProperties autopilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { Task response = this.CreateAutopilotDatabaseStreamInternalAsync( streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), - autopilotThroughput: autopilotThroughput, + throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -782,7 +782,7 @@ internal Task CreateDatabaseAsync( private Task CreateAutopilotDatabaseStreamInternalAsync( Stream streamPayload, - AutopilotThroughputProperties autopilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { @@ -794,7 +794,7 @@ private Task CreateAutopilotDatabaseStreamInternalAsync( cosmosContainerCore: null, partitionKey: null, streamPayload: streamPayload, - requestEnricher: (httpRequestMessage) => httpRequestMessage.AddAutoPilotThroughputHeader(autopilotThroughput?.Content?.OfferAutopilotSettings), + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), diagnosticsContext: null, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs index 1f005ad665..0aff8fc12a 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs @@ -169,16 +169,21 @@ internal void AddThroughputHeader(int? throughputValue) } } - internal void AddAutoPilotThroughputHeader(OfferAutopilotProperties offerAutopilotProperties) + internal void AddThroughputPropertiesHeader(ThroughputProperties throughputProperties) { - if (this.Headers.OfferThroughput != null) + if (throughputProperties.Throughput.HasValue && + (throughputProperties.MaxThroughput.HasValue || throughputProperties.AutoUpgradeMaxThroughputIncrementPercentage.HasValue)) { - throw new InvalidOperationException("Autopilot can not be configured with fixed offer"); + throw new InvalidOperationException("Autoscale provisioned throughput can not be configured with fixed offer"); } - if (offerAutopilotProperties != null) + if (throughputProperties.Throughput.HasValue) { - this.Headers.Add(HttpConstants.HttpHeaders.OfferAutopilotSettings, offerAutopilotProperties.GetJsonString()); + this.AddThroughputHeader(throughputProperties.Throughput); + } + else if (throughputProperties?.Content?.OfferAutopilotSettings != null) + { + this.Headers.Add(HttpConstants.HttpHeaders.OfferAutopilotSettings, throughputProperties.Content.OfferAutopilotSettings.GetJsonString()); } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs index 1496b37d9b..bc0bf1fa2a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs @@ -300,7 +300,7 @@ public abstract Task ReplaceThroughputAsync( /// The options for the throughput request. /// (Optional) representing request cancellation. /// The throughput response. - public abstract Task ReadAutopilotThroughputAsync( + public abstract Task ReadThroughputPropertiesAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); @@ -314,8 +314,8 @@ public abstract Task ReadAutopilotThroughputAsync( /// /// Request Units /// - public abstract Task ReplaceAutopilotThroughputAsync( - AutopilotThroughputProperties throughputProperties, + public abstract Task ReplaceThroughputPropertiesAsync( + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); #endif diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs index 794283357a..a5a4c9badd 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs @@ -167,32 +167,14 @@ public override #else internal #endif - async Task ReadAutopilotThroughputAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default) - { - string rid = await this.GetRIDAsync(cancellationToken); - - CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReadAutopilotThroughputAsync( - targetRID: rid, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - } - -#if INTERNAL - public override -#else - internal -#endif - async Task ReplaceAutopilotThroughputAsync( - AutopilotThroughputProperties throughputProperties, + async Task ReplaceThroughputPropertiesAsync( + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReplaceAutoPilotThroughputAsync( + return await cosmosOffers.ReplaceThroughputPropertiesAsync( rid, throughputProperties, requestOptions, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs index 7a872eb69e..e0fcf911ba 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs @@ -105,9 +105,9 @@ public override #else internal #endif - Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) + Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReadAutopilotThroughputAsync(requestOptions, cancellationToken)); + return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReadThroughputAsync(requestOptions, cancellationToken)); } #if INTERNAL @@ -115,9 +115,9 @@ public override #else internal #endif - Task ReplaceAutopilotThroughputAsync(AutopilotThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + Task ReplaceAutopilotThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReplaceAutopilotThroughputAsync(throughputProperties, requestOptions, cancellationToken)); + return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReplaceThroughputPropertiesAsync(throughputProperties, requestOptions, cancellationToken)); } public override Task CreateItemStreamAsync( diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs index 7846dca0ca..204153bd2d 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs @@ -196,21 +196,6 @@ internal Task CreateThroughputResponseAsync( }); } - internal Task CreateAutopilotThroughputResponseAsync( - Task cosmosResponseMessageTask) - { - return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => - { - cosmosResponseMessage.Content.Position = 0; - AutopilotThroughputProperties throughputProperties = this.ToObjectInternal(cosmosResponseMessage); - return new AutopilotThroughputResponse( - cosmosResponseMessage.StatusCode, - cosmosResponseMessage.Headers, - throughputProperties, - cosmosResponseMessage.Diagnostics); - }); - } - internal Task> CreateStoredProcedureExecuteResponseAsync(Task cosmosResponseMessageTask) { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index 4a5d0b7a64..11439ecf1a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -159,46 +159,6 @@ public abstract Task ReadThroughputAsync( CancellationToken cancellationToken = default(CancellationToken)); #if INTERNAL - /// - /// Gets database throughput in measurement of request units per second in the Azure Cosmos service. - /// - /// The options for the throughput request. - /// (Optional) representing request cancellation. - /// The throughput response. - /// - /// The provisioned throughput for this database. - /// - /// - /// Null value indicates a database with no throughput provisioned. - /// - /// Request Units - /// Set throughput on a database - /// - /// The following example shows how to get the throughput - /// - /// - /// - /// - /// - /// The following example shows how to get throughput, MinThroughput and is replace in progress - /// - /// - /// - /// - public abstract Task ReadAutopilotThroughputAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)); - /// /// Sets throughput provisioned for a database in measurement of request units per second in the Azure Cosmos service. /// @@ -213,15 +173,15 @@ public abstract Task ReadAutopilotThroughputAsync( /// The following example shows how to get the throughput. /// /// /// /// /// /// Request Units /// - public abstract Task ReplaceAutopilotThroughputAsync( - AutopilotThroughputProperties throughputProperties, + public abstract Task ReplaceThroughputPropertiesAsync( + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index 5f54e6a1d1..bc9542d7cb 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -129,7 +129,7 @@ public override #endif Task CreateContainerAsync( ContainerProperties containerProperties, - AutopilotThroughputProperties autopilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { @@ -142,7 +142,7 @@ Task CreateContainerAsync( Task response = this.ProcessCollectionCreateAsync( streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), - autoPilotThroughput: autopilotThroughput, + throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -154,33 +154,30 @@ public override #else internal #endif - async Task ReadAutopilotThroughputAsync( + async Task ReplaceThroughputPropertiesAsync( + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReadAutopilotThroughputAsync( + return await cosmosOffers.ReplaceThroughputPropertiesAsync( targetRID: rid, + throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); } -#if INTERNAL - public override -#else - internal -#endif - async Task ReplaceAutopilotThroughputAsync( - AutopilotThroughputProperties throughputProperties, + internal async Task ReplaceThroughputPropertiesIfExistsAsync( + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default(CancellationToken)) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReplaceAutoPilotThroughputAsync( + return await cosmosOffers.ReplaceThroughputPropertiesIfExistsAsync( targetRID: rid, - userAutopilotProperties: throughputProperties, + throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -739,7 +736,7 @@ internal void ValidateContainerProperties(ContainerProperties containerPropertie internal Task ProcessCollectionCreateAsync( Stream streamPayload, - AutopilotThroughputProperties autoPilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions, CancellationToken cancellationToken) { @@ -751,7 +748,7 @@ internal Task ProcessCollectionCreateAsync( partitionKey: null, streamPayload: streamPayload, requestOptions: requestOptions, - requestEnricher: (httpRequestMessage) => httpRequestMessage.AddAutoPilotThroughputHeader(autoPilotThroughput?.Content?.OfferAutopilotSettings), + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), diagnosticsContext: null, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index 2fe0656f18..96c18c6f41 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -213,9 +213,9 @@ public override #else internal #endif - Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) + Task ReplaceAutopilotThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReadAutopilotThroughputAsync(requestOptions, cancellationToken)); + return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReplaceThroughputPropertiesAsync(throughputProperties, requestOptions, cancellationToken)); } #if INTERNAL @@ -223,19 +223,9 @@ public override #else internal #endif - Task ReplaceAutopilotThroughputAsync(AutopilotThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + Task CreateContainerAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReplaceAutopilotThroughputAsync(throughputProperties, requestOptions, cancellationToken)); - } - -#if INTERNAL - public override -#else - internal -#endif - Task CreateContainerAsync(ContainerProperties containerProperties, AutopilotThroughputProperties autopilotThroughput, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) - { - return TaskHelper.RunInlineIfNeededAsync(() => this.database.CreateContainerAsync(containerProperties, autopilotThroughput, requestOptions, cancellationToken)); + return TaskHelper.RunInlineIfNeededAsync(() => this.database.CreateContainerAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); } public override Task UpsertUserAsync( diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs deleted file mode 100644 index 88e368ab6f..0000000000 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputProperties.cs +++ /dev/null @@ -1,83 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// ------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos -{ - using Microsoft.Azure.Documents; - using Newtonsoft.Json; - - /// - /// Represents a throughput of the resources in the Azure Cosmos DB service. - /// It is the standard pricing for the resource in the Azure Cosmos DB service. - /// - /// - /// It contains provisioned container throughput in measurement of request units per second in the Azure Cosmos service. - /// Refer to http://azure.microsoft.com/documentation/articles/documentdb-performance-levels/ for details on provision offer throughput. - /// -#if INTERNAL - public -#else - internal -#endif - class AutopilotThroughputProperties : ThroughputProperties - { - /// - /// Default constructor for serialization - /// - [JsonConstructor] - private AutopilotThroughputProperties() - { - } - - /// - /// The AutopilotThroughputProperties constructor - /// - /// The maximum throughput the resource can scale to. - public AutopilotThroughputProperties(int maxThroughput) - { - this.Content = OfferContentProperties.CreateAutoPilotOfferConent(maxThroughput); - } - - /// - /// The AutopilotThroughputProperties constructor - /// - /// The maximum throughput the resource can scale to. - /// This scales the maximum throughput by the percentage if maximum throughput is not enough - public AutopilotThroughputProperties( - int startingMaxThroughput, - int autoUpgradeMaxThroughputIncrementPercentage) - { - this.Content = OfferContentProperties.CreateAutoPilotOfferConent( - startingMaxThroughput, - autoUpgradeMaxThroughputIncrementPercentage); - } - - /// - [JsonIgnore] - public override int? Throughput => base.Throughput; - - /// - /// The maximum throughput the autopilot will scale to. - /// - [JsonIgnore] - public int? MaxThroughput - { - get => this.Content?.OfferAutopilotSettings?.MaxThroughput; - } - - /// - /// The amount to increment if the maximum RUs is getting throttled. - /// - [JsonIgnore] - public int? AutoUpgradeMaxThroughputIncrementPercentage - { - get => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; - } - - /// - /// Gets the version of this offer resource in the Azure Cosmos DB service. - /// - [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] - internal string OfferVersion { get; private set; } = Constants.Offers.OfferVersion_V2; - } -} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs deleted file mode 100644 index d4215f049b..0000000000 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/AutopilotThroughputResponse.cs +++ /dev/null @@ -1,105 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// ------------------------------------------------------------ - -namespace Microsoft.Azure.Cosmos -{ - using System; - using System.Net; - using Microsoft.Azure.Documents; - - /// - /// The cosmos throughput response - /// - #if INTERNAL - public -#else - internal -#endif - class AutopilotThroughputResponse : Response - { - /// - /// Create a as a no-op for mock testing - /// - protected AutopilotThroughputResponse() - : base() - { - } - - /// - /// A private constructor to ensure the factory is used to create the object. - /// This will prevent memory leaks when handling the HttpResponseMessage - /// - internal AutopilotThroughputResponse( - HttpStatusCode httpStatusCode, - Headers headers, - AutopilotThroughputProperties throughputProperties, - CosmosDiagnostics diagnostics) - { - this.StatusCode = httpStatusCode; - this.Headers = headers; - this.Resource = throughputProperties; - this.Diagnostics = diagnostics; - } - - /// - public override Headers Headers { get; } - - /// - public override AutopilotThroughputProperties Resource { get; } - - /// - public override HttpStatusCode StatusCode { get; } - - /// - public override CosmosDiagnostics Diagnostics { get; } - - /// - public override double RequestCharge => this.Headers?.RequestCharge ?? 0; - - /// - public override string ActivityId => this.Headers?.ActivityId; - - /// - public override string ETag => this.Headers?.ETag; - - /// - /// Gets minimum throughput in measurement of request units per second in the Azure Cosmos service. - /// - public int? MinThroughput - { - get - { - if (this.Headers?.GetHeaderValue(WFConstants.BackendHeaders.MinimumRUsForOffer) != null) - { - return int.Parse(this.Headers.GetHeaderValue(WFConstants.BackendHeaders.MinimumRUsForOffer)); - } - return null; - } - } - - /// - /// Gets the status whether offer replace is successful or pending. - /// - public bool? IsReplacePending - { - get - { - if (this.Headers.GetHeaderValue(WFConstants.BackendHeaders.OfferReplacePending) != null) - { - return Boolean.Parse(this.Headers.GetHeaderValue(WFConstants.BackendHeaders.OfferReplacePending)); - } - return null; - } - } - - /// - /// Get implicitly from - /// - /// Throughput response - public static implicit operator AutopilotThroughputProperties(AutopilotThroughputResponse response) - { - return response.Resource; - } - } -} diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 39a1c0ea4f..c55d0aaa4e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -41,22 +41,6 @@ internal async Task ReadThroughputAsync( cancellationToken: cancellationToken); } - internal async Task ReadAutopilotThroughputAsync( - string targetRID, - RequestOptions requestOptions, - CancellationToken cancellationToken = default(CancellationToken)) - { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); - - return await this.GetAutopilotThroughputResponseAsync( - streamPayload: null, - operationType: OperationType.Read, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), - resourceType: ResourceType.Offer, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - } - internal async Task ReadThroughputIfExistsAsync( string targetRID, RequestOptions requestOptions, @@ -82,34 +66,16 @@ internal async Task ReadThroughputIfExistsAsync( cancellationToken: cancellationToken); } - internal async Task ReplaceThroughputAsync( - string targetRID, - int throughput, - RequestOptions requestOptions, - CancellationToken cancellationToken = default(CancellationToken)) - { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); - OfferV2 newOffer = new OfferV2(offerV2, throughput); - - return await this.GetThroughputResponseAsync( - streamPayload: this.ClientContext.SerializerCore.ToStream(newOffer), - operationType: OperationType.Replace, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), - resourceType: ResourceType.Offer, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - } - - internal async Task ReplaceAutoPilotThroughputAsync( + internal async Task ReplaceThroughputPropertiesAsync( string targetRID, - AutopilotThroughputProperties userAutopilotProperties, + ThroughputProperties throughputProperties, RequestOptions requestOptions, CancellationToken cancellationToken) { - AutopilotThroughputProperties currentProperty = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); - currentProperty.Content = userAutopilotProperties.Content; + ThroughputProperties currentProperty = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + currentProperty.Content = throughputProperties.Content; - return await this.GetAutopilotThroughputResponseAsync( + return await this.GetThroughputResponseAsync( streamPayload: this.ClientContext.SerializerCore.ToStream(currentProperty), operationType: OperationType.Replace, linkUri: new Uri(currentProperty.SelfLink, UriKind.Relative), @@ -118,21 +84,21 @@ internal async Task ReplaceAutoPilotThroughputAsync cancellationToken: cancellationToken); } - internal async Task ReplaceThroughputIfExistsAsync( + internal async Task ReplaceThroughputPropertiesIfExistsAsync( string targetRID, - int throughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { try { - OfferV2 offerV2 = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); - OfferV2 newOffer = new OfferV2(offerV2, throughput); + ThroughputProperties currentProperty = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + currentProperty.Content = throughputProperties.Content; return await this.GetThroughputResponseAsync( - streamPayload: this.ClientContext.SerializerCore.ToStream(newOffer), + streamPayload: this.ClientContext.SerializerCore.ToStream(currentProperty), operationType: OperationType.Replace, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), + linkUri: new Uri(currentProperty.SelfLink, UriKind.Relative), resourceType: ResourceType.Offer, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -157,6 +123,32 @@ internal async Task ReplaceThroughputIfExistsAsync( } } + internal Task ReplaceThroughputAsync( + string targetRID, + int throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken = default(CancellationToken)) + { + return this.ReplaceThroughputPropertiesAsync( + targetRID, + ThroughputProperties.CreateFixedThroughput(throughput), + requestOptions, + cancellationToken); + } + + internal Task ReplaceThroughputIfExistsAsync( + string targetRID, + int throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken = default(CancellationToken)) + { + return this.ReplaceThroughputPropertiesIfExistsAsync( + targetRID, + ThroughputProperties.CreateFixedThroughput(throughput), + requestOptions, + cancellationToken); + } + private async Task GetOfferV2Async( string targetRID, bool failIfNotConfigured, @@ -261,28 +253,5 @@ private async Task GetThroughputResponseAsync( cancellationToken: cancellationToken); return await this.ClientContext.ResponseFactory.CreateThroughputResponseAsync(responseMessage); } - - private async Task GetAutopilotThroughputResponseAsync( - Stream streamPayload, - OperationType operationType, - Uri linkUri, - ResourceType resourceType, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Task responseMessage = this.ClientContext.ProcessResourceOperationStreamAsync( - resourceUri: linkUri, - resourceType: resourceType, - operationType: operationType, - cosmosContainerCore: null, - partitionKey: null, - streamPayload: streamPayload, - requestOptions: requestOptions, - requestEnricher: null, - diagnosticsContext: null, - cancellationToken: cancellationToken); - - return await this.ClientContext.ResponseFactory.CreateAutopilotThroughputResponseAsync(responseMessage); - } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs similarity index 88% rename from Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs rename to Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs index 0e1555c35d..eaf60c0cba 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotAutoUpgradeProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs @@ -7,17 +7,17 @@ namespace Microsoft.Azure.Cosmos using Microsoft.Azure.Documents; using Newtonsoft.Json; - internal sealed class OfferAutopilotAutoUpgradeProperties + internal sealed class OfferAutoscaleAutoUpgradeProperties { /// /// Default constructor for serialization /// [JsonConstructor] - private OfferAutopilotAutoUpgradeProperties() + private OfferAutoscaleAutoUpgradeProperties() { } - internal OfferAutopilotAutoUpgradeProperties(int incrementPercent) + internal OfferAutoscaleAutoUpgradeProperties(int incrementPercent) { this.ThroughputProperties = new AutoPilotThroughputProperties(incrementPercent); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs similarity index 78% rename from Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs rename to Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs index bd11a12bd1..627c17bd71 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutopilotProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs @@ -7,28 +7,28 @@ namespace Microsoft.Azure.Cosmos using Microsoft.Azure.Documents; using Newtonsoft.Json; - internal sealed class OfferAutopilotProperties + internal sealed class OfferAutoscaleProperties { /// /// Default constructor for serialization /// [JsonConstructor] - private OfferAutopilotProperties() + private OfferAutoscaleProperties() { } - internal OfferAutopilotProperties(int maxThroughput) + internal OfferAutoscaleProperties(int maxThroughput) { this.MaxThroughput = maxThroughput; this.AutopilotAutoUpgradeProperties = null; } - internal OfferAutopilotProperties( + internal OfferAutoscaleProperties( int startingMaxThroughput, int autoUpgradeMaxThroughputIncrementPercentage) { this.MaxThroughput = startingMaxThroughput; - this.AutopilotAutoUpgradeProperties = new OfferAutopilotAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage); + this.AutopilotAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage); } /// @@ -41,7 +41,7 @@ internal OfferAutopilotProperties( /// Scales the maximum through put automatically /// [JsonProperty(PropertyName = Constants.Properties.AutopilotAutoUpgradePolicy, NullValueHandling = NullValueHandling.Ignore)] - public OfferAutopilotAutoUpgradeProperties AutopilotAutoUpgradeProperties { get; private set; } + public OfferAutoscaleAutoUpgradeProperties AutopilotAutoUpgradeProperties { get; private set; } internal string GetJsonString() { diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs index ea57713079..8ee1eb10d8 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs @@ -24,7 +24,7 @@ private OfferContentProperties(int fixedThroughput) this.OfferAutopilotSettings = null; } - private OfferContentProperties(OfferAutopilotProperties autopilotProperties) + private OfferContentProperties(OfferAutoscaleProperties autopilotProperties) { this.OfferThroughput = null; this.OfferAutopilotSettings = autopilotProperties ?? throw new ArgumentNullException(nameof(autopilotProperties)); @@ -40,16 +40,28 @@ private OfferContentProperties(OfferAutopilotProperties autopilotProperties) /// Represents customizable throughput chosen by user for his collection in the Azure Cosmos DB service. /// [JsonProperty(PropertyName = Constants.Properties.AutopilotSettings, DefaultValueHandling = DefaultValueHandling.Ignore)] - public OfferAutopilotProperties OfferAutopilotSettings { get; private set; } + public OfferAutoscaleProperties OfferAutopilotSettings { get; private set; } + + /// + /// Represents Request Units(RU)/Minute throughput is enabled/disabled for collection in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferIsRUPerMinuteThroughputEnabled, DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? OfferIsRUPerMinuteThroughputEnabled { get; private set; } + + /// + /// Represents time stamp when offer was last replaced by user for collection in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferLastReplaceTimestamp, DefaultValueHandling = DefaultValueHandling.Ignore)] + internal long? OfferLastReplaceTimestamp { get; private set; } public static OfferContentProperties CreateFixedOfferConent(int throughput) { return new OfferContentProperties(fixedThroughput: throughput); } - public static OfferContentProperties CreateAutoPilotOfferConent(int maxThroughput) + public static OfferContentProperties CreateAutoscaleOfferConent(int maxThroughput) { - OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties(maxThroughput); + OfferAutoscaleProperties autopilotProperties = new OfferAutoscaleProperties(maxThroughput); return new OfferContentProperties(autopilotProperties); } @@ -57,7 +69,7 @@ public static OfferContentProperties CreateAutoPilotOfferConent( int startingMaxThroughput, int autoUpgradeMaxThroughputIncrementPercentage) { - OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties( + OfferAutoscaleProperties autopilotProperties = new OfferAutoscaleProperties( startingMaxThroughput, autoUpgradeMaxThroughputIncrementPercentage); return new OfferContentProperties(autopilotProperties); diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs index 3d5973d9d9..7f8a1177b9 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs @@ -5,6 +5,7 @@ namespace Microsoft.Azure.Cosmos { using System; + using System.Runtime.CompilerServices; using Microsoft.Azure.Documents; using Newtonsoft.Json; @@ -26,6 +27,22 @@ namespace Microsoft.Azure.Cosmos /// public class ThroughputProperties { + /// + /// Default constructor used for serialization and unit tests + /// + public ThroughputProperties() + { + } + + /// + /// Create a instance for fixed throughput + /// + private ThroughputProperties(OfferContentProperties offerContentProperties) + { + this.OfferVersion = Constants.Offers.OfferVersion_V2; + this.Content = offerContentProperties; + } + /// /// Gets the entity tag associated with the resource from the Azure Cosmos DB service. /// @@ -49,12 +66,102 @@ public class ThroughputProperties /// /// Gets the provisioned throughput for a resource in measurement of request units per second in the Azure Cosmos service. /// - public virtual int? Throughput + [JsonIgnore] + public int? Throughput { get => this.Content?.OfferThroughput; private set => this.Content = OfferContentProperties.CreateFixedOfferConent(value.Value); } + /// + /// The maximum throughput the autopilot will scale to. + /// + [JsonIgnore] +#if INTERNAL + public +#else + internal +#endif + int? MaxThroughput + { + get => this.Content?.OfferAutopilotSettings?.MaxThroughput; + } + + /// + /// The amount to increment if the maximum RUs is getting throttled. + /// + [JsonIgnore] +#if INTERNAL + public +#else + internal +#endif + int? AutoUpgradeMaxThroughputIncrementPercentage + { + get => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; + } + + /// + /// The Throughput properties for autoscale provisioned throughput offering + /// + /// The maximum throughput the resource can scale to. +#if INTERNAL + public +#else + internal +#endif + static ThroughputProperties CreateAutoScaleProvionedThroughput(int maxThroughput) + { + return new ThroughputProperties(OfferContentProperties.CreateAutoscaleOfferConent(maxThroughput)); + } + + /// + /// The Throughput properties for autoscale provisioned throughput offering + /// + /// The current provisioned throughput for the resource. +#if INTERNAL + public +#else + internal +#endif + static ThroughputProperties CreateFixedThroughput(int throughput) + { + return new ThroughputProperties(OfferContentProperties.CreateFixedOfferConent(throughput)); + } + + /// + /// The Throughput properties for autoscale provisioned throughput offering + /// + /// The maximum throughput the resource can scale to. + /// The percentage to increase the maximum value if the maximum is being throttled. +#if INTERNAL + public +#else + internal +#endif + static ThroughputProperties CreateAutoScaleProvionedThroughput( + int startingMaxThroughput, + int autoUpgradeMaxThroughputIncrementPercentage) + { + return new ThroughputProperties(OfferContentProperties.CreateAutoPilotOfferConent( + startingMaxThroughput, + autoUpgradeMaxThroughputIncrementPercentage)); + } + + /// + /// The AutopilotThroughputProperties constructor + /// + /// The maximum throughput the resource can scale to. + /// This scales the maximum throughput by the percentage if maximum throughput is not enough + private ThroughputProperties( + int startingMaxThroughput, + int autoUpgradeMaxThroughputIncrementPercentage) + { + this.Content = OfferContentProperties.CreateAutoPilotOfferConent( + startingMaxThroughput, + autoUpgradeMaxThroughputIncrementPercentage); + } + /// /// Gets the self-link associated with the resource from the Azure Cosmos DB service. /// @@ -80,5 +187,11 @@ public virtual int? Throughput [JsonProperty(PropertyName = "content", DefaultValueHandling = DefaultValueHandling.Ignore)] internal OfferContentProperties Content { get; set; } + + /// + /// Gets the version of this offer resource in the Azure Cosmos DB service. + /// + [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] + internal string OfferVersion { get; private set; } } } diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs index 4484a83de5..8bad357710 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs @@ -125,8 +125,7 @@ private CosmosSerializer GetSerializer() inputType == typeof(ConflictProperties) || inputType == typeof(ThroughputProperties) || inputType == typeof(OfferV2) || - inputType == typeof(PartitionedQueryExecutionInfo) || - inputType == typeof(AutopilotThroughputProperties)) + inputType == typeof(PartitionedQueryExecutionInfo)) { return CosmosSerializerCore.propertiesSerializer; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 7a3329aa80..89b0e53030 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -5,6 +5,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; + using System.Net; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -31,49 +32,79 @@ public void TestCleanup() } [TestMethod] - public async Task CreateDropAutopilotDatabase() + public async Task CreateDropAutoscaleDatabase() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( - nameof(CreateDropAutopilotDatabase) + Guid.NewGuid().ToString(), - new AutopilotThroughputProperties(5000)); + nameof(CreateDropAutoscaleDatabase) + Guid.NewGuid().ToString(), + ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); - AutopilotThroughputResponse autopilot = await database.ReadAutopilotThroughputAsync(); - Assert.IsNotNull(autopilot); - Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); + ThroughputResponse autoscale = await database.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(autoscale); + Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); - AutopilotThroughputResponse autopilotReplaced = await database.ReplaceAutopilotThroughputAsync( - new AutopilotThroughputProperties(10000)); - Assert.IsNotNull(autopilotReplaced); - Assert.AreEqual(10000, autopilotReplaced.Resource.MaxThroughput); + ThroughputResponse autoscaleReplaced = await database.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateAutoScaleProvionedThroughput(10000)); + Assert.IsNotNull(autoscaleReplaced); + Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxThroughput); await database.DeleteAsync(); } [TestMethod] - public async Task CreateDropAutopilotAutoUpgradeDatabase() + public async Task CreateDropFixedDatabase() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( - nameof(CreateDropAutopilotAutoUpgradeDatabase) + Guid.NewGuid(), - new AutopilotThroughputProperties( + nameof(CreateDropAutoscaleDatabase) + Guid.NewGuid().ToString(), + ThroughputProperties.CreateFixedThroughput(5000)); + + ThroughputResponse fixedDatabaseThroughput = await database.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(fixedDatabaseThroughput); + Assert.AreEqual(5000, fixedDatabaseThroughput.Resource.Throughput); + Assert.IsNull(fixedDatabaseThroughput.Resource.MaxThroughput); + Assert.IsNull(fixedDatabaseThroughput.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + ThroughputResponse fixedReplaced = await database.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateFixedThroughput(6000)); + Assert.IsNotNull(fixedReplaced); + Assert.AreEqual(6000, fixedReplaced.Resource.Throughput); + Assert.IsNull(fixedReplaced.Resource.MaxThroughput); + Assert.IsNull(fixedReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + ThroughputResponse fixedReplacedIfExists = await database.ReplaceThroughputPropertiesIfExistsAsync( + ThroughputProperties.CreateFixedThroughput(7000)); + Assert.IsNotNull(fixedReplacedIfExists); + Assert.AreEqual(7000, fixedReplacedIfExists.Resource.Throughput); + Assert.IsNull(fixedReplacedIfExists.Resource.MaxThroughput); + Assert.IsNull(fixedReplacedIfExists.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + + await database.DeleteAsync(); + } + + [TestMethod] + public async Task CreateDropAutoscaleAutoUpgradeDatabase() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + nameof(CreateDropAutoscaleAutoUpgradeDatabase) + Guid.NewGuid(), + ThroughputProperties.CreateAutoScaleProvionedThroughput( startingMaxThroughput: 5000, autoUpgradeMaxThroughputIncrementPercentage: 10)); // Container is required to validate database throughput upgrade scenarios Container container = await database.CreateContainerAsync("Test", "/id"); - AutopilotThroughputResponse autopilot = await database.ReadAutopilotThroughputAsync(); - Assert.IsNotNull(autopilot); - Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); - Assert.AreEqual(10, autopilot.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + ThroughputResponse autoscale = await database.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(autoscale); + Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); + Assert.AreEqual(10, autoscale.Resource.AutoUpgradeMaxThroughputIncrementPercentage); - AutopilotThroughputResponse autopilotReplaced = await database.ReplaceAutopilotThroughputAsync( - new AutopilotThroughputProperties(6000)); - Assert.IsNotNull(autopilotReplaced); - Assert.AreEqual(6000, autopilotReplaced.Resource.MaxThroughput); - Assert.IsNull(autopilotReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); + ThroughputResponse autoscaleReplaced = await database.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateAutoScaleProvionedThroughput(6000)); + Assert.IsNotNull(autoscaleReplaced); + Assert.AreEqual(6000, autoscaleReplaced.Resource.MaxThroughput); + Assert.IsNull(autoscaleReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); - AutopilotThroughputResponse autoUpgradeReplace = await database.ReplaceAutopilotThroughputAsync( - new AutopilotThroughputProperties( + ThroughputResponse autoUpgradeReplace = await database.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateAutoScaleProvionedThroughput( startingMaxThroughput: 7000, autoUpgradeMaxThroughputIncrementPercentage: 20)); Assert.IsNotNull(autoUpgradeReplace); @@ -85,42 +116,50 @@ public async Task CreateDropAutopilotAutoUpgradeDatabase() [TestMethod] [Ignore] // Not currently working with emulator - public async Task CreateDropAutopilotContainer() + public async Task CreateDropAutoscaleContainer() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString()); + + ThroughputResponse databaseThroughput = await database.ReadThroughputIfExistsAsync(requestOptions: null); + Assert.IsNotNull(databaseThroughput); + Assert.AreEqual(HttpStatusCode.NotFound, databaseThroughput.StatusCode); ContainerCore container = (ContainerInlineCore)await database.CreateContainerAsync( new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), - new AutopilotThroughputProperties(5000)); + ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); Assert.IsNotNull(container); - AutopilotThroughputResponse autopilot = await container.ReadAutopilotThroughputAsync(); - Assert.IsNotNull(autopilot); - Assert.AreEqual(5000, autopilot.Resource.MaxThroughput); + ThroughputResponse autoscale = await container.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(autoscale); + Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); + + ThroughputResponse autoscaleIfExists = await container.ReadThroughputIfExistsAsync(requestOptions: null); + Assert.IsNotNull(autoscaleIfExists); + Assert.AreEqual(5000, autoscaleIfExists.Resource.MaxThroughput); - AutopilotThroughputResponse autopilotReplaced = await container.ReplaceAutopilotThroughputAsync( - new AutopilotThroughputProperties(10000)); - Assert.IsNotNull(autopilotReplaced); - Assert.AreEqual(10000, autopilotReplaced.Resource.MaxThroughput); + ThroughputResponse autoscaleReplaced = await container.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateAutoScaleProvionedThroughput(10000)); + Assert.IsNotNull(autoscaleReplaced); + Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxThroughput); await database.DeleteAsync(); } [TestMethod] [Ignore] // Not currently working with emulator - public async Task ReadFixedWithAutopilotTests() + public async Task ReadFixedWithAutoscaleTests() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString()); - ContainerCore autopilotContainer = (ContainerInlineCore)await database.CreateContainerAsync( + ContainerCore autoscaleContainer = (ContainerInlineCore)await database.CreateContainerAsync( new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), - new AutopilotThroughputProperties(5000)); - Assert.IsNotNull(autopilotContainer); + ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); + Assert.IsNotNull(autoscaleContainer); - // Reading a autopilot container with fixed results - int? throughput = await autopilotContainer.ReadThroughputAsync(); + // Reading a autoscale container with fixed results + int? throughput = await autoscaleContainer.ReadThroughputAsync(); Assert.IsNotNull(throughput); await database.DeleteAsync(); @@ -140,12 +179,12 @@ public async Task ReadAutoPilotWithFixedTests() int? throughput = await fixedContainer.ReadThroughputAsync(); Assert.AreEqual(1000, throughput); - // Reading a fixed container with autopilot results in max throughput being null - AutopilotThroughputResponse autopilot = await fixedContainer.ReadAutopilotThroughputAsync(); - Assert.IsNotNull(autopilot); - Assert.IsNotNull(autopilot.Resource.Throughput); - Assert.AreEqual(1000, autopilot.Resource.Throughput); - Assert.IsNull(autopilot.Resource.MaxThroughput); + // Reading a fixed container with autoscale results in max throughput being null + ThroughputResponse autoscale = await fixedContainer.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(autoscale); + Assert.IsNotNull(autoscale.Resource.Throughput); + Assert.AreEqual(1000, autoscale.Resource.Throughput); + Assert.IsNull(autoscale.Resource.MaxThroughput); await database.DeleteAsync(); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs index 05d9b87327..08def0a6bb 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs @@ -146,7 +146,7 @@ public void ValidateCustomSerializerNotUsedForInternalTypes() $@"{{""id"":""{id}"",""operationType"":""Invalid"",""resourceType"":null,""resourceId"":null,""content"":null,""conflict_lsn"":0}}"); // Throughput doesn't have an id. - string defaultThroughputJson = @"{""Throughput"":null}"; + string defaultThroughputJson = @"{}"; ThroughputProperties property = JsonConvert.DeserializeObject(defaultThroughputJson); Assert.IsNull(property.Throughput); string propertyJson = JsonConvert.SerializeObject(property); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs index c264011498..2dd3384fb8 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs @@ -4,39 +4,32 @@ namespace Microsoft.Azure.Cosmos.Tests { - using System; - using System.Threading; + using System.IO; using System.Threading.Tasks; - using Microsoft.Azure.Documents; - using Microsoft.Azure.Cosmos.Handlers; - using Microsoft.Azure.Cosmos.Routing; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using Newtonsoft.Json.Linq; - using System.IO; [TestClass] public class CosmosThroughputTests { [TestMethod] - public async Task AutopilotThroughputSerializationTest() + public async Task AutoscaleThroughputSerializationTest() { - AutopilotThroughputProperties autopilotThroughputProperties = new AutopilotThroughputProperties(1000); - Assert.AreEqual(1000, autopilotThroughputProperties.MaxThroughput); - Assert.IsNull(autopilotThroughputProperties.Throughput); + ThroughputProperties autoscaleThroughputProperties = ThroughputProperties.CreateAutoScaleProvionedThroughput(1000); + Assert.AreEqual(1000, autoscaleThroughputProperties.MaxThroughput); + Assert.IsNull(autoscaleThroughputProperties.Throughput); - using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotThroughputProperties)) + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleThroughputProperties)) { - using(StreamReader reader = new StreamReader(stream)) + using (StreamReader reader = new StreamReader(stream)) { string output = await reader.ReadToEndAsync(); Assert.IsNotNull(output); - Assert.AreEqual("{\"offerVersion\":\"V2\",\"content\":{\"offerAutopilotSettings\":{\"maxThroughput\":1000}}}", output); + Assert.AreEqual("{\"content\":{\"offerAutopilotSettings\":{\"maxThroughput\":1000}},\"offerVersion\":\"V2\"}", output); } } - OfferAutopilotProperties autopilotProperties = new OfferAutopilotProperties(1000); - using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotProperties)) + OfferAutoscaleProperties autoscaleProperties = new OfferAutoscaleProperties(1000); + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleProperties)) { using (StreamReader reader = new StreamReader(stream)) { @@ -46,14 +39,14 @@ public async Task AutopilotThroughputSerializationTest() } } - using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotProperties)) + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleProperties)) { - OfferAutopilotProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); + OfferAutoscaleProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); Assert.IsNotNull(fromStream); Assert.AreEqual(1000, fromStream.MaxThroughput); } - OfferContentProperties content = OfferContentProperties.CreateAutoPilotOfferConent(1000); + OfferContentProperties content = OfferContentProperties.CreateAutoscaleOfferConent(1000); using (Stream stream = MockCosmosUtil.Serializer.ToStream(content)) { using (StreamReader reader = new StreamReader(stream)) @@ -72,9 +65,9 @@ public async Task AutopilotThroughputSerializationTest() Assert.IsNull(fromStream.OfferThroughput); } - using (Stream stream = MockCosmosUtil.Serializer.ToStream(autopilotThroughputProperties)) + using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleThroughputProperties)) { - AutopilotThroughputProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); + ThroughputProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); Assert.AreEqual(1000, fromStream.MaxThroughput); Assert.IsNull(fromStream.Throughput); ; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json index 991940ba1e..ad9cf2a0df 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json @@ -7551,9 +7551,11 @@ "Attributes": [], "MethodInfo": "System.Nullable`1[System.Int32] get_Throughput()" }, - "System.Nullable`1[System.Int32] Throughput": { + "System.Nullable`1[System.Int32] Throughput[Newtonsoft.Json.JsonIgnoreAttribute()]": { "Type": "Property", - "Attributes": [], + "Attributes": [ + "JsonIgnoreAttribute" + ], "MethodInfo": null }, "System.String ETag[Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = 1, PropertyName = \"_etag\")]": { From 17f4cbc9b0521f263ecd4d27f431ac294215fa29 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 13:24:48 -0700 Subject: [PATCH 08/15] Fixed internal overrides --- .../src/Resource/Container/Container.cs | 10 ---------- .../src/Resource/Container/ContainerInlineCore.cs | 12 +----------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs index bc0bf1fa2a..367825716b 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs @@ -294,16 +294,6 @@ public abstract Task ReplaceThroughputAsync( CancellationToken cancellationToken = default(CancellationToken)); #if INTERNAL - /// - /// Gets container throughput in measurement of request units per second in the Azure Cosmos service. - /// - /// The options for the throughput request. - /// (Optional) representing request cancellation. - /// The throughput response. - public abstract Task ReadThroughputPropertiesAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)); - /// /// Sets throughput provisioned for a container in measurement of request units per second in the Azure Cosmos service. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs index e0fcf911ba..fed5d6c0dd 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs @@ -105,17 +105,7 @@ public override #else internal #endif - Task ReadAutopilotThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken = default) - { - return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReadThroughputAsync(requestOptions, cancellationToken)); - } - -#if INTERNAL - public override -#else - internal -#endif - Task ReplaceAutopilotThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + Task ReplaceThroughputPropertiesAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { return TaskHelper.RunInlineIfNeededAsync(() => this.container.ReplaceThroughputPropertiesAsync(throughputProperties, requestOptions, cancellationToken)); } From 862c3186ebec3318b6113660ebffa8f34499e9b8 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 13:30:22 -0700 Subject: [PATCH 09/15] More internal build fixes --- Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs | 4 ++-- .../src/Resource/Database/DatabaseInlineCore.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index 11439ecf1a..c2802f438b 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -189,7 +189,7 @@ public abstract Task ReplaceThroughputPropertiesAsync( /// Creates a container as an asynchronous operation in the Azure Cosmos service. /// /// The object. - /// (Optional) The throughput provisioned for a container in measurement of Requests Units per second in the Azure Cosmos DB service. + /// (Optional) The throughput provisioned for a container in measurement of Requests Units per second in the Azure Cosmos DB service. /// (Optional) The options for the request. /// (Optional) representing request cancellation. /// A containing a which wraps a containing the read resource record. @@ -214,7 +214,7 @@ public abstract Task ReplaceThroughputPropertiesAsync( /// Request Units public abstract Task CreateContainerAsync( ContainerProperties containerProperties, - AutopilotThroughputProperties autopilotThroughput, + ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); #endif diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index 96c18c6f41..eb74b3c962 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -213,7 +213,7 @@ public override #else internal #endif - Task ReplaceAutopilotThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + Task ReplaceThroughputPropertiesAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { return TaskHelper.RunInlineIfNeededAsync(() => this.database.ReplaceThroughputPropertiesAsync(throughputProperties, requestOptions, cancellationToken)); } From a2daa522a35bbce7bd15ad7eaa97cffcbf0f5b61 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Thu, 9 Apr 2020 14:59:29 -0700 Subject: [PATCH 10/15] Fixed internal comments --- .../src/Resource/Offer/ThroughputProperties.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs index 7f8a1177b9..bd2b092047 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs @@ -5,7 +5,6 @@ namespace Microsoft.Azure.Cosmos { using System; - using System.Runtime.CompilerServices; using Microsoft.Azure.Documents; using Newtonsoft.Json; @@ -82,10 +81,7 @@ public int? Throughput #else internal #endif - int? MaxThroughput - { - get => this.Content?.OfferAutopilotSettings?.MaxThroughput; - } + int? MaxThroughput => this.Content?.OfferAutopilotSettings?.MaxThroughput; /// /// The amount to increment if the maximum RUs is getting throttled. @@ -96,15 +92,13 @@ public int? Throughput #else internal #endif - int? AutoUpgradeMaxThroughputIncrementPercentage - { - get => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; - } + int? AutoUpgradeMaxThroughputIncrementPercentage => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; /// /// The Throughput properties for autoscale provisioned throughput offering /// /// The maximum throughput the resource can scale to. + /// Returns a ThroughputProperties for autoscale provisioned throughput #if INTERNAL public #else @@ -112,13 +106,14 @@ public int? Throughput #endif static ThroughputProperties CreateAutoScaleProvionedThroughput(int maxThroughput) { - return new ThroughputProperties(OfferContentProperties.CreateAutoscaleOfferConent(maxThroughput)); + return new ThroughputProperties(OfferContentProperties.CreateAutoscaleOfferConent(maxThroughput)); } /// /// The Throughput properties for autoscale provisioned throughput offering /// /// The current provisioned throughput for the resource. + /// Returns a ThroughputProperties for fixed throughput #if INTERNAL public #else @@ -134,6 +129,7 @@ static ThroughputProperties CreateFixedThroughput(int throughput) /// /// The maximum throughput the resource can scale to. /// The percentage to increase the maximum value if the maximum is being throttled. + /// Returns a ThroughputProperties for autoscale provisioned throughput #if INTERNAL public #else @@ -192,6 +188,6 @@ private ThroughputProperties( /// Gets the version of this offer resource in the Azure Cosmos DB service. /// [JsonProperty(PropertyName = Constants.Properties.OfferVersion, DefaultValueHandling = DefaultValueHandling.Ignore)] - internal string OfferVersion { get; private set; } + internal string OfferVersion { get; private set; } } } From 63496aa5cdb25906fda02e3f8a738e8dddbf1fc2 Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Fri, 10 Apr 2020 04:49:21 -0700 Subject: [PATCH 11/15] Reverted file moves, fixed unit test --- .../src/Resource/{Offer => Settings}/ThroughputProperties.cs | 0 .../src/Resource/{Offer => Throughput}/ThroughputResponse.cs | 0 .../CosmosJsonSeriliazerUnitTests.cs | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename Microsoft.Azure.Cosmos/src/Resource/{Offer => Settings}/ThroughputProperties.cs (100%) rename Microsoft.Azure.Cosmos/src/Resource/{Offer => Throughput}/ThroughputResponse.cs (100%) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs similarity index 100% rename from Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputProperties.cs rename to Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/Throughput/ThroughputResponse.cs similarity index 100% rename from Microsoft.Azure.Cosmos/src/Resource/Offer/ThroughputResponse.cs rename to Microsoft.Azure.Cosmos/src/Resource/Throughput/ThroughputResponse.cs diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs index 3c6ab27fc1..2a5c074cbd 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs @@ -92,7 +92,7 @@ public void ValidatePropertySerialization() $@"{{""id"":""{id}"",""operationType"":""Invalid"",""resourceType"":null,""resourceId"":null,""content"":null,""conflict_lsn"":0}}"); // Throughput doesn't have an id. - string defaultThroughputJson = @"{""Throughput"":null}"; + string defaultThroughputJson = @"{}"; ThroughputProperties property = JsonConvert.DeserializeObject(defaultThroughputJson); Assert.IsNull(property.Throughput); string propertyJson = JsonConvert.SerializeObject(property, new JsonSerializerSettings() From 6b39d73cd19139cbda4039ce6779a17726fe143d Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Fri, 10 Apr 2020 12:11:04 -0700 Subject: [PATCH 12/15] Updated based on feedback --- .../src/Handler/RequestMessage.cs | 4 +- Microsoft.Azure.Cosmos/src/Headers/Headers.cs | 3 ++ .../Offer/OfferAutoscaleProperties.cs | 17 +++---- .../Resource/Offer/OfferContentProperties.cs | 10 +--- .../Resource/Settings/ThroughputProperties.cs | 48 ++++--------------- .../CosmosThroughputTests.cs | 44 ++++++++--------- .../CosmosThroughputTests.cs | 14 ++++-- .../DotNetSDKAPI.json | 5 -- 8 files changed, 57 insertions(+), 88 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs index 0aff8fc12a..8f2524c44e 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs @@ -172,7 +172,7 @@ internal void AddThroughputHeader(int? throughputValue) internal void AddThroughputPropertiesHeader(ThroughputProperties throughputProperties) { if (throughputProperties.Throughput.HasValue && - (throughputProperties.MaxThroughput.HasValue || throughputProperties.AutoUpgradeMaxThroughputIncrementPercentage.HasValue)) + (throughputProperties.MaxAutoscaleThroughput.HasValue || throughputProperties.AutoUpgradeMaxThroughputIncrementPercentage.HasValue)) { throw new InvalidOperationException("Autoscale provisioned throughput can not be configured with fixed offer"); } @@ -183,7 +183,7 @@ internal void AddThroughputPropertiesHeader(ThroughputProperties throughputPrope } else if (throughputProperties?.Content?.OfferAutopilotSettings != null) { - this.Headers.Add(HttpConstants.HttpHeaders.OfferAutopilotSettings, throughputProperties.Content.OfferAutopilotSettings.GetJsonString()); + this.Headers.OfferAutoscaleThroughput = throughputProperties.Content.OfferAutopilotSettings.GetJsonString(); } } diff --git a/Microsoft.Azure.Cosmos/src/Headers/Headers.cs b/Microsoft.Azure.Cosmos/src/Headers/Headers.cs index a314effffb..60daf309eb 100644 --- a/Microsoft.Azure.Cosmos/src/Headers/Headers.cs +++ b/Microsoft.Azure.Cosmos/src/Headers/Headers.cs @@ -170,6 +170,9 @@ internal string RetryAfterLiteral [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.OfferThroughput)] internal string OfferThroughput { get; set; } + [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.OfferAutopilotSettings)] + internal string OfferAutoscaleThroughput { get; set; } + [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.IfNoneMatch)] internal string IfNoneMatch { get; set; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs index 627c17bd71..fc749457aa 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs @@ -17,18 +17,19 @@ private OfferAutoscaleProperties() { } - internal OfferAutoscaleProperties(int maxThroughput) - { - this.MaxThroughput = maxThroughput; - this.AutopilotAutoUpgradeProperties = null; - } - internal OfferAutoscaleProperties( int startingMaxThroughput, - int autoUpgradeMaxThroughputIncrementPercentage) + int? autoUpgradeMaxThroughputIncrementPercentage) { this.MaxThroughput = startingMaxThroughput; - this.AutopilotAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage); + if (autoUpgradeMaxThroughputIncrementPercentage.HasValue) + { + this.AutopilotAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage.Value); + } + else + { + this.AutopilotAutoUpgradeProperties = null; + } } /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs index 8ee1eb10d8..583f65dab4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs @@ -59,15 +59,9 @@ public static OfferContentProperties CreateFixedOfferConent(int throughput) return new OfferContentProperties(fixedThroughput: throughput); } - public static OfferContentProperties CreateAutoscaleOfferConent(int maxThroughput) - { - OfferAutoscaleProperties autopilotProperties = new OfferAutoscaleProperties(maxThroughput); - return new OfferContentProperties(autopilotProperties); - } - - public static OfferContentProperties CreateAutoPilotOfferConent( + public static OfferContentProperties CreateAutoscaleOfferConent( int startingMaxThroughput, - int autoUpgradeMaxThroughputIncrementPercentage) + int? autoUpgradeMaxThroughputIncrementPercentage) { OfferAutoscaleProperties autopilotProperties = new OfferAutoscaleProperties( startingMaxThroughput, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs index bd2b092047..3753601121 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs @@ -27,9 +27,10 @@ namespace Microsoft.Azure.Cosmos public class ThroughputProperties { /// - /// Default constructor used for serialization and unit tests + /// Default constructor for serialization /// - public ThroughputProperties() + [JsonConstructor] + private ThroughputProperties() { } @@ -81,7 +82,7 @@ public int? Throughput #else internal #endif - int? MaxThroughput => this.Content?.OfferAutopilotSettings?.MaxThroughput; + int? MaxAutoscaleThroughput => this.Content?.OfferAutopilotSettings?.MaxThroughput; /// /// The amount to increment if the maximum RUs is getting throttled. @@ -94,21 +95,6 @@ public int? Throughput #endif int? AutoUpgradeMaxThroughputIncrementPercentage => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; - /// - /// The Throughput properties for autoscale provisioned throughput offering - /// - /// The maximum throughput the resource can scale to. - /// Returns a ThroughputProperties for autoscale provisioned throughput -#if INTERNAL - public -#else - internal -#endif - static ThroughputProperties CreateAutoScaleProvionedThroughput(int maxThroughput) - { - return new ThroughputProperties(OfferContentProperties.CreateAutoscaleOfferConent(maxThroughput)); - } - /// /// The Throughput properties for autoscale provisioned throughput offering /// @@ -127,7 +113,7 @@ static ThroughputProperties CreateFixedThroughput(int throughput) /// /// The Throughput properties for autoscale provisioned throughput offering /// - /// The maximum throughput the resource can scale to. + /// The staring maximum throughput the resource can scale to. /// The percentage to increase the maximum value if the maximum is being throttled. /// Returns a ThroughputProperties for autoscale provisioned throughput #if INTERNAL @@ -135,29 +121,15 @@ static ThroughputProperties CreateFixedThroughput(int throughput) #else internal #endif - static ThroughputProperties CreateAutoScaleProvionedThroughput( - int startingMaxThroughput, - int autoUpgradeMaxThroughputIncrementPercentage) + static ThroughputProperties CreateAutoscaleProvionedThroughput( + int maxAutoscaleThroughput, + int? autoUpgradeMaxThroughputIncrementPercentage = null) { - return new ThroughputProperties(OfferContentProperties.CreateAutoPilotOfferConent( - startingMaxThroughput, + return new ThroughputProperties(OfferContentProperties.CreateAutoscaleOfferConent( + maxAutoscaleThroughput, autoUpgradeMaxThroughputIncrementPercentage)); } - /// - /// The AutopilotThroughputProperties constructor - /// - /// The maximum throughput the resource can scale to. - /// This scales the maximum throughput by the percentage if maximum throughput is not enough - private ThroughputProperties( - int startingMaxThroughput, - int autoUpgradeMaxThroughputIncrementPercentage) - { - this.Content = OfferContentProperties.CreateAutoPilotOfferConent( - startingMaxThroughput, - autoUpgradeMaxThroughputIncrementPercentage); - } - /// /// Gets the self-link associated with the resource from the Azure Cosmos DB service. /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 89b0e53030..00086ca273 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -36,16 +36,16 @@ public async Task CreateDropAutoscaleDatabase() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( nameof(CreateDropAutoscaleDatabase) + Guid.NewGuid().ToString(), - ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(5000)); ThroughputResponse autoscale = await database.ReadThroughputAsync(requestOptions: null); Assert.IsNotNull(autoscale); - Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); + Assert.AreEqual(5000, autoscale.Resource.MaxAutoscaleThroughput); ThroughputResponse autoscaleReplaced = await database.ReplaceThroughputPropertiesAsync( - ThroughputProperties.CreateAutoScaleProvionedThroughput(10000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(10000)); Assert.IsNotNull(autoscaleReplaced); - Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxThroughput); + Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxAutoscaleThroughput); await database.DeleteAsync(); } @@ -60,21 +60,21 @@ public async Task CreateDropFixedDatabase() ThroughputResponse fixedDatabaseThroughput = await database.ReadThroughputAsync(requestOptions: null); Assert.IsNotNull(fixedDatabaseThroughput); Assert.AreEqual(5000, fixedDatabaseThroughput.Resource.Throughput); - Assert.IsNull(fixedDatabaseThroughput.Resource.MaxThroughput); + Assert.IsNull(fixedDatabaseThroughput.Resource.MaxAutoscaleThroughput); Assert.IsNull(fixedDatabaseThroughput.Resource.AutoUpgradeMaxThroughputIncrementPercentage); ThroughputResponse fixedReplaced = await database.ReplaceThroughputPropertiesAsync( ThroughputProperties.CreateFixedThroughput(6000)); Assert.IsNotNull(fixedReplaced); Assert.AreEqual(6000, fixedReplaced.Resource.Throughput); - Assert.IsNull(fixedReplaced.Resource.MaxThroughput); + Assert.IsNull(fixedReplaced.Resource.MaxAutoscaleThroughput); Assert.IsNull(fixedReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); ThroughputResponse fixedReplacedIfExists = await database.ReplaceThroughputPropertiesIfExistsAsync( ThroughputProperties.CreateFixedThroughput(7000)); Assert.IsNotNull(fixedReplacedIfExists); Assert.AreEqual(7000, fixedReplacedIfExists.Resource.Throughput); - Assert.IsNull(fixedReplacedIfExists.Resource.MaxThroughput); + Assert.IsNull(fixedReplacedIfExists.Resource.MaxAutoscaleThroughput); Assert.IsNull(fixedReplacedIfExists.Resource.AutoUpgradeMaxThroughputIncrementPercentage); await database.DeleteAsync(); @@ -85,8 +85,8 @@ public async Task CreateDropAutoscaleAutoUpgradeDatabase() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( nameof(CreateDropAutoscaleAutoUpgradeDatabase) + Guid.NewGuid(), - ThroughputProperties.CreateAutoScaleProvionedThroughput( - startingMaxThroughput: 5000, + ThroughputProperties.CreateAutoscaleProvionedThroughput( + maxAutoscaleThroughput: 5000, autoUpgradeMaxThroughputIncrementPercentage: 10)); // Container is required to validate database throughput upgrade scenarios @@ -94,21 +94,21 @@ public async Task CreateDropAutoscaleAutoUpgradeDatabase() ThroughputResponse autoscale = await database.ReadThroughputAsync(requestOptions: null); Assert.IsNotNull(autoscale); - Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); + Assert.AreEqual(5000, autoscale.Resource.MaxAutoscaleThroughput); Assert.AreEqual(10, autoscale.Resource.AutoUpgradeMaxThroughputIncrementPercentage); ThroughputResponse autoscaleReplaced = await database.ReplaceThroughputPropertiesAsync( - ThroughputProperties.CreateAutoScaleProvionedThroughput(6000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(6000)); Assert.IsNotNull(autoscaleReplaced); - Assert.AreEqual(6000, autoscaleReplaced.Resource.MaxThroughput); + Assert.AreEqual(6000, autoscaleReplaced.Resource.MaxAutoscaleThroughput); Assert.IsNull(autoscaleReplaced.Resource.AutoUpgradeMaxThroughputIncrementPercentage); ThroughputResponse autoUpgradeReplace = await database.ReplaceThroughputPropertiesAsync( - ThroughputProperties.CreateAutoScaleProvionedThroughput( - startingMaxThroughput: 7000, + ThroughputProperties.CreateAutoscaleProvionedThroughput( + maxAutoscaleThroughput: 7000, autoUpgradeMaxThroughputIncrementPercentage: 20)); Assert.IsNotNull(autoUpgradeReplace); - Assert.AreEqual(7000, autoUpgradeReplace.Resource.MaxThroughput); + Assert.AreEqual(7000, autoUpgradeReplace.Resource.MaxAutoscaleThroughput); Assert.AreEqual(20, autoUpgradeReplace.Resource.AutoUpgradeMaxThroughputIncrementPercentage); await database.DeleteAsync(); @@ -127,21 +127,21 @@ public async Task CreateDropAutoscaleContainer() ContainerCore container = (ContainerInlineCore)await database.CreateContainerAsync( new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), - ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(5000)); Assert.IsNotNull(container); ThroughputResponse autoscale = await container.ReadThroughputAsync(requestOptions: null); Assert.IsNotNull(autoscale); - Assert.AreEqual(5000, autoscale.Resource.MaxThroughput); + Assert.AreEqual(5000, autoscale.Resource.MaxAutoscaleThroughput); ThroughputResponse autoscaleIfExists = await container.ReadThroughputIfExistsAsync(requestOptions: null); Assert.IsNotNull(autoscaleIfExists); - Assert.AreEqual(5000, autoscaleIfExists.Resource.MaxThroughput); + Assert.AreEqual(5000, autoscaleIfExists.Resource.MaxAutoscaleThroughput); ThroughputResponse autoscaleReplaced = await container.ReplaceThroughputPropertiesAsync( - ThroughputProperties.CreateAutoScaleProvionedThroughput(10000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(10000)); Assert.IsNotNull(autoscaleReplaced); - Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxThroughput); + Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxAutoscaleThroughput); await database.DeleteAsync(); } @@ -155,7 +155,7 @@ public async Task ReadFixedWithAutoscaleTests() ContainerCore autoscaleContainer = (ContainerInlineCore)await database.CreateContainerAsync( new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), - ThroughputProperties.CreateAutoScaleProvionedThroughput(5000)); + ThroughputProperties.CreateAutoscaleProvionedThroughput(5000)); Assert.IsNotNull(autoscaleContainer); // Reading a autoscale container with fixed results @@ -184,7 +184,7 @@ public async Task ReadAutoPilotWithFixedTests() Assert.IsNotNull(autoscale); Assert.IsNotNull(autoscale.Resource.Throughput); Assert.AreEqual(1000, autoscale.Resource.Throughput); - Assert.IsNull(autoscale.Resource.MaxThroughput); + Assert.IsNull(autoscale.Resource.MaxAutoscaleThroughput); await database.DeleteAsync(); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs index 2dd3384fb8..d717c90877 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs @@ -14,8 +14,8 @@ public class CosmosThroughputTests [TestMethod] public async Task AutoscaleThroughputSerializationTest() { - ThroughputProperties autoscaleThroughputProperties = ThroughputProperties.CreateAutoScaleProvionedThroughput(1000); - Assert.AreEqual(1000, autoscaleThroughputProperties.MaxThroughput); + ThroughputProperties autoscaleThroughputProperties = ThroughputProperties.CreateAutoscaleProvionedThroughput(1000); + Assert.AreEqual(1000, autoscaleThroughputProperties.MaxAutoscaleThroughput); Assert.IsNull(autoscaleThroughputProperties.Throughput); using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleThroughputProperties)) @@ -28,7 +28,9 @@ public async Task AutoscaleThroughputSerializationTest() } } - OfferAutoscaleProperties autoscaleProperties = new OfferAutoscaleProperties(1000); + OfferAutoscaleProperties autoscaleProperties = new OfferAutoscaleProperties( + startingMaxThroughput: 1000, + autoUpgradeMaxThroughputIncrementPercentage: null); using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleProperties)) { using (StreamReader reader = new StreamReader(stream)) @@ -46,7 +48,9 @@ public async Task AutoscaleThroughputSerializationTest() Assert.AreEqual(1000, fromStream.MaxThroughput); } - OfferContentProperties content = OfferContentProperties.CreateAutoscaleOfferConent(1000); + OfferContentProperties content = OfferContentProperties.CreateAutoscaleOfferConent( + startingMaxThroughput: 1000, + autoUpgradeMaxThroughputIncrementPercentage: null); using (Stream stream = MockCosmosUtil.Serializer.ToStream(content)) { using (StreamReader reader = new StreamReader(stream)) @@ -68,7 +72,7 @@ public async Task AutoscaleThroughputSerializationTest() using (Stream stream = MockCosmosUtil.Serializer.ToStream(autoscaleThroughputProperties)) { ThroughputProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); - Assert.AreEqual(1000, fromStream.MaxThroughput); + Assert.AreEqual(1000, fromStream.MaxAutoscaleThroughput); Assert.IsNull(fromStream.Throughput); ; } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json index ad9cf2a0df..27589cc42c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json @@ -7585,11 +7585,6 @@ "JsonPropertyAttribute" ], "MethodInfo": null - }, - "Void .ctor()": { - "Type": "Constructor", - "Attributes": [], - "MethodInfo": "Void .ctor()" } }, "NestedTypes": {} From 457fdf8e2deba42074671e62ec89feec67ca289b Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Fri, 10 Apr 2020 12:23:36 -0700 Subject: [PATCH 13/15] Refactored everything to Autoscale instead of Autopilot --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 4 ++-- Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs | 4 ++-- .../Offer/OfferAutoscaleAutoUpgradeProperties.cs | 8 ++++---- .../src/Resource/Offer/OfferAutoscaleProperties.cs | 8 ++++---- .../src/Resource/Offer/OfferContentProperties.cs | 12 ++++++------ .../src/Resource/Settings/ThroughputProperties.cs | 6 +++--- .../CosmosThroughputTests.cs | 2 +- .../CosmosThroughputTests.cs | 4 ++-- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index e5ee901e2c..dace020c46 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -756,7 +756,7 @@ internal Task CreateDatabaseAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { - Task response = this.CreateAutopilotDatabaseStreamInternalAsync( + Task response = this.CreateAutoscaleDatabaseStreamInternalAsync( streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), throughputProperties: throughputProperties, requestOptions: requestOptions, @@ -780,7 +780,7 @@ internal Task CreateDatabaseAsync( return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); } - private Task CreateAutopilotDatabaseStreamInternalAsync( + private Task CreateAutoscaleDatabaseStreamInternalAsync( Stream streamPayload, ThroughputProperties throughputProperties, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs index 8f2524c44e..bf33bdd90f 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs @@ -181,9 +181,9 @@ internal void AddThroughputPropertiesHeader(ThroughputProperties throughputPrope { this.AddThroughputHeader(throughputProperties.Throughput); } - else if (throughputProperties?.Content?.OfferAutopilotSettings != null) + else if (throughputProperties?.Content?.OfferAutoscaleSettings != null) { - this.Headers.OfferAutoscaleThroughput = throughputProperties.Content.OfferAutopilotSettings.GetJsonString(); + this.Headers.OfferAutoscaleThroughput = throughputProperties.Content.OfferAutoscaleSettings.GetJsonString(); } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs index eaf60c0cba..2ac915e196 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleAutoUpgradeProperties.cs @@ -19,20 +19,20 @@ private OfferAutoscaleAutoUpgradeProperties() internal OfferAutoscaleAutoUpgradeProperties(int incrementPercent) { - this.ThroughputProperties = new AutoPilotThroughputProperties(incrementPercent); + this.ThroughputProperties = new AutoscaleThroughputProperties(incrementPercent); } [JsonProperty(PropertyName = Constants.Properties.AutopilotThroughputPolicy, NullValueHandling = NullValueHandling.Ignore)] - public AutoPilotThroughputProperties ThroughputProperties { get; private set; } + public AutoscaleThroughputProperties ThroughputProperties { get; private set; } internal string GetJsonString() { return JsonConvert.SerializeObject(this, Formatting.None); } - public class AutoPilotThroughputProperties + public class AutoscaleThroughputProperties { - public AutoPilotThroughputProperties(int incrementPercent) + public AutoscaleThroughputProperties(int incrementPercent) { this.IncrementPercent = incrementPercent; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs index fc749457aa..de29a083e8 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferAutoscaleProperties.cs @@ -24,16 +24,16 @@ internal OfferAutoscaleProperties( this.MaxThroughput = startingMaxThroughput; if (autoUpgradeMaxThroughputIncrementPercentage.HasValue) { - this.AutopilotAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage.Value); + this.AutoscaleAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(autoUpgradeMaxThroughputIncrementPercentage.Value); } else { - this.AutopilotAutoUpgradeProperties = null; + this.AutoscaleAutoUpgradeProperties = null; } } /// - /// The maximum throughput the autopilot will scale to. + /// The maximum throughput the autoscale will scale to. /// [JsonProperty(PropertyName = Constants.Properties.AutopilotMaxThroughput, NullValueHandling = NullValueHandling.Ignore)] public int? MaxThroughput { get; private set; } @@ -42,7 +42,7 @@ internal OfferAutoscaleProperties( /// Scales the maximum through put automatically /// [JsonProperty(PropertyName = Constants.Properties.AutopilotAutoUpgradePolicy, NullValueHandling = NullValueHandling.Ignore)] - public OfferAutoscaleAutoUpgradeProperties AutopilotAutoUpgradeProperties { get; private set; } + public OfferAutoscaleAutoUpgradeProperties AutoscaleAutoUpgradeProperties { get; private set; } internal string GetJsonString() { diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs index 583f65dab4..9283e6123c 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/OfferContentProperties.cs @@ -21,13 +21,13 @@ private OfferContentProperties() private OfferContentProperties(int fixedThroughput) { this.OfferThroughput = fixedThroughput; - this.OfferAutopilotSettings = null; + this.OfferAutoscaleSettings = null; } - private OfferContentProperties(OfferAutoscaleProperties autopilotProperties) + private OfferContentProperties(OfferAutoscaleProperties autoscaleProperties) { this.OfferThroughput = null; - this.OfferAutopilotSettings = autopilotProperties ?? throw new ArgumentNullException(nameof(autopilotProperties)); + this.OfferAutoscaleSettings = autoscaleProperties ?? throw new ArgumentNullException(nameof(autoscaleProperties)); } /// @@ -40,7 +40,7 @@ private OfferContentProperties(OfferAutoscaleProperties autopilotProperties) /// Represents customizable throughput chosen by user for his collection in the Azure Cosmos DB service. /// [JsonProperty(PropertyName = Constants.Properties.AutopilotSettings, DefaultValueHandling = DefaultValueHandling.Ignore)] - public OfferAutoscaleProperties OfferAutopilotSettings { get; private set; } + public OfferAutoscaleProperties OfferAutoscaleSettings { get; private set; } /// /// Represents Request Units(RU)/Minute throughput is enabled/disabled for collection in the Azure Cosmos DB service. @@ -63,10 +63,10 @@ public static OfferContentProperties CreateAutoscaleOfferConent( int startingMaxThroughput, int? autoUpgradeMaxThroughputIncrementPercentage) { - OfferAutoscaleProperties autopilotProperties = new OfferAutoscaleProperties( + OfferAutoscaleProperties autoscaleProperties = new OfferAutoscaleProperties( startingMaxThroughput, autoUpgradeMaxThroughputIncrementPercentage); - return new OfferContentProperties(autopilotProperties); + return new OfferContentProperties(autoscaleProperties); } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs index 3753601121..ca84c4fe25 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs @@ -74,7 +74,7 @@ public int? Throughput } /// - /// The maximum throughput the autopilot will scale to. + /// The maximum throughput the autoscale will scale to. /// [JsonIgnore] #if INTERNAL @@ -82,7 +82,7 @@ public int? Throughput #else internal #endif - int? MaxAutoscaleThroughput => this.Content?.OfferAutopilotSettings?.MaxThroughput; + int? MaxAutoscaleThroughput => this.Content?.OfferAutoscaleSettings?.MaxThroughput; /// /// The amount to increment if the maximum RUs is getting throttled. @@ -93,7 +93,7 @@ public int? Throughput #else internal #endif - int? AutoUpgradeMaxThroughputIncrementPercentage => this.Content?.OfferAutopilotSettings?.AutopilotAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; + int? AutoUpgradeMaxThroughputIncrementPercentage => this.Content?.OfferAutoscaleSettings?.AutoscaleAutoUpgradeProperties?.ThroughputProperties?.IncrementPercent; /// /// The Throughput properties for autoscale provisioned throughput offering diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 00086ca273..c81dea0fa5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -166,7 +166,7 @@ public async Task ReadFixedWithAutoscaleTests() } [TestMethod] - public async Task ReadAutoPilotWithFixedTests() + public async Task ReadAutoscaleWithFixedTests() { Database database = await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString()); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs index d717c90877..e4b5eb1805 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosThroughputTests.cs @@ -64,8 +64,8 @@ public async Task AutoscaleThroughputSerializationTest() using (Stream stream = MockCosmosUtil.Serializer.ToStream(content)) { OfferContentProperties fromStream = MockCosmosUtil.Serializer.FromStream(stream); - Assert.IsNotNull(fromStream.OfferAutopilotSettings); - Assert.AreEqual(1000, fromStream.OfferAutopilotSettings.MaxThroughput); + Assert.IsNotNull(fromStream.OfferAutoscaleSettings); + Assert.AreEqual(1000, fromStream.OfferAutoscaleSettings.MaxThroughput); Assert.IsNull(fromStream.OfferThroughput); } From a7e97d629d6115ed1f4f79a1963313cf419a3dbc Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Fri, 10 Apr 2020 12:35:42 -0700 Subject: [PATCH 14/15] Inlined method --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 31 +++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index dace020c46..b03f35c661 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -756,10 +756,16 @@ internal Task CreateDatabaseAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { - Task response = this.CreateAutoscaleDatabaseStreamInternalAsync( - streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), - throughputProperties: throughputProperties, + Task response = this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: this.DatabaseRootUri, + resourceType: ResourceType.Database, + operationType: OperationType.Create, requestOptions: requestOptions, + cosmosContainerCore: null, + partitionKey: null, + streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), + diagnosticsContext: null, cancellationToken: cancellationToken); return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); @@ -780,25 +786,6 @@ internal Task CreateDatabaseAsync( return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); } - private Task CreateAutoscaleDatabaseStreamInternalAsync( - Stream streamPayload, - ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return this.ClientContext.ProcessResourceOperationStreamAsync( - resourceUri: this.DatabaseRootUri, - resourceType: ResourceType.Database, - operationType: OperationType.Create, - requestOptions: requestOptions, - cosmosContainerCore: null, - partitionKey: null, - streamPayload: streamPayload, - requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), - diagnosticsContext: null, - cancellationToken: cancellationToken); - } - private Task CreateDatabaseStreamInternalAsync( Stream streamPayload, int? throughput = null, From 67042babdd3bdb00c9a0d42134cb91a0ebe2228e Mon Sep 17 00:00:00 2001 From: Jake Willey Date: Fri, 10 Apr 2020 14:15:50 -0700 Subject: [PATCH 15/15] Add autoscale with stream apis --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 66 +++++++++++++++++-- .../src/Handler/RequestMessage.cs | 7 +- Microsoft.Azure.Cosmos/src/Headers/Headers.cs | 3 - .../src/Resource/Database/Database.cs | 32 +++++++++ .../src/Resource/Database/DatabaseCore.cs | 27 ++++++++ .../Resource/Database/DatabaseInlineCore.cs | 14 ++++ .../CosmosThroughputTests.cs | 63 +++++++++++++++--- 7 files changed, 196 insertions(+), 16 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index b03f35c661..36210d15c0 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -750,6 +750,44 @@ internal DatabaseProperties PrepareDatabaseProperties(string id) return databaseProperties; } + /// + /// Send a request for creating a database. + /// + /// A database manages users, permissions and a set of containers. + /// Each Azure Cosmos DB Database Account is able to support multiple independent named databases, + /// with the database being the logical container for data. + /// + /// Each Database consists of one or more containers, each of which in turn contain one or more + /// documents. Since databases are an administrative resource, the Service Master Key will be + /// required in order to access and successfully complete any action using the User APIs. + /// + /// The database properties + /// (Optional) The throughput provisioned for a database in measurement of Request Units per second in the Azure Cosmos DB service. + /// (Optional) A set of options that can be set. + /// (Optional) representing request cancellation. + /// A containing a which wraps a containing the resource record. + /// Request Units + internal virtual Task CreateDatabaseStreamAsync( + DatabaseProperties databaseProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (databaseProperties == null) + { + throw new ArgumentNullException(nameof(databaseProperties)); + } + + this.ClientContext.ValidateResource(databaseProperties.Id); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(databaseProperties); + + return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseStreamInternalAsync( + streamPayload, + throughputProperties, + requestOptions, + cancellationToken)); + } + internal Task CreateDatabaseAsync( DatabaseProperties databaseProperties, ThroughputProperties throughputProperties, @@ -786,11 +824,31 @@ internal Task CreateDatabaseAsync( return this.ClientContext.ResponseFactory.CreateDatabaseResponseAsync(this.GetDatabase(databaseProperties.Id), response); } + private Task CreateDatabaseStreamInternalAsync( + Stream streamPayload, + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) + { + ThroughputProperties throughputProperties = null; + if (throughput.HasValue) + { + throughputProperties = ThroughputProperties.CreateFixedThroughput(throughput.Value); + } + + return this.CreateDatabaseStreamInternalAsync( + streamPayload, + throughputProperties, + requestOptions, + cancellationToken); + + } + private Task CreateDatabaseStreamInternalAsync( Stream streamPayload, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + ThroughputProperties throughputProperties, + RequestOptions requestOptions, + CancellationToken cancellationToken) { return this.ClientContext.ProcessResourceOperationStreamAsync( resourceUri: this.DatabaseRootUri, @@ -800,7 +858,7 @@ private Task CreateDatabaseStreamInternalAsync( cosmosContainerCore: null, partitionKey: null, streamPayload: streamPayload, - requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputHeader(throughput), + requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), diagnosticsContext: null, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs index bf33bdd90f..2c71410376 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs @@ -171,6 +171,11 @@ internal void AddThroughputHeader(int? throughputValue) internal void AddThroughputPropertiesHeader(ThroughputProperties throughputProperties) { + if (throughputProperties == null) + { + return; + } + if (throughputProperties.Throughput.HasValue && (throughputProperties.MaxAutoscaleThroughput.HasValue || throughputProperties.AutoUpgradeMaxThroughputIncrementPercentage.HasValue)) { @@ -183,7 +188,7 @@ internal void AddThroughputPropertiesHeader(ThroughputProperties throughputPrope } else if (throughputProperties?.Content?.OfferAutoscaleSettings != null) { - this.Headers.OfferAutoscaleThroughput = throughputProperties.Content.OfferAutoscaleSettings.GetJsonString(); + this.Headers.Add(HttpConstants.HttpHeaders.OfferAutopilotSettings, throughputProperties.Content.OfferAutoscaleSettings.GetJsonString()); } } diff --git a/Microsoft.Azure.Cosmos/src/Headers/Headers.cs b/Microsoft.Azure.Cosmos/src/Headers/Headers.cs index 60daf309eb..a314effffb 100644 --- a/Microsoft.Azure.Cosmos/src/Headers/Headers.cs +++ b/Microsoft.Azure.Cosmos/src/Headers/Headers.cs @@ -170,9 +170,6 @@ internal string RetryAfterLiteral [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.OfferThroughput)] internal string OfferThroughput { get; set; } - [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.OfferAutopilotSettings)] - internal string OfferAutoscaleThroughput { get; set; } - [CosmosKnownHeaderAttribute(HeaderName = HttpConstants.HttpHeaders.IfNoneMatch)] internal string IfNoneMatch { get; set; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index c2802f438b..48b75c7ed6 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -217,6 +217,38 @@ public abstract Task CreateContainerAsync( ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Creates a container as an asynchronous operation in the Azure Cosmos service. + /// + /// The object. + /// (Optional) The throughput provisioned for a container in measurement of Request Units per second in the Azure Cosmos DB service. + /// (Optional) The options for the container request. + /// (Optional) representing request cancellation. + /// A containing a containing the created resource record. + /// + /// Creates a container as an asynchronous operation in the Azure Cosmos service and return stream response. + /// + /// + /// + /// + /// + /// Request Units + public abstract Task CreateContainerStreamAsync( + ContainerProperties containerProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)); #endif /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index bc9542d7cb..0b6154d021 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -122,6 +122,33 @@ internal async Task ReplaceThroughputIfExistsAsync( requestOptions: requestOptions, cancellationToken: cancellationToken); } + +#if INTERNAL + public override +#else + internal +#endif + Task CreateContainerStreamAsync( + ContainerProperties containerProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (containerProperties == null) + { + throw new ArgumentNullException(nameof(containerProperties)); + } + + this.ValidateContainerProperties(containerProperties); + + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(containerProperties); + return this.ProcessCollectionCreateAsync( + streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), + throughputProperties: throughputProperties, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + #if INTERNAL public override #else diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index eb74b3c962..017e7e4ad2 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -228,6 +228,20 @@ Task CreateContainerAsync(ContainerProperties containerProper return TaskHelper.RunInlineIfNeededAsync(() => this.database.CreateContainerAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); } +#if INTERNAL + public override +#else + internal +#endif + Task CreateContainerStreamAsync( + ContainerProperties containerProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + return TaskHelper.RunInlineIfNeededAsync(() => this.database.CreateContainerStreamAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); + } + public override Task UpsertUserAsync( string id, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index c81dea0fa5..b1faf24a90 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -5,6 +5,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; + using System.IO; using System.Net; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -31,6 +32,30 @@ public void TestCleanup() this.cosmosClient.Dispose(); } + [TestMethod] + public async Task CreateDropAutoscaleDatabaseStreamApi() + { + string databaseId = Guid.NewGuid().ToString(); + using (ResponseMessage response = await this.cosmosClient.CreateDatabaseStreamAsync( + new DatabaseProperties(databaseId), + ThroughputProperties.CreateAutoscaleProvionedThroughput(5000))) + { + Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); + } + + DatabaseCore database = (DatabaseInlineCore)this.cosmosClient.GetDatabase(databaseId); + ThroughputResponse autoscale = await database.ReadThroughputAsync(requestOptions: null); + Assert.IsNotNull(autoscale); + Assert.AreEqual(5000, autoscale.Resource.MaxAutoscaleThroughput); + + ThroughputResponse autoscaleReplaced = await database.ReplaceThroughputPropertiesAsync( + ThroughputProperties.CreateAutoscaleProvionedThroughput(10000)); + Assert.IsNotNull(autoscaleReplaced); + Assert.AreEqual(10000, autoscaleReplaced.Resource.MaxAutoscaleThroughput); + + await database.DeleteAsync(); + } + [TestMethod] public async Task CreateDropAutoscaleDatabase() { @@ -114,16 +139,42 @@ public async Task CreateDropAutoscaleAutoUpgradeDatabase() await database.DeleteAsync(); } + [TestMethod] + [Ignore] // Not currently working with emulator + public async Task CreateDropAutoscaleContainerStreamApi() + { + DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString()); + + ThroughputResponse databaseThroughput = await database.ReadThroughputIfExistsAsync(requestOptions: null); + Assert.IsNotNull(databaseThroughput); + Assert.AreEqual(HttpStatusCode.NotFound, databaseThroughput.StatusCode); + + string streamContainerId = Guid.NewGuid().ToString(); + + using (ResponseMessage response = await database.CreateContainerStreamAsync( + new ContainerProperties(streamContainerId, "/pk"), + ThroughputProperties.CreateAutoscaleProvionedThroughput(5000))) + { + Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); + + ContainerCore streamContainer = (ContainerInlineCore)database.GetContainer(streamContainerId); + ThroughputResponse autoscaleIfExists = await streamContainer.ReadThroughputIfExistsAsync(requestOptions: null); + Assert.IsNotNull(autoscaleIfExists); + Assert.AreEqual(5000, autoscaleIfExists.Resource.MaxAutoscaleThroughput); + } + } + [TestMethod] [Ignore] // Not currently working with emulator public async Task CreateDropAutoscaleContainer() { DatabaseCore database = (DatabaseInlineCore)await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString()); - - ThroughputResponse databaseThroughput = await database.ReadThroughputIfExistsAsync(requestOptions: null); - Assert.IsNotNull(databaseThroughput); - Assert.AreEqual(HttpStatusCode.NotFound, databaseThroughput.StatusCode); + + ThroughputResponse databaseThroughput = await database.ReadThroughputIfExistsAsync(requestOptions: null); + Assert.IsNotNull(databaseThroughput); + Assert.AreEqual(HttpStatusCode.NotFound, databaseThroughput.StatusCode); ContainerCore container = (ContainerInlineCore)await database.CreateContainerAsync( new ContainerProperties(Guid.NewGuid().ToString(), "/pk"), @@ -134,10 +185,6 @@ public async Task CreateDropAutoscaleContainer() Assert.IsNotNull(autoscale); Assert.AreEqual(5000, autoscale.Resource.MaxAutoscaleThroughput); - ThroughputResponse autoscaleIfExists = await container.ReadThroughputIfExistsAsync(requestOptions: null); - Assert.IsNotNull(autoscaleIfExists); - Assert.AreEqual(5000, autoscaleIfExists.Resource.MaxAutoscaleThroughput); - ThroughputResponse autoscaleReplaced = await container.ReplaceThroughputPropertiesAsync( ThroughputProperties.CreateAutoscaleProvionedThroughput(10000)); Assert.IsNotNull(autoscaleReplaced);