Skip to content

Commit 4255a15

Browse files
authored
Merge pull request #4208 from david-driscoll/fix/slow-on-branch
attempt to fix performance issues with a cache
2 parents dad5d2c + 1200ae1 commit 4255a15

11 files changed

+81
-50
lines changed

src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs

+4-12
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,20 @@ namespace GitVersion.Configuration;
55

66
internal static class IgnoreConfigurationExtensions
77
{
8-
public static IEnumerable<ITag> Filter(this IIgnoreConfiguration ignore, IEnumerable<ITag> source)
8+
public static IEnumerable<ITag> Filter(this IIgnoreConfiguration ignore, ITag[] source)
99
{
1010
ignore.NotNull();
1111
source.NotNull();
1212

13-
if (!ignore.IsEmpty)
14-
{
15-
return source.Where(element => ShouldBeIgnored(element.Commit, ignore));
16-
}
17-
return source;
13+
return !ignore.IsEmpty ? source.Where(element => ShouldBeIgnored(element.Commit, ignore)) : source;
1814
}
1915

20-
public static IEnumerable<ICommit> Filter(this IIgnoreConfiguration ignore, IEnumerable<ICommit> source)
16+
public static IEnumerable<ICommit> Filter(this IIgnoreConfiguration ignore, ICommit[] source)
2117
{
2218
ignore.NotNull();
2319
source.NotNull();
2420

25-
if (!ignore.IsEmpty)
26-
{
27-
return source.Where(element => ShouldBeIgnored(element, ignore));
28-
}
29-
return source;
21+
return !ignore.IsEmpty ? source.Where(element => ShouldBeIgnored(element, ignore)) : source;
3022
}
3123

3224
private static bool ShouldBeIgnored(ICommit commit, IIgnoreConfiguration ignore)

src/GitVersion.Core/Core/RepositoryStore.cs

+11-10
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ internal class RepositoryStore(ILog log, IGitRepository repository) : IRepositor
6060
this.log.Info("Using latest commit on specified branch");
6161
}
6262

63-
commits = ignore.Filter(commits);
63+
commits = ignore.Filter(commits.ToArray());
6464
return commits.FirstOrDefault();
6565
}
6666

@@ -219,8 +219,7 @@ public IReadOnlyList<ICommit> GetCommitLog(ICommit? baseVersionSource, ICommit c
219219
SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time
220220
};
221221

222-
var commits = this.repository.Commits.QueryBy(filter).ToArray();
223-
222+
var commits = FilterCommits(filter).ToArray();
224223
return ignore.Filter(commits).ToList();
225224
}
226225

@@ -232,16 +231,16 @@ public IReadOnlyList<ICommit> GetCommitsReacheableFromHead(ICommit? headCommit,
232231
SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse
233232
};
234233

235-
var commits = this.repository.Commits.QueryBy(filter);
234+
var commits = FilterCommits(filter).ToArray();
236235
return ignore.Filter(commits).ToList();
237236
}
238237

239238
public IReadOnlyList<ICommit> GetCommitsReacheableFrom(IGitObject commit, IBranch branch)
240239
{
241240
var filter = new CommitFilter { IncludeReachableFrom = branch };
242-
var commitCollection = this.repository.Commits.QueryBy(filter);
243241

244-
return commitCollection.Where(c => c.Sha == commit.Sha).ToList();
242+
var commits = FilterCommits(filter);
243+
return commits.Where(c => c.Sha == commit.Sha).ToList();
245244
}
246245

247246
public ICommit? GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMergeBase)
@@ -251,18 +250,20 @@ public IReadOnlyList<ICommit> GetCommitsReacheableFrom(IGitObject commit, IBranc
251250
IncludeReachableFrom = commitToFindCommonBase,
252251
ExcludeReachableFrom = findMergeBase
253252
};
254-
var commitCollection = this.repository.Commits.QueryBy(filter);
255253

256-
return commitCollection.FirstOrDefault(c => c.Parents.Contains(findMergeBase));
254+
var commits = FilterCommits(filter);
255+
return commits.FirstOrDefault(c => c.Parents.Contains(findMergeBase));
257256
}
258257

