Skip to content

Commit 619226c

Browse files
author
Pascal van Buijtene
committed
Reduce memory usage by caching commits on their sha hash
1 parent b874c3f commit 619226c

File tree

8 files changed

+39
-20
lines changed

8 files changed

+39
-20
lines changed

src/GitVersion.LibGit2Sharp/Git/Branch.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ internal sealed class Branch : IBranch
1010

1111
private readonly LibGit2Sharp.Branch innerBranch;
1212

13-
internal Branch(LibGit2Sharp.Branch branch, LibGit2Sharp.Diff diff)
13+
internal Branch(LibGit2Sharp.Branch branch, LibGit2Sharp.Diff diff, CommitFactory commitFactory)
1414
{
1515
this.innerBranch = branch.NotNull();
1616
Name = new(branch.CanonicalName);
1717

1818
var commit = this.innerBranch.Tip;
19-
Tip = commit is null ? null : new Commit(commit, diff);
19+
Tip = commit is null ? null : commitFactory.GetOrCreate(commit, diff);
2020

2121
var commits = this.innerBranch.Commits;
22-
Commits = new CommitCollection(commits, diff);
22+
Commits = new CommitCollection(commits, diff, commitFactory);
2323
}
2424

2525
public ReferenceName Name { get; }

src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ internal sealed class BranchCollection : IBranchCollection
88
private readonly LibGit2Sharp.BranchCollection innerCollection;
99
private readonly Lazy<IReadOnlyCollection<IBranch>> branches;
1010
private readonly Diff diff;
11+
private readonly CommitFactory commitFactory;
1112

12-
internal BranchCollection(LibGit2Sharp.BranchCollection collection, Diff diff)
13+
internal BranchCollection(LibGit2Sharp.BranchCollection collection, Diff diff, CommitFactory commitFactory)
1314
{
1415
this.innerCollection = collection.NotNull();
15-
this.branches = new Lazy<IReadOnlyCollection<IBranch>>(() => [.. this.innerCollection.Select(branch => new Branch(branch, diff))]);
16+
this.branches = new Lazy<IReadOnlyCollection<IBranch>>(() => [.. this.innerCollection.Select(branch => new Branch(branch, diff, commitFactory))]);
1617
this.diff = diff.NotNull();
18+
this.commitFactory = commitFactory;
1719
}
1820

1921
public IEnumerator<IBranch> GetEnumerator()
@@ -27,7 +29,7 @@ public IBranch? this[string name]
2729
{
2830
name = name.NotNull();
2931
var branch = this.innerCollection[name];
30-
return branch is null ? null : new Branch(branch, this.diff);
32+
return branch is null ? null : new Branch(branch, this.diff, this.commitFactory);
3133
}
3234
}
3335

src/GitVersion.LibGit2Sharp/Git/Commit.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ internal sealed class Commit : GitObject, ICommit
1414
private readonly LibGit2Sharp.Commit innerCommit;
1515
private readonly LibGit2Sharp.Diff repoDiff;
1616

17-
internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff) : base(innerCommit)
17+
internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff, CommitFactory commitFactory) : base(innerCommit)
1818
{
1919
this.innerCommit = innerCommit.NotNull();
20-
this.parentsLazy = new(() => innerCommit.Parents.Select(parent => new Commit(parent, repoDiff)).ToList());
20+
this.parentsLazy = new(() => innerCommit.Parents.Select(parent => commitFactory.GetOrCreate(parent, repoDiff)).ToList());
2121
When = innerCommit.Committer.When;
2222
this.repoDiff = repoDiff;
2323
}

src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ internal sealed class CommitCollection : ICommitCollection
88
private readonly ICommitLog innerCollection;
99
private readonly Lazy<IReadOnlyCollection<ICommit>> commits;
1010
private readonly Diff diff;
11+
private readonly CommitFactory commitFactory;
1112

12-
internal CommitCollection(ICommitLog collection, Diff diff)
13+
internal CommitCollection(ICommitLog collection, Diff diff, CommitFactory commitFactory)
1314
{
1415
this.innerCollection = collection.NotNull();
15-
this.commits = new Lazy<IReadOnlyCollection<ICommit>>(() => [.. this.innerCollection.Select(commit => new Commit(commit, diff))]);
16+
this.commits = new Lazy<IReadOnlyCollection<ICommit>>(() => [.. this.innerCollection.Select(commit => commitFactory.GetOrCreate(commit, diff))]);
1617
this.diff = diff.NotNull();
18+
this.commitFactory = commitFactory;
1719
}
1820

1921
public IEnumerator<ICommit> GetEnumerator()
@@ -36,7 +38,7 @@ public IEnumerable<ICommit> QueryBy(CommitFilter commitFilter)
3638
SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy
3739
};
3840
var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter);
39-
return new CommitCollection(commitLog, this.diff);
41+
return new CommitCollection(commitLog, this.diff, this.commitFactory);
4042

