Skip to content

Commit 6e223ea

Browse files
committed
Add caching for remotes, references, and ref specs
Introduces caching mechanisms for remotes, references, and ref specs in `GitRepository`. Refactors related collections to utilize the new cache for improved efficiency and consistency.
1 parent 457d0a8 commit 6e223ea

File tree

5 files changed

+51
-38
lines changed

5 files changed

+51
-38
lines changed

src/GitVersion.LibGit2Sharp/Git/GitRepository.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ internal sealed partial class GitRepository
1212
private readonly ConcurrentDictionary<string, Branch> cachedBranches = new();
1313
private readonly ConcurrentDictionary<string, Commit> cachedCommits = new();
1414
private readonly ConcurrentDictionary<string, Tag> cachedTags = new();
15+
private readonly ConcurrentDictionary<string, Remote> cachedRemotes = new();
16+
private readonly ConcurrentDictionary<string, Reference> cachedReferences = new();
17+
private readonly ConcurrentDictionary<string, RefSpec> cachedRefSpecs = new();
1518

1619
private IRepository RepositoryInstance
1720
{
@@ -30,8 +33,8 @@ private IRepository RepositoryInstance
3033
public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff, this);
3134
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff, this);
3235
public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff, this);
33-
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes);
34-
public IReferenceCollection References => new ReferenceCollection(RepositoryInstance.Refs);
36+
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes, this);
37+
public IReferenceCollection References => new ReferenceCollection(RepositoryInstance.Refs, this);
3538

3639
public void DiscoverRepository(string? gitDirectory)
3740
{
@@ -77,6 +80,15 @@ public Commit GetOrCreate(LibGit2Sharp.Commit innerCommit, Diff repoDiff)
7780
public Tag GetOrCreate(LibGit2Sharp.Tag innerTag, Diff repoDiff)
7881
=> cachedTags.GetOrAdd(innerTag.CanonicalName, _ => new Tag(innerTag, repoDiff, this));
7982

83+
public Remote GetOrCreate(LibGit2Sharp.Remote innerRemote)
84+
=> cachedRemotes.GetOrAdd(innerRemote.Name, _ => new Remote(innerRemote, this));
85+
86+
public Reference GetOrCreate(LibGit2Sharp.Reference innerReference)
87+
=> cachedReferences.GetOrAdd(innerReference.CanonicalName, _ => new Reference(innerReference));
88+
89+
public RefSpec GetOrCreate(LibGit2Sharp.RefSpec innerRefSpec)
90+
=> cachedRefSpecs.GetOrAdd(innerRefSpec.Specification, _ => new RefSpec(innerRefSpec));
91+
8092
public void Dispose()
8193
{
8294
if (this.repositoryLazy is { IsValueCreated: true }) RepositoryInstance.Dispose();

src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ internal sealed class RefSpecCollection : IRefSpecCollection
66
{
77
private readonly Lazy<IReadOnlyCollection<IRefSpec>> refSpecs;
88

9-
internal RefSpecCollection(LibGit2Sharp.RefSpecCollection collection)
9+
internal RefSpecCollection(LibGit2Sharp.RefSpecCollection innerCollection, GitRepository repo)
1010
{
11-
collection = collection.NotNull();
12-
this.refSpecs = new Lazy<IReadOnlyCollection<IRefSpec>>(() => [.. collection.Select(tag => new RefSpec(tag))]);
11+
innerCollection = innerCollection.NotNull();
12+
this.refSpecs = new Lazy<IReadOnlyCollection<IRefSpec>>(() => [.. innerCollection.Select(repo.GetOrCreate)]);
1313
}
1414

1515
public IEnumerator<IRefSpec> GetEnumerator() => this.refSpecs.Value.GetEnumerator();

src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,38 @@ namespace GitVersion.Git;
55
internal sealed class ReferenceCollection : IReferenceCollection
66
{
77
private readonly LibGit2Sharp.ReferenceCollection innerCollection;
8-
private IReadOnlyCollection<IReference>? references;
8+
private readonly GitRepository repo;
9+
private readonly Lazy<IReadOnlyCollection<IReference>> references;
910

10-
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection) => this.innerCollection = collection.NotNull();
11-
12-
public IEnumerator<IReference> GetEnumerator()
11+
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection, GitRepository repo)
1312
{
14-
this.references ??= [.. this.innerCollection.Select(reference => new Reference(reference))];
15-
return this.references.GetEnumerator();
13+
this.innerCollection = collection.NotNull();
14+
this.repo = repo.NotNull();
15+
this.references = new Lazy<IReadOnlyCollection<IReference>>(() => [.. this.innerCollection.Select(repo.GetOrCreate)]);
1616
}
1717

18-
public void Add(string name, string canonicalRefNameOrObject, bool allowOverwrite = false) => this.innerCollection.Add(name, canonicalRefNameOrObject, allowOverwrite);
19-
20-
public void UpdateTarget(IReference directRef, IObjectId targetId)
21-
{
22-
RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId));
23-
this.references = null;
24-
}
18+
public IEnumerator<IReference> GetEnumerator() => this.references.Value.GetEnumerator();
2519

