Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Performance: Fixes query improvement to load values lazily #2869

Merged
merged 13 commits into from
Nov 16, 2021
21 changes: 16 additions & 5 deletions Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,31 @@ sealed class QueryMetrics
/// QueryMetrics that with all members having default (but not null) members.
/// </summary>
public static readonly QueryMetrics Empty = new QueryMetrics(
backendMetrics: BackendMetrics.Empty,
deliminatedString: string.Empty,
indexUtilizationInfo: IndexUtilizationInfo.Empty,
clientSideMetrics: ClientSideMetrics.Empty);

public QueryMetrics(
BackendMetrics backendMetrics,
IndexUtilizationInfo indexUtilizationInfo,
ClientSideMetrics clientSideMetrics)
BackendMetrics backendMetrics,
IndexUtilizationInfo indexUtilizationInfo,
ClientSideMetrics clientSideMetrics)
{
this.BackendMetrics = backendMetrics ?? throw new ArgumentNullException(nameof(backendMetrics));
this.BackendMetrics = backendMetrics ?? throw new ArgumentNullException(nameof(indexUtilizationInfo));
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
this.IndexUtilizationInfo = indexUtilizationInfo ?? throw new ArgumentNullException(nameof(indexUtilizationInfo));
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
this.ClientSideMetrics = clientSideMetrics ?? throw new ArgumentNullException(nameof(clientSideMetrics));
}

public QueryMetrics(
string deliminatedString,
IndexUtilizationInfo indexUtilizationInfo,
ClientSideMetrics clientSideMetrics)
: this(!String.IsNullOrWhiteSpace(deliminatedString) &&
BackendMetricsParser.TryParse(deliminatedString, out BackendMetrics backendMetrics)
? backendMetrics
: BackendMetrics.Empty, indexUtilizationInfo, clientSideMetrics)
{
}

public BackendMetrics BackendMetrics { get; }

