From ea9086eee4f6dd383fddfc57138e5b5ee78a112d Mon Sep 17 00:00:00 2001 From: Ananth Mudumba Date: Fri, 9 Jan 2026 15:02:03 -0800 Subject: [PATCH 1/3] HPK: Add internal CosmosClientOptions flag for length aware range comparer rollout control. This change adds an internal-only CosmosClientOptions.UseLengthAwareRangeComparer property to enable controlled rollout of the HPK EPK range comparator fix. This is useful for both V3 and compute gatway rollout control. Background: The HPK EPK normalization fix (released in V3 Preview 3.56.0-preview.0) currently uses an environment variable feature flag (default=True). However, Compute doesn't support environment variables - it only supports TenantConfigurationProvider and CosmosClientOptions for feature flag control. This Change: - Adds internal bool UseLengthAwareRangeComparer to CosmosClientOptions (default=true) - Threads the parameter through the entire query pipeline to QueryRangeUtils - Updates all test call sites to explicitly pass useLengthAwareRangeComparer: true - No public API surface changes (internal-only property) --- .../src/CosmosClientOptions.cs | 14 +++ Microsoft.Azure.Cosmos/src/DocumentClient.cs | 6 +- .../CosmosQueryExecutionContextFactory.cs | 28 ++++-- ...dSearchCrossPartitionQueryPipelineStage.cs | 9 +- ...OrderByCrossPartitionQueryPipelineStage.cs | 88 +++++++++++++------ ...yQueryPartitionRangePageAsyncEnumerator.cs | 19 ++-- ...arallelCrossPartitionQueryPipelineStage.cs | 11 ++- .../QueryPartitionRangePageAsyncEnumerator.cs | 7 +- ...misticDirectExecutionQueryPipelineStage.cs | 9 +- .../Query/Core/Pipeline/PipelineFactory.cs | 18 ++-- .../src/Query/Core/QueryRangeUtils.cs | 14 +-- .../Query/v3Query/CosmosQueryClientCore.cs | 2 +- .../src/Query/v3Query/QueryIterator.cs | 3 +- .../src/Resource/ClientContextCore.cs | 3 +- .../src/Routing/CollectionRoutingMap.cs | 18 ++-- .../src/Routing/PartitionKeyRangeCache.cs | 7 +- .../Query/OrderByPipelineStageBenchmark.cs | 3 +- .../FeedRange/ChangeFeedIteratorCoreTests.cs | 2 + ...yPartitionRangePageAsyncEnumeratorTests.cs | 9 +- .../Pipeline/NonStreamingOrderByQueryTests.cs | 3 +- ...ByCrossPartitionQueryPipelineStageTests.cs | 65 ++++++++------ ...elCrossPartitionQueryPipelineStageTests.cs | 26 +++--- .../QueryPartitionRangePageEnumeratorTests.cs | 9 +- 23 files changed, 244 insertions(+), 129 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index 5c23191678..acd66065ae 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -466,6 +466,20 @@ public System.Text.Json.JsonSerializerOptions UseSystemTextJsonSerializerWithOpt /// The default value for this parameter is 'false'. /// internal bool EnableStreamPassThrough { get; set; } = false; + + /// + /// Gets or sets a value indicating whether to use length-aware range comparators for EPK range comparisons. + /// Length-aware range comparators were introduced in Range class to handle EPK range comparisons correctly + /// in the case of a container's physical partition set consisting of fully and partially specified EPK values. + /// By default, length-aware range comparator is enabled. Refer to Range.cs in Msdata project for more details. + /// Range.LengthAwareMinComparer/LengthAwareMaxComparer. + /// Setting the value to false will disable length-aware range comparator and switch to using the regular + /// Range.MinComparer/MaxComparer. + /// + /// + /// The default value is true. + /// + internal bool UseLengthAwareRangeComparer { get; set; } = true; /// /// (Direct/TCP) Controls the amount of idle time after which unused connections are closed. diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 2dc3f36f2b..bd8441a70c 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -125,6 +125,7 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private readonly bool IsLocalQuorumConsistency = false; private readonly bool isReplicaAddressValidationEnabled; private readonly bool enableAsyncCacheExceptionNoSharing; + private readonly bool useLengthAwareRangeComparator; //Fault Injection private readonly IChaosInterceptorFactory chaosInterceptorFactory; @@ -457,6 +458,7 @@ internal DocumentClient(Uri serviceEndpoint, /// This is distributed tracing flag /// This is the chaos interceptor used for fault injection /// A boolean flag indicating if stack trace optimization is enabled. + /// A boolean flag indicating if length-aware range comparators should be used for EPK range comparisons. /// /// The service endpoint can be obtained from the Azure Management Portal. /// If you are connecting using one of the Master Keys, these can be obtained along with the endpoint from the Azure Management Portal @@ -486,7 +488,8 @@ internal DocumentClient(Uri serviceEndpoint, RemoteCertificateValidationCallback remoteCertificateValidationCallback = null, CosmosClientTelemetryOptions cosmosClientTelemetryOptions = null, IChaosInterceptorFactory chaosInterceptorFactory = null, - bool enableAsyncCacheExceptionNoSharing = true) + bool enableAsyncCacheExceptionNoSharing = true, + bool useLengthAwareRangeComparer = true) { if (sendingRequestEventArgs != null) { @@ -514,6 +517,7 @@ internal DocumentClient(Uri serviceEndpoint, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); this.chaosInterceptorFactory = chaosInterceptorFactory; this.chaosInterceptor = chaosInterceptorFactory?.CreateInterceptor(this); + this.useLengthAwareRangeComparator = useLengthAwareRangeComparer; this.Initialize( serviceEndpoint: serviceEndpoint, diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs index 4a1c518fb9..72ee1435a5 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs @@ -267,7 +267,8 @@ private static async Task> TryCreateFromPartitione containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace); + trace, + inputParameters.UseLengthAwareRangeComparer); Debug.Assert(targetRanges != null, $"{nameof(CosmosQueryExecutionContextFactory)} Assert!", "targetRanges != null"); @@ -517,13 +518,14 @@ private static TryCatch TryCreatePassthroughQueryExecutionC isMinInclusive: true, isMaxInclusive: false))) .ToList(), + partitionKey: inputParameters.PartitionKey, queryPaginationOptions: new QueryExecutionOptions( pageSizeHint: inputParameters.MaxItemCount), - partitionKey: inputParameters.PartitionKey, containerQueryProperties: containerQueryProperties, maxConcurrency: inputParameters.MaxConcurrency, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: inputParameters.InitialUserContinuationToken); + continuationToken: inputParameters.InitialUserContinuationToken, + inputParameters.UseLengthAwareRangeComparer); } private static TryCatch TryCreateFullQueryPipeline( @@ -567,7 +569,8 @@ private static TryCatch TryCreateFullQueryPipeline( allRanges: allFeedRanges, isContinuationExpected: cosmosQueryContext.IsContinuationExpected, maxConcurrency: inputParameters.MaxConcurrency, - requestContinuationToken: inputParameters.InitialUserContinuationToken); + requestContinuationToken: inputParameters.InitialUserContinuationToken, + useLengthAwareRangeComparer: inputParameters.UseLengthAwareRangeComparer); } private static async Task GetPartitionedQueryExecutionInfoAsync( @@ -627,7 +630,8 @@ private static async Task GetPartitionedQueryExec ContainerQueryProperties containerQueryProperties, IReadOnlyDictionary properties, FeedRangeInternal feedRangeInternal, - ITrace trace) + ITrace trace, + bool useLengthAwareRangeComparer = true) { List targetRanges; if (containerQueryProperties.EffectiveRangesForPartitionKey != null) @@ -838,7 +842,8 @@ private InputParameters( bool enableOptimisticDirectExecution, bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, - TestInjections testInjections) + TestInjections testInjections, + bool useLengthAwareRangeComparer = true) { this.SqlQuerySpec = sqlQuerySpec ?? throw new ArgumentNullException(nameof(sqlQuerySpec)); this.InitialUserContinuationToken = initialUserContinuationToken; @@ -854,6 +859,7 @@ private InputParameters( this.IsHybridSearchQueryPlanOptimizationDisabled = isHybridSearchQueryPlanOptimizationDisabled; this.EnableDistributedQueryGatewayMode = enableDistributedQueryGatewayMode; this.TestInjections = testInjections; + this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } public static InputParameters Create( @@ -870,7 +876,8 @@ public static InputParameters Create( bool enableOptimisticDirectExecution, bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, - TestInjections testInjections) + TestInjections testInjections, + bool useLengthAwareRangeComparer = true) { if (sqlQuerySpec == null) { @@ -909,7 +916,8 @@ public static InputParameters Create( enableOptimisticDirectExecution: enableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: isHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: enableDistributedQueryGatewayMode, - testInjections: testInjections); + testInjections: testInjections, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); } public SqlQuerySpec SqlQuerySpec { get; } @@ -926,6 +934,7 @@ public static InputParameters Create( public bool EnableOptimisticDirectExecution { get; } public bool IsHybridSearchQueryPlanOptimizationDisabled { get; } public bool EnableDistributedQueryGatewayMode { get; } + public bool UseLengthAwareRangeComparer { get; } public InputParameters WithContinuationToken(CosmosElement token) { @@ -943,7 +952,8 @@ public InputParameters WithContinuationToken(CosmosElement token) this.EnableOptimisticDirectExecution, this.IsHybridSearchQueryPlanOptimizationDisabled, this.EnableDistributedQueryGatewayMode, - this.TestInjections); + this.TestInjections, + this.UseLengthAwareRangeComparer); } } diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs index 867ef4a0c1..0143484a09 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs @@ -92,7 +92,8 @@ public static TryCatch MonadicCreate( IReadOnlyList allRanges, int maxItemCount, bool isContinuationExpected, - int maxConcurrency) + int maxConcurrency, + bool useLengthAwareRangeComparer) { TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryInfo) { @@ -110,7 +111,8 @@ TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryI emitRawOrderByPayload: true, isContinuationExpected: isContinuationExpected, maxConcurrency: maxConcurrency, - requestContinuationToken: null); + requestContinuationToken: null, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); } State state; @@ -133,7 +135,8 @@ TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryI containerQueryProperties: containerQueryProperties, prefetchPolicy: PrefetchPolicy.PrefetchAll, maxConcurrency: maxConcurrency, - continuationToken: null); + continuationToken: null, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); if (tryCatchGlobalStatisticsPipeline.Failed) { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs index 29f4639ef3..636e66e227 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs @@ -59,6 +59,8 @@ private sealed class InitializationParameters public int MaxConcurrency { get; } + public bool UseLengthAwareRangeComparer { get; } + public InitializationParameters( IDocumentContainer documentContainer, ContainerQueryProperties containerQueryProperties, @@ -68,7 +70,8 @@ public InitializationParameters( IReadOnlyList orderByColumns, QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, - int maxConcurrency) + int maxConcurrency, + bool useLengthAwareRangeComparer) { this.DocumentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.ContainerQueryProperties = containerQueryProperties; @@ -79,6 +82,7 @@ public InitializationParameters( this.QueryPaginationOptions = queryPaginationOptions ?? throw new ArgumentNullException(nameof(queryPaginationOptions)); this.EmitRawOrderByPayload = emitRawOrderByPayload; this.MaxConcurrency = maxConcurrency; + this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } } @@ -100,7 +104,8 @@ public static TryCatch MonadicCreate( int maxConcurrency, bool nonStreamingOrderBy, bool emitRawOrderByPayload, - CosmosElement continuationToken) + CosmosElement continuationToken, + bool useLengthAwareRangeComparer) { if (documentContainer == null) { @@ -144,7 +149,8 @@ public static TryCatch MonadicCreate( queryPaginationOptions, emitRawOrderByPayload, maxConcurrency, - continuationToken); + continuationToken, + useLengthAwareRangeComparer); } SqlQuerySpec rewrittenQueryForOrderBy = new SqlQuerySpec( @@ -160,7 +166,8 @@ public static TryCatch MonadicCreate( orderByColumns, queryPaginationOptions, emitRawOrderByPayload, - maxConcurrency)); + maxConcurrency, + useLengthAwareRangeComparer)); } private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( @@ -170,7 +177,8 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( OrderByQueryPartitionRangePageAsyncEnumerator uninitializedEnumerator, OrderByContinuationToken token, ITrace trace, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + bool useLengthAwareComparer) { cancellationToken.ThrowIfCancellationRequested(); @@ -214,7 +222,8 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( partitionKey: null, uninitializedEnumerator.QueryPaginationOptions, uninitializedEnumerator.Filter, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareComparer); uninitializedEnumeratorsAndTokens.Enqueue((childPaginator, token)); } else @@ -232,7 +241,8 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( partitionKey: null, uninitializedEnumerator.QueryPaginationOptions, uninitializedEnumerator.Filter, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareComparer); uninitializedEnumeratorsAndTokens.Enqueue((childPaginator, token)); } } @@ -336,6 +346,7 @@ private sealed class StreamingOrderByCrossPartitionQueryPipelineStage : IQueryPi private QueryState state; private bool returnedFinalPage; + private bool UseLengthAwareComparer; private static class Expressions { @@ -356,7 +367,8 @@ private StreamingOrderByCrossPartitionQueryPipelineStage( bool emitRawOrderByPayload, int maxConcurrency, IEnumerable<(OrderByQueryPartitionRangePageAsyncEnumerator, OrderByContinuationToken)> uninitializedEnumeratorsAndTokens, - QueryState state) + QueryState state, + bool useLengthAwareComparer) { this.documentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.containerQueryProperties = containerQueryProperties; @@ -367,6 +379,7 @@ private StreamingOrderByCrossPartitionQueryPipelineStage( this.maxConcurrency = maxConcurrency < 0 ? throw new ArgumentOutOfRangeException($"{nameof(maxConcurrency)} must be a non negative number.") : maxConcurrency; this.uninitializedEnumeratorsAndTokens = new Queue<(OrderByQueryPartitionRangePageAsyncEnumerator, OrderByContinuationToken)>(uninitializedEnumeratorsAndTokens ?? throw new ArgumentNullException(nameof(uninitializedEnumeratorsAndTokens))); this.state = state ?? InitializingQueryState; + this.UseLengthAwareComparer = useLengthAwareComparer; } private StreamingOrderByCrossPartitionQueryPipelineStage( @@ -431,7 +444,7 @@ private async ValueTask MoveNextAsync_Initialize_FromBeginningAsync( { if (IsSplitException(uninitializedEnumerator.Current.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token: null, trace, cancellationToken); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token: null, trace, cancellationToken, this.UseLengthAwareComparer); } this.uninitializedEnumeratorsAndTokens.Enqueue((uninitializedEnumerator, token: null)); @@ -518,7 +531,7 @@ private async ValueTask MoveNextAsync_Initialize_FilterAsync( { if (IsSplitException(filterMonad.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken, this.UseLengthAwareComparer); } this.Current = TryCatch.FromException(filterMonad.Exception); @@ -558,7 +571,7 @@ private async ValueTask MoveNextAsync_Initialize_FilterAsync( { if (IsSplitException(filterMonad.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken, this.UseLengthAwareComparer); } } @@ -601,7 +614,8 @@ private async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( OrderByQueryPartitionRangePageAsyncEnumerator uninitializedEnumerator, OrderByContinuationToken token, ITrace trace, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + bool useLengthAwareComparer) { await OrderByCrossPartitionQueryPipelineStage.MoveNextAsync_InitializeAsync_HandleSplitAsync( this.documentContainer, @@ -610,7 +624,8 @@ await OrderByCrossPartitionQueryPipelineStage.MoveNextAsync_InitializeAsync_Hand uninitializedEnumerator, token, trace, - cancellationToken); + cancellationToken, + useLengthAwareComparer); // Recursively retry return await this.MoveNextAsync(trace, cancellationToken); @@ -848,7 +863,8 @@ public static TryCatch MonadicCreate( QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, int maxConcurrency, - CosmosElement continuationToken) + CosmosElement continuationToken, + bool useLengthAwareRangeComparer) { // TODO (brchon): For now we are not honoring non deterministic ORDER BY queries, since there is a bug in the continuation logic. // We can turn it back on once the bug is fixed. @@ -871,7 +887,8 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, TrueFilter, - PrefetchPolicy.PrefetchSinglePage), + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer), (OrderByContinuationToken)null)) .ToList(); } @@ -960,7 +977,8 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -988,7 +1006,8 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1011,7 +1030,8 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1051,7 +1071,8 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter, - PrefetchPolicy.PrefetchSinglePage); + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1067,7 +1088,8 @@ public static TryCatch MonadicCreate( emitRawOrderByPayload, maxConcurrency, enumeratorsAndTokens, - continuationToken == null ? null : new QueryState(continuationToken)); + continuationToken == null ? null : new QueryState(continuationToken), + useLengthAwareRangeComparer); return TryCatch.FromResult(stage); } @@ -1802,7 +1824,8 @@ private async Task MoveNextAsync_InitializeAsync(ITrace this.parameters.QueryPaginationOptions, this.parameters.MaxConcurrency, trace, - cancellationToken); + cancellationToken, + this.parameters.UseLengthAwareRangeComparer); IReadOnlyList sortOrders = this.parameters.OrderByColumns.Select(column => column.SortOrder).ToList(); @@ -1826,7 +1849,8 @@ public static IQueryPipelineStage Create( IReadOnlyList orderByColumns, QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, - int maxConcurrency) + int maxConcurrency, + bool useLengthAwareRangeComparer) { int pageSize = queryPaginationOptions.PageSizeLimit.GetValueOrDefault(MaximumPageSize) > 0 ? Math.Min(MaximumPageSize, queryPaginationOptions.PageSizeLimit.Value) : @@ -1841,7 +1865,8 @@ public static IQueryPipelineStage Create( orderByColumns, queryPaginationOptions, emitRawOrderByPayload, - maxConcurrency); + maxConcurrency, + useLengthAwareRangeComparer); return new NonStreamingOrderByPipelineStage( parameters, @@ -1857,16 +1882,20 @@ private sealed class OrderByCrossPartitionRangePageEnumerator : ITracingAsyncEnu private readonly Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens; + private readonly bool UseLengthAwareComparer; + public TryCatch Current { get; private set; } private OrderByCrossPartitionRangePageEnumerator( IDocumentContainer documentContainer, Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens, - ContainerQueryProperties containerQueryProperties) + ContainerQueryProperties containerQueryProperties, + bool useLengthAwareComparer) { this.documentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.enumeratorsAndTokens = enumeratorsAndTokens ?? throw new ArgumentNullException(nameof(enumeratorsAndTokens)); this.containerQueryProperties = containerQueryProperties; + this.UseLengthAwareComparer = useLengthAwareComparer; } public static async Task>> CreateAsync( @@ -1878,7 +1907,8 @@ public static async Task>> Cr QueryExecutionOptions queryPaginationOptions, int maxConcurrency, ITrace trace, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + bool useLengthAwareRangeComparer) { Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens = new Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)>(targetRanges.Count); @@ -1892,7 +1922,8 @@ public static async Task>> Cr partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchAll); + PrefetchPolicy.PrefetchAll, + useLengthAwareRangeComparer); enumeratorsAndTokens.Enqueue(new (enumerator, null)); } @@ -1903,7 +1934,7 @@ await ParallelPrefetch.PrefetchInParallelAsync( trace, cancellationToken); - return new OrderByCrossPartitionRangePageEnumerator(documentContainer, enumeratorsAndTokens, containerQueryProperties); + return new OrderByCrossPartitionRangePageEnumerator(documentContainer, enumeratorsAndTokens, containerQueryProperties, useLengthAwareRangeComparer); } public async ValueTask DisposeAsync() @@ -1965,7 +1996,8 @@ await MoveNextAsync_InitializeAsync_HandleSplitAsync( enumerator, token, trace, - cancellationToken); + cancellationToken, + this.UseLengthAwareComparer); } else { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs index 404dccb513..095467ab24 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs @@ -27,7 +27,8 @@ public static OrderByQueryPartitionRangePageAsyncEnumerator Create( PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, string filter, - PrefetchPolicy prefetchPolicy) + PrefetchPolicy prefetchPolicy, + bool useLengthAwareRangeComparer) { InnerEnumerator enumerator = new InnerEnumerator( queryDataSource, @@ -36,7 +37,8 @@ public static OrderByQueryPartitionRangePageAsyncEnumerator Create( feedRangeState, partitionKey, queryPaginationOptions, - filter); + filter, + useLengthAwareRangeComparer); BufferedPartitionRangePageAsyncEnumeratorBase bufferedEnumerator = prefetchPolicy switch { @@ -118,7 +120,8 @@ public InnerEnumerator( FeedRangeState feedRangeState, PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, - string filter) + string filter, + bool useLengthAwareRangeComparer) : base(feedRangeState) { this.queryDataSource = queryDataSource ?? throw new ArgumentNullException(nameof(queryDataSource)); @@ -126,7 +129,8 @@ public InnerEnumerator( this.SqlQuerySpec = sqlQuerySpec ?? throw new ArgumentNullException(nameof(sqlQuerySpec)); this.PartitionKey = partitionKey; this.QueryPaginationOptions = queryPaginationOptions ?? QueryExecutionOptions.Default; - this.Filter = filter; + this.Filter = filter; + this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } public SqlQuerySpec SqlQuerySpec { get; } @@ -137,6 +141,8 @@ public InnerEnumerator( public string Filter { get; } + public bool UseLengthAwareRangeComparer { get; } + public InnerEnumerator CloneWithMaxPageSize() { QueryExecutionOptions options = new QueryExecutionOptions( @@ -151,14 +157,15 @@ public InnerEnumerator CloneWithMaxPageSize() this.FeedRangeState, this.PartitionKey, options, - this.Filter); + this.Filter, + this.UseLengthAwareRangeComparer); } public override ValueTask DisposeAsync() => default; protected override async Task> GetNextPageAsync(ITrace trace, CancellationToken cancellationToken) { - FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.PartitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties); + FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.PartitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties, this.UseLengthAwareRangeComparer); TryCatch monadicQueryPage = await this.queryDataSource .MonadicQueryAsync( diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs index 5a2fc378d2..36920478ea 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs @@ -137,7 +137,8 @@ public static TryCatch MonadicCreate( ContainerQueryProperties containerQueryProperties, int maxConcurrency, PrefetchPolicy prefetchPolicy, - CosmosElement continuationToken) + CosmosElement continuationToken, + bool useLengthAwareRangeComparer) { if (targetRanges == null) { @@ -159,7 +160,7 @@ public static TryCatch MonadicCreate( CrossPartitionRangePageAsyncEnumerator crossPartitionPageEnumerator = new CrossPartitionRangePageAsyncEnumerator( feedRangeProvider: documentContainer, - createPartitionRangeEnumerator: ParallelCrossPartitionQueryPipelineStage.MakeCreateFunction(documentContainer, sqlQuerySpec, queryPaginationOptions, partitionKey, containerQueryProperties), + createPartitionRangeEnumerator: ParallelCrossPartitionQueryPipelineStage.MakeCreateFunction(documentContainer, sqlQuerySpec, queryPaginationOptions, partitionKey, containerQueryProperties, useLengthAwareRangeComparer), comparer: Comparer.Singleton, maxConcurrency: maxConcurrency, prefetchPolicy: prefetchPolicy, @@ -245,13 +246,15 @@ private static CreatePartitionRangePageAsyncEnumerator Ma SqlQuerySpec sqlQuerySpec, QueryExecutionOptions queryPaginationOptions, Cosmos.PartitionKey? partitionKey, - ContainerQueryProperties containerQueryProperties) => (FeedRangeState feedRangeState) => new QueryPartitionRangePageAsyncEnumerator( + ContainerQueryProperties containerQueryProperties, + bool useLengthAwareRangeComparer) => (FeedRangeState feedRangeState) => new QueryPartitionRangePageAsyncEnumerator( queryDataSource, sqlQuerySpec, feedRangeState, partitionKey, queryPaginationOptions, - containerQueryProperties); + containerQueryProperties, + useLengthAwareRangeComparer); private sealed class Comparer : IComparer> { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs index 8e918d16f7..c067c5afbe 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs @@ -20,6 +20,7 @@ internal sealed class QueryPartitionRangePageAsyncEnumerator : PartitionRangePag private readonly QueryExecutionOptions queryPaginationOptions; private readonly ContainerQueryProperties containerQueryProperties; private readonly Cosmos.PartitionKey? partitionKey; + private readonly bool useLengthAwareRangeComparer; public QueryPartitionRangePageAsyncEnumerator( IQueryDataSource queryDataSource, @@ -27,7 +28,8 @@ public QueryPartitionRangePageAsyncEnumerator( FeedRangeState feedRangeState, Cosmos.PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, - ContainerQueryProperties containerQueryProperties) + ContainerQueryProperties containerQueryProperties, + bool useLengthAwareRangeComparer) : base(feedRangeState) { this.queryDataSource = queryDataSource ?? throw new ArgumentNullException(nameof(queryDataSource)); @@ -35,6 +37,7 @@ public QueryPartitionRangePageAsyncEnumerator( this.queryPaginationOptions = queryPaginationOptions; this.partitionKey = partitionKey; this.containerQueryProperties = containerQueryProperties; + this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; } public override ValueTask DisposeAsync() => default; @@ -46,7 +49,7 @@ protected override Task> GetNextPageAsync(ITrace trace, Canc throw new ArgumentNullException(nameof(trace)); } - FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.partitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties); + FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.partitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties, this.useLengthAwareRangeComparer); return this.queryDataSource.MonadicQueryAsync( sqlQuerySpec: this.sqlQuerySpec, feedRangeState: new FeedRangeState(feedRange, this.FeedRangeState.State), diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs index e91f98291b..dc98ca966f 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs @@ -151,7 +151,8 @@ public static TryCatch MonadicCreate( partitionKey: inputParameters.PartitionKey, containerQueryProperties: containerQueryProperties, continuationToken: inputParameters.InitialUserContinuationToken, - cancellationToken: cancellationToken); + cancellationToken: cancellationToken, + useLengthAwareRangeComparer: inputParameters.UseLengthAwareRangeComparer); if (pipelineStage.Failed) { @@ -242,7 +243,8 @@ public static TryCatch MonadicCreate( QueryExecutionOptions queryPaginationOptions, ContainerQueryProperties containerQueryProperties, CosmosElement continuationToken, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + bool useLengthAwareRangeComparer) { if (targetRange == null) { @@ -277,7 +279,8 @@ public static TryCatch MonadicCreate( feedRangeState, partitionKey, queryPaginationOptions, - containerQueryProperties); + containerQueryProperties, + useLengthAwareRangeComparer); OptimisticDirectExecutionQueryPipelineImpl stage = new OptimisticDirectExecutionQueryPipelineImpl(partitionPageEnumerator); return TryCatch.FromResult(stage); diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs index a1603e26f7..43326f9727 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs @@ -40,7 +40,8 @@ public static TryCatch MonadicCreate( IReadOnlyList allRanges, bool isContinuationExpected, int maxConcurrency, - CosmosElement requestContinuationToken) + CosmosElement requestContinuationToken, + bool useLengthAwareRangeComparer = true) { if (documentContainer == null) { @@ -91,7 +92,8 @@ public static TryCatch MonadicCreate( isContinuationExpected: true, emitRawOrderByPayload: false, maxConcurrency: maxConcurrency, - requestContinuationToken: requestContinuationToken); + requestContinuationToken: requestContinuationToken, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); } else { @@ -105,7 +107,8 @@ public static TryCatch MonadicCreate( allRanges: allRanges, maxItemCount: maxItemCount, isContinuationExpected: isContinuationExpected, - maxConcurrency: maxConcurrency); + maxConcurrency: maxConcurrency, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); if (hybridSearchQueryInfo.Skip != null) { @@ -152,7 +155,8 @@ public static TryCatch MonadicCreate( bool emitRawOrderByPayload, bool isContinuationExpected, int maxConcurrency, - CosmosElement requestContinuationToken) + CosmosElement requestContinuationToken, + bool useLengthAwareRangeComparer) { // We need to compute the optimal initial page size for order-by queries long optimalPageSize = maxItemCount; @@ -218,7 +222,8 @@ public static TryCatch MonadicCreate( nonStreamingOrderBy: queryInfo.HasNonStreamingOrderBy, emitRawOrderByPayload: emitRawOrderByPayload, continuationToken: continuationToken, - containerQueryProperties: containerQueryProperties); + containerQueryProperties: containerQueryProperties, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); } else { @@ -231,7 +236,8 @@ public static TryCatch MonadicCreate( containerQueryProperties: containerQueryProperties, prefetchPolicy: prefetchPolicy, maxConcurrency: maxConcurrency, - continuationToken: continuationToken); + continuationToken: continuationToken, + useLengthAwareRangeComparer: useLengthAwareRangeComparer); } if (queryInfo.HasAggregates && !queryInfo.HasGroupBy) diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs index 0f2fc818bc..77f7d01048 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs @@ -22,7 +22,7 @@ internal static class QueryRangeUtils /// Since such an epk range does not exist at the container level, Service generates a GoneException. /// This method restrics the range of each enumerator by intersecting it with physical partition range. /// - public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? partitionKey, FeedRangeInternal feedRange, ContainerQueryProperties containerQueryProperties) + public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? partitionKey, FeedRangeInternal feedRange, ContainerQueryProperties containerQueryProperties, bool useLengthAwareRangeComparer) { // We sadly need to check the partition key, since a user can set a partition key in the request options with a different continuation token. // In the future the partition filtering and continuation information needs to be a tightly bounded contract (like cross feed range state). @@ -56,11 +56,11 @@ public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? parti bool maxInclusive; //LengthAwareComparer is the default Range comparer and flag is used to ovverride the default comparer to legacy Min/Max comparer. - IComparer> minComparer = IsLengthAwareComparisonEnabled + IComparer> minComparer = useLengthAwareRangeComparer ? Documents.Routing.Range.LengthAwareMinComparer.Instance : Documents.Routing.Range.MinComparer.Instance; - IComparer> maxComparer = IsLengthAwareComparisonEnabled + IComparer> maxComparer = useLengthAwareRangeComparer ? Documents.Routing.Range.LengthAwareMaxComparer.Instance : Documents.Routing.Range.MaxComparer.Instance; @@ -117,16 +117,18 @@ public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? parti /// /// The list of partition key ranges to trim /// The EPK ranges to use as boundaries + /// Whether to use length-aware range comparers /// A list of trimmed partition key ranges that fit within the provided ranges public static List LimitPartitionKeyRangesToProvidedRanges( List partitionKeyRanges, - IReadOnlyList> providedRanges) + IReadOnlyList> providedRanges, + bool useLengthAwareComparer = true) { - IComparer> minComparer = IsLengthAwareComparisonEnabled + IComparer> minComparer = useLengthAwareComparer ? Documents.Routing.Range.LengthAwareMinComparer.Instance : Documents.Routing.Range.MinComparer.Instance; - IComparer> maxComparer = IsLengthAwareComparisonEnabled + IComparer> maxComparer = useLengthAwareComparer ? Documents.Routing.Range.LengthAwareMaxComparer.Instance : Documents.Routing.Range.MaxComparer.Instance; diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs index 2f5b9f15c5..7ab008d7dd 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs @@ -240,7 +240,7 @@ public override async Task> GetTargetPartitionKeyRangeBy forceRefresh, childTrace); - return QueryRangeUtils.LimitPartitionKeyRangesToProvidedRanges(ranges, providedRanges); + return QueryRangeUtils.LimitPartitionKeyRangesToProvidedRanges(ranges, providedRanges, this.clientContext.ClientOptions.UseLengthAwareRangeComparer); } } diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs index cc09cd3215..c265a38c84 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs @@ -151,7 +151,8 @@ public static QueryIterator Create( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode && (clientContext.ClientOptions.ConnectionMode == ConnectionMode.Gateway), - testInjections: queryRequestOptions.TestSettings); + testInjections: queryRequestOptions.TestSettings, + useLengthAwareRangeComparer: clientContext.ClientOptions.UseLengthAwareRangeComparer); return new QueryIterator( cosmosQueryContext, diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs index 0014ed843a..f348414a9d 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs @@ -88,7 +88,8 @@ internal static CosmosClientContext Create( remoteCertificateValidationCallback: ClientContextCore.SslCustomValidationCallBack(clientOptions.GetServerCertificateCustomValidationCallback()), cosmosClientTelemetryOptions: clientOptions.CosmosClientTelemetryOptions, chaosInterceptorFactory: clientOptions.ChaosInterceptorFactory, - enableAsyncCacheExceptionNoSharing: clientOptions.EnableAsyncCacheExceptionNoSharing); + enableAsyncCacheExceptionNoSharing: clientOptions.EnableAsyncCacheExceptionNoSharing, + useLengthAwareRangeComparer: clientOptions.UseLengthAwareRangeComparer); return ClientContextCore.Create( cosmosClient, diff --git a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs index e88c090248..8b8bded6ed 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs @@ -38,7 +38,8 @@ private CollectionRoutingMap( Dictionary> rangeById, List orderedPartitionKeyRanges, string collectionUniqueId, - string changeFeedNextIfNoneMatch) + string changeFeedNextIfNoneMatch, + bool useLengthAwareRangeComparer = true) { this.rangeById = rangeById; this.orderedPartitionKeyRanges = orderedPartitionKeyRanges; @@ -72,10 +73,7 @@ private CollectionRoutingMap( return range.Status == PartitionKeyRangeStatus.Offline ? CollectionRoutingMap.InvalidPkRangeId : pkId; }); - //LengthAwareComparer is the default Range comparer and flag is used to ovverride the default comparer to legacy Min/Max comparer. - bool useLengthAwareComparer = ConfigurationManager.IsLengthAwareRangeComparatorEnabled(); - - this.comparers = useLengthAwareComparer + this.comparers = useLengthAwareRangeComparer ? (Range.LengthAwareMinComparer.Instance, Range.LengthAwareMaxComparer.Instance) : (Range.MinComparer.Instance, Range.MaxComparer.Instance); } @@ -83,7 +81,8 @@ private CollectionRoutingMap( public static CollectionRoutingMap TryCreateCompleteRoutingMap( IEnumerable> ranges, string collectionUniqueId, - string changeFeedNextIfNoneMatch = null) + string changeFeedNextIfNoneMatch = null, + bool useLengthAwareRangeComparer = true) { Dictionary> rangeById = new Dictionary>(StringComparer.Ordinal); @@ -102,7 +101,7 @@ public static CollectionRoutingMap TryCreateCompleteRoutingMap( return null; } - return new CollectionRoutingMap(rangeById, orderedRanges, collectionUniqueId, changeFeedNextIfNoneMatch); + return new CollectionRoutingMap(rangeById, orderedRanges, collectionUniqueId, changeFeedNextIfNoneMatch, useLengthAwareRangeComparer); } public string CollectionUniqueId { get; private set; } @@ -212,7 +211,8 @@ public ServiceIdentity TryGetInfoByPartitionKeyRangeId(string partitionKeyRangeI public CollectionRoutingMap TryCombine( IEnumerable> ranges, - string changeFeedNextIfNoneMatch) + string changeFeedNextIfNoneMatch, + bool useLengthAwareComparer = true) { HashSet newGoneRanges = new HashSet(ranges.SelectMany(tuple => tuple.Item1.Parents ?? Enumerable.Empty())); newGoneRanges.UnionWith(this.goneRanges); @@ -239,7 +239,7 @@ public CollectionRoutingMap TryCombine( return null; } - return new CollectionRoutingMap(newRangeById, newOrderedRanges, this.CollectionUniqueId, changeFeedNextIfNoneMatch); + return new CollectionRoutingMap(newRangeById, newOrderedRanges, this.CollectionUniqueId, changeFeedNextIfNoneMatch, useLengthAwareComparer); } private class MinPartitionKeyTupleComparer : IComparer> diff --git a/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs b/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs index 8a31c924fb..1ba6378b02 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs @@ -31,13 +31,15 @@ internal class PartitionKeyRangeCache : IRoutingMapProvider, ICollectionRoutingM private readonly IStoreModel storeModel; private readonly CollectionCache collectionCache; private readonly IGlobalEndpointManager endpointManager; + private readonly bool useLengthAwareRangeComparer; public PartitionKeyRangeCache( ICosmosAuthorizationTokenProvider authorizationTokenProvider, IStoreModel storeModel, CollectionCache collectionCache, IGlobalEndpointManager endpointManager, - bool enableAsyncCacheExceptionNoSharing = true) + bool enableAsyncCacheExceptionNoSharing = true, + bool useLengthAwareRangeComparer = true) { this.routingMapCache = new AsyncCacheNonBlocking( keyEqualityComparer: StringComparer.Ordinal, @@ -46,6 +48,7 @@ public PartitionKeyRangeCache( this.storeModel = storeModel; this.collectionCache = collectionCache; this.endpointManager = endpointManager; + this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; } public virtual async Task> TryGetOverlappingRangesAsync( @@ -246,7 +249,7 @@ private async Task GetRoutingMapForCollectionAsync( } else { - routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch); + routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch, this.useLengthAwareRangeComparer); } if (routingMap == null) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs index 1ebfb165f2..ad2124b8a2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs @@ -70,7 +70,8 @@ private static async Task CreateAndRunPipeline(IDocumentContainer documentContai nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); IQueryPipelineStage pipeline = pipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs index 251b199468..5a1190ef26 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs @@ -5,12 +5,14 @@ namespace Microsoft.Azure.Cosmos.Tests.FeedRange { using System; + using System.ClientModel; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.ChangeFeed; + using Microsoft.Azure.Cosmos.ChangeFeed.Pagination; using Microsoft.Azure.Cosmos.CosmosElements; using Microsoft.Azure.Cosmos.Pagination; using Microsoft.Azure.Cosmos.Query.Core.Monads; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs index 6c189e92e7..fb6470e67c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs @@ -58,15 +58,16 @@ protected override Task>> CreateEnum IAsyncEnumerator> enumerator = new TracingAsyncEnumerator>( OrderByQueryPartitionRangePageAsyncEnumerator.Create( - queryDataSource: documentContainer, + queryDataSource: documentContainer, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), sqlQuerySpec: new Cosmos.Query.Core.SqlQuerySpec("SELECT * FROM c"), feedRangeState: new FeedRangeState(ranges[0], state), partitionKey: null, queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), - filter: "filter", - PrefetchPolicy.PrefetchSinglePage), - NoOpTrace.Singleton, + filter: "filter", + PrefetchPolicy.PrefetchSinglePage, + useLengthAwareRangeComparer: true), + NoOpTrace.Singleton, cancellationToken); return Task.FromResult(enumerator); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs index f9645ef2a5..357e3c7ced 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs @@ -725,7 +725,8 @@ private static async Task RunParityTests( nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(pipelineStage.Succeeded); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs index 0d819b7bdd..b8ec2ea5c8 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs @@ -80,8 +80,9 @@ public void MonadicCreate_NullContinuationToken() maxConcurrency: 10, nonStreamingOrderBy: false, continuationToken: null, - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -103,8 +104,9 @@ public void MonadicCreate_NonCosmosArrayContinuationToken() maxConcurrency: 10, nonStreamingOrderBy: false, continuationToken: CosmosObject.Create(new Dictionary()), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -127,8 +129,9 @@ public void MonadicCreate_EmptyArrayContinuationToken() maxConcurrency: 10, nonStreamingOrderBy: false, continuationToken: CosmosArray.Create(new List()), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -151,8 +154,9 @@ public void MonadicCreate_NonParallelContinuationToken() maxConcurrency: 10, nonStreamingOrderBy: false, continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -194,8 +198,9 @@ public void MonadicCreate_SingleOrderByContinuationToken() { OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -241,8 +246,9 @@ public void MonadicCreate_SingleOrderByContinuationToken() { OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -304,8 +310,9 @@ public void MonadicCreate_MultipleOrderByContinuationToken() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken1), OrderByContinuationToken.ToCosmosElement(orderByContinuationToken2) }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -348,8 +355,9 @@ public void MonadicCreate_OrderByWithResumeValues() { OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -392,8 +400,9 @@ public void MonadicCreate_OrderByWithResumeValues() { OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -446,8 +455,9 @@ public async Task TestFormattedFiltersForTargetPartitionWithContinuationTokenAsy maxConcurrency: 0, nonStreamingOrderBy: false, continuationToken: CosmosElement.Parse(continuationToken), - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -486,8 +496,9 @@ FROM c maxConcurrency: 10, nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -537,8 +548,9 @@ FROM c maxConcurrency: 10, nonStreamingOrderBy: false, continuationToken: null, - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -601,8 +613,9 @@ FROM c maxConcurrency: 10, nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: continuationToken, - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false); + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + emitRawOrderByPayload: false, + useLengthAwareRangeComparer: true); monadicQueryPipelineStage.ThrowIfFailed(); IQueryPipelineStage queryPipelineStage = monadicQueryPipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs index 248058d2ef..a65c631bad 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs @@ -39,7 +39,8 @@ public void MonadicCreate_NullContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: null); + continuationToken: null, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -57,7 +58,8 @@ public void MonadicCreate_NonCosmosArrayContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosObject.Create(new Dictionary())); + continuationToken: CosmosObject.Create(new Dictionary()), + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -76,7 +78,8 @@ public void MonadicCreate_EmptyArrayContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List())); + continuationToken: CosmosArray.Create(new List()), + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -95,7 +98,8 @@ public void MonadicCreate_NonParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") })); + continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") }), + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -118,7 +122,8 @@ public void MonadicCreate_SingleParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token) })); + continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token) }), + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -148,12 +153,8 @@ public void MonadicCreate_MultipleParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create( - new List() - { - ParallelContinuationToken.ToCosmosElement(token1), - ParallelContinuationToken.ToCosmosElement(token2) - })); + continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token1), ParallelContinuationToken.ToCosmosElement(token2) }), + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicCreate.Succeeded); } @@ -189,7 +190,8 @@ async Task CreatePipelineStateAsync(IDocumentContainer docu containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: aggressivePrefetch ? PrefetchPolicy.PrefetchAll : PrefetchPolicy.PrefetchSinglePage, - continuationToken: continuationToken); + continuationToken: continuationToken, + useLengthAwareRangeComparer: true); Assert.IsTrue(monadicQueryPipelineStage.Succeeded); IQueryPipelineStage queryPipelineStage = monadicQueryPipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs index 4a6c71303c..84e2b9c5ef 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs @@ -101,7 +101,8 @@ public async Task TestSplitAsync() feedRangeState: feedRangeState, partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), + useLengthAwareRangeComparer: true), trace: NoOpTrace.Singleton); HashSet resourceIdentifiers = await this.DrainFullyAsync(enumerable); @@ -144,7 +145,8 @@ protected override IAsyncEnumerable> CreateEnumerable( feedRangeState: feedRangeState, partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), + useLengthAwareRangeComparer: true), trace: NoOpTrace.Singleton); } @@ -167,7 +169,8 @@ protected override Task>> CreateEnumeratorA feedRangeState: new FeedRangeState(ranges[0], state), partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), + useLengthAwareRangeComparer: true), trace: NoOpTrace.Singleton, cancellationToken: default); From 7117b83c6ca45ad47149380ec8de3f636659eebf Mon Sep 17 00:00:00 2001 From: Ananth Mudumba Date: Mon, 12 Jan 2026 10:06:34 -0800 Subject: [PATCH 2/3] Test fixes for PartitionKeyRangeCache mocks --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 6 +- .../CosmosQueryExecutionContextFactory.cs | 12 +- .../Query/Core/Pipeline/PipelineFactory.cs | 2 +- .../src/Routing/CollectionRoutingMap.cs | 10 +- .../src/Routing/PartitionKeyRangeCache.cs | 13 +- .../CosmosItemTests.cs | 3 +- .../FeedToken/QueryFeedTokenTests.cs | 3 +- .../Mocks/MockDocumentClient.cs | 4 +- .../Batch/BatchAsyncBatcherTests.cs | 2 +- .../Batch/BatchAsyncContainerExecutorTests.cs | 10 +- .../Batch/BatchAsyncOperationContextTests.cs | 2 +- ...lkPartitionKeyRangeGoneRetryPolicyTests.cs | 2 +- .../PartitionSynchronizerCoreTests.cs | 7 + .../CollectionRoutingMapTest.cs | 37 +- .../FeedRange/ChangeFeedIteratorCoreTests.cs | 2 - .../GatewayAddressCacheTests.cs | 4 +- .../GatewayStoreModelTest.cs | 34 +- .../PartitionKeyRangeCacheTest.cs | 4 +- .../PartitionKeyRangeHandlerTests.cs | 3 +- ...misticDirectExecutionQueryBaselineTests.cs | 3 +- .../Query/Pipeline/FactoryTests.cs | 3 +- .../Query/Pipeline/FullPipelineTests.cs | 6 +- .../Pipeline/NonStreamingOrderByQueryTests.cs | 3 +- .../Query/SubpartitionTests.cs | 3 +- .../RetryHandlerTests.cs | 2 +- .../IRoutingMapProviderExtensionsTest.cs | 444 +++++++++--------- .../Routing/PartitionRoutingHelperTest.cs | 8 +- .../Tracing/TraceWriterBaselineTests.cs | 3 +- .../Utils/MockDocumentClient.cs | 2 +- .../Utils/TestUtils.cs | 2 +- 30 files changed, 328 insertions(+), 311 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index bd8441a70c..a809a7ab7a 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -125,7 +125,7 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private readonly bool IsLocalQuorumConsistency = false; private readonly bool isReplicaAddressValidationEnabled; private readonly bool enableAsyncCacheExceptionNoSharing; - private readonly bool useLengthAwareRangeComparator; + private readonly bool useLengthAwareRangeComparer; //Fault Injection private readonly IChaosInterceptorFactory chaosInterceptorFactory; @@ -517,7 +517,7 @@ internal DocumentClient(Uri serviceEndpoint, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); this.chaosInterceptorFactory = chaosInterceptorFactory; this.chaosInterceptor = chaosInterceptorFactory?.CreateInterceptor(this); - this.useLengthAwareRangeComparator = useLengthAwareRangeComparer; + this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; this.Initialize( serviceEndpoint: serviceEndpoint, @@ -1105,7 +1105,7 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeCli retryPolicy: this.retryPolicy, telemetryToServiceHelper: this.telemetryToServiceHelper, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); - this.partitionKeyRangeCache = new PartitionKeyRangeCache(this, this.GatewayStoreModel, this.collectionCache, this.GlobalEndpointManager, this.enableAsyncCacheExceptionNoSharing); + this.partitionKeyRangeCache = new PartitionKeyRangeCache(this, this.GatewayStoreModel, this.collectionCache, this.GlobalEndpointManager, this.useLengthAwareRangeComparer, this.enableAsyncCacheExceptionNoSharing); this.ResetSessionTokenRetryPolicy = new ResetSessionTokenRetryPolicyFactory(this.sessionContainer, this.collectionCache, this.retryPolicy); gatewayStoreModel.SetCaches(this.partitionKeyRangeCache, this.collectionCache); diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs index 72ee1435a5..147cdea0e0 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs @@ -455,7 +455,8 @@ private static async Task> TryCreateSpecializedDoc containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace); + trace, + inputParameters.UseLengthAwareRangeComparer); List allRanges = await cosmosQueryContext.QueryClient.GetTargetPartitionKeyRangesAsync( cosmosQueryContext.ResourceLink, @@ -631,7 +632,7 @@ private static async Task GetPartitionedQueryExec IReadOnlyDictionary properties, FeedRangeInternal feedRangeInternal, ITrace trace, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer) { List targetRanges; if (containerQueryProperties.EffectiveRangesForPartitionKey != null) @@ -782,7 +783,8 @@ private static Documents.PartitionKeyDefinition GetPartitionKeyDefinition(InputP containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace); + trace, + inputParameters.UseLengthAwareRangeComparer); } else { @@ -843,7 +845,7 @@ private InputParameters( bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, TestInjections testInjections, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer) { this.SqlQuerySpec = sqlQuerySpec ?? throw new ArgumentNullException(nameof(sqlQuerySpec)); this.InitialUserContinuationToken = initialUserContinuationToken; @@ -877,7 +879,7 @@ public static InputParameters Create( bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, TestInjections testInjections, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer) { if (sqlQuerySpec == null) { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs index 43326f9727..12157c933b 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs @@ -41,7 +41,7 @@ public static TryCatch MonadicCreate( bool isContinuationExpected, int maxConcurrency, CosmosElement requestContinuationToken, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer) { if (documentContainer == null) { diff --git a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs index 8b8bded6ed..ac7a1846be 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs @@ -39,7 +39,7 @@ private CollectionRoutingMap( List orderedPartitionKeyRanges, string collectionUniqueId, string changeFeedNextIfNoneMatch, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer) { this.rangeById = rangeById; this.orderedPartitionKeyRanges = orderedPartitionKeyRanges; @@ -80,9 +80,9 @@ private CollectionRoutingMap( public static CollectionRoutingMap TryCreateCompleteRoutingMap( IEnumerable> ranges, - string collectionUniqueId, - string changeFeedNextIfNoneMatch = null, - bool useLengthAwareRangeComparer = true) + string collectionUniqueId, + bool useLengthAwareRangeComparer, + string changeFeedNextIfNoneMatch = null) { Dictionary> rangeById = new Dictionary>(StringComparer.Ordinal); @@ -212,7 +212,7 @@ public ServiceIdentity TryGetInfoByPartitionKeyRangeId(string partitionKeyRangeI public CollectionRoutingMap TryCombine( IEnumerable> ranges, string changeFeedNextIfNoneMatch, - bool useLengthAwareComparer = true) + bool useLengthAwareComparer) { HashSet newGoneRanges = new HashSet(ranges.SelectMany(tuple => tuple.Item1.Parents ?? Enumerable.Empty())); newGoneRanges.UnionWith(this.goneRanges); diff --git a/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs b/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs index 1ba6378b02..52a13a5c58 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/PartitionKeyRangeCache.cs @@ -30,16 +30,16 @@ internal class PartitionKeyRangeCache : IRoutingMapProvider, ICollectionRoutingM private readonly ICosmosAuthorizationTokenProvider authorizationTokenProvider; private readonly IStoreModel storeModel; private readonly CollectionCache collectionCache; - private readonly IGlobalEndpointManager endpointManager; + private readonly IGlobalEndpointManager endpointManager; private readonly bool useLengthAwareRangeComparer; public PartitionKeyRangeCache( ICosmosAuthorizationTokenProvider authorizationTokenProvider, IStoreModel storeModel, CollectionCache collectionCache, - IGlobalEndpointManager endpointManager, - bool enableAsyncCacheExceptionNoSharing = true, - bool useLengthAwareRangeComparer = true) + IGlobalEndpointManager endpointManager, + bool useLengthAwareRangeComparer, + bool enableAsyncCacheExceptionNoSharing = true) { this.routingMapCache = new AsyncCacheNonBlocking( keyEqualityComparer: StringComparer.Ordinal, @@ -47,7 +47,7 @@ public PartitionKeyRangeCache( this.authorizationTokenProvider = authorizationTokenProvider; this.storeModel = storeModel; this.collectionCache = collectionCache; - this.endpointManager = endpointManager; + this.endpointManager = endpointManager; this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; } @@ -244,7 +244,8 @@ private async Task GetRoutingMapForCollectionAsync( HashSet goneRanges = new HashSet(ranges.SelectMany(range => range.Parents ?? Enumerable.Empty())); routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( tuples.Where(tuple => !goneRanges.Contains(tuple.Item1.Id)), - string.Empty, + string.Empty, + false, changeFeedNextIfNoneMatch); } else diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index 6882b42e8d..b93f955d8a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -2186,7 +2186,8 @@ public async Task ItemEpkQuerySingleKeyRangeValidation() {"x-ms-effective-partition-key-string", "AA" } }, feedRangeInternal: null, - trace: NoOpTrace.Singleton); + trace: NoOpTrace.Singleton, + useLengthAwareRangeComparer: false); Assert.IsTrue(partitionKeyRanges.Count == 1, "Only 1 partition key range should be selected since the EPK option is set."); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs index 74a8cf6f7c..69d1b2f30a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs @@ -73,7 +73,8 @@ public async Task GetTargetPartitionKeyRangesAsyncWithFeedRange() containerQueryProperties: containerQueryProperties, properties: null, feedRangeInternal: feedToken as FeedRangeInternal, - NoOpTrace.Singleton); + NoOpTrace.Singleton, + useLengthAwareRangeComparer: false); Assert.IsTrue(partitionKeyRanges.Count == 1, "Only 1 partition key range should be selected since the FeedRange represents a single range."); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Mocks/MockDocumentClient.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Mocks/MockDocumentClient.cs index 74b12a9e04..26513b7160 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Mocks/MockDocumentClient.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Mocks/MockDocumentClient.cs @@ -180,9 +180,9 @@ private void Init() { Tuple.Create(new PartitionKeyRange{ Id = "0", MinInclusive = "", MaxExclusive = "FF"}, (ServiceIdentity)null) }, - string.Empty); + string.Empty, false); - this.partitionKeyRangeCache = new Mock(null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(null, null, null, null, false, false); this.partitionKeyRangeCache.Setup( m => m.TryLookupAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs index 763598e64c..b00048da4f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs @@ -799,7 +799,7 @@ private class ClientWithSplitDetection : MockDocumentClient public ClientWithSplitDetection() { - this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false, false); this.partitionKeyRangeCache.Setup( m => m.TryGetOverlappingRangesAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs index d77afc627a..a814cd9834 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs @@ -62,7 +62,7 @@ public async Task RetryOnSplit() { Tuple.Create(new PartitionKeyRange{ Id = "0", MinInclusive = "", MaxExclusive = "FF"}, (ServiceIdentity)null) }, - string.Empty); + string.Empty, false); mockContainer.Setup(x => x.GetRoutingMapAsync(It.IsAny())).Returns(Task.FromResult(routingMap)); BatchAsyncContainerExecutor executor = new BatchAsyncContainerExecutor(mockContainer.Object, mockedContext.Object, 20, BatchAsyncContainerExecutorCache.DefaultMaxBulkRequestBodySizeInBytes); TransactionalBatchOperationResult result = await executor.AddAsync(itemBatchOperation, NoOpTrace.Singleton); @@ -120,7 +120,7 @@ public async Task RetryOnNameStale() { Tuple.Create(new PartitionKeyRange{ Id = "0", MinInclusive = "", MaxExclusive = "FF"}, (ServiceIdentity)null) }, - string.Empty); + string.Empty, false); mockContainer.Setup(x => x.GetRoutingMapAsync(It.IsAny())).Returns(Task.FromResult(routingMap)); BatchAsyncContainerExecutor executor = new BatchAsyncContainerExecutor(mockContainer.Object, mockedContext.Object, 20, BatchAsyncContainerExecutorCache.DefaultMaxBulkRequestBodySizeInBytes); TransactionalBatchOperationResult result = await executor.AddAsync(itemBatchOperation, NoOpTrace.Singleton); @@ -178,7 +178,7 @@ public async Task RetryOn429() { Tuple.Create(new PartitionKeyRange{ Id = "0", MinInclusive = "", MaxExclusive = "FF"}, (ServiceIdentity)null) }, - string.Empty); + string.Empty, false); mockContainer.Setup(x => x.GetRoutingMapAsync(It.IsAny())).Returns(Task.FromResult(routingMap)); BatchAsyncContainerExecutor executor = new BatchAsyncContainerExecutor(mockContainer.Object, mockedContext.Object, 20, BatchAsyncContainerExecutorCache.DefaultMaxBulkRequestBodySizeInBytes); TransactionalBatchOperationResult result = await executor.AddAsync(itemBatchOperation, NoOpTrace.Singleton); @@ -235,7 +235,7 @@ public async Task DoesNotRecalculatePartitionKeyRangeOnNoSplits() { Tuple.Create(new PartitionKeyRange{ Id = "0", MinInclusive = "", MaxExclusive = "FF"}, (ServiceIdentity)null) }, - string.Empty); + string.Empty, false); mockContainer.Setup(x => x.GetRoutingMapAsync(It.IsAny())).Returns(Task.FromResult(routingMap)); BatchAsyncContainerExecutor executor = new BatchAsyncContainerExecutor(mockContainer.Object, mockedContext.Object, 20, BatchAsyncContainerExecutorCache.DefaultMaxBulkRequestBodySizeInBytes); TransactionalBatchOperationResult result = await executor.AddAsync(itemBatchOperation, NoOpTrace.Singleton); @@ -377,7 +377,7 @@ private class ClientWithSplitDetection : MockDocumentClient public ClientWithSplitDetection() { - this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false, false); this.partitionKeyRangeCache.Setup( m => m.TryGetOverlappingRangesAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs index a5bd3b374e..e3d7348150 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs @@ -297,7 +297,7 @@ private class ClientWithSplitDetection : MockDocumentClient public ClientWithSplitDetection() { - this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false, false); this.partitionKeyRangeCache.Setup( m => m.TryGetOverlappingRangesAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BulkPartitionKeyRangeGoneRetryPolicyTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BulkPartitionKeyRangeGoneRetryPolicyTests.cs index fe75375e6d..6c9cbd2e1b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BulkPartitionKeyRangeGoneRetryPolicyTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BulkPartitionKeyRangeGoneRetryPolicyTests.cs @@ -145,7 +145,7 @@ private class ClientWithSplitDetection : MockDocumentClient public ClientWithSplitDetection() { - this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false, false); this.partitionKeyRangeCache.Setup( m => m.TryGetOverlappingRangesAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/PartitionSynchronizerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/PartitionSynchronizerCoreTests.cs index 140e8bb098..2e0dd999a6 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/PartitionSynchronizerCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/PartitionSynchronizerCoreTests.cs @@ -63,6 +63,7 @@ public async Task HandlePartitionGoneAsync_PKRangeBasedLease_Split() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -128,6 +129,7 @@ public async Task HandlePartitionGoneAsync_EpkBasedLease_Split() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -198,6 +200,7 @@ public async Task HandlePartitionGoneAsync_PKRangeBasedLease_Merge() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -258,6 +261,7 @@ public async Task HandlePartitionGoneAsync_EpkBasedLease_Merge() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -308,6 +312,7 @@ public async Task CreateMissingLeases_NoLeases() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -355,6 +360,7 @@ public async Task CreateMissingLeases_SomePKRangeLeases() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() @@ -408,6 +414,7 @@ public async Task CreateMissingLeases_SomePKRangeAndEPKLeases() Mock.Of(), new Mock(false).Object, this.endpointManager, + false, false); List resultingRanges = new List() diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CollectionRoutingMapTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CollectionRoutingMapTest.cs index cb7baf2de5..ed0f12b209 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CollectionRoutingMapTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CollectionRoutingMapTest.cs @@ -55,7 +55,7 @@ public void TestCollectionRoutingMap() serviceIdentity3), - }, string.Empty); + }, string.Empty, false); Assert.AreEqual("0", routingMap.OrderedPartitionKeyRanges[0].Id); Assert.AreEqual("1", routingMap.OrderedPartitionKeyRanges[1].Id); @@ -131,10 +131,8 @@ public void TestCollectionRoutingMapWithLengthAwareRangeComparators(bool isRouti { try { - // Arrange: Set environment variable to "true" since the default is only true for Preview. - Environment.SetEnvironmentVariable(ConfigurationManager.UseLengthAwareRangeComparator, "true"); - - CollectionRoutingMap routingMap = this.GenerateRoutingMap(isRoutingMapFullySpecified); + // Arrange: Set useLengthAwareComparer flag to "true" since the default is only true for Preview. + CollectionRoutingMap routingMap = this.GenerateRoutingMap(isRoutingMapFullySpecified, true); // Test scenario 1.1: Input EPK is partial and falls on the boundary between two overlapping ranges. // The LengthAware comparators are able to correctly compare partial and full EPK ranges.Routing map is hybrid of fully specified and partially specified EPK ranges. @@ -250,10 +248,10 @@ public void TestCollectionRoutingMapWithLengthAwareRangeComparators(bool isRouti public void TestLegacyComparatorsUsedWhenLengthAwareComparatorFlagIsFalse() { try - { - // Arrange: Set environment variable to force legacy comparator usage. - Environment.SetEnvironmentVariable(ConfigurationManager.UseLengthAwareRangeComparator, "false"); - CollectionRoutingMap routingMap = this.GenerateRoutingMap(false); + { + + // Arrange: Set useLengthAwareComparer to false to force legacy comparator usage. + CollectionRoutingMap routingMap = this.GenerateRoutingMap(false, false); // Test scenario: Input EPK is partial and falls on the boundary between two overlapping ranges. @@ -275,7 +273,7 @@ public void TestLegacyComparatorsUsedWhenLengthAwareComparatorFlagIsFalse() } } - private CollectionRoutingMap GenerateRoutingMap(bool isFullySpecified) + private CollectionRoutingMap GenerateRoutingMap(bool isFullySpecified, bool useLengthAwareComparer) { IEnumerable> partitionKeyRangeTuples = new[] { @@ -404,7 +402,8 @@ string PadTo64(string value) CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( partitionKeyRangeTuples, - string.Empty); + string.Empty, + useLengthAwareComparer); return routingMap; } @@ -419,7 +418,7 @@ public void TestInvalidRoutingMap() Tuple.Create(new PartitionKeyRange {Id = "1", MinInclusive = "0000000020", MaxExclusive = "0000000030"}, (ServiceIdentity)null), Tuple.Create(new PartitionKeyRange { Id = "2", MinInclusive = "0000000025", MaxExclusive = "0000000035"}, (ServiceIdentity)null), }, - string.Empty); + string.Empty, false); } [TestMethod] @@ -431,7 +430,7 @@ public void TestIncompleteRoutingMap() Tuple.Create(new PartitionKeyRange{ Id = "2", MinInclusive = "", MaxExclusive = "0000000030"}, (ServiceIdentity)null), Tuple.Create(new PartitionKeyRange{ Id = "3", MinInclusive = "0000000031", MaxExclusive = "FF"}, (ServiceIdentity)null), }, - string.Empty); + string.Empty, false); Assert.IsNull(routingMap); @@ -441,7 +440,7 @@ public void TestIncompleteRoutingMap() Tuple.Create(new PartitionKeyRange{Id = "2", MinInclusive = "", MaxExclusive = "0000000030"}, (ServiceIdentity)null), Tuple.Create(new PartitionKeyRange{Id = "3", MinInclusive = "0000000030", MaxExclusive = "FF"}, (ServiceIdentity)null), }, - string.Empty); + string.Empty, false); Assert.IsNotNull(routingMap); } @@ -456,7 +455,7 @@ public void TestGoneRanges() Tuple.Create(new PartitionKeyRange{ Id = "3", MinInclusive = "0000000030", MaxExclusive = "0000000032", Parents = new Collection{"5"}}, (ServiceIdentity)null), Tuple.Create(new PartitionKeyRange{ Id = "4", MinInclusive = "0000000032", MaxExclusive = "FF"}, (ServiceIdentity)null), }, - string.Empty); + string.Empty, false); Assert.IsTrue(routingMap.IsGone("1")); Assert.IsTrue(routingMap.IsGone("0")); @@ -501,7 +500,7 @@ public void TestTryCombineRanges() MinInclusive = "0000000070", MaxExclusive = "FF"}, (ServiceIdentity)null), - }, string.Empty); + }, string.Empty, false); CollectionRoutingMap newRoutingMap = routingMap.TryCombine( new[] @@ -522,7 +521,7 @@ public void TestTryCombineRanges() MaxExclusive = "0000000030"}, (ServiceIdentity)null), }, - null); + null, false); Assert.IsNotNull(newRoutingMap); @@ -561,7 +560,7 @@ public void TestTryCombineRanges() MaxExclusive = "0000000030"}, (ServiceIdentity)null), }, - null); + null, false); Assert.IsNotNull(newRoutingMap); @@ -576,7 +575,7 @@ public void TestTryCombineRanges() MaxExclusive = "0000000002"}, (ServiceIdentity)null), }, - null); + null, false); Assert.IsNull(newRoutingMap); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs index 5a1190ef26..251b199468 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/FeedRange/ChangeFeedIteratorCoreTests.cs @@ -5,14 +5,12 @@ namespace Microsoft.Azure.Cosmos.Tests.FeedRange { using System; - using System.ClientModel; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.ChangeFeed; - using Microsoft.Azure.Cosmos.ChangeFeed.Pagination; using Microsoft.Azure.Cosmos.CosmosElements; using Microsoft.Azure.Cosmos.Pagination; using Microsoft.Azure.Cosmos.Query.Core.Monads; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs index aa088340fd..61787f537f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs @@ -60,7 +60,7 @@ public GatewayAddressCacheTests() } }; - this.partitionKeyRangeCache = new Mock(null, null, null, null, false); + this.partitionKeyRangeCache = new Mock(null, null, null, null, false, false); this.partitionKeyRangeCache .Setup(m => m.TryGetOverlappingRangesAsync( It.IsAny(), @@ -806,7 +806,7 @@ public async Task GlobalAddressResolver_OpenConnectionsToAllReplicasAsync_WhenIn .Returns(Task.FromResult(containerProperties)); string exceptionMessage = "Failed to lookup partition key ranges."; - Mock partitionKeyRangeCache = new(null, null, null, null, false); + Mock partitionKeyRangeCache = new(null, null, null, null, false, false); partitionKeyRangeCache .Setup(m => m.TryGetOverlappingRangesAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index 1a52543ee2..ba3eaaeb81 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -290,7 +290,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsr, ConsistencyLevel.Session, new Mock().Object, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: Mock.Of()); @@ -317,7 +317,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsrQueryPlan, ConsistencyLevel.Session, new Mock().Object, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: Mock.Of()); @@ -371,7 +371,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsr, ConsistencyLevel.Session, new Mock().Object, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: Mock.Of()); @@ -401,7 +401,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsrNoSessionToken, ConsistencyLevel.Session, sessionContainer, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: globalEndpointManager.Object); @@ -442,7 +442,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( It.IsAny(), NoOpTrace.Singleton)).Returns(Task.FromResult(containerProperties)); - Mock mockPartitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false); + Mock mockPartitionKeyRangeCache = new Mock(MockBehavior.Strict, null, null, null, null, false, false); mockPartitionKeyRangeCache.Setup(x => x.TryGetPartitionKeyRangeByIdAsync( containerProperties.ResourceId, partitionKeyRangeId, @@ -489,7 +489,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsrSprocExecute, ConsistencyLevel.Session, new Mock().Object, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: Mock.Of()); @@ -528,7 +528,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( dsrNoSessionToken, ConsistencyLevel.Session, sessionContainer, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(new SessionContainer("testhost"), gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: globalEndpointManager.Object); @@ -1005,7 +1005,7 @@ public async Task GatewayStoreModel_AvoidGlobalSessionToken() isThinClientEnabled: false); Mock clientCollectionCache = new Mock(new SessionContainer("testhost"), storeModel, null, null, null, false); - Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false); + Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false, false); sessionContainer.SetSessionToken( ResourceId.NewDocumentCollectionId(42, 129).DocumentCollectionId.ToString(), @@ -1103,7 +1103,7 @@ Task sendFunc(HttpRequestMessage request) Mock clientCollectionCache = new Mock(new SessionContainer("testhost"), storeModel, null, null, null, false); - Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false); + Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false, false); storeModel.SetCaches(partitionKeyRangeCache.Object, clientCollectionCache.Object); INameValueCollection headers = new RequestNameValueCollection(); @@ -1171,7 +1171,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( documentServiceRequestToChild, ConsistencyLevel.Session, sessionContainer, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(sessionContainer, gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: globalEndpointManager.Object); @@ -1237,7 +1237,7 @@ await GatewayStoreModel.ApplySessionTokenAsync( documentServiceRequestToChild, ConsistencyLevel.Session, sessionContainer, - partitionKeyRangeCache: new Mock(null, null, null, null, false).Object, + partitionKeyRangeCache: new Mock(null, null, null, null, false, false).Object, clientCollectionCache: new Mock(sessionContainer, gatewayStoreModel, null, null, null, false).Object, globalEndpointManager: globalEndpointManager.Object); @@ -1297,7 +1297,7 @@ public async Task ThinClient_ProcessMessageAsync_Success_ShouldReturnDocumentSer storeModel, clientCollectionCache, endpointManager, - false).Object; + false, false).Object; storeModel.SetCaches(partitionKeyRangeCache, clientCollectionCache); @@ -1378,7 +1378,7 @@ public async Task ThinClient_ProcessMessageAsync_WithUnsupportedOperations_Shoul storeModel, clientCollectionCache, multiEndpointMgr, - false).Object; + false, false).Object; storeModel.SetCaches(partitionKeyRangeCache, clientCollectionCache); @@ -1469,7 +1469,7 @@ public async Task ThinClient_ProcessMessageAsync_404_ShouldThrowDocumentClientEx storeModel, clientCollectionCache, endpointManager, - false).Object; + false, false).Object; storeModel.SetCaches(partitionKeyRangeCache, clientCollectionCache); @@ -1553,12 +1553,12 @@ public async Task ThinClient_PartitionLevelFailoverEnabled_ResolvesPartitionKeyR storeModel, mockCollectionCache.Object, endpointManager, - false); + false, false); PartitionKeyRange pkRange = new PartitionKeyRange { Id = "0", MinInclusive = "", MaxExclusive = "FF" }; List pkRanges = new List { pkRange }; IEnumerable> rangeTuples = pkRanges.Select(r => Tuple.Create(r, (ServiceIdentity)null)); - CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(rangeTuples, "testCollectionRid"); + CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(rangeTuples, "testCollectionRid", false); mockPartitionKeyRangeCache .Setup(c => c.TryLookupAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -1725,7 +1725,7 @@ static async Task messageHandler(HttpRequestMessage request isThinClientEnabled: false); ClientCollectionCache clientCollectionCache = new Mock(new SessionContainer("testhost"), storeModel, null, null, null, false).Object; - PartitionKeyRangeCache partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache, endpointManager, false).Object; + PartitionKeyRangeCache partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache, endpointManager, false, false).Object; storeModel.SetCaches(partitionKeyRangeCache, clientCollectionCache); await executeWithGatewayStoreModel(storeModel); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeCacheTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeCacheTest.cs index 41b53d293a..6f47751e42 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeCacheTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeCacheTest.cs @@ -98,7 +98,7 @@ public async Task TryGetOverlappingRangesAsync_WithFreshContainer_ShouldNotAddSa .Returns(new ValueTask(authToken)); // Act. - PartitionKeyRangeCache partitionKeyRangeCache = new(mockTokenProvider.Object, mockStoreModel.Object, mockCollectioNCache.Object, endpointManager, enableAsyncCacheExceptionNoSharing: false); + PartitionKeyRangeCache partitionKeyRangeCache = new(mockTokenProvider.Object, mockStoreModel.Object, mockCollectioNCache.Object, endpointManager, useLengthAwareRangeComparer: false, enableAsyncCacheExceptionNoSharing: false); IReadOnlyList partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( containerRId, FeedRangeEpk.FullRange.Range, @@ -207,7 +207,7 @@ public async Task TryGetOverlappingRangesAsync_WhenGatewayThrowsServiceUnavailab mockTokenProvider.Setup(x => x.GetUserAuthorizationTokenAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new ValueTask(authToken)); - PartitionKeyRangeCache partitionKeyRangeCache = new(mockTokenProvider.Object, mockStoreModel.Object, mockCollectioNCache.Object, mockedEndpointManager.Object, enableAsyncCacheExceptionNoSharing: false); + PartitionKeyRangeCache partitionKeyRangeCache = new(mockTokenProvider.Object, mockStoreModel.Object, mockCollectioNCache.Object, mockedEndpointManager.Object, useLengthAwareRangeComparer: false, enableAsyncCacheExceptionNoSharing: false); if (shouldSucceed) { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeHandlerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeHandlerTests.cs index e2a83f73aa..e7e95afbfc 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeHandlerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeHandlerTests.cs @@ -660,13 +660,14 @@ public async Task PartitionKeyRangeGoneTracePlumbingTest() collectionCache.Setup(c => c.ResolveCollectionAsync(It.IsAny(), default, trace)) .ReturnsAsync(containerProperties); - CollectionRoutingMap collectionRoutingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(new List>(), collectionRid); + CollectionRoutingMap collectionRoutingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(new List>(), collectionRid, false); Mock partitionKeyRangeCache = new Mock( MockBehavior.Strict, new Mock().Object, new Mock().Object, collectionCache.Object, endpointManager, + false, false); partitionKeyRangeCache.Setup(c => c.TryLookupAsync(collectionRid, null, It.IsAny(), trace)) .ReturnsAsync(collectionRoutingMap); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs index b751ac3dc8..3f613c3f19 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs @@ -1030,7 +1030,8 @@ private static IQueryPipelineStage CreateQueryPipelineStage( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings); + testInjections: queryRequestOptions.TestSettings, + useLengthAwareRangeComparer: true); List targetPkRanges = new(); foreach (FeedRangeEpk feedRangeEpk in containerRanges) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs index e7021a86f0..3148425814 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs @@ -34,7 +34,8 @@ public void TestCreate() maxItemCount: 10, isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: default); ; + requestContinuationToken: default, + useLengthAwareRangeComparer: false); ; Assert.IsTrue(monadicCreatePipeline.Succeeded); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs index 1a5400f941..04754d3b7c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs @@ -341,7 +341,8 @@ private static IQueryPipelineStage CreateQueryPipelineStage( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings); + testInjections: queryRequestOptions.TestSettings, + useLengthAwareRangeComparer: false); string databaseId = "db1234"; string resourceLink = $"dbs/{databaseId}/colls"; @@ -620,7 +621,8 @@ private static async Task CreatePipelineAsync( containerQueryProperties: new ContainerQueryProperties(), isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: state); + requestContinuationToken: state, + useLengthAwareRangeComparer: false); tryCreatePipeline.ThrowIfFailed(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs index 357e3c7ced..551db2ce2e 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs @@ -681,7 +681,8 @@ private static async Task RunParityTests( ranges, isContinuationExpected: true, maxConcurrency: MaxConcurrency, - requestContinuationToken: null); + requestContinuationToken: null, + useLengthAwareRangeComparer: false); Assert.IsTrue(tryCreatePipeline.Succeeded); return RunPipelineStage(tryCreatePipeline.Result, pageSize); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs index 01648d77d4..ddbdd33440 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs @@ -138,7 +138,8 @@ private static IQueryPipelineStage CreateQueryPipelineStage( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings); + testInjections: queryRequestOptions.TestSettings, + useLengthAwareRangeComparer: false); List targetPkRanges = new(); foreach (FeedRangeEpk feedRangeEpk in containerRanges) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs index ca52e5d356..81e2d35388 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs @@ -141,7 +141,7 @@ private class TestPartitionKeyRangeCache : PartitionKeyRangeCache private readonly IReadOnlyList overlappingRanges; public TestPartitionKeyRangeCache(IReadOnlyList overlappingRanges) - : base(null, null, null, null) // Pass nulls or mocks as needed for base constructor + : base(null, null, null, null, false, false) // Pass nulls or mocks as needed for base constructor { this.overlappingRanges = overlappingRanges; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/IRoutingMapProviderExtensionsTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/IRoutingMapProviderExtensionsTest.cs index b4629fe063..a476fb66dd 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/IRoutingMapProviderExtensionsTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/IRoutingMapProviderExtensionsTest.cs @@ -1,223 +1,223 @@ -//------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------ - -namespace Microsoft.Azure.Cosmos.Tests.Routing -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Routing; - using Microsoft.Azure.Cosmos.Tracing; - using Microsoft.Azure.Documents; - using Microsoft.Azure.Documents.Routing; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - /// - /// Tests class. - /// - [TestClass] - public class IRoutingMapProviderExtensionsTest - { - private class MockRoutingMapProvider : IRoutingMapProvider - { - readonly CollectionRoutingMap routingMap; - - public MockRoutingMapProvider(IList ranges) - { - this.routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(ranges.Select(r => Tuple.Create(r, (ServiceIdentity)null)), ""); - } - - public Task> TryGetOverlappingRangesAsync( - string collectionIdOrNameBasedLink, - Range range, - ITrace trace, - bool forceRefresh = false) - { - return Task.FromResult(this.routingMap.GetOverlappingRanges(range)); - } - - public Task TryGetPartitionKeyRangeByIdAsync( - string collectionResourceId, - string partitionKeyRangeId, - ITrace trace, - bool forceRefresh = false) - { - return Task.FromResult(this.routingMap.TryGetRangeByPartitionKeyRangeId(partitionKeyRangeId)); - } - } - - private readonly MockRoutingMapProvider routingMapProvider = - new MockRoutingMapProvider( - new[] - { - new PartitionKeyRange{MinInclusive = "", MaxExclusive = "000A", Id="0"}, - new PartitionKeyRange{MinInclusive = "000A", MaxExclusive = "000D", Id="1"}, - new PartitionKeyRange{MinInclusive = "000D", MaxExclusive = "0012", Id="2"}, - new PartitionKeyRange{MinInclusive = "0012", MaxExclusive = "0015", Id="3"}, - new PartitionKeyRange{MinInclusive = "0015", MaxExclusive = "0020", Id="4"}, - new PartitionKeyRange{MinInclusive = "0020", MaxExclusive = "0040", Id="5"}, - new PartitionKeyRange{MinInclusive = "0040", MaxExclusive = "FF", Id="6"}, - }); - - /// - /// Tests case when input is not sorted. - /// - [TestMethod] - [Owner("padmaa")] - public async Task TestNonSortedRanges() - { - IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] { new Range("0B", "0B", true, true), new Range("0A", "0A", true, true) }, - NoOpTrace.Singleton); - - Assert.AreEqual("6", string.Join(",", ranges.Select(r => r.Id))); - } - - /// - /// Tests case when input contains overlapping ranges. - /// - [TestMethod] - [Owner("padmaa")] - [ExpectedException(typeof(ArgumentException))] - public async Task TestOverlappingRanges1() - { - await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] { new Range("0A", "0D", true, true), new Range("0B", "0E", true, true) }, - NoOpTrace.Singleton); - } - - /// - /// Tests case when input contains overlapping ranges. - /// - [TestMethod] - [Owner("padmaa")] - [ExpectedException(typeof(ArgumentException))] - public async Task TestOverlappingRanges2() - { - await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] { new Range("0A", "0D", true, true), new Range("0D", "0E", true, true) }, - NoOpTrace.Singleton); - } - - /// - /// Tests case with various overlapping options. - /// - [TestMethod] - [Owner("padmaa")] - public async Task TestDuplicates() - { - { - // Deep Copy Duplicate - IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("", "FF", true, false), - // Duplicate - new Range("", "FF", true, false), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); - } - - { - // Shallow Copy Duplicate - List> queryRanges = new List>() - { - new Range("", "FF", true, false), - }; - queryRanges.Add(queryRanges.Last()); - - IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - queryRanges, - NoOpTrace.Singleton); - - Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); - } - } - - /// - /// Tests case with various overlapping options. - /// - [TestMethod] - [Owner("padmaa")] - public async Task TestGetOverlappingRanges() - { - IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("000B", "000E", true, false), - new Range("000E", "000F", true, false), - new Range("000F", "0010", true, true), - new Range("0015", "0015", true, true) - }, - NoOpTrace.Singleton); - - Assert.AreEqual("1,2,4", string.Join(",", ranges.Select(r => r.Id))); - - // query for minimal point - ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("", "", true, true), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("0", string.Join(",", ranges.Select(r => r.Id))); - - // query for empty range - ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("", "", true, false), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("", string.Join(",", ranges.Select(r => r.Id))); - - // entire range - ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("", "FF", true, false), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); - - // matching range - ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("0012", "0015", true, false), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("3", string.Join(",", ranges.Select(r => r.Id))); - - // matching range and a little bit more. - ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( - "dbs/db1/colls/coll1", - new[] - { - new Range("0012", "0015", false, true), - }, - NoOpTrace.Singleton); - - Assert.AreEqual("3,4", string.Join(",", ranges.Select(r => r.Id))); - } - - } +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests.Routing +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Routing; + using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Documents; + using Microsoft.Azure.Documents.Routing; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + /// + /// Tests class. + /// + [TestClass] + public class IRoutingMapProviderExtensionsTest + { + private class MockRoutingMapProvider : IRoutingMapProvider + { + readonly CollectionRoutingMap routingMap; + + public MockRoutingMapProvider(IList ranges) + { + this.routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap(ranges.Select(r => Tuple.Create(r, (ServiceIdentity)null)), "", false); + } + + public Task> TryGetOverlappingRangesAsync( + string collectionIdOrNameBasedLink, + Range range, + ITrace trace, + bool forceRefresh = false) + { + return Task.FromResult(this.routingMap.GetOverlappingRanges(range)); + } + + public Task TryGetPartitionKeyRangeByIdAsync( + string collectionResourceId, + string partitionKeyRangeId, + ITrace trace, + bool forceRefresh = false) + { + return Task.FromResult(this.routingMap.TryGetRangeByPartitionKeyRangeId(partitionKeyRangeId)); + } + } + + private readonly MockRoutingMapProvider routingMapProvider = + new MockRoutingMapProvider( + new[] + { + new PartitionKeyRange{MinInclusive = "", MaxExclusive = "000A", Id="0"}, + new PartitionKeyRange{MinInclusive = "000A", MaxExclusive = "000D", Id="1"}, + new PartitionKeyRange{MinInclusive = "000D", MaxExclusive = "0012", Id="2"}, + new PartitionKeyRange{MinInclusive = "0012", MaxExclusive = "0015", Id="3"}, + new PartitionKeyRange{MinInclusive = "0015", MaxExclusive = "0020", Id="4"}, + new PartitionKeyRange{MinInclusive = "0020", MaxExclusive = "0040", Id="5"}, + new PartitionKeyRange{MinInclusive = "0040", MaxExclusive = "FF", Id="6"}, + }); + + /// + /// Tests case when input is not sorted. + /// + [TestMethod] + [Owner("padmaa")] + public async Task TestNonSortedRanges() + { + IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] { new Range("0B", "0B", true, true), new Range("0A", "0A", true, true) }, + NoOpTrace.Singleton); + + Assert.AreEqual("6", string.Join(",", ranges.Select(r => r.Id))); + } + + /// + /// Tests case when input contains overlapping ranges. + /// + [TestMethod] + [Owner("padmaa")] + [ExpectedException(typeof(ArgumentException))] + public async Task TestOverlappingRanges1() + { + await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] { new Range("0A", "0D", true, true), new Range("0B", "0E", true, true) }, + NoOpTrace.Singleton); + } + + /// + /// Tests case when input contains overlapping ranges. + /// + [TestMethod] + [Owner("padmaa")] + [ExpectedException(typeof(ArgumentException))] + public async Task TestOverlappingRanges2() + { + await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] { new Range("0A", "0D", true, true), new Range("0D", "0E", true, true) }, + NoOpTrace.Singleton); + } + + /// + /// Tests case with various overlapping options. + /// + [TestMethod] + [Owner("padmaa")] + public async Task TestDuplicates() + { + { + // Deep Copy Duplicate + IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("", "FF", true, false), + // Duplicate + new Range("", "FF", true, false), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); + } + + { + // Shallow Copy Duplicate + List> queryRanges = new List>() + { + new Range("", "FF", true, false), + }; + queryRanges.Add(queryRanges.Last()); + + IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + queryRanges, + NoOpTrace.Singleton); + + Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); + } + } + + /// + /// Tests case with various overlapping options. + /// + [TestMethod] + [Owner("padmaa")] + public async Task TestGetOverlappingRanges() + { + IList ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("000B", "000E", true, false), + new Range("000E", "000F", true, false), + new Range("000F", "0010", true, true), + new Range("0015", "0015", true, true) + }, + NoOpTrace.Singleton); + + Assert.AreEqual("1,2,4", string.Join(",", ranges.Select(r => r.Id))); + + // query for minimal point + ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("", "", true, true), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("0", string.Join(",", ranges.Select(r => r.Id))); + + // query for empty range + ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("", "", true, false), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("", string.Join(",", ranges.Select(r => r.Id))); + + // entire range + ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("", "FF", true, false), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("0,1,2,3,4,5,6", string.Join(",", ranges.Select(r => r.Id))); + + // matching range + ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("0012", "0015", true, false), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("3", string.Join(",", ranges.Select(r => r.Id))); + + // matching range and a little bit more. + ranges = await this.routingMapProvider.TryGetOverlappingRangesAsync( + "dbs/db1/colls/coll1", + new[] + { + new Range("0012", "0015", false, true), + }, + NoOpTrace.Singleton); + + Assert.AreEqual("3,4", string.Join(",", ranges.Select(r => r.Id))); + } + + } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/PartitionRoutingHelperTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/PartitionRoutingHelperTest.cs index 032b099a48..83db50eb99 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/PartitionRoutingHelperTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Routing/PartitionRoutingHelperTest.cs @@ -102,7 +102,7 @@ public async Task TestAddFormattedContinuationToHeader() CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( - testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty); + testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty, false); RoutingMapProvider routingMapProvider = new RoutingMapProvider(routingMap); foreach (AddFormattedContinuationToHeaderTestUnit positiveTestData in testData.TestSet.Postive) @@ -221,7 +221,7 @@ public async Task TestGetPartitionRoutingInfo() CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( - testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty); + testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty, false); foreach (GetPartitionRoutingInfoTestCase testCase in testData.TestCases) { @@ -706,7 +706,7 @@ private static async Task PrefixPartitionKeyTestRunnerAsync( CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( rangesAndServiceIdentity, - collectionRid); + collectionRid, false); RoutingMapProvider routingMapProvider = new RoutingMapProvider(routingMap); TryCatch tryGetQueryPlan = @@ -747,7 +747,7 @@ private static async Task PrefixPartitionKeyChangeFeedTestRunnerAsync( CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( rangesAndServiceIdentity, - collectionRid); + collectionRid, false); RoutingMapProvider routingMapProvider = new RoutingMapProvider(routingMap); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs index 9b9ba1b29a..b03599b5af 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs @@ -763,7 +763,8 @@ private static IQueryPipelineStage CreatePipeline(IDocumentContainer documentCon allRanges: new List() { FeedRangeEpk.FullRange }, isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: state); + requestContinuationToken: state, + useLengthAwareRangeComparer: false); tryCreatePipeline.ThrowIfFailed(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs index 754287088e..ce0a02fa21 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs @@ -231,7 +231,7 @@ private void Init() using GlobalEndpointManager endpointManager = new(mockDocumentClient.Object, new ConnectionPolicy()); - this.partitionKeyRangeCache = new Mock(null, null, null, endpointManager, false); + this.partitionKeyRangeCache = new Mock(null, null, null, endpointManager, false, false); this.partitionKeyRangeCache.Setup( m => m.TryLookupAsync( It.IsAny(), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/TestUtils.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/TestUtils.cs index ffdd8b98e7..47ea54d214 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/TestUtils.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/TestUtils.cs @@ -63,7 +63,7 @@ public static void SetupCachesInGatewayStoreModel( // Prepare mocked caches. Mock clientCollectionCache = new Mock(new SessionContainer("testhost"), storeModel, null, null, null, false); - Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false); + Mock partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache.Object, endpointManager, false, false); ContainerProperties containerProperties = ContainerProperties.CreateWithResourceId("test"); containerProperties.PartitionKey = partitionKeyDefinition; From 3aaaee0a0a768effa3ef162397139edccf3ebdcc Mon Sep 17 00:00:00 2001 From: Ananth Mudumba Date: Tue, 20 Jan 2026 13:22:22 -0800 Subject: [PATCH 3/3] Moved useLengthAwareRangeComparer to ContainerQueryProperties to reduce code churn --- .../src/CosmosClientOptions.cs | 11 ++- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 11 +-- .../CosmosQueryExecutionContextFactory.cs | 31 +++---- ...dSearchCrossPartitionQueryPipelineStage.cs | 9 +- ...OrderByCrossPartitionQueryPipelineStage.cs | 88 ++++++------------- ...yQueryPartitionRangePageAsyncEnumerator.cs | 19 ++-- ...arallelCrossPartitionQueryPipelineStage.cs | 11 +-- .../QueryPartitionRangePageAsyncEnumerator.cs | 7 +- ...misticDirectExecutionQueryPipelineStage.cs | 9 +- .../Query/Core/Pipeline/PipelineFactory.cs | 18 ++-- .../QueryClient/ContainerQueryProperties.cs | 9 +- .../src/Query/Core/QueryRangeUtils.cs | 24 ++--- .../Query/v3Query/CosmosQueryClientCore.cs | 3 +- .../src/Query/v3Query/QueryIterator.cs | 3 +- .../src/Routing/CollectionRoutingMap.cs | 7 +- .../src/Routing/RangeComparerProvider.cs | 24 +++++ .../CosmosItemTests.cs | 5 +- .../FeedToken/QueryFeedTokenTests.cs | 5 +- .../Query/OrderByPipelineStageBenchmark.cs | 3 +- ...misticDirectExecutionQueryBaselineTests.cs | 6 +- ...yPartitionRangePageAsyncEnumeratorTests.cs | 3 +- .../Query/Pipeline/FactoryTests.cs | 9 +- .../Query/Pipeline/FullPipelineTests.cs | 62 +++++++------ .../Pipeline/NonStreamingOrderByQueryTests.cs | 6 +- ...ByCrossPartitionQueryPipelineStageTests.cs | 39 +++----- ...elCrossPartitionQueryPipelineStageTests.cs | 22 ++--- .../QueryPartitionRangePageEnumeratorTests.cs | 9 +- .../Query/SubpartitionTests.cs | 6 +- .../Tracing/TraceWriterBaselineTests.cs | 3 +- 29 files changed, 190 insertions(+), 272 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Routing/RangeComparerProvider.cs diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index acd66065ae..7ed8862878 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -478,9 +478,14 @@ public System.Text.Json.JsonSerializerOptions UseSystemTextJsonSerializerWithOpt /// /// /// The default value is true. - /// - internal bool UseLengthAwareRangeComparer { get; set; } = true; - + /// + internal bool UseLengthAwareRangeComparer { get; set; } = +#if !INTERNAL + true; +#else + false; +#endif + /// /// (Direct/TCP) Controls the amount of idle time after which unused connections are closed. /// diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index a809a7ab7a..f4fbcfca01 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -125,7 +125,6 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private readonly bool IsLocalQuorumConsistency = false; private readonly bool isReplicaAddressValidationEnabled; private readonly bool enableAsyncCacheExceptionNoSharing; - private readonly bool useLengthAwareRangeComparer; //Fault Injection private readonly IChaosInterceptorFactory chaosInterceptorFactory; @@ -489,7 +488,7 @@ internal DocumentClient(Uri serviceEndpoint, CosmosClientTelemetryOptions cosmosClientTelemetryOptions = null, IChaosInterceptorFactory chaosInterceptorFactory = null, bool enableAsyncCacheExceptionNoSharing = true, - bool useLengthAwareRangeComparer = true) + bool useLengthAwareRangeComparer = false) { if (sendingRequestEventArgs != null) { @@ -517,7 +516,7 @@ internal DocumentClient(Uri serviceEndpoint, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); this.chaosInterceptorFactory = chaosInterceptorFactory; this.chaosInterceptor = chaosInterceptorFactory?.CreateInterceptor(this); - this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; + this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; this.Initialize( serviceEndpoint: serviceEndpoint, @@ -1105,7 +1104,7 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeCli retryPolicy: this.retryPolicy, telemetryToServiceHelper: this.telemetryToServiceHelper, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); - this.partitionKeyRangeCache = new PartitionKeyRangeCache(this, this.GatewayStoreModel, this.collectionCache, this.GlobalEndpointManager, this.useLengthAwareRangeComparer, this.enableAsyncCacheExceptionNoSharing); + this.partitionKeyRangeCache = new PartitionKeyRangeCache(this, this.GatewayStoreModel, this.collectionCache, this.GlobalEndpointManager, this.UseLengthAwareRangeComparer, this.enableAsyncCacheExceptionNoSharing); this.ResetSessionTokenRetryPolicy = new ResetSessionTokenRetryPolicyFactory(this.sessionContainer, this.collectionCache, this.retryPolicy); gatewayStoreModel.SetCaches(this.partitionKeyRangeCache, this.collectionCache); @@ -1233,7 +1232,9 @@ internal ApiType ApiType get; private set; } - internal bool UseMultipleWriteLocations { get; private set; } + internal bool UseMultipleWriteLocations { get; private set; } + + internal bool UseLengthAwareRangeComparer { get; private set; } /// /// Gets the endpoint Uri for the service endpoint from the Azure Cosmos DB service. diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs index 147cdea0e0..b1419eaff1 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CosmosQueryExecutionContextFactory.cs @@ -267,8 +267,7 @@ private static async Task> TryCreateFromPartitione containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace, - inputParameters.UseLengthAwareRangeComparer); + trace); Debug.Assert(targetRanges != null, $"{nameof(CosmosQueryExecutionContextFactory)} Assert!", "targetRanges != null"); @@ -455,8 +454,7 @@ private static async Task> TryCreateSpecializedDoc containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace, - inputParameters.UseLengthAwareRangeComparer); + trace); List allRanges = await cosmosQueryContext.QueryClient.GetTargetPartitionKeyRangesAsync( cosmosQueryContext.ResourceLink, @@ -525,8 +523,7 @@ private static TryCatch TryCreatePassthroughQueryExecutionC containerQueryProperties: containerQueryProperties, maxConcurrency: inputParameters.MaxConcurrency, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: inputParameters.InitialUserContinuationToken, - inputParameters.UseLengthAwareRangeComparer); + continuationToken: inputParameters.InitialUserContinuationToken); } private static TryCatch TryCreateFullQueryPipeline( @@ -570,8 +567,7 @@ private static TryCatch TryCreateFullQueryPipeline( allRanges: allFeedRanges, isContinuationExpected: cosmosQueryContext.IsContinuationExpected, maxConcurrency: inputParameters.MaxConcurrency, - requestContinuationToken: inputParameters.InitialUserContinuationToken, - useLengthAwareRangeComparer: inputParameters.UseLengthAwareRangeComparer); + requestContinuationToken: inputParameters.InitialUserContinuationToken); } private static async Task GetPartitionedQueryExecutionInfoAsync( @@ -631,8 +627,7 @@ private static async Task GetPartitionedQueryExec ContainerQueryProperties containerQueryProperties, IReadOnlyDictionary properties, FeedRangeInternal feedRangeInternal, - ITrace trace, - bool useLengthAwareRangeComparer) + ITrace trace) { List targetRanges; if (containerQueryProperties.EffectiveRangesForPartitionKey != null) @@ -783,8 +778,7 @@ private static Documents.PartitionKeyDefinition GetPartitionKeyDefinition(InputP containerQueryProperties, inputParameters.Properties, inputParameters.InitialFeedRange, - trace, - inputParameters.UseLengthAwareRangeComparer); + trace); } else { @@ -844,8 +838,7 @@ private InputParameters( bool enableOptimisticDirectExecution, bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, - TestInjections testInjections, - bool useLengthAwareRangeComparer) + TestInjections testInjections) { this.SqlQuerySpec = sqlQuerySpec ?? throw new ArgumentNullException(nameof(sqlQuerySpec)); this.InitialUserContinuationToken = initialUserContinuationToken; @@ -861,7 +854,6 @@ private InputParameters( this.IsHybridSearchQueryPlanOptimizationDisabled = isHybridSearchQueryPlanOptimizationDisabled; this.EnableDistributedQueryGatewayMode = enableDistributedQueryGatewayMode; this.TestInjections = testInjections; - this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } public static InputParameters Create( @@ -878,8 +870,7 @@ public static InputParameters Create( bool enableOptimisticDirectExecution, bool isHybridSearchQueryPlanOptimizationDisabled, bool enableDistributedQueryGatewayMode, - TestInjections testInjections, - bool useLengthAwareRangeComparer) + TestInjections testInjections) { if (sqlQuerySpec == null) { @@ -918,8 +909,7 @@ public static InputParameters Create( enableOptimisticDirectExecution: enableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: isHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: enableDistributedQueryGatewayMode, - testInjections: testInjections, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + testInjections: testInjections); } public SqlQuerySpec SqlQuerySpec { get; } @@ -954,8 +944,7 @@ public InputParameters WithContinuationToken(CosmosElement token) this.EnableOptimisticDirectExecution, this.IsHybridSearchQueryPlanOptimizationDisabled, this.EnableDistributedQueryGatewayMode, - this.TestInjections, - this.UseLengthAwareRangeComparer); + this.TestInjections); } } diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs index 0143484a09..867ef4a0c1 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs @@ -92,8 +92,7 @@ public static TryCatch MonadicCreate( IReadOnlyList allRanges, int maxItemCount, bool isContinuationExpected, - int maxConcurrency, - bool useLengthAwareRangeComparer) + int maxConcurrency) { TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryInfo) { @@ -111,8 +110,7 @@ TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryI emitRawOrderByPayload: true, isContinuationExpected: isContinuationExpected, maxConcurrency: maxConcurrency, - requestContinuationToken: null, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + requestContinuationToken: null); } State state; @@ -135,8 +133,7 @@ TryCatch ComponentPipelineFactory(QueryInfo rewrittenQueryI containerQueryProperties: containerQueryProperties, prefetchPolicy: PrefetchPolicy.PrefetchAll, maxConcurrency: maxConcurrency, - continuationToken: null, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + continuationToken: null); if (tryCatchGlobalStatisticsPipeline.Failed) { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs index 636e66e227..29f4639ef3 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs @@ -59,8 +59,6 @@ private sealed class InitializationParameters public int MaxConcurrency { get; } - public bool UseLengthAwareRangeComparer { get; } - public InitializationParameters( IDocumentContainer documentContainer, ContainerQueryProperties containerQueryProperties, @@ -70,8 +68,7 @@ public InitializationParameters( IReadOnlyList orderByColumns, QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, - int maxConcurrency, - bool useLengthAwareRangeComparer) + int maxConcurrency) { this.DocumentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.ContainerQueryProperties = containerQueryProperties; @@ -82,7 +79,6 @@ public InitializationParameters( this.QueryPaginationOptions = queryPaginationOptions ?? throw new ArgumentNullException(nameof(queryPaginationOptions)); this.EmitRawOrderByPayload = emitRawOrderByPayload; this.MaxConcurrency = maxConcurrency; - this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } } @@ -104,8 +100,7 @@ public static TryCatch MonadicCreate( int maxConcurrency, bool nonStreamingOrderBy, bool emitRawOrderByPayload, - CosmosElement continuationToken, - bool useLengthAwareRangeComparer) + CosmosElement continuationToken) { if (documentContainer == null) { @@ -149,8 +144,7 @@ public static TryCatch MonadicCreate( queryPaginationOptions, emitRawOrderByPayload, maxConcurrency, - continuationToken, - useLengthAwareRangeComparer); + continuationToken); } SqlQuerySpec rewrittenQueryForOrderBy = new SqlQuerySpec( @@ -166,8 +160,7 @@ public static TryCatch MonadicCreate( orderByColumns, queryPaginationOptions, emitRawOrderByPayload, - maxConcurrency, - useLengthAwareRangeComparer)); + maxConcurrency)); } private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( @@ -177,8 +170,7 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( OrderByQueryPartitionRangePageAsyncEnumerator uninitializedEnumerator, OrderByContinuationToken token, ITrace trace, - CancellationToken cancellationToken, - bool useLengthAwareComparer) + CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -222,8 +214,7 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( partitionKey: null, uninitializedEnumerator.QueryPaginationOptions, uninitializedEnumerator.Filter, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareComparer); + PrefetchPolicy.PrefetchSinglePage); uninitializedEnumeratorsAndTokens.Enqueue((childPaginator, token)); } else @@ -241,8 +232,7 @@ private static async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( partitionKey: null, uninitializedEnumerator.QueryPaginationOptions, uninitializedEnumerator.Filter, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareComparer); + PrefetchPolicy.PrefetchSinglePage); uninitializedEnumeratorsAndTokens.Enqueue((childPaginator, token)); } } @@ -346,7 +336,6 @@ private sealed class StreamingOrderByCrossPartitionQueryPipelineStage : IQueryPi private QueryState state; private bool returnedFinalPage; - private bool UseLengthAwareComparer; private static class Expressions { @@ -367,8 +356,7 @@ private StreamingOrderByCrossPartitionQueryPipelineStage( bool emitRawOrderByPayload, int maxConcurrency, IEnumerable<(OrderByQueryPartitionRangePageAsyncEnumerator, OrderByContinuationToken)> uninitializedEnumeratorsAndTokens, - QueryState state, - bool useLengthAwareComparer) + QueryState state) { this.documentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.containerQueryProperties = containerQueryProperties; @@ -379,7 +367,6 @@ private StreamingOrderByCrossPartitionQueryPipelineStage( this.maxConcurrency = maxConcurrency < 0 ? throw new ArgumentOutOfRangeException($"{nameof(maxConcurrency)} must be a non negative number.") : maxConcurrency; this.uninitializedEnumeratorsAndTokens = new Queue<(OrderByQueryPartitionRangePageAsyncEnumerator, OrderByContinuationToken)>(uninitializedEnumeratorsAndTokens ?? throw new ArgumentNullException(nameof(uninitializedEnumeratorsAndTokens))); this.state = state ?? InitializingQueryState; - this.UseLengthAwareComparer = useLengthAwareComparer; } private StreamingOrderByCrossPartitionQueryPipelineStage( @@ -444,7 +431,7 @@ private async ValueTask MoveNextAsync_Initialize_FromBeginningAsync( { if (IsSplitException(uninitializedEnumerator.Current.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token: null, trace, cancellationToken, this.UseLengthAwareComparer); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token: null, trace, cancellationToken); } this.uninitializedEnumeratorsAndTokens.Enqueue((uninitializedEnumerator, token: null)); @@ -531,7 +518,7 @@ private async ValueTask MoveNextAsync_Initialize_FilterAsync( { if (IsSplitException(filterMonad.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken, this.UseLengthAwareComparer); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken); } this.Current = TryCatch.FromException(filterMonad.Exception); @@ -571,7 +558,7 @@ private async ValueTask MoveNextAsync_Initialize_FilterAsync( { if (IsSplitException(filterMonad.Exception)) { - return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken, this.UseLengthAwareComparer); + return await this.MoveNextAsync_InitializeAsync_HandleSplitAsync(uninitializedEnumerator, token, trace, cancellationToken); } } @@ -614,8 +601,7 @@ private async ValueTask MoveNextAsync_InitializeAsync_HandleSplitAsync( OrderByQueryPartitionRangePageAsyncEnumerator uninitializedEnumerator, OrderByContinuationToken token, ITrace trace, - CancellationToken cancellationToken, - bool useLengthAwareComparer) + CancellationToken cancellationToken) { await OrderByCrossPartitionQueryPipelineStage.MoveNextAsync_InitializeAsync_HandleSplitAsync( this.documentContainer, @@ -624,8 +610,7 @@ await OrderByCrossPartitionQueryPipelineStage.MoveNextAsync_InitializeAsync_Hand uninitializedEnumerator, token, trace, - cancellationToken, - useLengthAwareComparer); + cancellationToken); // Recursively retry return await this.MoveNextAsync(trace, cancellationToken); @@ -863,8 +848,7 @@ public static TryCatch MonadicCreate( QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, int maxConcurrency, - CosmosElement continuationToken, - bool useLengthAwareRangeComparer) + CosmosElement continuationToken) { // TODO (brchon): For now we are not honoring non deterministic ORDER BY queries, since there is a bug in the continuation logic. // We can turn it back on once the bug is fixed. @@ -887,8 +871,7 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, TrueFilter, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer), + PrefetchPolicy.PrefetchSinglePage), (OrderByContinuationToken)null)) .ToList(); } @@ -977,8 +960,7 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + PrefetchPolicy.PrefetchSinglePage); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1006,8 +988,7 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + PrefetchPolicy.PrefetchSinglePage); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1030,8 +1011,7 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + PrefetchPolicy.PrefetchSinglePage); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1071,8 +1051,7 @@ public static TryCatch MonadicCreate( partitionKey, queryPaginationOptions, filter, - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + PrefetchPolicy.PrefetchSinglePage); enumeratorsAndTokens.Add((remoteEnumerator, token)); } @@ -1088,8 +1067,7 @@ public static TryCatch MonadicCreate( emitRawOrderByPayload, maxConcurrency, enumeratorsAndTokens, - continuationToken == null ? null : new QueryState(continuationToken), - useLengthAwareRangeComparer); + continuationToken == null ? null : new QueryState(continuationToken)); return TryCatch.FromResult(stage); } @@ -1824,8 +1802,7 @@ private async Task MoveNextAsync_InitializeAsync(ITrace this.parameters.QueryPaginationOptions, this.parameters.MaxConcurrency, trace, - cancellationToken, - this.parameters.UseLengthAwareRangeComparer); + cancellationToken); IReadOnlyList sortOrders = this.parameters.OrderByColumns.Select(column => column.SortOrder).ToList(); @@ -1849,8 +1826,7 @@ public static IQueryPipelineStage Create( IReadOnlyList orderByColumns, QueryExecutionOptions queryPaginationOptions, bool emitRawOrderByPayload, - int maxConcurrency, - bool useLengthAwareRangeComparer) + int maxConcurrency) { int pageSize = queryPaginationOptions.PageSizeLimit.GetValueOrDefault(MaximumPageSize) > 0 ? Math.Min(MaximumPageSize, queryPaginationOptions.PageSizeLimit.Value) : @@ -1865,8 +1841,7 @@ public static IQueryPipelineStage Create( orderByColumns, queryPaginationOptions, emitRawOrderByPayload, - maxConcurrency, - useLengthAwareRangeComparer); + maxConcurrency); return new NonStreamingOrderByPipelineStage( parameters, @@ -1882,20 +1857,16 @@ private sealed class OrderByCrossPartitionRangePageEnumerator : ITracingAsyncEnu private readonly Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens; - private readonly bool UseLengthAwareComparer; - public TryCatch Current { get; private set; } private OrderByCrossPartitionRangePageEnumerator( IDocumentContainer documentContainer, Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens, - ContainerQueryProperties containerQueryProperties, - bool useLengthAwareComparer) + ContainerQueryProperties containerQueryProperties) { this.documentContainer = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer)); this.enumeratorsAndTokens = enumeratorsAndTokens ?? throw new ArgumentNullException(nameof(enumeratorsAndTokens)); this.containerQueryProperties = containerQueryProperties; - this.UseLengthAwareComparer = useLengthAwareComparer; } public static async Task>> CreateAsync( @@ -1907,8 +1878,7 @@ public static async Task>> Cr QueryExecutionOptions queryPaginationOptions, int maxConcurrency, ITrace trace, - CancellationToken cancellationToken, - bool useLengthAwareRangeComparer) + CancellationToken cancellationToken) { Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)> enumeratorsAndTokens = new Queue<(OrderByQueryPartitionRangePageAsyncEnumerator enumerator, OrderByContinuationToken token)>(targetRanges.Count); @@ -1922,8 +1892,7 @@ public static async Task>> Cr partitionKey, queryPaginationOptions, filter: null, - PrefetchPolicy.PrefetchAll, - useLengthAwareRangeComparer); + PrefetchPolicy.PrefetchAll); enumeratorsAndTokens.Enqueue(new (enumerator, null)); } @@ -1934,7 +1903,7 @@ await ParallelPrefetch.PrefetchInParallelAsync( trace, cancellationToken); - return new OrderByCrossPartitionRangePageEnumerator(documentContainer, enumeratorsAndTokens, containerQueryProperties, useLengthAwareRangeComparer); + return new OrderByCrossPartitionRangePageEnumerator(documentContainer, enumeratorsAndTokens, containerQueryProperties); } public async ValueTask DisposeAsync() @@ -1996,8 +1965,7 @@ await MoveNextAsync_InitializeAsync_HandleSplitAsync( enumerator, token, trace, - cancellationToken, - this.UseLengthAwareComparer); + cancellationToken); } else { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs index 095467ab24..404dccb513 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByQueryPartitionRangePageAsyncEnumerator.cs @@ -27,8 +27,7 @@ public static OrderByQueryPartitionRangePageAsyncEnumerator Create( PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, string filter, - PrefetchPolicy prefetchPolicy, - bool useLengthAwareRangeComparer) + PrefetchPolicy prefetchPolicy) { InnerEnumerator enumerator = new InnerEnumerator( queryDataSource, @@ -37,8 +36,7 @@ public static OrderByQueryPartitionRangePageAsyncEnumerator Create( feedRangeState, partitionKey, queryPaginationOptions, - filter, - useLengthAwareRangeComparer); + filter); BufferedPartitionRangePageAsyncEnumeratorBase bufferedEnumerator = prefetchPolicy switch { @@ -120,8 +118,7 @@ public InnerEnumerator( FeedRangeState feedRangeState, PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, - string filter, - bool useLengthAwareRangeComparer) + string filter) : base(feedRangeState) { this.queryDataSource = queryDataSource ?? throw new ArgumentNullException(nameof(queryDataSource)); @@ -129,8 +126,7 @@ public InnerEnumerator( this.SqlQuerySpec = sqlQuerySpec ?? throw new ArgumentNullException(nameof(sqlQuerySpec)); this.PartitionKey = partitionKey; this.QueryPaginationOptions = queryPaginationOptions ?? QueryExecutionOptions.Default; - this.Filter = filter; - this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; + this.Filter = filter; } public SqlQuerySpec SqlQuerySpec { get; } @@ -141,8 +137,6 @@ public InnerEnumerator( public string Filter { get; } - public bool UseLengthAwareRangeComparer { get; } - public InnerEnumerator CloneWithMaxPageSize() { QueryExecutionOptions options = new QueryExecutionOptions( @@ -157,15 +151,14 @@ public InnerEnumerator CloneWithMaxPageSize() this.FeedRangeState, this.PartitionKey, options, - this.Filter, - this.UseLengthAwareRangeComparer); + this.Filter); } public override ValueTask DisposeAsync() => default; protected override async Task> GetNextPageAsync(ITrace trace, CancellationToken cancellationToken) { - FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.PartitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties, this.UseLengthAwareRangeComparer); + FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.PartitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties); TryCatch monadicQueryPage = await this.queryDataSource .MonadicQueryAsync( diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs index 36920478ea..5a2fc378d2 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/ParallelCrossPartitionQueryPipelineStage.cs @@ -137,8 +137,7 @@ public static TryCatch MonadicCreate( ContainerQueryProperties containerQueryProperties, int maxConcurrency, PrefetchPolicy prefetchPolicy, - CosmosElement continuationToken, - bool useLengthAwareRangeComparer) + CosmosElement continuationToken) { if (targetRanges == null) { @@ -160,7 +159,7 @@ public static TryCatch MonadicCreate( CrossPartitionRangePageAsyncEnumerator crossPartitionPageEnumerator = new CrossPartitionRangePageAsyncEnumerator( feedRangeProvider: documentContainer, - createPartitionRangeEnumerator: ParallelCrossPartitionQueryPipelineStage.MakeCreateFunction(documentContainer, sqlQuerySpec, queryPaginationOptions, partitionKey, containerQueryProperties, useLengthAwareRangeComparer), + createPartitionRangeEnumerator: ParallelCrossPartitionQueryPipelineStage.MakeCreateFunction(documentContainer, sqlQuerySpec, queryPaginationOptions, partitionKey, containerQueryProperties), comparer: Comparer.Singleton, maxConcurrency: maxConcurrency, prefetchPolicy: prefetchPolicy, @@ -246,15 +245,13 @@ private static CreatePartitionRangePageAsyncEnumerator Ma SqlQuerySpec sqlQuerySpec, QueryExecutionOptions queryPaginationOptions, Cosmos.PartitionKey? partitionKey, - ContainerQueryProperties containerQueryProperties, - bool useLengthAwareRangeComparer) => (FeedRangeState feedRangeState) => new QueryPartitionRangePageAsyncEnumerator( + ContainerQueryProperties containerQueryProperties) => (FeedRangeState feedRangeState) => new QueryPartitionRangePageAsyncEnumerator( queryDataSource, sqlQuerySpec, feedRangeState, partitionKey, queryPaginationOptions, - containerQueryProperties, - useLengthAwareRangeComparer); + containerQueryProperties); private sealed class Comparer : IComparer> { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs index c067c5afbe..8e918d16f7 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/Parallel/QueryPartitionRangePageAsyncEnumerator.cs @@ -20,7 +20,6 @@ internal sealed class QueryPartitionRangePageAsyncEnumerator : PartitionRangePag private readonly QueryExecutionOptions queryPaginationOptions; private readonly ContainerQueryProperties containerQueryProperties; private readonly Cosmos.PartitionKey? partitionKey; - private readonly bool useLengthAwareRangeComparer; public QueryPartitionRangePageAsyncEnumerator( IQueryDataSource queryDataSource, @@ -28,8 +27,7 @@ public QueryPartitionRangePageAsyncEnumerator( FeedRangeState feedRangeState, Cosmos.PartitionKey? partitionKey, QueryExecutionOptions queryPaginationOptions, - ContainerQueryProperties containerQueryProperties, - bool useLengthAwareRangeComparer) + ContainerQueryProperties containerQueryProperties) : base(feedRangeState) { this.queryDataSource = queryDataSource ?? throw new ArgumentNullException(nameof(queryDataSource)); @@ -37,7 +35,6 @@ public QueryPartitionRangePageAsyncEnumerator( this.queryPaginationOptions = queryPaginationOptions; this.partitionKey = partitionKey; this.containerQueryProperties = containerQueryProperties; - this.useLengthAwareRangeComparer = useLengthAwareRangeComparer; } public override ValueTask DisposeAsync() => default; @@ -49,7 +46,7 @@ protected override Task> GetNextPageAsync(ITrace trace, Canc throw new ArgumentNullException(nameof(trace)); } - FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.partitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties, this.useLengthAwareRangeComparer); + FeedRangeInternal feedRange = QueryRangeUtils.LimitHpkFeedRangeToPartition(this.partitionKey, this.FeedRangeState.FeedRange, this.containerQueryProperties); return this.queryDataSource.MonadicQueryAsync( sqlQuerySpec: this.sqlQuerySpec, feedRangeState: new FeedRangeState(feedRange, this.FeedRangeState.State), diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs index dc98ca966f..e91f98291b 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/OptimisticDirectExecution/OptimisticDirectExecutionQueryPipelineStage.cs @@ -151,8 +151,7 @@ public static TryCatch MonadicCreate( partitionKey: inputParameters.PartitionKey, containerQueryProperties: containerQueryProperties, continuationToken: inputParameters.InitialUserContinuationToken, - cancellationToken: cancellationToken, - useLengthAwareRangeComparer: inputParameters.UseLengthAwareRangeComparer); + cancellationToken: cancellationToken); if (pipelineStage.Failed) { @@ -243,8 +242,7 @@ public static TryCatch MonadicCreate( QueryExecutionOptions queryPaginationOptions, ContainerQueryProperties containerQueryProperties, CosmosElement continuationToken, - CancellationToken cancellationToken, - bool useLengthAwareRangeComparer) + CancellationToken cancellationToken) { if (targetRange == null) { @@ -279,8 +277,7 @@ public static TryCatch MonadicCreate( feedRangeState, partitionKey, queryPaginationOptions, - containerQueryProperties, - useLengthAwareRangeComparer); + containerQueryProperties); OptimisticDirectExecutionQueryPipelineImpl stage = new OptimisticDirectExecutionQueryPipelineImpl(partitionPageEnumerator); return TryCatch.FromResult(stage); diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs index 12157c933b..a1603e26f7 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/PipelineFactory.cs @@ -40,8 +40,7 @@ public static TryCatch MonadicCreate( IReadOnlyList allRanges, bool isContinuationExpected, int maxConcurrency, - CosmosElement requestContinuationToken, - bool useLengthAwareRangeComparer) + CosmosElement requestContinuationToken) { if (documentContainer == null) { @@ -92,8 +91,7 @@ public static TryCatch MonadicCreate( isContinuationExpected: true, emitRawOrderByPayload: false, maxConcurrency: maxConcurrency, - requestContinuationToken: requestContinuationToken, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + requestContinuationToken: requestContinuationToken); } else { @@ -107,8 +105,7 @@ public static TryCatch MonadicCreate( allRanges: allRanges, maxItemCount: maxItemCount, isContinuationExpected: isContinuationExpected, - maxConcurrency: maxConcurrency, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + maxConcurrency: maxConcurrency); if (hybridSearchQueryInfo.Skip != null) { @@ -155,8 +152,7 @@ public static TryCatch MonadicCreate( bool emitRawOrderByPayload, bool isContinuationExpected, int maxConcurrency, - CosmosElement requestContinuationToken, - bool useLengthAwareRangeComparer) + CosmosElement requestContinuationToken) { // We need to compute the optimal initial page size for order-by queries long optimalPageSize = maxItemCount; @@ -222,8 +218,7 @@ public static TryCatch MonadicCreate( nonStreamingOrderBy: queryInfo.HasNonStreamingOrderBy, emitRawOrderByPayload: emitRawOrderByPayload, continuationToken: continuationToken, - containerQueryProperties: containerQueryProperties, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + containerQueryProperties: containerQueryProperties); } else { @@ -236,8 +231,7 @@ public static TryCatch MonadicCreate( containerQueryProperties: containerQueryProperties, prefetchPolicy: prefetchPolicy, maxConcurrency: maxConcurrency, - continuationToken: continuationToken, - useLengthAwareRangeComparer: useLengthAwareRangeComparer); + continuationToken: continuationToken); } if (queryInfo.HasAggregates && !queryInfo.HasGroupBy) diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/ContainerQueryProperties.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/ContainerQueryProperties.cs index 18d8c59a0b..67b9c62016 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/ContainerQueryProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/ContainerQueryProperties.cs @@ -15,13 +15,15 @@ public ContainerQueryProperties( IReadOnlyList> effectivePartitionKeyRanges, PartitionKeyDefinition partitionKeyDefinition, Cosmos.VectorEmbeddingPolicy vectorEmbeddingPolicy, - Cosmos.GeospatialType geospatialType) + Cosmos.GeospatialType geospatialType, + bool useLengthAwareRangeComparer) { this.ResourceId = resourceId; this.EffectiveRangesForPartitionKey = effectivePartitionKeyRanges; this.PartitionKeyDefinition = partitionKeyDefinition; this.VectorEmbeddingPolicy = vectorEmbeddingPolicy; - this.GeospatialType = geospatialType; + this.GeospatialType = geospatialType; + this.UseLengthAwareRangeComparer = useLengthAwareRangeComparer; } public string ResourceId { get; } @@ -34,6 +36,7 @@ public ContainerQueryProperties( public Cosmos.VectorEmbeddingPolicy VectorEmbeddingPolicy { get; } - public Cosmos.GeospatialType GeospatialType { get; } + public Cosmos.GeospatialType GeospatialType { get; } + public bool UseLengthAwareRangeComparer { get; } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs index 77f7d01048..087fb956cf 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryRangeUtils.cs @@ -7,7 +7,8 @@ namespace Microsoft.Azure.Cosmos.Query.Core using System; using System.Collections.Generic; using System.Diagnostics; - using Microsoft.Azure.Cosmos.Query.Core.QueryClient; + using Microsoft.Azure.Cosmos.Query.Core.QueryClient; + using Microsoft.Azure.Cosmos.Routing; using Microsoft.Azure.Documents.Routing; internal static class QueryRangeUtils @@ -22,7 +23,7 @@ internal static class QueryRangeUtils /// Since such an epk range does not exist at the container level, Service generates a GoneException. /// This method restrics the range of each enumerator by intersecting it with physical partition range. /// - public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? partitionKey, FeedRangeInternal feedRange, ContainerQueryProperties containerQueryProperties, bool useLengthAwareRangeComparer) + public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? partitionKey, FeedRangeInternal feedRange, ContainerQueryProperties containerQueryProperties) { // We sadly need to check the partition key, since a user can set a partition key in the request options with a different continuation token. // In the future the partition filtering and continuation information needs to be a tightly bounded contract (like cross feed range state). @@ -54,15 +55,8 @@ public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? parti bool minInclusive; String overlappingMax; bool maxInclusive; - - //LengthAwareComparer is the default Range comparer and flag is used to ovverride the default comparer to legacy Min/Max comparer. - IComparer> minComparer = useLengthAwareRangeComparer - ? Documents.Routing.Range.LengthAwareMinComparer.Instance - : Documents.Routing.Range.MinComparer.Instance; - - IComparer> maxComparer = useLengthAwareRangeComparer - ? Documents.Routing.Range.LengthAwareMaxComparer.Instance - : Documents.Routing.Range.MaxComparer.Instance; + + (IComparer> minComparer, IComparer> maxComparer) = RangeComparerProvider.GetComparers(containerQueryProperties.UseLengthAwareRangeComparer); if (minComparer.Compare( epkForPartitionKey, @@ -124,13 +118,7 @@ public static FeedRangeInternal LimitHpkFeedRangeToPartition(PartitionKey? parti IReadOnlyList> providedRanges, bool useLengthAwareComparer = true) { - IComparer> minComparer = useLengthAwareComparer - ? Documents.Routing.Range.LengthAwareMinComparer.Instance - : Documents.Routing.Range.MinComparer.Instance; - - IComparer> maxComparer = useLengthAwareComparer - ? Documents.Routing.Range.LengthAwareMaxComparer.Instance - : Documents.Routing.Range.MaxComparer.Instance; + (IComparer> minComparer, IComparer> maxComparer) = RangeComparerProvider.GetComparers(useLengthAwareComparer); // Compute the overall min and max from providedRanges string overallMin = providedRanges[0].Min; diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs index 7ab008d7dd..8f3c7ca366 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs @@ -85,7 +85,8 @@ public override async Task GetCachedContainerQueryProp effectivePartitionKeyRange, containerProperties.PartitionKey, containerProperties.VectorEmbeddingPolicy, - containerProperties.GeospatialConfig.GeospatialType); + containerProperties.GeospatialConfig.GeospatialType, + this.documentClient.UseLengthAwareRangeComparer); } public override async Task> TryGetPartitionedQueryExecutionInfoAsync( diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs index c265a38c84..cc09cd3215 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs @@ -151,8 +151,7 @@ public static QueryIterator Create( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode && (clientContext.ClientOptions.ConnectionMode == ConnectionMode.Gateway), - testInjections: queryRequestOptions.TestSettings, - useLengthAwareRangeComparer: clientContext.ClientOptions.UseLengthAwareRangeComparer); + testInjections: queryRequestOptions.TestSettings); return new QueryIterator( cosmosQueryContext, diff --git a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs index ac7a1846be..12e7f1c57c 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/CollectionRoutingMap.cs @@ -72,15 +72,12 @@ private CollectionRoutingMap( } return range.Status == PartitionKeyRangeStatus.Offline ? CollectionRoutingMap.InvalidPkRangeId : pkId; }); - - this.comparers = useLengthAwareRangeComparer - ? (Range.LengthAwareMinComparer.Instance, Range.LengthAwareMaxComparer.Instance) - : (Range.MinComparer.Instance, Range.MaxComparer.Instance); + this.comparers = RangeComparerProvider.GetComparers(useLengthAwareRangeComparer); } public static CollectionRoutingMap TryCreateCompleteRoutingMap( IEnumerable> ranges, - string collectionUniqueId, + string collectionUniqueId, bool useLengthAwareRangeComparer, string changeFeedNextIfNoneMatch = null) { diff --git a/Microsoft.Azure.Cosmos/src/Routing/RangeComparerProvider.cs b/Microsoft.Azure.Cosmos/src/Routing/RangeComparerProvider.cs new file mode 100644 index 0000000000..ac54e7fad5 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Routing/RangeComparerProvider.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Routing +{ + using System.Collections.Generic; + using Microsoft.Azure.Documents.Routing; + + internal class RangeComparerProvider + { + /// + /// Gets the minimum and maximum range comparers based on the current configuration. + /// + /// Tuple of (minComparer, maxComparer) + public static (IComparer> minComparer, IComparer> maxComparer) GetComparers(bool useLengthAwareComparison) + { + return ( + useLengthAwareComparison ? Range.LengthAwareMinComparer.Instance : Range.MinComparer.Instance, + useLengthAwareComparison ? Range.LengthAwareMaxComparer.Instance : Range.MaxComparer.Instance + ); + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index b93f955d8a..5091d8ed78 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -2173,7 +2173,7 @@ public async Task ItemEpkQuerySingleKeyRangeValidation() //new List> { new Documents.Routing.Range("AA", "AA", true, true) }, containerResponse.Resource.PartitionKey, vectorEmbeddingPolicy: null, - containerResponse.Resource.GeospatialConfig.GeospatialType); + containerResponse.Resource.GeospatialConfig.GeospatialType, false); // There should only be one range since the EPK option is set. List partitionKeyRanges = await CosmosQueryExecutionContextFactory.GetTargetPartitionKeyRangesAsync( @@ -2186,8 +2186,7 @@ public async Task ItemEpkQuerySingleKeyRangeValidation() {"x-ms-effective-partition-key-string", "AA" } }, feedRangeInternal: null, - trace: NoOpTrace.Singleton, - useLengthAwareRangeComparer: false); + trace: NoOpTrace.Singleton); Assert.IsTrue(partitionKeyRanges.Count == 1, "Only 1 partition key range should be selected since the EPK option is set."); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs index 69d1b2f30a..2bf1d9ea4b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/FeedToken/QueryFeedTokenTests.cs @@ -57,7 +57,7 @@ public async Task GetTargetPartitionKeyRangesAsyncWithFeedRange() effectivePartitionKeyRanges: null, containerResponse.Resource.PartitionKey, vectorEmbeddingPolicy: null, - containerResponse.Resource.GeospatialConfig.GeospatialType); + containerResponse.Resource.GeospatialConfig.GeospatialType, false); IReadOnlyList feedTokens = await container.GetFeedRangesAsync(); @@ -73,8 +73,7 @@ public async Task GetTargetPartitionKeyRangesAsyncWithFeedRange() containerQueryProperties: containerQueryProperties, properties: null, feedRangeInternal: feedToken as FeedRangeInternal, - NoOpTrace.Singleton, - useLengthAwareRangeComparer: false); + NoOpTrace.Singleton); Assert.IsTrue(partitionKeyRanges.Count == 1, "Only 1 partition key range should be selected since the FeedRange represents a single range."); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs index ad2124b8a2..1ebfb165f2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/OrderByPipelineStageBenchmark.cs @@ -70,8 +70,7 @@ private static async Task CreateAndRunPipeline(IDocumentContainer documentContai nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); IQueryPipelineStage pipeline = pipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs index 3f613c3f19..e47cbc470a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OptimisticDirectExecutionQueryBaselineTests.cs @@ -1030,8 +1030,7 @@ private static IQueryPipelineStage CreateQueryPipelineStage( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings, - useLengthAwareRangeComparer: true); + testInjections: queryRequestOptions.TestSettings); List targetPkRanges = new(); foreach (FeedRangeEpk feedRangeEpk in containerRanges) @@ -1326,7 +1325,8 @@ public override Task GetCachedContainerQueryProperties }, new PartitionKeyDefinition(), vectorEmbeddingPolicy: null, - Cosmos.GeospatialType.Geometry)); + Cosmos.GeospatialType.Geometry, + false)); } public override Task GetClientDisableOptimisticDirectExecutionAsync() diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs index fb6470e67c..b7d7927c59 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/OrderByQueryPartitionRangePageAsyncEnumeratorTests.cs @@ -65,8 +65,7 @@ protected override Task>> CreateEnum partitionKey: null, queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), filter: "filter", - PrefetchPolicy.PrefetchSinglePage, - useLengthAwareRangeComparer: true), + PrefetchPolicy.PrefetchSinglePage), NoOpTrace.Singleton, cancellationToken); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs index 3148425814..abffd707ca 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FactoryTests.cs @@ -27,15 +27,14 @@ public void TestCreate() sqlQuerySpec: new SqlQuerySpec("SELECT * FROM c"), targetRanges: new List() { FeedRangeEpk.FullRange }, partitionKey: null, - containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), + containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), allRanges: new List() { FeedRangeEpk.FullRange }, - queryInfo: new QueryInfo() { }, + queryInfo: new QueryInfo() { }, hybridSearchQueryInfo: null, - maxItemCount: 10, + maxItemCount: 10, isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: default, - useLengthAwareRangeComparer: false); ; + requestContinuationToken: default); ; Assert.IsTrue(monadicCreatePipeline.Succeeded); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs index 04754d3b7c..ba51c787ab 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs @@ -253,7 +253,7 @@ public async Task Tracing() numTraces++; } } - + rootTrace.SetWalkingStateRecursively(); Assert.AreEqual(numTraces, rootTrace.Children.Count); } @@ -296,12 +296,12 @@ public async Task OffsetLimitPageSize() private async Task TestPageSizeAsync(string query, int expectedPageSize, int expectedResults, MockInMemoryContainer inMemoryContainer, DocumentContainer documentContainer) { - IQueryPipelineStage queryPipelineStage = CreateQueryPipelineStage( + IQueryPipelineStage queryPipelineStage = CreateQueryPipelineStage( documentContainer, query, partitionKeyDefinition, null, - new QueryRequestOptions()); + new QueryRequestOptions()); List elements = new List(); while (await queryPipelineStage.MoveNextAsync(NoOpTrace.Singleton, cancellationToken: default)) @@ -316,7 +316,7 @@ private async Task TestPageSizeAsync(string query, int expectedPageSize, int exp Assert.AreEqual(expected: expectedResults, actual: elements.Count); } - private static IQueryPipelineStage CreateQueryPipelineStage( + private static IQueryPipelineStage CreateQueryPipelineStage( DocumentContainer documentContainer, string query, PartitionKeyDefinition partitionKeyDefinition, @@ -338,11 +338,10 @@ private static IQueryPipelineStage CreateQueryPipelineStage( properties: new Dictionary() { { "x-ms-query-partitionkey-definition", partitionKeyDefinition } }, partitionedQueryExecutionInfo: null, returnResultsInDeterministicOrder: null, - enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, - isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, + enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, + isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings, - useLengthAwareRangeComparer: false); + testInjections: queryRequestOptions.TestSettings); string databaseId = "db1234"; string resourceLink = $"dbs/{databaseId}/colls"; @@ -373,30 +372,30 @@ private static IQueryPipelineStage CreateQueryPipelineStage( mockClient.Setup(x => x.TryGetPartitionedQueryExecutionInfoAsync( It.IsAny(), It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(( - SqlQuerySpec sqlQuerySpec, - ResourceType resourceType, - PartitionKeyDefinition partitionKeyDefinition, - VectorEmbeddingPolicy vectorEmbeddingPolicy, - bool requireFormattableOrderByQuery, - bool isContinuationExpected, - bool allowNonValueAggregateQuery, - bool hasLogicalPartitionKey, - bool allowDCount, - bool useSystemPrefix, + .Returns(( + SqlQuerySpec sqlQuerySpec, + ResourceType resourceType, + PartitionKeyDefinition partitionKeyDefinition, + VectorEmbeddingPolicy vectorEmbeddingPolicy, + bool requireFormattableOrderByQuery, + bool isContinuationExpected, + bool allowNonValueAggregateQuery, + bool hasLogicalPartitionKey, + bool allowDCount, + bool useSystemPrefix, bool isHybridSearchQueryPlanOptimizationDisabled, - Cosmos.GeospatialType geospatialType, + Cosmos.GeospatialType geospatialType, CancellationToken cancellationToken) => { CosmosSerializerCore serializerCore = new(); @@ -424,11 +423,11 @@ private static IQueryPipelineStage CreateQueryPipelineStage( isContinuationExpected: true, allowNonValueAggregateQuery: true, useSystemPrefix: false, - correlatedActivityId: Guid.NewGuid()); - + correlatedActivityId: Guid.NewGuid()); + IQueryPipelineStage queryPipelineStage = CosmosQueryExecutionContextFactory.Create( documentContainer, - cosmosQueryContextCore, + cosmosQueryContextCore, inputParameters, NoOpTrace.Singleton); @@ -614,15 +613,14 @@ private static async Task CreatePipelineAsync( new SqlQuerySpec(query), feedRanges, partitionKey: null, - GetQueryPlan(query), - hybridSearchQueryInfo: null, + GetQueryPlan(query), + hybridSearchQueryInfo: null, allRanges: feedRanges, maxItemCount: pageSize, - containerQueryProperties: new ContainerQueryProperties(), + containerQueryProperties: new ContainerQueryProperties(), isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: state, - useLengthAwareRangeComparer: false); + requestContinuationToken: state); tryCreatePipeline.ThrowIfFailed(); @@ -633,13 +631,13 @@ private static QueryInfo GetQueryPlan(string query) { TryCatch info = QueryPartitionProviderTestInstance.Object.TryGetPartitionedQueryExecutionInfoInternal( JsonConvert.SerializeObject(new SqlQuerySpec(query)), - partitionKeyDefinition, + partitionKeyDefinition, vectorEmbeddingPolicy: null, requireFormattableOrderByQuery: true, isContinuationExpected: false, allowNonValueAggregateQuery: true, allowDCount: true, - hasLogicalPartitionKey: false, + hasLogicalPartitionKey: false, hybridSearchSkipOrderByRewrite: false, useSystemPrefix: false, geospatialType: Cosmos.GeospatialType.Geography); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs index 551db2ce2e..f9645ef2a5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/NonStreamingOrderByQueryTests.cs @@ -681,8 +681,7 @@ private static async Task RunParityTests( ranges, isContinuationExpected: true, maxConcurrency: MaxConcurrency, - requestContinuationToken: null, - useLengthAwareRangeComparer: false); + requestContinuationToken: null); Assert.IsTrue(tryCreatePipeline.Succeeded); return RunPipelineStage(tryCreatePipeline.Result, pageSize); @@ -726,8 +725,7 @@ private static async Task RunParityTests( nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(pipelineStage.Succeeded); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs index b8ec2ea5c8..47dd212109 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/OrderByCrossPartitionQueryPipelineStageTests.cs @@ -81,8 +81,7 @@ public void MonadicCreate_NullContinuationToken() nonStreamingOrderBy: false, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } @@ -105,8 +104,7 @@ public void MonadicCreate_NonCosmosArrayContinuationToken() nonStreamingOrderBy: false, continuationToken: CosmosObject.Create(new Dictionary()), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -130,8 +128,7 @@ public void MonadicCreate_EmptyArrayContinuationToken() nonStreamingOrderBy: false, continuationToken: CosmosArray.Create(new List()), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -155,8 +152,7 @@ public void MonadicCreate_NonParallelContinuationToken() nonStreamingOrderBy: false, continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -199,8 +195,7 @@ public void MonadicCreate_SingleOrderByContinuationToken() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } @@ -247,8 +242,7 @@ public void MonadicCreate_SingleOrderByContinuationToken() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -311,8 +305,7 @@ public void MonadicCreate_MultipleOrderByContinuationToken() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken2) }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -356,8 +349,7 @@ public void MonadicCreate_OrderByWithResumeValues() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } @@ -401,8 +393,7 @@ public void MonadicCreate_OrderByWithResumeValues() OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); } } @@ -456,8 +447,7 @@ public async Task TestFormattedFiltersForTargetPartitionWithContinuationTokenAsy nonStreamingOrderBy: false, continuationToken: CosmosElement.Parse(continuationToken), containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -497,8 +487,7 @@ FROM c nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -549,8 +538,7 @@ FROM c nonStreamingOrderBy: false, continuationToken: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); Assert.IsTrue(monadicCreate.Succeeded); IQueryPipelineStage queryPipelineStage = monadicCreate.Result; @@ -614,8 +602,7 @@ FROM c nonStreamingOrderBy: nonStreamingOrderBy, continuationToken: continuationToken, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - emitRawOrderByPayload: false, - useLengthAwareRangeComparer: true); + emitRawOrderByPayload: false); monadicQueryPipelineStage.ThrowIfFailed(); IQueryPipelineStage queryPipelineStage = monadicQueryPipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs index a65c631bad..9a64210f4f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/ParallelCrossPartitionQueryPipelineStageTests.cs @@ -39,8 +39,7 @@ public void MonadicCreate_NullContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: null, - useLengthAwareRangeComparer: true); + continuationToken: null); Assert.IsTrue(monadicCreate.Succeeded); } @@ -58,8 +57,7 @@ public void MonadicCreate_NonCosmosArrayContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosObject.Create(new Dictionary()), - useLengthAwareRangeComparer: true); + continuationToken: CosmosObject.Create(new Dictionary())); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -78,8 +76,7 @@ public void MonadicCreate_EmptyArrayContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List()), - useLengthAwareRangeComparer: true); + continuationToken: CosmosArray.Create(new List())); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -98,8 +95,7 @@ public void MonadicCreate_NonParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") }), - useLengthAwareRangeComparer: true); + continuationToken: CosmosArray.Create(new List() { CosmosString.Create("asdf") })); Assert.IsTrue(monadicCreate.Failed); Assert.IsTrue(monadicCreate.InnerMostException is MalformedContinuationTokenException); } @@ -122,8 +118,7 @@ public void MonadicCreate_SingleParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token) }), - useLengthAwareRangeComparer: true); + continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token) })); Assert.IsTrue(monadicCreate.Succeeded); } @@ -153,8 +148,8 @@ public void MonadicCreate_MultipleParallelContinuationToken() containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: PrefetchPolicy.PrefetchSinglePage, - continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token1), ParallelContinuationToken.ToCosmosElement(token2) }), - useLengthAwareRangeComparer: true); + continuationToken: CosmosArray.Create(new List() { ParallelContinuationToken.ToCosmosElement(token1), ParallelContinuationToken.ToCosmosElement(token2) })); + Assert.IsTrue(monadicCreate.Succeeded); } @@ -190,8 +185,7 @@ async Task CreatePipelineStateAsync(IDocumentContainer docu containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), maxConcurrency: 10, prefetchPolicy: aggressivePrefetch ? PrefetchPolicy.PrefetchAll : PrefetchPolicy.PrefetchSinglePage, - continuationToken: continuationToken, - useLengthAwareRangeComparer: true); + continuationToken: continuationToken); Assert.IsTrue(monadicQueryPipelineStage.Succeeded); IQueryPipelineStage queryPipelineStage = monadicQueryPipelineStage.Result; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs index 84e2b9c5ef..4a6c71303c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPartitionRangePageEnumeratorTests.cs @@ -101,8 +101,7 @@ public async Task TestSplitAsync() feedRangeState: feedRangeState, partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), - useLengthAwareRangeComparer: true), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), trace: NoOpTrace.Singleton); HashSet resourceIdentifiers = await this.DrainFullyAsync(enumerable); @@ -145,8 +144,7 @@ protected override IAsyncEnumerable> CreateEnumerable( feedRangeState: feedRangeState, partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), - useLengthAwareRangeComparer: true), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), trace: NoOpTrace.Singleton); } @@ -169,8 +167,7 @@ protected override Task>> CreateEnumeratorA feedRangeState: new FeedRangeState(ranges[0], state), partitionKey: null, containerQueryProperties: new Cosmos.Query.Core.QueryClient.ContainerQueryProperties(), - queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10), - useLengthAwareRangeComparer: true), + queryPaginationOptions: new QueryExecutionOptions(pageSizeHint: 10)), trace: NoOpTrace.Singleton, cancellationToken: default); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs index ddbdd33440..5bcdd9c489 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/SubpartitionTests.cs @@ -138,8 +138,7 @@ private static IQueryPipelineStage CreateQueryPipelineStage( enableOptimisticDirectExecution: queryRequestOptions.EnableOptimisticDirectExecution, isHybridSearchQueryPlanOptimizationDisabled: queryRequestOptions.IsHybridSearchQueryPlanOptimizationDisabled, enableDistributedQueryGatewayMode: queryRequestOptions.EnableDistributedQueryGatewayMode, - testInjections: queryRequestOptions.TestSettings, - useLengthAwareRangeComparer: false); + testInjections: queryRequestOptions.TestSettings); List targetPkRanges = new(); foreach (FeedRangeEpk feedRangeEpk in containerRanges) @@ -336,7 +335,8 @@ public override Task GetCachedContainerQueryProperties }, SubpartitionTests.CreatePartitionKeyDefinition(), vectorEmbeddingPolicy: null, - Cosmos.GeospatialType.Geometry)); + Cosmos.GeospatialType.Geometry, + false)); } public override Task GetClientDisableOptimisticDirectExecutionAsync() diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs index b03599b5af..9b9ba1b29a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs @@ -763,8 +763,7 @@ private static IQueryPipelineStage CreatePipeline(IDocumentContainer documentCon allRanges: new List() { FeedRangeEpk.FullRange }, isContinuationExpected: true, maxConcurrency: 10, - requestContinuationToken: state, - useLengthAwareRangeComparer: false); + requestContinuationToken: state); tryCreatePipeline.ThrowIfFailed();