Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add consistency level to client and query options #541

Merged
merged 4 commits into from
Jul 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Microsoft.Azure.Cosmos/src/CosmosClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -226,7 +227,8 @@ public CosmosClient(
transportClientHandlerFactory: clientOptionsClone.TransportClientHandlerFactory,
connectionPolicy: clientOptionsClone.GetConnectionPolicy(),
enableCpuMonitor: clientOptionsClone.EnableCpuMonitor,
storeClientFactory: clientOptionsClone.StoreClientFactory);
storeClientFactory: clientOptionsClone.StoreClientFactory,
desiredConsistencyLevel: clientOptionsClone.GetDocumentsConsistencyLevel());

this.Init(
clientOptionsClone,
Expand Down Expand Up @@ -622,8 +624,7 @@ internal async virtual Task<ConsistencyLevel> GetAccountConsistencyLevelAsync()
{
if (!this.accountConsistencyLevel.HasValue)
{
await this.DocumentClient.EnsureValidClientAsync();
this.accountConsistencyLevel = (ConsistencyLevel)this.DocumentClient.ConsistencyLevel;
this.accountConsistencyLevel = await this.DocumentClient.GetDefaultConsistencyLevelAsync();
}

return this.accountConsistencyLevel.Value;
Expand Down
33 changes: 32 additions & 1 deletion Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
Expand Down Expand Up @@ -139,6 +140,12 @@ public Collection<RequestHandler> CustomHandlers
/// <seealso cref="CosmosClientBuilder.WithConnectionModeGateway(int?)"/>
public ConnectionMode ConnectionMode { get; set; }

/// <summary>
/// This can be used to weaken the database account consistency level for read operations.
/// If this is not set the database account consistency level will be used for all requests.
/// </summary>
public ConsistencyLevel? ConsistencyLevel { get; set; }

/// <summary>
/// Get ot set the number of times client should retry on rate throttled requests.
/// </summary>
Expand Down Expand Up @@ -171,7 +178,7 @@ public Collection<RequestHandler> CustomHandlers
/// <summary>
/// Gets the user json serializer with the CosmosJsonSerializerWrapper or the default
/// </summary>
[JsonConverter(typeof(ClientOptionJsonConverter))]
kirankumarkolli marked this conversation as resolved.
Show resolved Hide resolved
[JsonIgnore]
internal CosmosSerializer CosmosSerializerWithWrapperOrDefault => this.Serializer == null ? this.PropertiesSerializer : new CosmosJsonSerializerWrapper(this.Serializer);

/// <summary>
Expand Down Expand Up @@ -332,6 +339,30 @@ internal ConnectionPolicy GetConnectionPolicy()
return connectionPolicy;
}

internal Documents.ConsistencyLevel? GetDocumentsConsistencyLevel()
{
if (!this.ConsistencyLevel.HasValue)
{
return null;
}

switch (this.ConsistencyLevel.Value)
{
case Cosmos.ConsistencyLevel.BoundedStaleness:
return Documents.ConsistencyLevel.BoundedStaleness;
case Cosmos.ConsistencyLevel.ConsistentPrefix:
return Documents.ConsistencyLevel.BoundedStaleness;
case Cosmos.ConsistencyLevel.Eventual:
return Documents.ConsistencyLevel.Eventual;
case Cosmos.ConsistencyLevel.Session:
return Documents.ConsistencyLevel.Session;
case Cosmos.ConsistencyLevel.Strong:
return Documents.ConsistencyLevel.Strong;
default:
throw new ArgumentException($"Unsupported ConsistencyLevel {this.ConsistencyLevel.Value}");
}
}

internal static string GetAccountEndpoint(string connectionString)
{
return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint);
Expand Down
4 changes: 2 additions & 2 deletions Microsoft.Azure.Cosmos/src/DocumentClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1443,7 +1443,7 @@ internal async Task<IDictionary<string, object>> GetQueryEngineConfigurationAsyn
return this.accountServiceConfiguration.QueryEngineConfiguration;
}

