Skip to content

Commit

Permalink
[Internal] Query: Adds environment variable for overriding EnableOpti…
Browse files Browse the repository at this point in the history
…misticDirectExecution default (#4299)

* Configured default value for EnableOptimisticDirectExecution setting to honor environment variable.

* Updated tests to include case insensitive checks no environment variable name.

* Addressed comments.

* Removed unused using.
  • Loading branch information
adityasa authored and kundadebdatta committed Feb 7, 2024
1 parent 9dc9c7f commit 04e1d08
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class QueryRequestOptions : RequestOptions
/// <value>
/// Direct (optimistic) execution offers improved performance for several kinds of queries such as a single partition streaming query.
/// </value>
public bool EnableOptimisticDirectExecution { get; set; } = true;
public bool EnableOptimisticDirectExecution { get; set; } = ConfigurationManager.IsOptimisticDirectExecutionEnabled(defaultValue: true);

/// <summary>
/// Gets or sets the maximum number of items that can be buffered client side during
Expand Down
17 changes: 17 additions & 0 deletions Microsoft.Azure.Cosmos/src/Util/ConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ internal static class ConfigurationManager
/// </summary>
internal static readonly string PartitionLevelFailoverEnabled = "AZURE_COSMOS_PARTITION_LEVEL_FAILOVER_ENABLED";

/// <summary>
/// Environment variable name for overriding optimistic direct execution of queries.
/// </summary>
internal static readonly string OptimisticDirectExecutionEnabled = "AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED";

public static T GetEnvironmentVariable<T>(string variable, T defaultValue)
{
string value = Environment.GetEnvironmentVariable(variable);
Expand Down Expand Up @@ -72,5 +77,17 @@ public static bool IsPartitionLevelFailoverEnabled(
variable: ConfigurationManager.PartitionLevelFailoverEnabled,
defaultValue: defaultValue);
}

/// <summary>
/// Gets the boolean value indicating whether optimistic direct execution is enabled based on the environment variable override.
/// </summary>
public static bool IsOptimisticDirectExecutionEnabled(
bool defaultValue)
{
return ConfigurationManager
.GetEnvironmentVariable(
variable: OptimisticDirectExecutionEnabled,
defaultValue: defaultValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,136 @@ public async Task TestClientDisableOdeDefaultValue()
bool success = bool.TryParse(properties.QueryEngineConfiguration[ClientDisableOptimisticDirectExecution].ToString(), out bool clientDisablOde);
Assert.IsTrue(success, $"Parsing must succeed. Value supplied '{ClientDisableOptimisticDirectExecution}'");
Assert.IsFalse(clientDisablOde);
}

[TestMethod]
public async Task TestOdeEnvironmentVariable()
{
QueryRequestOptions options = new QueryRequestOptions();
Assert.IsTrue(options.EnableOptimisticDirectExecution);

foreach ((string name, string value, bool expectedValue) in new[]
{
// Environment variables are case insensitive in windows
("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", "true", true),
("AZURE_COSMOS_optimistic_direct_execution_enabled", "True", true),
("azure_cosmos_optimistic_direct_execution_enabled", "TRUE", true),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", "truE", true),
("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", "false", false),
("AZURE_COSMOS_optimistic_direct_execution_enabled", "False", false),
("azure_cosmos_optimistic_direct_execution_enabled", "FALSE", false),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", "false", false),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", string.Empty, true),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), "false", true),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), null, true),
("enableode", "false", true)
})
{
try
{
// Test new value
Environment.SetEnvironmentVariable(name, value);
QueryRequestOptions options2 = new QueryRequestOptions();
bool areEqual = expectedValue == options2.EnableOptimisticDirectExecution;
Assert.IsTrue(areEqual, $"EnvironmentVariable:'{name}', value:'{value}', expected:'{expectedValue}', actual:'{options2.EnableOptimisticDirectExecution}'");
}
finally
{
// Remove side effects.
Environment.SetEnvironmentVariable(name, null);
}
}

