in Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsParser.cs [22:282]
public static unsafe bool TryParse(string deliminatedString, out ServerSideMetricsInternal serverSideMetrics)
{
if (deliminatedString == null)
{
throw new ArgumentNullException(nameof(deliminatedString));
}
if (deliminatedString.Length == 0)
{
// Stack allocating a zero length buffer returns a null pointer
// so we special case the zero length string.
serverSideMetrics = ServerSideMetricsInternal.Empty;
return true;
}
// QueryMetrics
long retrievedDocumentCount = default;
long retrievedDocumentSize = default;
long outputDocumentCount = default;
long outputDocumentSize = default;
double indexHitRatio = default;
TimeSpan totalQueryExecutionTime = default;
// QueryPreparationTimes
TimeSpan queryCompilationTime = default;
TimeSpan logicalPlanBuildTime = default;
TimeSpan physicalPlanBuildTime = default;
TimeSpan queryOptimizationTime = default;
// QueryTimes
TimeSpan indexLookupTime = default;
TimeSpan documentLoadTime = default;
TimeSpan vmExecutionTime = default;
TimeSpan documentWriteTime = default;
// RuntimeExecutionTimes
TimeSpan systemFunctionExecutionTime = default;
TimeSpan userDefinedFunctionExecutionTime = default;
const int MaxStackAlloc = 4 * 1024;
int corpusLengthInBytes = deliminatedString.Length * 4;
ReadOnlySpan<byte> corpus = (corpusLengthInBytes <= MaxStackAlloc) ? stackalloc byte[corpusLengthInBytes] : new byte[corpusLengthInBytes];
fixed (char* deliminatedStringPointer = deliminatedString)
{
fixed (byte* corpusPointer = corpus)
{
int bytesEncoded = Encoding.UTF8.GetBytes(deliminatedStringPointer, deliminatedString.Length, corpusPointer, corpus.Length);
corpus = corpus.Slice(0, bytesEncoded);
}
}
while (!corpus.IsEmpty)
{
(ServerSideMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory<byte> buffer) = ServerSideMetricsTokenizer.Read(corpus);
int bytesConsumed;
if (!tokenType.HasValue)
{
// If the token is unknown, then just skip till the next field (';' or EOF)
// since the token must have been added recently in the service and the newer SDKs should know how to parse it
// this avoids breaking old clients
int nextTokenIndex = corpus.IndexOf((byte)';');
if (nextTokenIndex == -1)
{
// The next token does not exist, so just seek to the end
bytesConsumed = corpus.Length;
}
else
{
bytesConsumed = nextTokenIndex;
}
}
else
{
switch (tokenType.Value)
{
case ServerSideMetricsTokenizer.TokenType.DocumentLoadTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.DocumentLoadTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out documentLoadTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.WriteOutputTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.WriteOutputTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out documentWriteTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.IndexLookupTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.IndexLookupTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out indexLookupTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.IndexUtilizationRatio:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.IndexUtilizationRatio.Length);
if (!ServerSideMetricsParser.TryParseDoubleField(corpus, out indexHitRatio, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.QueryLogicalPlanBuildTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryLogicalPlanBuildTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out logicalPlanBuildTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.OutputDocumentCount:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.OutputDocumentCount.Length);
if (!ServerSideMetricsParser.TryParseLongField(corpus, out outputDocumentCount, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.OutputDocumentSize:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.OutputDocumentSize.Length);
if (!ServerSideMetricsParser.TryParseLongField(corpus, out outputDocumentSize, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.QueryPhysicalPlanBuildTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryPhysicalPlanBuildTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out physicalPlanBuildTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.QueryCompileTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryCompileTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out queryCompilationTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.QueryOptimizationTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryOptimizationTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out queryOptimizationTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.RetrievedDocumentCount:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.RetrievedDocumentCount.Length);
if (!ServerSideMetricsParser.TryParseLongField(corpus, out retrievedDocumentCount, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.RetrievedDocumentSize:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.RetrievedDocumentSize.Length);
if (!ServerSideMetricsParser.TryParseLongField(corpus, out retrievedDocumentSize, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.SystemFunctionExecuteTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.SystemFunctionExecuteTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out systemFunctionExecutionTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.TotalExecutionTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.TotalExecutionTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out totalQueryExecutionTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.UserFunctionExecuteTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.UserFunctionExecuteTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out userDefinedFunctionExecutionTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
case ServerSideMetricsTokenizer.TokenType.VMExecutionTimeInMs:
corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.VMExecutionTimeInMs.Length);
if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out vmExecutionTime, out bytesConsumed))
{
serverSideMetrics = default;
return false;
}
break;
default:
serverSideMetrics = default;
return false;
}
}
corpus = corpus.Slice(bytesConsumed);
if (!corpus.IsEmpty)
{
(ServerSideMetricsTokenizer.TokenType? semicolonToken, ReadOnlyMemory<byte> semicolonBuffer) = ServerSideMetricsTokenizer.Read(corpus);
if (!semicolonToken.HasValue || (semicolonToken != ServerSideMetricsTokenizer.TokenType.SemiColonDelimiter))
{
serverSideMetrics = default;
return false;
}
corpus = corpus.Slice(1);
}
}
serverSideMetrics = new ServerSideMetricsInternal(
retrievedDocumentCount: retrievedDocumentCount,
retrievedDocumentSize: retrievedDocumentSize,
outputDocumentCount: outputDocumentCount,
outputDocumentSize: outputDocumentSize,
indexHitRatio: indexHitRatio,
totalQueryExecutionTime: totalQueryExecutionTime,
queryPreparationTimes: new QueryPreparationTimesInternal(
queryCompilationTime: queryCompilationTime,
logicalPlanBuildTime: logicalPlanBuildTime,
physicalPlanBuildTime: physicalPlanBuildTime,
queryOptimizationTime: queryOptimizationTime),
indexLookupTime: indexLookupTime,
documentLoadTime: documentLoadTime,
vmExecutionTime: vmExecutionTime,
runtimeExecutionTimes: new RuntimeExecutionTimesInternal(
queryEngineExecutionTime: vmExecutionTime - indexLookupTime - documentLoadTime - documentWriteTime,
systemFunctionExecutionTime: systemFunctionExecutionTime,
userDefinedFunctionExecutionTime: userDefinedFunctionExecutionTime),
documentWriteTime: documentWriteTime);
return true;
}