From ec258135c3402d8178f45ccd3db538c9e954e391 Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Wed, 9 Oct 2024 10:32:49 +0200 Subject: [PATCH 1/2] attempt to fix performance issues with a cache --- src/GitVersion.Core/Core/RepositoryStore.cs | 2 +- .../Git/BranchCollection.cs | 13 +++++++----- .../Git/CommitCollection.cs | 17 +++++++++++++--- .../Git/RefSpecCollection.cs | 9 ++++++--- .../Git/ReferenceCollection.cs | 16 +++++++++++---- .../Git/RemoteCollection.cs | 20 ++++++++++++++----- .../Git/TagCollection.cs | 9 ++++++--- 7 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/GitVersion.Core/Core/RepositoryStore.cs b/src/GitVersion.Core/Core/RepositoryStore.cs index d0fe0d9151..aaa1856c15 100644 --- a/src/GitVersion.Core/Core/RepositoryStore.cs +++ b/src/GitVersion.Core/Core/RepositoryStore.cs @@ -219,7 +219,7 @@ public IReadOnlyList GetCommitLog(ICommit? baseVersionSource, ICommit c SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time }; - var commits = this.repository.Commits.QueryBy(filter).ToArray(); + var commits = this.repository.Commits.QueryBy(filter); return ignore.Filter(commits).ToList(); } diff --git a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs index 447ca4fbe8..fe0da131c0 100644 --- a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs @@ -6,12 +6,16 @@ namespace GitVersion.Git; internal sealed class BranchCollection : IBranchCollection { private readonly LibGit2Sharp.BranchCollection innerCollection; + private readonly Lazy> branches; internal BranchCollection(LibGit2Sharp.BranchCollection collection) - => this.innerCollection = collection.NotNull(); + { + this.innerCollection = collection.NotNull(); + this.branches = new Lazy>(() => this.innerCollection.Select(branch => new Branch(branch)).ToArray()); + } public IEnumerator GetEnumerator() - => this.innerCollection.Select(branch => new Branch(branch)).GetEnumerator(); + => this.branches.Value.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -27,12 +31,11 @@ public IBranch? this[string name] public IEnumerable ExcludeBranches(IEnumerable branchesToExclude) { - branchesToExclude = branchesToExclude.NotNull(); + var toExclude = branchesToExclude as IBranch[] ?? branchesToExclude.ToArray(); return this.Where(BranchIsNotExcluded); - bool BranchIsNotExcluded(IBranch branch) - => branchesToExclude.All(branchToExclude => !branch.Equals(branchToExclude)); + bool BranchIsNotExcluded(IBranch branch) => toExclude.All(branchToExclude => !branch.Equals(branchToExclude)); } public void UpdateTrackedBranch(IBranch branch, string remoteTrackingReferenceName) diff --git a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs index e6dcee288c..9bc0c89227 100644 --- a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs @@ -6,11 +6,16 @@ namespace GitVersion.Git; internal sealed class CommitCollection : ICommitCollection { private readonly ICommitLog innerCollection; + private readonly Lazy> commits; - internal CommitCollection(ICommitLog collection) => this.innerCollection = collection.NotNull(); + internal CommitCollection(ICommitLog collection) + { + this.innerCollection = collection.NotNull(); + this.commits = new Lazy>(() => this.innerCollection.Select(commit => new Commit(commit)).ToArray()); + } public IEnumerator GetEnumerator() - => this.innerCollection.Select(commit => new Commit(commit)).GetEnumerator(); + => this.commits.Value.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -21,7 +26,13 @@ public IEnumerable QueryBy(CommitFilter commitFilter) { var includeReachableFrom = GetReacheableFrom(commitFilter.IncludeReachableFrom); var excludeReachableFrom = GetReacheableFrom(commitFilter.ExcludeReachableFrom); - var filter = new LibGit2Sharp.CommitFilter { IncludeReachableFrom = includeReachableFrom, ExcludeReachableFrom = excludeReachableFrom, FirstParentOnly = commitFilter.FirstParentOnly, SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy }; + var filter = new LibGit2Sharp.CommitFilter + { + IncludeReachableFrom = includeReachableFrom, + ExcludeReachableFrom = excludeReachableFrom, + FirstParentOnly = commitFilter.FirstParentOnly, + SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy + }; var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter); return new CommitCollection(commitLog); diff --git a/src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs b/src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs index a465fcbd5d..3d1ef7d004 100644 --- a/src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs @@ -4,11 +4,14 @@ namespace GitVersion.Git; internal sealed class RefSpecCollection : IRefSpecCollection { - private readonly LibGit2Sharp.RefSpecCollection innerCollection; + private readonly Lazy> refSpecs; internal RefSpecCollection(LibGit2Sharp.RefSpecCollection collection) - => this.innerCollection = collection.NotNull(); + { + collection = collection.NotNull(); + this.refSpecs = new Lazy>(() => collection.Select(tag => new RefSpec(tag)).ToArray()); + } - public IEnumerator GetEnumerator() => this.innerCollection.Select(tag => new RefSpec(tag)).GetEnumerator(); + public IEnumerator GetEnumerator() => this.refSpecs.Value.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } diff --git a/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs b/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs index 1159dfe87a..a230af724c 100644 --- a/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs @@ -5,15 +5,23 @@ namespace GitVersion.Git; internal sealed class ReferenceCollection : IReferenceCollection { private readonly LibGit2Sharp.ReferenceCollection innerCollection; + private IReadOnlyCollection? references; - internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection) - => this.innerCollection = collection.NotNull(); + internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection) => this.innerCollection = collection.NotNull(); - public IEnumerator GetEnumerator() => this.innerCollection.Select(reference => new Reference(reference)).GetEnumerator(); + public IEnumerator GetEnumerator() + { + this.references ??= this.innerCollection.Select(reference => new Reference(reference)).ToArray(); + return this.references.GetEnumerator(); + } public void Add(string name, string canonicalRefNameOrObject, bool allowOverwrite = false) => this.innerCollection.Add(name, canonicalRefNameOrObject, allowOverwrite); - public void UpdateTarget(IReference directRef, IObjectId targetId) => RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId)); + public void UpdateTarget(IReference directRef, IObjectId targetId) + { + RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId)); + this.references = null; + } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs b/src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs index 5fc8433621..9ecea312db 100644 --- a/src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs @@ -5,12 +5,15 @@ namespace GitVersion.Git; internal sealed class RemoteCollection : IRemoteCollection { private readonly LibGit2Sharp.RemoteCollection innerCollection; + private IReadOnlyCollection? remotes; - internal RemoteCollection(LibGit2Sharp.RemoteCollection collection) - => this.innerCollection = collection.NotNull(); + internal RemoteCollection(LibGit2Sharp.RemoteCollection collection) => this.innerCollection = collection.NotNull(); public IEnumerator GetEnumerator() - => this.innerCollection.Select(reference => new Remote(reference)).GetEnumerator(); + { + this.remotes ??= this.innerCollection.Select(reference => new Remote(reference)).ToArray(); + return this.remotes.GetEnumerator(); + } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -23,8 +26,15 @@ public IRemote? this[string name] } } - public void Remove(string remoteName) => this.innerCollection.Remove(remoteName); + public void Remove(string remoteName) + { + this.innerCollection.Remove(remoteName); + this.remotes = null; + } public void Update(string remoteName, string refSpec) - => this.innerCollection.Update(remoteName, r => r.FetchRefSpecs.Add(refSpec)); + { + this.innerCollection.Update(remoteName, r => r.FetchRefSpecs.Add(refSpec)); + this.remotes = null; + } } diff --git a/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs b/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs index 65f5637cda..a5ad79d237 100644 --- a/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs @@ -4,13 +4,16 @@ namespace GitVersion.Git; internal sealed class TagCollection : ITagCollection { - private readonly LibGit2Sharp.TagCollection innerCollection; + private readonly Lazy> tags; internal TagCollection(LibGit2Sharp.TagCollection collection) - => this.innerCollection = collection.NotNull(); + { + collection = collection.NotNull(); + this.tags = new Lazy>(() => collection.Select(tag => new Tag(tag)).ToArray()); + } public IEnumerator GetEnumerator() - => this.innerCollection.Select(tag => new Tag(tag)).GetEnumerator(); + => this.tags.Value.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } From 1200ae1ba4f20f30f0fe961b0c856e95da93266e Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Tue, 15 Oct 2024 10:53:57 +0200 Subject: [PATCH 2/2] code cleanup --- .../IgnoreConfigurationExtensions.cs | 16 ++++---------- src/GitVersion.Core/Core/RepositoryStore.cs | 21 ++++++++++--------- .../Core/TaggedSemanticVersionRepository.cs | 6 +++--- .../MainlineVersionStrategy.cs | 2 +- .../MergeMessageVersionStrategy.cs | 2 +- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs b/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs index d99c33db76..eeaf3a0ded 100644 --- a/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs +++ b/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs @@ -5,28 +5,20 @@ namespace GitVersion.Configuration; internal static class IgnoreConfigurationExtensions { - public static IEnumerable Filter(this IIgnoreConfiguration ignore, IEnumerable source) + public static IEnumerable Filter(this IIgnoreConfiguration ignore, ITag[] source) { ignore.NotNull(); source.NotNull(); - if (!ignore.IsEmpty) - { - return source.Where(element => ShouldBeIgnored(element.Commit, ignore)); - } - return source; + return !ignore.IsEmpty ? source.Where(element => ShouldBeIgnored(element.Commit, ignore)) : source; } - public static IEnumerable Filter(this IIgnoreConfiguration ignore, IEnumerable source) + public static IEnumerable Filter(this IIgnoreConfiguration ignore, ICommit[] source) { ignore.NotNull(); source.NotNull(); - if (!ignore.IsEmpty) - { - return source.Where(element => ShouldBeIgnored(element, ignore)); - } - return source; + return !ignore.IsEmpty ? source.Where(element => ShouldBeIgnored(element, ignore)) : source; } private static bool ShouldBeIgnored(ICommit commit, IIgnoreConfiguration ignore) diff --git a/src/GitVersion.Core/Core/RepositoryStore.cs b/src/GitVersion.Core/Core/RepositoryStore.cs index aaa1856c15..bc8554f32e 100644 --- a/src/GitVersion.Core/Core/RepositoryStore.cs +++ b/src/GitVersion.Core/Core/RepositoryStore.cs @@ -60,7 +60,7 @@ internal class RepositoryStore(ILog log, IGitRepository repository) : IRepositor this.log.Info("Using latest commit on specified branch"); } - commits = ignore.Filter(commits); + commits = ignore.Filter(commits.ToArray()); return commits.FirstOrDefault(); } @@ -219,8 +219,7 @@ public IReadOnlyList GetCommitLog(ICommit? baseVersionSource, ICommit c SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time }; - var commits = this.repository.Commits.QueryBy(filter); - + var commits = FilterCommits(filter).ToArray(); return ignore.Filter(commits).ToList(); } @@ -232,16 +231,16 @@ public IReadOnlyList GetCommitsReacheableFromHead(ICommit? headCommit, SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse }; - var commits = this.repository.Commits.QueryBy(filter); + var commits = FilterCommits(filter).ToArray(); return ignore.Filter(commits).ToList(); } public IReadOnlyList GetCommitsReacheableFrom(IGitObject commit, IBranch branch) { var filter = new CommitFilter { IncludeReachableFrom = branch }; - var commitCollection = this.repository.Commits.QueryBy(filter); - return commitCollection.Where(c => c.Sha == commit.Sha).ToList(); + var commits = FilterCommits(filter); + return commits.Where(c => c.Sha == commit.Sha).ToList(); } public ICommit? GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMergeBase) @@ -251,18 +250,20 @@ public IReadOnlyList GetCommitsReacheableFrom(IGitObject commit, IBranc IncludeReachableFrom = commitToFindCommonBase, ExcludeReachableFrom = findMergeBase }; - var commitCollection = this.repository.Commits.QueryBy(filter); - return commitCollection.FirstOrDefault(c => c.Parents.Contains(findMergeBase)); + var commits = FilterCommits(filter); + return commits.FirstOrDefault(c => c.Parents.Contains(findMergeBase)); } public bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit) { var filter = new CommitFilter { IncludeReachableFrom = branch, ExcludeReachableFrom = baseVersionSource, FirstParentOnly = true }; - var commitCollection = this.repository.Commits.QueryBy(filter); - return commitCollection.Contains(firstMatchingCommit); + var commits = FilterCommits(filter); + return commits.Contains(firstMatchingCommit); } + private IEnumerable FilterCommits(CommitFilter filter) => this.repository.Commits.QueryBy(filter); + public ICommit? FindMergeBase(ICommit commit, ICommit mainlineTip) => this.repository.FindMergeBase(commit, mainlineTip); private IBranch? FindBranch(string branchName) => this.repository.Branches.FirstOrDefault(x => x.Name.EquivalentTo(branchName)); diff --git a/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs b/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs index 24649b9687..f6f0de0459 100644 --- a/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs +++ b/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs @@ -49,7 +49,7 @@ IEnumerable GetElements() { var semanticVersions = GetTaggedSemanticVersions(tagPrefix, format, ignore); - foreach (var commit in ignore.Filter(branch.Commits)) + foreach (var commit in ignore.Filter(branch.Commits.ToArray())) { foreach (var semanticVersion in semanticVersions[commit]) { @@ -88,7 +88,7 @@ public ILookup GetTaggedSemanticVersionsOfMerge using (this.log.IndentLog($"Getting tagged semantic versions by track merge target '{branch.Name.Canonical}'. " + $"TagPrefix: {tagPrefix} and Format: {format}")) { - var shaHashSet = new HashSet(ignore.Filter(branch.Commits).Select(element => element.Id.Sha)); + var shaHashSet = new HashSet(ignore.Filter(branch.Commits.ToArray()).Select(element => element.Id.Sha)); foreach (var semanticVersion in GetTaggedSemanticVersions(tagPrefix, format, ignore).SelectMany(v => v)) { @@ -124,7 +124,7 @@ IEnumerable GetElements() { this.log.Info($"Getting tagged semantic versions. TagPrefix: {tagPrefix} and Format: {format}"); - foreach (var tag in ignore.Filter(this.repositoryStore.Tags)) + foreach (var tag in ignore.Filter(this.repositoryStore.Tags.ToArray())) { if (SemanticVersion.TryParse(tag.Name.Friendly, tagPrefix, out var semanticVersion, format)) { diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MainlineVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MainlineVersionStrategy.cs index 2dd181c896..1e0dd74209 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MainlineVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MainlineVersionStrategy.cs @@ -82,7 +82,7 @@ public IEnumerable GetBaseVersions(EffectiveBranchConfiguration con configuration: branchConfiguration ); - var commitsInReverseOrder = Context.Configuration.Ignore.Filter(Context.CurrentBranchCommits); + var commitsInReverseOrder = Context.Configuration.Ignore.Filter(Context.CurrentBranchCommits.ToArray()); TaggedSemanticVersions taggedSemanticVersion = TaggedSemanticVersions.OfBranch; if (branchConfiguration.TrackMergeTarget == true) taggedSemanticVersion |= TaggedSemanticVersions.OfMergeTargets; diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs index 7dfe751dc3..2ffeaf3d9e 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs @@ -33,7 +33,7 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur || !configuration.Value.TrackMergeMessage) yield break; - foreach (var commit in configuration.Value.Ignore.Filter(Context.CurrentBranchCommits)) + foreach (var commit in configuration.Value.Ignore.Filter(Context.CurrentBranchCommits.ToArray())) { if (MergeMessage.TryParse(commit, Context.Configuration, out var mergeMessage) && mergeMessage.Version is not null