2620
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
2721

22+
public void Add(string name, string canonicalRefNameOrObject, bool allowOverwrite = false)
23+
=> this.innerCollection.Add(name, canonicalRefNameOrObject, allowOverwrite);
24+
25+
public void UpdateTarget(IReference directRef, IObjectId targetId)
26+
=> RepositoryExtensions.RunSafe(() => this.innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId));
27+
2828
public IReference? this[string name]
2929
{
3030
get
3131
{
3232
var reference = this.innerCollection[name];
33-
return reference is null ? null : new Reference(reference);
33+
return reference is null ? null : this.repo.GetOrCreate(reference);
3434
}
3535
}
3636

3737
public IReference? this[ReferenceName referenceName] => this[referenceName.Canonical];
3838

3939
public IReference? Head => this["HEAD"];
4040

41-
public IEnumerable<IReference> FromGlob(string prefix) => this.innerCollection.FromGlob(prefix).Select(reference => new Reference(reference));
41+
public IEnumerable<IReference> FromGlob(string prefix) => this.innerCollection.FromGlob(prefix).Select(reference => this.repo.GetOrCreate(reference));
4242
}

src/GitVersion.LibGit2Sharp/Git/Remote.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,27 @@ internal sealed class Remote : IRemote
99
private static readonly LambdaKeyComparer<IRemote, string> comparerHelper = new(x => x.Name);
1010

1111
private readonly LibGit2Sharp.Remote innerRemote;
12+
private readonly GitRepository repo;
1213

13-
internal Remote(LibGit2Sharp.Remote remote) => this.innerRemote = remote.NotNull();
14+
internal Remote(LibGit2Sharp.Remote remote, GitRepository repo)
15+
{
16+
this.innerRemote = remote.NotNull();
17+
this.repo = repo.NotNull();
18+
}
1419

1520
public int CompareTo(IRemote? other) => comparerHelper.Compare(this, other);
1621
public bool Equals(IRemote? other) => equalityHelper.Equals(this, other);
1722
public string Name => this.innerRemote.Name;
1823
public string Url => this.innerRemote.Url;
1924

20-
public IEnumerable<IRefSpec> RefSpecs
25+
private IEnumerable<IRefSpec> RefSpecs
2126
{
2227
get
2328
{
2429
var refSpecs = this.innerRemote.RefSpecs;
2530
return refSpecs is null
2631
? []
27-
: new RefSpecCollection((LibGit2Sharp.RefSpecCollection)refSpecs);
32+
: new RefSpecCollection((LibGit2Sharp.RefSpecCollection)refSpecs, repo);
2833
}
2934
}
3035

src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,32 @@ namespace GitVersion.Git;
55
internal sealed class RemoteCollection : IRemoteCollection
66
{
77
private readonly LibGit2Sharp.RemoteCollection innerCollection;
8-
private IReadOnlyCollection<IRemote>? remotes;
8+
private readonly GitRepository repo;
9+
private readonly Lazy<IReadOnlyCollection<IRemote>> remotes;
910

10-
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection) => this.innerCollection = collection.NotNull();
11-
12-
public IEnumerator<IRemote> GetEnumerator()
11+
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection, GitRepository repo)
1312
{
14-
this.remotes ??= [.. this.innerCollection.Select(reference => new Remote(reference))];
15-
return this.remotes.GetEnumerator();
13+
this.innerCollection = collection.NotNull();
14+
this.repo = repo.NotNull();
15+
this.remotes = new Lazy<IReadOnlyCollection<IRemote>>(() => [.. this.innerCollection.Select(repo.GetOrCreate)]);
1616
}
1717

18+
public IEnumerator<IRemote> GetEnumerator() => this.remotes.Value.GetEnumerator();
19+
1820
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1921

2022
public IRemote? this[string name]
2123
{
2224
get
2325
{
2426
var remote = this.innerCollection[name];
25-
return remote is null ? null : new Remote(remote);
27+
return remote is null ? null : this.repo.GetOrCreate(remote);
2628
}
2729
}
2830

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

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

0 commit comments

Comments
 (0)