Merge pull request #716 from dotnet-maestro-bot/merge/release/2.2-to-master

[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
Ryan Nowak 2018-08-14 17:17:29 -07:00 committed by GitHub
commit 8e273b9280
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 27 deletions

View File

@ -9,6 +9,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Generated from https://github.com/Azure/azure-rest-api-specs
public partial class MatcherFindCandidateSetAzureBenchmark : MatcherBenchmarkBase
{
// SegmentCount should be max-segments + 1, but we don't have a good way to compute
// it here, so using 16 as a safe guess.
private const int SegmentCount = 16;
private const int SampleCount = 100;
private BarebonesMatcher _baseline;
@ -58,7 +62,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var httpContext = Requests[sample];
var path = httpContext.Request.Path.Value;
Span<PathSegment> segments = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
Span<PathSegment> segments = stackalloc PathSegment[SegmentCount];
var count = FastPathTokenizer.Tokenize(path, segments);
var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

View File

@ -11,6 +11,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Use https://editor2.swagger.io/ to convert from yaml to json-
public partial class MatcherFindCandidateSetGithubBenchmark : MatcherBenchmarkBase
{
// SegmentCount should be max-segments + 1, but we don't have a good way to compute
// it here, so using 16 as a safe guess.
private const int SegmentCount = 16;
private BarebonesMatcher _baseline;
private DfaMatcher _dfa;
@ -50,7 +54,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var httpContext = Requests[i];
var path = httpContext.Request.Path.Value;
Span<PathSegment> segments = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
Span<PathSegment> segments = stackalloc PathSegment[SegmentCount];
var count = FastPathTokenizer.Tokenize(path, segments);
var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

View File

@ -7,8 +7,11 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{
public class MatcheFindCandidateSetSingleEntryBenchmark : MatcherBenchmarkBase
public class MatcherFindCandidateSetSingleEntryBenchmark : MatcherBenchmarkBase
{
// SegmentCount should be max-segments + 1
private const int SegmentCount = 2;
private TrivialMatcher _baseline;
private DfaMatcher _dfa;
@ -22,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Requests[0] = new DefaultHttpContext();
Requests[0].RequestServices = CreateServices();
Requests[0].Request.Path = "/plaintext";
_baseline = (TrivialMatcher)SetupMatcher(new TrivialMatcherBuilder());
_dfa = (DfaMatcher)SetupMatcher(CreateDfaMatcherBuilder());
}
@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
var httpContext = Requests[0];
var path = httpContext.Request.Path.Value;
Span<PathSegment> segments = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
Span<PathSegment> segments = stackalloc PathSegment[SegmentCount];
var count = FastPathTokenizer.Tokenize(path, segments);
var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

View File

@ -9,6 +9,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
public class MatcherFindCandidateSetSmallEntryCountBenchmark : MatcherBenchmarkBase
{
// SegmentCount should be max-segments + 1
private const int SegmentCount = 6;
private TrivialMatcher _baseline;
private DfaMatcher _dfa;
@ -87,7 +90,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var httpContext = Requests[0];
var path = httpContext.Request.Path.Value;
Span<PathSegment> segments = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
Span<PathSegment> segments = stackalloc PathSegment[SegmentCount];
var count = FastPathTokenizer.Tokenize(path, segments);
var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

View File

@ -13,11 +13,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
private readonly EndpointSelector _selector;
private readonly DfaState[] _states;
public DfaMatcher(EndpointSelector selector, DfaState[] states)
private readonly int _maxSegmentCount;
public DfaMatcher(EndpointSelector selector, DfaState[] states, int maxSegmentCount)
{
_selector = selector;
_states = states;
_maxSegmentCount = maxSegmentCount;
}
public sealed override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
@ -38,7 +40,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var path = httpContext.Request.Path.Value;
// First tokenize the path into series of segments.
Span<PathSegment> buffer = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
Span<PathSegment> buffer = stackalloc PathSegment[_maxSegmentCount];
var count = FastPathTokenizer.Tokenize(path, buffer);
var segments = buffer.Slice(0, count);

View File

@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// stage.
var work = new List<(MatcherEndpoint endpoint, List<DfaNode> parents)>();
var root = new DfaNode() { Depth = 0, Label = "/" };
var root = new DfaNode() { PathDepth = 0, Label = "/" };
// To prepare for this we need to compute the max depth, as well as
// a seed list of items to process (entry, root).
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
next = new DfaNode()
{
Depth = parent.Depth + 1,
PathDepth = parent.PathDepth + 1,
Label = parent.Label + literal + "/",
};
parent.Literals.Add(literal, next);
@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
parent.CatchAll = new DfaNode()
{
Depth = parent.Depth + 1,
PathDepth = parent.PathDepth + 1,
Label = parent.Label + "{*...}/",
};
@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
parent.Parameters = new DfaNode()
{
Depth = parent.Depth + 1,
PathDepth = parent.PathDepth + 1,
Label = parent.Label + "{...}/",
};
}
@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
parent.Parameters = new DfaNode()
{
Depth = parent.Depth + 1,
PathDepth = parent.PathDepth + 1,
Label = parent.Label + "{...}/",
};
}
@ -217,6 +217,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
var root = BuildDfaTree();
var maxSegmentCount = 0;
root.Visit((node) => maxSegmentCount = Math.Max(maxSegmentCount, node.PathDepth));
// The max segment count is the maximum path-node-depth +1. We need
// the +1 to capture any additional content after the 'last' segment.
maxSegmentCount++;
var states = new List<DfaState>();
var tableBuilders = new List<(JumpTableBuilder pathBuilder, PolicyJumpTableBuilder policyBuilder)>();
AddNode(root, states, tableBuilders);
@ -251,7 +258,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
tableBuilders[i].policyBuilder?.Build());
}
return new DfaMatcher(_selector, states.ToArray());
return new DfaMatcher(_selector, states.ToArray(), maxSegmentCount);
}
private int AddNode(

View File

@ -22,7 +22,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
// The depth of the node. The depth indicates the number of segments
// that must be processed to arrive at this node.
public int Depth { get; set; }
//
// This value is not computed for Policy nodes and will be set to -1.
public int PathDepth { get; set; } = -1;
// Just for diagnostics and debugging
public string Label { get; set; }
@ -71,7 +73,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var builder = new StringBuilder();
builder.Append(Label);
builder.Append(" d:");
builder.Append(Depth);
builder.Append(PathDepth);
builder.Append(" m:");
builder.Append(Matches.Count);
builder.Append(" c: ");

View File

@ -9,16 +9,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
// to PathTokenizer.
internal static class FastPathTokenizer
{
// The default limit for the number of segments we tokenize.
//
// Historically the limit on the number of segments routing supports is 28.
// RoutePrecedence computes precedence based on a decimal, which supports 28
// or 29 digits.
//
// So setting this limit to 32 should work pretty well. We also expect the tokenizer
// to be used with stackalloc, so we want a small number.
public const int DefaultSegmentCount = 32;
// This section tokenizes the path by marking the sequence of slashes, and their
// and the length of the text between them.
//