[Perf] Reduce allocations in Link generation code paths

This commit is contained in:
mnltejaswini 2016-02-24 17:25:32 -08:00
parent a80a63271f
commit 1c9a54aeb8
4 changed files with 25 additions and 9 deletions

View File

@ -22,10 +22,16 @@ namespace Microsoft.AspNetCore.Routing.Internal
public IList<LinkGenerationMatch> GetMatches(VirtualPathContext context) public IList<LinkGenerationMatch> GetMatches(VirtualPathContext context)
{ {
var results = new List<LinkGenerationMatch>(); // Perf: Avoid allocation for List if there aren't any Matches or Criteria
Walk(results, context, _root, isFallbackPath: false); if (_root.Matches.Count > 0 || _root.Criteria.Count > 0)
results.Sort(LinkGenerationMatchComparer.Instance); {
return results; var results = new List<LinkGenerationMatch>();
Walk(results, context, _root, isFallbackPath: false);
results.Sort(LinkGenerationMatchComparer.Instance);
return results;
}
return null;
} }
// We need to recursively walk the decision tree based on the provided route data // We need to recursively walk the decision tree based on the provided route data

View File

@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(logger)); throw new ArgumentNullException(nameof(logger));
} }
if (constraints == null) if (constraints == null || constraints.Count == 0)
{ {
return true; return true;
} }

View File

@ -171,7 +171,8 @@ namespace Microsoft.AspNetCore.Routing.Template
// Add any ambient values that don't match parameters - they need to be visible to constraints // Add any ambient values that don't match parameters - they need to be visible to constraints
// but they will ignored by link generation. // but they will ignored by link generation.
var combinedValues = new RouteValueDictionary(context.AcceptedValues); // Perf: Lazily allocate RouteValueDictionary only when needed as in most cases combined is same as accepted values
RouteValueDictionary combinedValues = null;
if (ambientValues != null) if (ambientValues != null)
{ {
foreach (var kvp in ambientValues) foreach (var kvp in ambientValues)
@ -181,6 +182,10 @@ namespace Microsoft.AspNetCore.Routing.Template
var parameter = GetParameter(kvp.Key); var parameter = GetParameter(kvp.Key);
if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key)) if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key))
{ {
if (combinedValues == null)
{
combinedValues = new RouteValueDictionary(context.AcceptedValues);
}
combinedValues.Add(kvp.Key, kvp.Value); combinedValues.Add(kvp.Key, kvp.Value);
} }
} }
@ -190,7 +195,7 @@ namespace Microsoft.AspNetCore.Routing.Template
return new TemplateValuesResult() return new TemplateValuesResult()
{ {
AcceptedValues = context.AcceptedValues, AcceptedValues = context.AcceptedValues,
CombinedValues = combinedValues, CombinedValues = combinedValues ?? context.AcceptedValues
}; };
} }

View File

@ -138,9 +138,14 @@ namespace Microsoft.AspNetCore.Routing.Tree
// order. We just need to iterate them and use the first one that can generate a link. // order. We just need to iterate them and use the first one that can generate a link.
var matches = _linkGenerationTree.GetMatches(context); var matches = _linkGenerationTree.GetMatches(context);
foreach (var match in matches) if (matches == null)
{ {
var path = GenerateVirtualPath(context, match.Entry); return null;
}
for (var i = 0; i < matches.Count; i++)
{
var path = GenerateVirtualPath(context, matches[i].Entry);
if (path != null) if (path != null)
{ {
return path; return path;