diff --git a/src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs b/src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs index 23d9c14397a..2b79814029e 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs @@ -360,6 +360,8 @@ private static List BucketConsumedItems( buckets.Insert(~matchingBucketIndex, matchingBucket); } + matchingBucket.Lookup.EnsureCapacity(items.Count); + // We already have a bucket for this type of item, so add this item to // the bucket. matchingBucket.AddItem(item); diff --git a/src/Build/BackEnd/Components/RequestBuilder/Lookup.cs b/src/Build/BackEnd/Components/RequestBuilder/Lookup.cs index 8a275483719..7448add2d57 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/Lookup.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/Lookup.cs @@ -376,7 +376,7 @@ private void MergeScopeIntoLastScope() // adds to the world if (PrimaryAddTable != null) { - SecondaryTable ??= new ItemDictionary(); + SecondaryTable ??= new ItemDictionary(PrimaryAddTable.ItemTypesCount); SecondaryTable.ImportItems(PrimaryAddTable); } @@ -706,6 +706,24 @@ internal void AddNewItemsOfItemType(string itemType, ICollection + /// Attempts to set the initial capacity of the primary add table. + /// + /// + internal void EnsureCapacity(int capacity) + { + if (PrimaryAddTable is null) + { + PrimaryAddTable = new ItemDictionary(capacity); + } +#if NET + else + { + PrimaryAddTable.EnsureCapacity(capacity); + } +#endif + } + /// /// Implements a true add, an item that has been created in a batch. /// @@ -812,7 +830,7 @@ internal void ModifyItems(string itemType, ICollection grou } } - #endregion +#endregion #region Private Methods diff --git a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs index a8ea306fb91..03b4ee3d7bd 100644 --- a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs +++ b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs @@ -1384,6 +1384,7 @@ private void GatherTaskItemOutputs(bool outputTargetIsItem, string outputTargetN { // Only count non-null elements. We sometimes have a single-element array where the element is null bool hasElements = false; + _batchBucket.Lookup.EnsureCapacity(outputs.Length); foreach (ITaskItem output in outputs) { @@ -1548,6 +1549,8 @@ private void GatherArrayStringAndValueOutputs(bool outputTargetIsItem, string ou { if (outputTargetIsItem) { + _batchBucket.Lookup.EnsureCapacity(outputs.Length); + // to store the outputs as items, use the string representations of the outputs as item-specs foreach (string output in outputs) { diff --git a/src/Build/Collections/ItemDictionary.cs b/src/Build/Collections/ItemDictionary.cs index 39834b4dafa..fbe1ca4cd82 100644 --- a/src/Build/Collections/ItemDictionary.cs +++ b/src/Build/Collections/ItemDictionary.cs @@ -82,7 +82,27 @@ public ItemDictionary(IEnumerable items) /// /// Number of items in total, for debugging purposes. /// - public int Count => _nodes.Count; + public int Count + { + get + { + lock (_itemLists) + { + return _nodes.Count; + } + } + } + + public int ItemTypesCount + { + get + { + lock (_itemLists) + { + return _itemLists.Count; + } + } + } /// /// Get the item types that have at least one item in this collection @@ -128,6 +148,16 @@ public ICollection this[string itemtype] } } +#if NET + public void EnsureCapacity(int desiredCapacity) + { + lock (_itemLists) + { + _itemLists.EnsureCapacity(desiredCapacity); + } + } +#endif + /// /// Empty the collection ///