foreach (string value in new[]
{
"'",
"-",
"asdf",
"'true'",
"'false'"
})
{
bool receivedException = false;
try
{
// Test new value
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", value);
QueryRequestOptions options2 = new QueryRequestOptions();
}
catch(FormatException fe)
{
Assert.IsTrue(fe.ToString().Contains($@"String '{value}' was not recognized as a valid Boolean."));
receivedException = true;
}
finally
{
// Remove side effects.
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", null);
}

Assert.IsTrue(receivedException, $"Expected exception was not received for value '{value}'");
}

await this.TestQueryExecutionUsingODEEnvironmentVariable(
environmentVariableValue: "false",
expectODEPipeline: false);

await this.TestQueryExecutionUsingODEEnvironmentVariable(
environmentVariableValue: "true",
expectODEPipeline: true);
}

private async Task TestQueryExecutionUsingODEEnvironmentVariable(string environmentVariableValue, bool expectODEPipeline)
{
IReadOnlyList<int> empty = new List<int>(0);
IReadOnlyList<int> first5Integers = Enumerable.Range(0, 5).ToList();
IReadOnlyList<int> first7Integers = Enumerable.Range(0, NumberOfDocuments).ToList();
IReadOnlyList<int> first7IntegersReversed = Enumerable.Range(0, NumberOfDocuments).Reverse().ToList();

try
{
// Test query execution using environment variable
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", environmentVariableValue);
PartitionKey partitionKeyValue = new PartitionKey("/value");
List<DirectExecutionTestCase> singlePartitionContainerTestCases = new List<DirectExecutionTestCase>()
{
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: null, // Uses environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: expectODEPipeline ? TestInjections.PipelineType.OptimisticDirectExecution : TestInjections.PipelineType.Passthrough),
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: false, // Overrides environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: TestInjections.PipelineType.Passthrough),
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: true, // Overrides environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: TestInjections.PipelineType.OptimisticDirectExecution),
};

IReadOnlyList<string> documents = CreateDocuments(NumberOfDocuments, PartitionKeyField, NumberField, NullField);

await this.CreateIngestQueryDeleteAsync(
ConnectionModes.Direct | ConnectionModes.Gateway,
CollectionTypes.SinglePartition,
documents,
(container, documents) => RunTests(singlePartitionContainerTestCases, container),
"/" + PartitionKeyField);
}
finally
{
// Attempt to protect other ODE tests from side-effects in case of test failure.
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", null);
}
}

private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCases, Container container)
Expand All @@ -536,9 +666,13 @@ private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCase
{
MaxItemCount = pageSize,
PartitionKey = testCase.PartitionKey,
EnableOptimisticDirectExecution = testCase.EnableOptimisticDirectExecution,
TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, new TestInjections.ResponseStats())
};
};

if(testCase.EnableOptimisticDirectExecution.HasValue)
{
feedOptions.EnableOptimisticDirectExecution = testCase.EnableOptimisticDirectExecution.Value;
}

List<CosmosElement> items = await RunQueryAsync(
container,
Expand Down Expand Up @@ -600,7 +734,7 @@ private static DirectExecutionTestCase CreateInput(
string query,
IReadOnlyList<int> expectedResult,
PartitionKey? partitionKey,
bool enableOptimisticDirectExecution,
bool? enableOptimisticDirectExecution,
int[] pageSizeOptions,
TestInjections.PipelineType expectedPipelineType)
{
Expand All @@ -612,15 +746,15 @@ private readonly struct DirectExecutionTestCase
public string Query { get; }
public IReadOnlyList<int> ExpectedResult { get; }
public PartitionKey? PartitionKey { get; }
public bool EnableOptimisticDirectExecution { get; }
public bool? EnableOptimisticDirectExecution { get; }
public int[] PageSizeOptions { get; }
public TestInjections.PipelineType ExpectedPipelineType { get; }

public DirectExecutionTestCase(
string query,
IReadOnlyList<int> expectedResult,
PartitionKey? partitionKey,
bool enableOptimisticDirectExecution,
bool? enableOptimisticDirectExecution,
int[] pageSizeOptions,
TestInjections.PipelineType expectedPipelineType)
{
Expand Down

0 comments on commit 04e1d08

Please sign in to comment.