public IndexUtilizationInfo IndexUtilizationInfo { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Pipeline.CrossPartition.OrderBy
using Microsoft.Azure.Cosmos.Query.Core.Monads;
using Microsoft.Azure.Cosmos.Query.Core.Pipeline.CrossPartition.Parallel;
using Microsoft.Azure.Cosmos.Query.Core.Pipeline.Pagination;
using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
using Microsoft.Azure.Cosmos.Tracing;
using ResourceId = Documents.ResourceId;

Expand Down Expand Up @@ -1108,7 +1109,9 @@ private static (string leftFilter, string targetFilter, string rightFilter) GetF
// If there is a tie in the sort order the documents should be in _rid order in the same direction as the index (given by the backend)
ResourceId rid = ResourceId.Parse(orderByResult.Rid);
int ridOrderCompare = continuationRid.Document.CompareTo(rid.Document);
if ((orderByQueryPage.Page.CosmosQueryExecutionInfo == null) || orderByQueryPage.Page.CosmosQueryExecutionInfo.ReverseRidEnabled)

Lazy<CosmosQueryExecutionInfo> cosmosQueryExecutionInfo = orderByQueryPage.Page.CosmosQueryExecutionInfo;
if ((cosmosQueryExecutionInfo == null) || cosmosQueryExecutionInfo.Value.ReverseRidEnabled)
{
// If reverse rid is enabled on the backend then fallback to the old way of doing it.
if (sortOrders[0] == SortOrder.Descending)
Expand All @@ -1119,7 +1122,7 @@ private static (string leftFilter, string targetFilter, string rightFilter) GetF
else
{
// Go by the whatever order the index wants
if (orderByQueryPage.Page.CosmosQueryExecutionInfo.ReverseIndexScan)
if (cosmosQueryExecutionInfo.Value.ReverseIndexScan)
{
ridOrderCompare = -ridOrderCompare;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Pipeline.Pagination
using Microsoft.Azure.Cosmos.CosmosElements;
using Microsoft.Azure.Cosmos.Pagination;
using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
using Newtonsoft.Json;
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved

internal sealed class QueryPage : Page<QueryState>
{
Expand All @@ -25,7 +26,7 @@ public QueryPage(
double requestCharge,
string activityId,
long responseLengthInBytes,
CosmosQueryExecutionInfo cosmosQueryExecutionInfo,
Lazy<CosmosQueryExecutionInfo> cosmosQueryExecutionInfo,
string disallowContinuationTokenMessage,
IReadOnlyDictionary<string, string> additionalHeaders,
QueryState state)
Expand All @@ -41,7 +42,7 @@ public QueryPage(

public long ResponseLengthInBytes { get; }

public CosmosQueryExecutionInfo CosmosQueryExecutionInfo { get; }
public Lazy<CosmosQueryExecutionInfo> CosmosQueryExecutionInfo { get; }

public string DisallowContinuationTokenMessage { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ protected override async Task<DocumentFeedResponse<CosmosElement>> ExecuteIntern
{
partitionIdentifier,
new QueryMetrics(
BackendMetrics.ParseFromDelimitedString(response.ResponseHeaders[HttpConstants.HttpHeaders.QueryMetrics]),
response.ResponseHeaders[HttpConstants.HttpHeaders.QueryMetrics],
IndexUtilizationInfo.CreateFromString(response.ResponseHeaders[HttpConstants.HttpHeaders.IndexUtilization]),
new ClientSideMetrics(
this.retries,
Expand Down
27 changes: 13 additions & 14 deletions Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,12 +285,13 @@ private static TryCatch<QueryPage> GetCosmosElementResponse(
{
using (cosmosResponseMessage)
{
if (
cosmosResponseMessage.Headers.QueryMetricsText != null &&
BackendMetricsParser.TryParse(cosmosResponseMessage.Headers.QueryMetricsText, out BackendMetrics backendMetrics))
if (cosmosResponseMessage.Headers.QueryMetricsText != null)
{
QueryMetricsTraceDatum datum = new QueryMetricsTraceDatum(
new QueryMetrics(backendMetrics, IndexUtilizationInfo.Empty, ClientSideMetrics.Empty));
new Lazy<QueryMetrics>(() => new QueryMetrics(
cosmosResponseMessage.Headers.QueryMetricsText,
IndexUtilizationInfo.Empty,
ClientSideMetrics.Empty)));
trace.AddDatum("Query Metrics", datum);
}

Expand All @@ -317,16 +318,6 @@ private static TryCatch<QueryPage> GetCosmosElementResponse(
resourceType,
requestOptions.CosmosSerializationFormatOptions);

CosmosQueryExecutionInfo cosmosQueryExecutionInfo;
if (cosmosResponseMessage.Headers.TryGetValue(QueryExecutionInfoHeader, out string queryExecutionInfoString))
{
cosmosQueryExecutionInfo = JsonConvert.DeserializeObject<CosmosQueryExecutionInfo>(queryExecutionInfoString);
}
else
{
cosmosQueryExecutionInfo = default;
}

QueryState queryState;
if (cosmosResponseMessage.Headers.ContinuationToken != null)
{
Expand All @@ -346,6 +337,14 @@ private static TryCatch<QueryPage> GetCosmosElementResponse(
}
}

Lazy<CosmosQueryExecutionInfo> cosmosQueryExecutionInfo = default;
if (cosmosResponseMessage.Headers.TryGetValue(QueryExecutionInfoHeader, out string queryExecutionInfoString))
{
cosmosQueryExecutionInfo =
new Lazy<CosmosQueryExecutionInfo>(
() => JsonConvert.DeserializeObject<CosmosQueryExecutionInfo>(queryExecutionInfoString));
}

QueryPage response = new QueryPage(
documents,
cosmosResponseMessage.Headers.RequestCharge,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ namespace Microsoft.Azure.Cosmos.Tracing.TraceData

internal sealed class QueryMetricsTraceDatum : TraceDatum
{
public QueryMetricsTraceDatum(QueryMetrics queryMetrics)
private readonly Lazy<QueryMetrics> LazyQueryMetrics;

public QueryMetricsTraceDatum(Lazy<QueryMetrics> queryMetrics)
{
this.QueryMetrics = queryMetrics ?? throw new ArgumentNullException(nameof(queryMetrics));
this.LazyQueryMetrics = queryMetrics ?? throw new ArgumentNullException(nameof(queryMetrics));
}

public QueryMetrics QueryMetrics { get; }
public QueryMetrics QueryMetrics => this.LazyQueryMetrics.Value;

internal override void Accept(ITraceDatumVisitor traceDatumVisitor)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ private async Task ValidateQueryMetricsHeadersOverContinuations(
string indexUtilization = response.ResponseHeaders[WFConstants.BackendHeaders.IndexUtilization];

QueryMetrics queryMetrics = new QueryMetrics(
BackendMetrics.ParseFromDelimitedString(responseQueryMetrics),
responseQueryMetrics,
IndexUtilizationInfo.CreateFromString(indexUtilization),
ClientSideMetrics.Empty);
this.ValidateQueryMetrics(queryMetrics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@
using (rootTrace = TraceForBaselineTesting.GetRootTrace())
{
QueryMetricsTraceDatum datum = new QueryMetricsTraceDatum(
new QueryMetrics(
new Lazy<QueryMetrics>(() => new QueryMetrics(
BackendMetricsTests.MockBackendMetrics,
IndexUtilizationInfoTests.MockIndexUtilizationInfo,
ClientSideMetricsTests.MockClientSideMetrics));
ClientSideMetricsTests.MockClientSideMetrics)));
rootTrace.AddDatum("Query Metrics", datum);
}
]]></Setup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ namespace Microsoft.Azure.Cosmos.Tests.Tracing
[TestClass]
public sealed class TraceWriterBaselineTests : BaselineTests<TraceWriterBaselineTests.Input, TraceWriterBaselineTests.Output>
{
private static readonly QueryMetrics MockQueryMetrics = new QueryMetrics(
private static readonly Lazy<QueryMetrics> MockQueryMetrics = new Lazy<QueryMetrics>(() => new QueryMetrics(
BackendMetricsTests.MockBackendMetrics,
IndexUtilizationInfoTests.MockIndexUtilizationInfo,
ClientSideMetricsTests.MockClientSideMetrics);
ClientSideMetricsTests.MockClientSideMetrics));

private static readonly Documents.PartitionKeyDefinition partitionKeyDefinition = new Documents.PartitionKeyDefinition()
{
Expand Down Expand Up @@ -315,10 +315,10 @@ public void TraceData()
using (rootTrace = TraceForBaselineTesting.GetRootTrace())
{
QueryMetricsTraceDatum datum = new QueryMetricsTraceDatum(
new QueryMetrics(
new Lazy<QueryMetrics>(() => new QueryMetrics(
BackendMetricsTests.MockBackendMetrics,
IndexUtilizationInfoTests.MockIndexUtilizationInfo,
ClientSideMetricsTests.MockClientSideMetrics));
ClientSideMetricsTests.MockClientSideMetrics)));
rootTrace.AddDatum("Query Metrics", datum);
}
endLineNumber = GetLineNumber();
Expand Down