internal async Task<ConsistencyLevel> GetDefaultConsistencyLevelAsync()
internal virtual async Task<ConsistencyLevel> GetDefaultConsistencyLevelAsync()
{
await this.EnsureValidClientAsync();
return (ConsistencyLevel)this.accountServiceConfiguration.DefaultConsistencyLevel;
Expand Down Expand Up @@ -6435,7 +6435,7 @@ private bool IsValidConsistency(Documents.ConsistencyLevel backendConsistency, D
return true;
}

return ValidationHelpers.ValidateConsistencyLevel(backendConsistency, desiredConsistency);
return ValidationHelpers.IsValidConsistencyLevelOverwrite(backendConsistency, desiredConsistency);
}

private void InitializeDirectConnectivity(IStoreClientFactory storeClientFactory)
Expand Down
14 changes: 13 additions & 1 deletion Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class CosmosClientBuilder
/// CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(
/// accountEndpoint: "https://testcosmos.documents.azure.com:443/",
/// accountKey: "SuperSecretKey")
/// .UseConsistencyLevel(ConsistencyLevel.Strong)
/// .WithConsistencyLevel(ConsistencyLevel.Strong)
/// .WithApplicationRegion("East US 2");
/// CosmosClient client = cosmosClientBuilder.Build();
/// ]]>
Expand Down Expand Up @@ -172,6 +172,18 @@ public CosmosClientBuilder WithConnectionModeDirect()
return this;
}

/// <summary>
/// This can be used to weaken the database account consistency level for read operations.
/// If this is not set the database account consistency level will be used for all requests.
/// </summary>
/// <param name="consistencyLevel">The desired consistency level for the client.</param>
/// <returns>The current <see cref="CosmosClientBuilder"/>.</returns>
public CosmosClientBuilder WithConsistencyLevel(Cosmos.ConsistencyLevel consistencyLevel)
{
this.clientOptions.ConsistencyLevel = consistencyLevel;
return this;
}

/// <summary>
/// Sets the connection mode to Gateway. This is used by the client when connecting to the Azure Cosmos DB service.
/// </summary>
Expand Down
71 changes: 42 additions & 29 deletions Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ namespace Microsoft.Azure.Cosmos.Handlers
internal class RequestInvokerHandler : RequestHandler
{
private readonly CosmosClient client;
private Cosmos.ConsistencyLevel? AccountConsistencyLevel = null;
private Cosmos.ConsistencyLevel? RequestedClientConsistencyLevel;

public RequestInvokerHandler(CosmosClient client)
{
this.client = client;
this.RequestedClientConsistencyLevel = this.client.ClientOptions.ConsistencyLevel;
}

public override async Task<ResponseMessage> SendAsync(
Expand All @@ -40,37 +43,9 @@ public override async Task<ResponseMessage> SendAsync(
{
// Fill request options
promotedRequestOptions.PopulateRequestOptions(request);

// Validate the request consistency compatibility with account consistency
// Type based access context for requested consistency preferred for performance
Cosmos.ConsistencyLevel? consistencyLevel = null;
if (promotedRequestOptions is ItemRequestOptions)
{
consistencyLevel = (promotedRequestOptions as ItemRequestOptions).ConsistencyLevel;
}
else if (promotedRequestOptions is QueryRequestOptions)
{
consistencyLevel = (promotedRequestOptions as QueryRequestOptions).ConsistencyLevel;
}
else if (promotedRequestOptions is StoredProcedureRequestOptions)
{
consistencyLevel = (promotedRequestOptions as StoredProcedureRequestOptions).ConsistencyLevel;
}

if (consistencyLevel.HasValue)
{
Cosmos.ConsistencyLevel accountConsistency = await this.client.GetAccountConsistencyLevelAsync();
if (!ValidationHelpers.ValidateConsistencyLevel(accountConsistency, consistencyLevel.Value))
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentUICulture,
RMResources.InvalidConsistencyLevel,
consistencyLevel.Value.ToString(),
accountConsistency));
}
}
}

