Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Security;
using System.Text;
using Microsoft.Azure.Cosmos.CosmosElements;
using Microsoft.Azure.Cosmos.Query;
Expand Down Expand Up @@ -50,7 +51,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; } = GetDefaultODEValue();

/// <summary>
/// Gets or sets the maximum number of items that can be buffered client side during
Expand Down Expand Up @@ -280,5 +281,29 @@ internal static void FillContinuationToken(
request.Headers.ContinuationToken = continuationToken;
}
}

/// <summary>
/// Returns the default value for ODE when QueryRequestOptions are initialized.
/// </summary>
/// <returns>If an environment variable named EnableOptimisticDirectExecution has as a boolean (true/false) value, it will be honored, otherwise default value of True</returns>
private static bool GetDefaultODEValue()
{
string enableODEEnvironmentValue;
try
{
enableODEEnvironmentValue = Environment.GetEnvironmentVariable(nameof(EnableOptimisticDirectExecution));
}
catch (SecurityException)
{
// Ignore permission failure in trying to retrieve the environment variable.
enableODEEnvironmentValue = null;
}

bool defaultODEValue = (enableODEEnvironmentValue != null &&
bool.TryParse(enableODEEnvironmentValue, out bool environmentValue))
? environmentValue
: true;
return defaultODEValue;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,109 @@ 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
("enableoptimisticdirectexecution", "true", true),
("EnableOptimisticDirectExecution", "True", true),
("enableOptimisticDirectExecution", "TRUE", true),
("ENABLEOPTIMISTICDIRECTEXECUTION", "truE", true),
("enableoptimisticdirectexecution", "false", false),
("EnableOptimisticDirectExecution", "False", false),
("ENABLEOPTIMISTICDIRECTEXECUTION", "FALSE", false),
("Enableoptimisticdirectexecution", "false", false),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), "false", false),
("enableode", "false", true),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), null, true),
("EnableOptimisticDirectExecution", string.Empty, true),
("EnableOptimisticDirectExecution", "", true),
("EnableOptimisticDirectExecution", "'", true),
("EnableOptimisticDirectExecution", "-", true),
("EnableOptimisticDirectExecution", "asdf", true),
})
{
try
{
// Test new value
Environment.SetEnvironmentVariable(name, value);
QueryRequestOptions options2 = new QueryRequestOptions();
Assert.AreEqual(expectedValue, options2.EnableOptimisticDirectExecution, $"EnvironmentVariable:'{name}', expected:'{expectedValue}', actual:'{options2.EnableOptimisticDirectExecution}'");
}
finally
{
// Remove side effects.
Environment.SetEnvironmentVariable(name, null);
}
}

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("EnableOptimisticDirectExecution", 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("EnableOptimisticDirectExecution", null);
}
}

private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCases, Container container)
Expand All @@ -536,9 +639,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 +707,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 +719,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