Skip to content

Commit 6258e24

Browse files
authored
Query: Add Optimistic Direct Execution configuration override support on the Client (#4122)
* Added ability to accept the AllowOptimisticDirectExecution flag from the backend and use that flag to decide if the Ode pipeline should be used or not. * Added comment and removed extra spacing * Added test coverage * Added exception handling logic * Resolved comments * Added null check for key parameter * Removed changes to common test infra * Removed all changes from QueryPartitionProviderTestInstance * Remove changes pt2 * Removed the dictionary in QueryPartitionProvider and added a bool instead * Updated GetClientDisableOptimisticDirectExecution() * Fixed comments * Revert QueryIterator.cs * Undoing changes to settings.json * Undoing changes to QueryIterator.cs * Updated error message * Made functions static * Cast to bool instead of recasting in GetClientDisableOptimisticDirectExecution() * Added ignore flag * Fixed merge conflicts * Updated GetPartitionedQueryExecutionInfoAndPartitionProvider() * Updated return type in OffsetLimitPageSize()
1 parent 07aa28e commit 6258e24

File tree

7 files changed

+219
-40
lines changed

7 files changed

+219
-40
lines changed

Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.ExecutionContext
3232

3333
internal static class CosmosQueryExecutionContextFactory
3434
{
35+
internal const string ClientDisableOptimisticDirectExecution = "clientDisableOptimisticDirectExecution";
3536
private const string InternalPartitionKeyDefinitionProperty = "x-ms-query-partitionkey-definition";
3637
private const string QueryInspectionPattern = @"\s+(GROUP\s+BY\s+|COUNT\s*\(|MIN\s*\(|MAX\s*\(|AVG\s*\(|SUM\s*\(|DISTINCT\s+)";
3738
private const string OptimisticDirectExecution = "OptimisticDirectExecution";
@@ -250,9 +251,9 @@ private static async Task<TryCatch<IQueryPipelineStage>> TryCreateFromPartitione
250251

251252
TryCatch<IQueryPipelineStage> tryCreatePipelineStage;
252253
Documents.PartitionKeyRange targetRange = await TryGetTargetRangeOptimisticDirectExecutionAsync(
253-
inputParameters,
254-
partitionedQueryExecutionInfo,
255-
cosmosQueryContext,
254+
inputParameters,
255+
partitionedQueryExecutionInfo,
256+
cosmosQueryContext,
256257
containerQueryProperties,
257258
trace);
258259

@@ -761,13 +762,18 @@ private static Documents.PartitionKeyDefinition GetPartitionKeyDefinition(InputP
761762
ContainerQueryProperties containerQueryProperties,
762763
ITrace trace)
763764
{
764-
if (!inputParameters.EnableOptimisticDirectExecution)
765+
bool clientDisableOptimisticDirectExecution = await cosmosQueryContext.QueryClient.GetClientDisableOptimisticDirectExecutionAsync();
766+
767+
// Use the Ode code path only if ClientDisableOptimisticDirectExecution is false and EnableOptimisticDirectExecution is true
768+
if (clientDisableOptimisticDirectExecution || !inputParameters.EnableOptimisticDirectExecution)
765769
{
766-
if (inputParameters.InitialUserContinuationToken != null
767-
&& OptimisticDirectExecutionContinuationToken.IsOptimisticDirectExecutionContinuationToken(inputParameters.InitialUserContinuationToken))
770+
if (inputParameters.InitialUserContinuationToken != null
771+
&& OptimisticDirectExecutionContinuationToken.IsOptimisticDirectExecutionContinuationToken(inputParameters.InitialUserContinuationToken))
768772
{
769-
throw new MalformedContinuationTokenException($"The continuation token supplied requires the Optimistic Direct Execution flag to be enabled in QueryRequestOptions for the query execution to resume. " +
770-
$"{inputParameters.InitialUserContinuationToken}");
773+
string errorMessage = "Execution of this query using the supplied continuation token requires EnableOptimisticDirectExecution to be set in QueryRequestOptions. " +
774+
"If the error persists after that, contact system administrator.";
775+
776+
throw new MalformedContinuationTokenException($"{errorMessage} Continuation Token: {inputParameters.InitialUserContinuationToken}");
771777
}
772778

773779
return null;

Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/CosmosQueryClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public abstract Task<TryCatch<QueryPage>> ExecuteItemQueryAsync(
6363
ITrace trace,
6464
CancellationToken cancellationToken);
6565

66+
public abstract Task<bool> GetClientDisableOptimisticDirectExecutionAsync();
67+
6668
public abstract Task<PartitionedQueryExecutionInfo> ExecuteQueryPlanRequestAsync(
6769
string resourceUri,
6870
Documents.ResourceType resourceType,

Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPartitionProvider.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.QueryPlan
1212
using System.Text;
1313
using Microsoft.Azure.Cosmos.Core.Trace;
1414
using Microsoft.Azure.Cosmos.Query.Core.Exceptions;
15+
using Microsoft.Azure.Cosmos.Query.Core.ExecutionContext;
1516
using Microsoft.Azure.Cosmos.Query.Core.Monads;
1617
using Microsoft.Azure.Cosmos.Routing;
1718
using Microsoft.Azure.Cosmos.Tracing;
@@ -46,6 +47,9 @@ internal sealed class QueryPartitionProvider : IDisposable
4647
private bool disposed;
4748
private string queryengineConfiguration;
4849

50+
// TODO: Move this into a config class of its own
51+
public bool ClientDisableOptimisticDirectExecution { get; private set; }
52+
4953
public QueryPartitionProvider(IDictionary<string, object> queryengineConfiguration)
5054
{
5155
if (queryengineConfiguration == null)
@@ -60,6 +64,7 @@ public QueryPartitionProvider(IDictionary<string, object> queryengineConfigurati
6064

6165
this.disposed = false;
6266
this.queryengineConfiguration = JsonConvert.SerializeObject(queryengineConfiguration);
67+
this.ClientDisableOptimisticDirectExecution = GetClientDisableOptimisticDirectExecution((IReadOnlyDictionary<string, object>)queryengineConfiguration);
6368
this.serviceProvider = IntPtr.Zero;
6469

6570
this.serviceProviderStateLock = new object();
@@ -92,6 +97,7 @@ public void Update(IDictionary<string, object> queryengineConfiguration)
9297
if (!string.Equals(this.queryengineConfiguration, newConfiguration))
9398
{
9499
this.queryengineConfiguration = newConfiguration;
100+
this.ClientDisableOptimisticDirectExecution = GetClientDisableOptimisticDirectExecution((IReadOnlyDictionary<string, object>)queryengineConfiguration);
95101

96102
if (!this.disposed && this.serviceProvider != IntPtr.Zero)
97103
{
@@ -132,6 +138,7 @@ public TryCatch<PartitionedQueryExecutionInfo> TryGetPartitionedQueryExecutionIn
132138
allowDCount: allowDCount,
133139
useSystemPrefix: useSystemPrefix,
134140
geospatialType: geospatialType);
141+
135142
if (!tryGetInternalQueryInfo.Succeeded)
136143
{
137144
return TryCatch<PartitionedQueryExecutionInfo>.FromException(tryGetInternalQueryInfo.Exception);
@@ -141,6 +148,16 @@ public TryCatch<PartitionedQueryExecutionInfo> TryGetPartitionedQueryExecutionIn
141148
return TryCatch<PartitionedQueryExecutionInfo>.FromResult(queryInfo);
142149
}
143150

151+
private static bool GetClientDisableOptimisticDirectExecution(IReadOnlyDictionary<string, object> queryengineConfiguration)
152+
{
153+
if (queryengineConfiguration.TryGetValue(CosmosQueryExecutionContextFactory.ClientDisableOptimisticDirectExecution, out object queryConfigProperty))
154+
{
155+
return (bool)queryConfigProperty;
156+
}
157+
158+
return false;
159+
}
160+
144161
internal PartitionedQueryExecutionInfo ConvertPartitionedQueryExecutionInfo(
145162
PartitionedQueryExecutionInfoInternal queryInfoInternal,
146163
PartitionKeyDefinition partitionKeyDefinition)

Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ public override async Task<PartitionedQueryExecutionInfo> ExecuteQueryPlanReques
209209
return partitionedQueryExecutionInfo;
210210
}
211211

212+
public override async Task<bool> GetClientDisableOptimisticDirectExecutionAsync()
213+
{
214+
QueryPartitionProvider provider = await this.clientContext.DocumentClient.QueryPartitionProvider;
215+
return provider.ClientDisableOptimisticDirectExecution;
216+
}
217+
212218
public override async Task<List<PartitionKeyRange>> GetTargetPartitionKeyRangeByFeedRangeAsync(
213219
string resourceLink,
214220
string collectionResourceId,

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/OptimisticDirectExecutionQueryTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public sealed class OptimisticDirectExecutionQueryTests : QueryTestsBase
1717
private const string PartitionKeyField = "key";
1818
private const string NumberField = "numberField";
1919
private const string NullField = "nullField";
20+
private const string ClientDisableOptimisticDirectExecution = "clientDisableOptimisticDirectExecution";
2021

2122
private static class PageSizeOptions
2223
{
@@ -538,6 +539,22 @@ await this.CreateIngestQueryDeleteAsync(
538539
documents,
539540
(container, documents) => RunFailingTests(container, invalidQueries),
540541
"/" + PartitionKeyField);
542+
}
543+
544+
//TODO: Remove Ignore flag once emulator is updated to 1101
545+
[Ignore]
546+
[TestMethod]
547+
public async Task TestClientDisableOdeDefaultValue()
548+
{
549+
string authKey = Utils.ConfigurationManager.AppSettings["MasterKey"];
550+
string endpoint = Utils.ConfigurationManager.AppSettings["GatewayEndpoint"];
551+
552+
CosmosClient client = new CosmosClient($"AccountEndpoint={endpoint};AccountKey={authKey}");
553+
AccountProperties properties = await client.ReadAccountAsync();
554+
555+
bool success = bool.TryParse(properties.QueryEngineConfiguration[ClientDisableOptimisticDirectExecution].ToString(), out bool clientDisablOde);
556+
Assert.IsTrue(success, $"Parsing must succeed. Value supplied '{ClientDisableOptimisticDirectExecution}'");
557+
Assert.IsFalse(clientDisablOde);
541558
}
542559

543560
private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCases, Container container)

0 commit comments

Comments
 (0)