4143
static object? GetReacheableFrom(object? item) =>
4244
item switch
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Concurrent;
2+
3+
namespace GitVersion.Git;
4+
5+
internal sealed class CommitFactory
6+
{
7+
private static readonly ConcurrentDictionary<string, Commit> _cachedCommits = new();
8+
9+
public Commit GetOrCreate(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff) =>
10+
_cachedCommits.GetOrAdd(innerCommit.Sha, new Commit(innerCommit, repoDiff, this));
11+
}

src/GitVersion.LibGit2Sharp/Git/GitRepository.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace GitVersion.Git;
77
internal sealed partial class GitRepository
88
{
99
private Lazy<IRepository>? repositoryLazy;
10+
private readonly CommitFactory commitFactory = new();
1011

1112
private IRepository RepositoryInstance
1213
{
@@ -16,16 +17,17 @@ private IRepository RepositoryInstance
1617
return lazy.Value;
1718
}
1819
}
20+
1921
public string Path => RepositoryInstance.Info.Path;
2022
public string WorkingDirectory => RepositoryInstance.Info.WorkingDirectory;
2123
public bool IsHeadDetached => RepositoryInstance.Info.IsHeadDetached;
2224
public bool IsShallow => RepositoryInstance.Info.IsShallow;
23-
public IBranch Head => new Branch(RepositoryInstance.Head, RepositoryInstance.Diff);
25+
public IBranch Head => new Branch(RepositoryInstance.Head, RepositoryInstance.Diff, this.commitFactory);
2426

25-
public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff);
27+
public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff, this.commitFactory);
2628
public IReferenceCollection Refs => new ReferenceCollection(RepositoryInstance.Refs);
27-
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff);
28-
public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff);
29+
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff, this.commitFactory);
30+
public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff, this.commitFactory);
2931
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes);
3032

3133
public void DiscoverRepository(string? gitDirectory)
@@ -48,7 +50,7 @@ public void DiscoverRepository(string? gitDirectory)
4850
var first = (Commit)commit;
4951
var second = (Commit)otherCommit;
5052
var mergeBase = RepositoryInstance.ObjectDatabase.FindMergeBase(first, second);
51-
return mergeBase == null ? null : new Commit(mergeBase, RepositoryInstance.Diff);
53+
return mergeBase == null ? null : this.commitFactory.GetOrCreate(mergeBase, RepositoryInstance.Diff);
5254
});
5355
}
5456

src/GitVersion.LibGit2Sharp/Git/Tag.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ internal sealed class Tag : ITag
1111
private readonly LibGit2Sharp.Tag innerTag;
1212
private readonly Diff diff;
1313
private readonly Lazy<ICommit?> commitLazy;
14+
private readonly CommitFactory commitFactory;
1415

15-
internal Tag(LibGit2Sharp.Tag tag, Diff diff)
16+
internal Tag(LibGit2Sharp.Tag tag, Diff diff, CommitFactory commitFactory)
1617
{
1718
this.innerTag = tag.NotNull();
1819
this.commitLazy = new(PeeledTargetCommit);
1920
this.diff = diff.NotNull();
21+
this.commitFactory = commitFactory;
2022
Name = new(this.innerTag.CanonicalName);
2123
}
2224

@@ -35,7 +37,7 @@ internal Tag(LibGit2Sharp.Tag tag, Diff diff)
3537
target = annotation.Target;
3638
}
3739

38-
return target is LibGit2Sharp.Commit commit ? new Commit(commit, this.diff) : null;
40+
return target is LibGit2Sharp.Commit commit ? this.commitFactory.GetOrCreate(commit, this.diff) : null;
3941
}
4042

4143
public override bool Equals(object? obj) => Equals(obj as ITag);

src/GitVersion.LibGit2Sharp/Git/TagCollection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ internal sealed class TagCollection : ITagCollection
66
{
77
private readonly Lazy<IReadOnlyCollection<ITag>> tags;
88

9-
internal TagCollection(LibGit2Sharp.TagCollection collection, LibGit2Sharp.Diff diff)
9+
internal TagCollection(LibGit2Sharp.TagCollection collection, LibGit2Sharp.Diff diff, CommitFactory commitFactory)
1010
{
1111
collection = collection.NotNull();
12-
this.tags = new Lazy<IReadOnlyCollection<ITag>>(() => [.. collection.Select(tag => new Tag(tag, diff))]);
12+
this.tags = new Lazy<IReadOnlyCollection<ITag>>(() => [.. collection.Select(tag => new Tag(tag, diff, commitFactory))]);
1313
}
1414

1515
public IEnumerator<ITag> GetEnumerator()

0 commit comments

Comments
 (0)