Minor matcher builder allocation optimization (#771)

This commit is contained in:
James Newton-King 2018-09-06 13:47:34 +12:00 committed by GitHub
parent dbebdbecd6
commit 1c74973c6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 9 deletions

View File

@ -592,12 +592,23 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Start with the current node as the root. // Start with the current node as the root.
var work = new List<DfaNode>() { node, }; var work = new List<DfaNode>() { node, };
List<DfaNode> previousWork = null;
for (var i = 0; i < _nodeBuilders.Length; i++) for (var i = 0; i < _nodeBuilders.Length; i++)
{ {
var nodeBuilder = _nodeBuilders[i]; var nodeBuilder = _nodeBuilders[i];
// Build a list of each // Build a list of each
var nextWork = new List<DfaNode>(); List<DfaNode> nextWork;
if (previousWork == null)
{
nextWork = new List<DfaNode>();
}
else
{
// Reuse previous collection for the next collection
previousWork.Clear();
nextWork = previousWork;
}
for (var j = 0; j < work.Count; j++) for (var j = 0; j < work.Count; j++)
{ {
@ -639,6 +650,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
parent.Matches?.Clear(); parent.Matches?.Clear();
} }
previousWork = work;
work = nextWork; work = nextWork;
} }
} }

View File

@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
for (var i = 0; i < endpoints.Count; i++) for (var i = 0; i < endpoints.Count; i++)
{ {
if (endpoints[i].Metadata.GetMetadata<IHttpMethodMetadata>()?.HttpMethods.Any() == true) if (endpoints[i].Metadata.GetMetadata<IHttpMethodMetadata>()?.HttpMethods.Count > 0)
{ {
return true; return true;
} }
@ -219,31 +219,41 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// <returns></returns> /// <returns></returns>
public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges) public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges)
{ {
var destinations = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); Dictionary<string, int> destinations = null;
var corsPreflightDestinations = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); Dictionary<string, int> corsPreflightDestinations = null;
for (var i = 0; i < edges.Count; i++) for (var i = 0; i < edges.Count; i++)
{ {
// We create this data, so it's safe to cast it. // We create this data, so it's safe to cast it.
var key = (EdgeKey)edges[i].State; var key = (EdgeKey)edges[i].State;
if (key.IsCorsPreflightRequest) if (key.IsCorsPreflightRequest)
{ {
if (corsPreflightDestinations == null)
{
corsPreflightDestinations = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
corsPreflightDestinations.Add(key.HttpMethod, edges[i].Destination); corsPreflightDestinations.Add(key.HttpMethod, edges[i].Destination);
} }
else else
{ {
if (destinations == null)
{
destinations = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
destinations.Add(key.HttpMethod, edges[i].Destination); destinations.Add(key.HttpMethod, edges[i].Destination);
} }
} }
int corsPreflightExitDestination = exitDestination; int corsPreflightExitDestination = exitDestination;
if (corsPreflightDestinations.TryGetValue(AnyMethod, out var matchesAnyVerb)) if (corsPreflightDestinations != null && corsPreflightDestinations.TryGetValue(AnyMethod, out var matchesAnyVerb))
{ {
// If we have endpoints that match any HTTP method, use that as the exit. // If we have endpoints that match any HTTP method, use that as the exit.
corsPreflightExitDestination = matchesAnyVerb; corsPreflightExitDestination = matchesAnyVerb;
corsPreflightDestinations.Remove(AnyMethod); corsPreflightDestinations.Remove(AnyMethod);
} }
if (destinations.TryGetValue(AnyMethod, out matchesAnyVerb)) if (destinations != null && destinations.TryGetValue(AnyMethod, out matchesAnyVerb))
{ {
// If we have endpoints that match any HTTP method, use that as the exit. // If we have endpoints that match any HTTP method, use that as the exit.
exitDestination = matchesAnyVerb; exitDestination = matchesAnyVerb;
@ -304,7 +314,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_corsPreflightExitDestination = corsPreflightExitDestination; _corsPreflightExitDestination = corsPreflightExitDestination;
_corsPreflightDestinations = corsPreflightDestinations; _corsPreflightDestinations = corsPreflightDestinations;
_supportsCorsPreflight = _corsPreflightDestinations.Count > 0; _supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0;
} }
public override int GetDestination(HttpContext httpContext) public override int GetDestination(HttpContext httpContext)
@ -318,12 +328,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
httpContext.Request.Headers.TryGetValue(AccessControlRequestMethod, out var accessControlRequestMethod) && httpContext.Request.Headers.TryGetValue(AccessControlRequestMethod, out var accessControlRequestMethod) &&
!StringValues.IsNullOrEmpty(accessControlRequestMethod)) !StringValues.IsNullOrEmpty(accessControlRequestMethod))
{ {
return _corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination) return _corsPreflightDestinations != null &&
_corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination)
? destination ? destination
: _corsPreflightExitDestination; : _corsPreflightExitDestination;
} }
return _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination; return _destinations != null &&
_destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination;
} }
} }