diff options
author | Javi Fontan <jfontan@gmail.com> | 2018-05-14 17:16:16 +0200 |
---|---|---|
committer | Javi Fontan <jfontan@gmail.com> | 2018-05-14 17:16:16 +0200 |
commit | 939793b42974c12abf2d2b65facee489004a9e06 (patch) | |
tree | 9e8386962b8000781c851dc9367839d9e8d2ce65 /remote.go | |
parent | e63b032e91ce35e0ecd5f27d43be655625e8af36 (diff) | |
download | go-git-939793b42974c12abf2d2b65facee489004a9e06.tar.gz |
git: remote, Do not iterate all references on update.
The current code iterates all the references in the remote to check if
they match the refspec. This is OK when the refspec is a wildcard but
is a waste of time when they are not.
A hash with references is generated for fast access before starting the
update and used only when the refspec is not a wildcard.
In a repository with 7800 references this meant 7800 * 7800 checks. With
the current code it took 8m30s to update the references. With the new
code it takes less than 0.5s.
References are already extensively tested in remote_test.go.
Signed-off-by: Javi Fontan <jfontan@gmail.com>
Diffstat (limited to 'remote.go')
-rw-r--r-- | remote.go | 24 |
1 files changed, 22 insertions, 2 deletions
@@ -371,14 +371,22 @@ func (r *Remote) addReferencesToUpdate( refspecs []config.RefSpec, localRefs []*plumbing.Reference, remoteRefs storer.ReferenceStorer, - req *packp.ReferenceUpdateRequest) error { + req *packp.ReferenceUpdateRequest, +) error { + // This references dictionary will be used to search references by name. + refsDict := make(map[string]*plumbing.Reference) + for _, ref := range localRefs { + refsDict[ref.Name().String()] = ref + } + for _, rs := range refspecs { if rs.IsDelete() { if err := r.deleteReferences(rs, remoteRefs, req); err != nil { return err } } else { - if err := r.addOrUpdateReferences(rs, localRefs, remoteRefs, req); err != nil { + err := r.addOrUpdateReferences(rs, localRefs, refsDict, remoteRefs, req) + if err != nil { return err } } @@ -390,9 +398,21 @@ func (r *Remote) addReferencesToUpdate( func (r *Remote) addOrUpdateReferences( rs config.RefSpec, localRefs []*plumbing.Reference, + refsDict map[string]*plumbing.Reference, remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest, ) error { + // If it is not a wilcard refspec we can directly search for the reference + // in the references dictionary. + if !rs.IsWildcard() { + ref, ok := refsDict[rs.Src()] + if !ok { + return nil + } + + return r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req) + } + for _, ref := range localRefs { err := r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req) if err != nil { |