Skip to content

Commit fc28ffc

Browse files
authored
Use CopyOnWritePropertyDictionary.ImportProperties for batching (#8747)
Fixes #8673 Context High memory allocations in CopyOnWritePropertyDictionary ImmutableDictionary was reported by partners. Changes Made Use CopyOnWritePropertyDictionary.ImportProperties in obvious places as oppose to CopyOnWritePropertyDictionary.Set in loop. Testing Unit tests. Local. Perf measure. Notes
1 parent 9deb5b5 commit fc28ffc

File tree

3 files changed

+56
-50
lines changed

3 files changed

+56
-50
lines changed

src/Build/Instance/ProjectInstance.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,11 +2942,9 @@ private Dictionary<ProjectItem, ProjectItemInstance> CreateItemsSnapshot(ICollec
29422942
if (item.DirectMetadata != null)
29432943
{
29442944
directMetadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
2945-
foreach (ProjectMetadata directMetadatum in item.DirectMetadata)
2946-
{
2947-
ProjectMetadataInstance directMetadatumInstance = new ProjectMetadataInstance(directMetadatum);
2948-
directMetadata.Set(directMetadatumInstance);
2949-
}
2945+
2946+
IEnumerable<ProjectMetadataInstance> projectMetadataInstances = item.DirectMetadata.Select(directMetadatum => new ProjectMetadataInstance(directMetadatum));
2947+
directMetadata.ImportProperties(projectMetadataInstances);
29502948
}
29512949

29522950
// For externally constructed ProjectItem, fall back to the publicly available EvaluateInclude

src/Build/Instance/ProjectItemDefinitionInstance.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Diagnostics;
77
using System.Diagnostics.CodeAnalysis;
8+
using System.Linq;
89
using Microsoft.Build.BackEnd;
910
using Microsoft.Build.Collections;
1011
using Microsoft.Build.Construction;
@@ -58,11 +59,9 @@ internal ProjectItemDefinitionInstance(ProjectItemDefinition itemDefinition)
5859
if (itemDefinition.MetadataCount > 0)
5960
{
6061
_metadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
61-
}
6262

63-
foreach (ProjectMetadata originalMetadata in itemDefinition.Metadata)
64-
{
65-
_metadata.Set(new ProjectMetadataInstance(originalMetadata));
63+
IEnumerable<ProjectMetadataInstance> projectMetadataInstances = itemDefinition.Metadata.Select(originalMetadata => new ProjectMetadataInstance(originalMetadata));
64+
_metadata.ImportProperties(projectMetadataInstances);
6665
}
6766
}
6867

src/Build/Instance/ProjectItemInstance.cs

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,8 @@ internal ProjectItemInstance(ProjectInstance project, string itemType, string in
114114
if (directMetadata?.GetEnumerator().MoveNext() == true)
115115
{
116116
metadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
117-
foreach (KeyValuePair<string, string> metadatum in directMetadata)
118-
{
119-
metadata.Set(new ProjectMetadataInstance(metadatum.Key, metadatum.Value));
120-
}
117+
IEnumerable<ProjectMetadataInstance> directMetadataInstances = directMetadata.Select(metadatum => new ProjectMetadataInstance(metadatum.Key, metadatum.Value));
118+
metadata.ImportProperties(directMetadataInstances);
121119
}
122120

123121
CommonConstructor(project, itemType, includeEscaped, includeEscaped, metadata, null /* need to add item definition metadata */, definingFileEscaped);
@@ -587,11 +585,10 @@ void ITranslatable.Translate(ITranslator translator)
587585
internal static void SetMetadata(IEnumerable<KeyValuePair<string, string>> metadataList, IEnumerable<ProjectItemInstance> items)
588586
{
589587
// Set up a single dictionary that can be applied to all the items
590-
CopyOnWritePropertyDictionary<ProjectMetadataInstance> metadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
591-
foreach (KeyValuePair<string, string> metadatum in metadataList)
592-
{
593-
metadata.Set(new ProjectMetadataInstance(metadatum.Key, metadatum.Value));
594-
}
588+
CopyOnWritePropertyDictionary<ProjectMetadataInstance> metadata = new();
589+
590+
IEnumerable<ProjectMetadataInstance> projectMetadataInstances = metadataList.Select(metadatum => new ProjectMetadataInstance(metadatum.Key, metadatum.Value));
591+
metadata.ImportProperties(projectMetadataInstances);
595592

596593
foreach (ProjectItemInstance item in items)
597594
{
@@ -1096,40 +1093,45 @@ internal CopyOnWritePropertyDictionary<ProjectMetadataInstance> MetadataCollecti
10961093

10971094
CopyOnWritePropertyDictionary<ProjectMetadataInstance> allMetadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
10981095

1099-
// Next, any inherited item definitions. Front of the list is highest priority,
1100-
// so walk backwards.
1101-
for (int i = _itemDefinitions.Count - 1; i >= 0; i--)
1096+
allMetadata.ImportProperties(metaData());
1097+
1098+
return allMetadata;
1099+
1100+
IEnumerable<ProjectMetadataInstance> metaData()
11021101
{
1103-
foreach (ProjectMetadataInstance metadatum in _itemDefinitions[i].Metadata)
1102+
// Next, any inherited item definitions. Front of the list is highest priority,
1103+
// so walk backwards.
1104+
for (int i = _itemDefinitions.Count - 1; i >= 0; i--)
11041105
{
1105-
if (metadatum != null)
1106-
{
1107-
allMetadata.Set(metadatum);
1108-
}
1109-
else
1106+
foreach (ProjectMetadataInstance metadatum in _itemDefinitions[i].Metadata)
11101107
{
1111-
Debug.Fail($"metadatum from {_itemDefinitions[i]} is null, see https://github.com/dotnet/msbuild/issues/5267");
1108+
if (metadatum != null)
1109+
{
1110+
yield return metadatum;
1111+
}
1112+
else
1113+
{
1114+
Debug.Fail($"metadatum from {_itemDefinitions[i]} is null, see https://github.com/dotnet/msbuild/issues/5267");
1115+
}
11121116
}
11131117
}
1114-
}
11151118

1116-
// Finally any direct metadata win.
1117-
if (_directMetadata != null)
1118-
{
1119-
foreach (ProjectMetadataInstance metadatum in _directMetadata)
1119+
// Finally any direct metadata win.
1120+
if (_directMetadata != null)
11201121
{
1121-
if (metadatum != null)
1122+
foreach (ProjectMetadataInstance metadatum in _directMetadata)
11221123
{
1123-
allMetadata.Set(metadatum);
1124-
}
1125-
else
1126-
{
1127-
Debug.Fail("metadatum in _directMetadata is null, see https://github.com/dotnet/msbuild/issues/5267");
1124+
if (metadatum != null)
1125+
{
1126+
yield return metadatum;
1127+
}
1128+
else
1129+
{
1130+
Debug.Fail("metadatum in _directMetadata is null, see https://github.com/dotnet/msbuild/issues/5267");
1131+
}
11281132
}
11291133
}
11301134
}
1131-
1132-
return allMetadata;
11331135
}
11341136
}
11351137

@@ -1694,12 +1696,21 @@ internal void TranslateWithInterning(ITranslator translator, LookasideStringInte
16941696
if (translator.TranslateNullable(_directMetadata))
16951697
{
16961698
int count = translator.Reader.ReadInt32();
1697-
_directMetadata = (count == 0) ? null : new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
1698-
for (int i = 0; i < count; i++)
1699+
if (count > 0)
1700+
{
1701+
IEnumerable<ProjectMetadataInstance> metaData =
1702+
Enumerable.Range(0, count).Select(_ =>
1703+
{
1704+
int key = translator.Reader.ReadInt32();
1705+
int value = translator.Reader.ReadInt32();
1706+
return new ProjectMetadataInstance(interner.GetString(key), interner.GetString(value), allowItemSpecModifiers: true);
1707+
});
1708+
_directMetadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
1709+
_directMetadata.ImportProperties(metaData);
1710+
}
1711+
else
16991712
{
1700-
int key = translator.Reader.ReadInt32();
1701-
int value = translator.Reader.ReadInt32();
1702-
_directMetadata.Set(new ProjectMetadataInstance(interner.GetString(key), interner.GetString(value), allowItemSpecModifiers: true));
1713+
_directMetadata = null;
17031714
}
17041715
}
17051716
}
@@ -1962,10 +1973,8 @@ public void SetMetadata(IEnumerable<Pair<ProjectMetadataElement, string>> metada
19621973
{
19631974
// Set up a single dictionary that can be applied to all the items
19641975
CopyOnWritePropertyDictionary<ProjectMetadataInstance> metadata = new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
1965-
foreach (Pair<ProjectMetadataElement, string> metadatum in metadataList)
1966-
{
1967-
metadata.Set(new ProjectMetadataInstance(metadatum.Key.Name, metadatum.Value));
1968-
}
1976+
IEnumerable<ProjectMetadataInstance> projectMetadataInstances = metadataList.Select(metadatum => new ProjectMetadataInstance(metadatum.Key.Name, metadatum.Value));
1977+
metadata.ImportProperties(projectMetadataInstances);
19691978

19701979
foreach (ProjectItemInstance item in destinationItems)
19711980
{

0 commit comments

Comments
 (0)