await this.ValidateAndSetConsistencyLevelAsync(request);
await this.client.DocumentClient.EnsureValidClientAsync();
await request.AssertPartitioningDetailsAsync(this.client, cancellationToken);
this.FillMultiMasterContext(request);
Expand Down Expand Up @@ -207,5 +182,43 @@ private void FillMultiMasterContext(RequestMessage request)
request.Headers.Set(HttpConstants.HttpHeaders.AllowTentativeWrites, bool.TrueString);
}
}

private async Task ValidateAndSetConsistencyLevelAsync(RequestMessage requestMessage)
{
// Validate the request consistency compatibility with account consistency
// Type based access context for requested consistency preferred for performance
Cosmos.ConsistencyLevel? consistencyLevel = null;
RequestOptions promotedRequestOptions = requestMessage.RequestOptions;
if (promotedRequestOptions != null && promotedRequestOptions.BaseConsistencyLevel.HasValue)
{
consistencyLevel = promotedRequestOptions.BaseConsistencyLevel;
}
else if (this.RequestedClientConsistencyLevel.HasValue)
{
consistencyLevel = this.RequestedClientConsistencyLevel;
}

if (consistencyLevel.HasValue)
{
if (!this.AccountConsistencyLevel.HasValue)
{
this.AccountConsistencyLevel = await this.client.GetAccountConsistencyLevelAsync();
}

if (ValidationHelpers.IsValidConsistencyLevelOverwrite(this.AccountConsistencyLevel.Value, consistencyLevel.Value))
{
// ConsistencyLevel compatibility with back-end configuration will be done by RequestInvokeHandler
requestMessage.Headers.Add(HttpConstants.HttpHeaders.ConsistencyLevel, consistencyLevel.Value.ToString());
}
else
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentUICulture,
RMResources.InvalidConsistencyLevel,
consistencyLevel.Value.ToString(),
this.AccountConsistencyLevel));
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ public class ItemRequestOptions : RequestOptions
/// for each individual request.
/// </para>
/// </remarks>
public ConsistencyLevel? ConsistencyLevel { get; set; }
public ConsistencyLevel? ConsistencyLevel
{
get => this.BaseConsistencyLevel;
set => this.BaseConsistencyLevel = value;
}

/// <summary>
/// Fill the CosmosRequestMessage headers with the set properties
Expand All @@ -117,7 +121,6 @@ internal override void PopulateRequestOptions(RequestMessage request)
}

RequestOptions.SetSessionToken(request, this.SessionToken);
RequestOptions.SetConsistencyLevel(request, this.ConsistencyLevel);

base.PopulateRequestOptions(request);
}
Expand Down
35 changes: 19 additions & 16 deletions Microsoft.Azure.Cosmos/src/RequestOptions/QueryRequestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,25 @@ public class QueryRequestOptions : RequestOptions
/// </remarks>
public PartitionKey? PartitionKey { get; set; }

/// <summary>
/// Gets or sets the consistency level required for the request in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The consistency level required for the request.
/// </value>
/// <remarks>
/// Azure Cosmos DB offers 5 different consistency levels. Strong, Bounded Staleness, Session, Consistent Prefix and Eventual - in order of strongest to weakest consistency. <see cref="ConnectionPolicy"/>
/// <para>
/// While this is set at a database account level, Azure Cosmos DB allows a developer to override the default consistency level
/// for each individual request.
/// </para>
/// </remarks>
public ConsistencyLevel? ConsistencyLevel
{
get => this.BaseConsistencyLevel;
set => this.BaseConsistencyLevel = value;
}

/// <summary>
/// Gets or sets the token for use with session consistency in the Azure Cosmos DB service.
/// </summary>
Expand Down Expand Up @@ -121,21 +140,6 @@ public class QueryRequestOptions : RequestOptions
/// </remarks>
internal string SessionToken { get; set; }

/// <summary>
/// Gets or sets the consistency level required for the request in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The consistency level required for the request.
/// </value>
/// <remarks>
/// Azure Cosmos DB offers 5 different consistency levels. Strong, Bounded Staleness, Session, Consistent Prefix and Eventual - in order of strongest to weakest consistency. <see cref="ConnectionPolicy"/>
/// <para>
/// While this is set at a database account level, Azure Cosmos DB allows a developer to override the default consistency level
/// for each individual request.
/// </para>
/// </remarks>
internal ConsistencyLevel? ConsistencyLevel { get; set; }