259258
public bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit)
260259
{
261260
var filter = new CommitFilter { IncludeReachableFrom = branch, ExcludeReachableFrom = baseVersionSource, FirstParentOnly = true };
262-
var commitCollection = this.repository.Commits.QueryBy(filter);
263-
return commitCollection.Contains(firstMatchingCommit);
261+
var commits = FilterCommits(filter);
262+
return commits.Contains(firstMatchingCommit);
264263
}
265264

265+
private IEnumerable<ICommit> FilterCommits(CommitFilter filter) => this.repository.Commits.QueryBy(filter);
266+
266267
public ICommit? FindMergeBase(ICommit commit, ICommit mainlineTip) => this.repository.FindMergeBase(commit, mainlineTip);
267268

268269
private IBranch? FindBranch(string branchName) => this.repository.Branches.FirstOrDefault(x => x.Name.EquivalentTo(branchName));

src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ IEnumerable<SemanticVersionWithTag> GetElements()
4949
{
5050
var semanticVersions = GetTaggedSemanticVersions(tagPrefix, format, ignore);
5151

52-
foreach (var commit in ignore.Filter(branch.Commits))
52+
foreach (var commit in ignore.Filter(branch.Commits.ToArray()))
5353
{
5454
foreach (var semanticVersion in semanticVersions[commit])
5555
{
@@ -88,7 +88,7 @@ public ILookup<ICommit, SemanticVersionWithTag> GetTaggedSemanticVersionsOfMerge
8888
using (this.log.IndentLog($"Getting tagged semantic versions by track merge target '{branch.Name.Canonical}'. " +
8989
$"TagPrefix: {tagPrefix} and Format: {format}"))
9090
{
91-
var shaHashSet = new HashSet<string>(ignore.Filter(branch.Commits).Select(element => element.Id.Sha));
91+
var shaHashSet = new HashSet<string>(ignore.Filter(branch.Commits.ToArray()).Select(element => element.Id.Sha));
9292

9393
foreach (var semanticVersion in GetTaggedSemanticVersions(tagPrefix, format, ignore).SelectMany(v => v))
9494
{
@@ -124,7 +124,7 @@ IEnumerable<SemanticVersionWithTag> GetElements()
124124
{
125125
this.log.Info($"Getting tagged semantic versions. TagPrefix: {tagPrefix} and Format: {format}");
126126

127-
foreach (var tag in ignore.Filter(this.repositoryStore.Tags))
127+
foreach (var tag in ignore.Filter(this.repositoryStore.Tags.ToArray()))
128128
{
129129
if (SemanticVersion.TryParse(tag.Name.Friendly, tagPrefix, out var semanticVersion, format))
130130
{

src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MainlineVersionStrategy.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public IEnumerable<BaseVersion> GetBaseVersions(EffectiveBranchConfiguration con
8282
configuration: branchConfiguration
8383
);
8484

85-
var commitsInReverseOrder = Context.Configuration.Ignore.Filter(Context.CurrentBranchCommits);
85+
var commitsInReverseOrder = Context.Configuration.Ignore.Filter(Context.CurrentBranchCommits.ToArray());
8686

8787
TaggedSemanticVersions taggedSemanticVersion = TaggedSemanticVersions.OfBranch;
8888
if (branchConfiguration.TrackMergeTarget == true) taggedSemanticVersion |= TaggedSemanticVersions.OfMergeTargets;

src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private IEnumerable<BaseVersion> GetBaseVersionsInternal(EffectiveBranchConfigur
3333
|| !configuration.Value.TrackMergeMessage)
3434
yield break;
3535

36-
foreach (var commit in configuration.Value.Ignore.Filter(Context.CurrentBranchCommits))
36+
foreach (var commit in configuration.Value.Ignore.Filter(Context.CurrentBranchCommits.ToArray()))
3737
{
3838
if (MergeMessage.TryParse(commit, Context.Configuration, out var mergeMessage)
3939
&& mergeMessage.Version is not null

src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ namespace GitVersion.Git;
66
internal sealed class BranchCollection : IBranchCollection
77
{
88
private readonly LibGit2Sharp.BranchCollection innerCollection;
9+
private readonly Lazy<IReadOnlyCollection<IBranch>> branches;
910

1011
internal BranchCollection(LibGit2Sharp.BranchCollection collection)
11-
=> this.innerCollection = collection.NotNull();
12+
{
13+
this.innerCollection = collection.NotNull();
14+
this.branches = new Lazy<IReadOnlyCollection<IBranch>>(() => this.innerCollection.Select(branch => new Branch(branch)).ToArray());
15+
}
1216

1317
public IEnumerator<IBranch> GetEnumerator()
14-
=> this.innerCollection.Select(branch => new Branch(branch)).GetEnumerator();
18+
=> this.branches.Value.GetEnumerator();
1519

1620
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1721

@@ -27,12 +31,11 @@ public IBranch? this[string name]
2731

2832
public IEnumerable<IBranch> ExcludeBranches(IEnumerable<IBranch> branchesToExclude)
2933
{
30-
branchesToExclude = branchesToExclude.NotNull();
34+
var toExclude = branchesToExclude as IBranch[] ?? branchesToExclude.ToArray();
3135

3236
return this.Where(BranchIsNotExcluded);
3337

34-
bool BranchIsNotExcluded(IBranch branch)
35-
=> branchesToExclude.All(branchToExclude => !branch.Equals(branchToExclude));
38+
bool BranchIsNotExcluded(IBranch branch) => toExclude.All(branchToExclude => !branch.Equals(branchToExclude));
3639
}
3740

3841
public void UpdateTrackedBranch(IBranch branch, string remoteTrackingReferenceName)

src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ namespace GitVersion.Git;
66
internal sealed class CommitCollection : ICommitCollection
77
{
88
private readonly ICommitLog innerCollection;
9+
private readonly Lazy<IReadOnlyCollection<ICommit>> commits;
910

10-
internal CommitCollection(ICommitLog collection) => this.innerCollection = collection.NotNull();
11+
internal CommitCollection(ICommitLog collection)
12+
{
13+
this.innerCollection = collection.NotNull();
14+
this.commits = new Lazy<IReadOnlyCollection<ICommit>>(() => this.innerCollection.Select(commit => new Commit(commit)).ToArray());
15+
}
1116

1217
public IEnumerator<ICommit> GetEnumerator()
13-
=> this.innerCollection.Select(commit => new Commit(commit)).GetEnumerator();
18+
=> this.commits.Value.GetEnumerator();
1419

1520
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1621

@@ -21,7 +26,13 @@ public IEnumerable<ICommit> QueryBy(CommitFilter commitFilter)
2126
{
2227
var includeReachableFrom = GetReacheableFrom(commitFilter.IncludeReachableFrom);
2328
var excludeReachableFrom = GetReacheableFrom(commitFilter.ExcludeReachableFrom);
24-
var filter = new LibGit2Sharp.CommitFilter { IncludeReachableFrom = includeReachableFrom, ExcludeReachableFrom = excludeReachableFrom, FirstParentOnly = commitFilter.FirstParentOnly, SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy };
29+
var filter = new LibGit2Sharp.CommitFilter
30+
{
31+
IncludeReachableFrom = includeReachableFrom,
32+
ExcludeReachableFrom = excludeReachableFrom,
33+
FirstParentOnly = commitFilter.FirstParentOnly,
34+
SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy
35+
};
2536
var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter);
2637
return new CommitCollection(commitLog);
2738

src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ namespace GitVersion.Git;
44

55
internal sealed class RefSpecCollection : IRefSpecCollection
66
{
7-
private readonly LibGit2Sharp.RefSpecCollection innerCollection;
7+
private readonly Lazy<IReadOnlyCollection<IRefSpec>> refSpecs;
88

99
internal RefSpecCollection(LibGit2Sharp.RefSpecCollection collection)
10-
=> this.innerCollection = collection.NotNull();
10+
{
11+
collection = collection.NotNull();
12+
this.refSpecs = new Lazy<IReadOnlyCollection<IRefSpec>>(() => collection.Select(tag => new RefSpec(tag)).ToArray());
13+
}
1114

12-
public IEnumerator<IRefSpec> GetEnumerator() => this.innerCollection.Select(tag => new RefSpec(tag)).GetEnumerator();
15+
public IEnumerator<IRefSpec> GetEnumerator() => this.refSpecs.Value.GetEnumerator();
1316
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1417
}

src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,23 @@ namespace GitVersion.Git;
55
internal sealed class ReferenceCollection : IReferenceCollection
66
{
77
private readonly LibGit2Sharp.ReferenceCollection innerCollection;
8+
private IReadOnlyCollection<IReference>? references;
89

9-
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection)
10-
=> this.innerCollection = collection.NotNull();
10+
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection) => this.innerCollection = collection.NotNull();
1111

12-
public IEnumerator<IReference> GetEnumerator() => this.innerCollection.Select(reference => new Reference(reference)).GetEnumerator();
12+
public IEnumerator<IReference> GetEnumerator()
13+
{
14+
this.references ??= this.innerCollection.Select(reference => new Reference(reference)).ToArray();
15+
return this.references.GetEnumerator();
16+
}
1317

1418
public void Add(string name, string canonicalRefNameOrObject, bool allowOverwrite = false) => this.innerCollection.Add(name, canonicalRefNameOrObject, allowOverwrite);
1519

16-
public void UpdateTarget(IReference directRef, IObjectId targetId) => RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId));
20+
public void UpdateTarget(IReference directRef, IObjectId targetId)
21+
{
22+
RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId));
23+
this.references = null;
24+
}
1725

1826
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1927

src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs

+15-5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ namespace GitVersion.Git;
55
internal sealed class RemoteCollection : IRemoteCollection
66
{
77
private readonly LibGit2Sharp.RemoteCollection innerCollection;
8+
private IReadOnlyCollection<IRemote>? remotes;
89

9-
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection)
10-
=> this.innerCollection = collection.NotNull();
10+
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection) => this.innerCollection = collection.NotNull();
1111

1212
public IEnumerator<IRemote> GetEnumerator()
13-
=> this.innerCollection.Select(reference => new Remote(reference)).GetEnumerator();
13+
{
14+
this.remotes ??= this.innerCollection.Select(reference => new Remote(reference)).ToArray();
15+
return this.remotes.GetEnumerator();
16+
}
1417

1518
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1619

@@ -23,8 +26,15 @@ public IRemote? this[string name]
2326
}
2427
}
2528

26-
public void Remove(string remoteName) => this.innerCollection.Remove(remoteName);
29+
public void Remove(string remoteName)
30+
{
31+
this.innerCollection.Remove(remoteName);
32+
this.remotes = null;
33+
}
2734

2835
public void Update(string remoteName, string refSpec)
29-
=> this.innerCollection.Update(remoteName, r => r.FetchRefSpecs.Add(refSpec));
36+
{
37+
this.innerCollection.Update(remoteName, r => r.FetchRefSpecs.Add(refSpec));
38+
this.remotes = null;
39+
}
3040
}

src/GitVersion.LibGit2Sharp/Git/TagCollection.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ namespace GitVersion.Git;
44

55
internal sealed class TagCollection : ITagCollection
66
{
7-
private readonly LibGit2Sharp.TagCollection innerCollection;
7+
private readonly Lazy<IReadOnlyCollection<ITag>> tags;
88

99
internal TagCollection(LibGit2Sharp.TagCollection collection)
10-
=> this.innerCollection = collection.NotNull();
10+
{
11+
collection = collection.NotNull();
12+
this.tags = new Lazy<IReadOnlyCollection<ITag>>(() => collection.Select(tag => new Tag(tag)).ToArray());
13+
}
1114

1215
public IEnumerator<ITag> GetEnumerator()
13-
=> this.innerCollection.Select(tag => new Tag(tag)).GetEnumerator();
16+
=> this.tags.Value.GetEnumerator();
1417

1518
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1619
}

0 commit comments

Comments
 (0)