in src/StructuredLogger/Search/Search.cs [55:135]
private bool Visit(BaseNode node, NodeQueryMatcher matcher, List<SearchResult> results, CancellationToken cancellationToken)
{
var isMatch = false;
var containsMatch = false;
if (cancellationToken.IsCancellationRequested)
{
return false;
}
if (resultCount < maxResults)
{
var result = matcher.IsMatch(node);
if (result != null)
{
isMatch = true;
lock (results)
{
results.Add(result);
resultCount++;
}
}
}
else if (!markResultsInTree)
{
// we save a lot of time if we don't have to visit the entire tree to mark results
// after we've found maximum allowed results
return false;
}
if (node is TreeNode treeNode && treeNode.HasChildren)
{
var children = treeNode.Children;
if (node is Project)
{
var tasks = new System.Threading.Tasks.Task<List<SearchResult>>[children.Count];
for (int i = 0; i < children.Count; i++)
{
var child = children[i];
var task = TPLTask.Run(() =>
{
var list = new List<SearchResult>();
Visit(child, matcher, list, cancellationToken);
return list;
});
tasks[i] = task;
}
TPLTask.WaitAll(tasks);
lock (results)
{
for (int i = 0; i < tasks.Length; i++)
{
var task = tasks[i];
var subList = task.Result;
results.AddRange(subList);
containsMatch |= subList.Count > 0;
}
}
}
else
{
for (int i = 0; i < children.Count; i++)
{
var child = children[i];
containsMatch |= Visit(child, matcher, results, cancellationToken);
}
}
}
// setting these flags on each node is expensive so do it only if the feature is enabled
if (markResultsInTree)
{
node.IsSearchResult = isMatch;
node.ContainsSearchResult = containsMatch;
}
return isMatch || containsMatch;
}