internal CosmosSerializationOptions CosmosSerializationOptions { get; set; }

/// <summary>
Expand All @@ -161,7 +165,6 @@ internal override void PopulateRequestOptions(RequestMessage request)
}

RequestOptions.SetSessionToken(request, this.SessionToken);
RequestOptions.SetConsistencyLevel(request, this.ConsistencyLevel);

// Flow the pageSize only when we are not doing client eval
if (this.MaxItemCount.HasValue)
Expand Down
27 changes: 13 additions & 14 deletions Microsoft.Azure.Cosmos/src/RequestOptions/RequestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ public class RequestOptions
/// </summary>
internal bool IsEffectivePartitionKeyRouting { get; set; }

/// <summary>
/// Gets or sets the consistency level required for the request in the Azure Cosmos DB service.
/// Not every request supports consistency level. This allows each child to decide to expose it
/// and use the same base logic
/// </summary>
/// <value>
/// The consistency level required for the request.
/// </value>
/// <remarks>
/// ConsistencyLevel compatibility will validated and set by RequestInvokeHandler
/// </remarks>
internal virtual ConsistencyLevel? BaseConsistencyLevel { get; set; }

/// <summary>
/// Fill the CosmosRequestMessage headers with the set properties
/// </summary>
Expand Down Expand Up @@ -85,20 +98,6 @@ internal bool TryGetResourceUri(out Uri resourceUri)
return false;
}

/// <summary>
/// Set the consistency level
/// </summary>
/// <param name="request">The current request.</param>
/// <param name="consistencyLevel">The desired Consistency level.</param>
internal static void SetConsistencyLevel(RequestMessage request, ConsistencyLevel? consistencyLevel)
{
if (consistencyLevel != null && consistencyLevel.HasValue)
{
// ConsistencyLevel compatibility with back-end configuration will be done by RequestInvokeHandler
request.Headers.Add(HttpConstants.HttpHeaders.ConsistencyLevel, consistencyLevel.ToString());
}
}

/// <summary>
/// Set the session token
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ public class StoredProcedureRequestOptions : RequestOptions
/// for each individual request.
/// </para>
/// </remarks>
public ConsistencyLevel? ConsistencyLevel { get; set; }
public ConsistencyLevel? ConsistencyLevel
{
get => this.BaseConsistencyLevel;
set => this.BaseConsistencyLevel = value;
}

/// <summary>
/// Fill the CosmosRequestMessage headers with the set properties
Expand All @@ -89,7 +93,6 @@ internal override void PopulateRequestOptions(RequestMessage request)
}

RequestOptions.SetSessionToken(request, this.SessionToken);
RequestOptions.SetConsistencyLevel(request, this.ConsistencyLevel);

base.PopulateRequestOptions(request);
}
Expand Down
6 changes: 3 additions & 3 deletions Microsoft.Azure.Cosmos/src/ValidationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ namespace Microsoft.Azure.Cosmos

internal static class ValidationHelpers
{
public static bool ValidateConsistencyLevel(Cosmos.ConsistencyLevel backendConsistency, Cosmos.ConsistencyLevel desiredConsistency)
public static bool IsValidConsistencyLevelOverwrite(Cosmos.ConsistencyLevel backendConsistency, Cosmos.ConsistencyLevel desiredConsistency)
{
return ValidationHelpers.ValidateConsistencyLevel((Documents.ConsistencyLevel)backendConsistency, (Documents.ConsistencyLevel)desiredConsistency);
return ValidationHelpers.IsValidConsistencyLevelOverwrite((Documents.ConsistencyLevel)backendConsistency, (Documents.ConsistencyLevel)desiredConsistency);
}

public static bool ValidateConsistencyLevel(Documents.ConsistencyLevel backendConsistency, Documents.ConsistencyLevel desiredConsistency)
public static bool IsValidConsistencyLevelOverwrite(Documents.ConsistencyLevel backendConsistency, Documents.ConsistencyLevel desiredConsistency)
{
switch (backendConsistency)
{
Expand Down
Loading