Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 841b62a

Browse files
committed
plumbing: the commit walker can skip externally-seen commits
When the revlist is computing the set of hashes needed to transfer, it doesn't need to walk over commits it has already processed. So, it can instruct the commit walker not to walk those commits by passing in its own `seen` map. For a 36K object repo, this brought the time for `revlist.Objects` down from 50s to 30s.
1 parent bb3217c commit 841b62a

File tree

5 files changed

+45
-15
lines changed

5 files changed

+45
-15
lines changed

plumbing/object/commit_walker.go

+14-8
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import (
88
)
99

1010
type commitPreIterator struct {
11-
seen map[plumbing.Hash]bool
12-
stack []CommitIter
13-
start *Commit
11+
seenExternal map[plumbing.Hash]bool
12+
seen map[plumbing.Hash]bool
13+
stack []CommitIter
14+
start *Commit
1415
}
1516

1617
// NewCommitPreorderIter returns a CommitIter that walks the commit history,
@@ -20,16 +21,21 @@ type commitPreIterator struct {
2021
// and will return the error. Other errors might be returned if the history
2122
// cannot be traversed (e.g. missing objects). Ignore allows to skip some
2223
// commits from being iterated.
23-
func NewCommitPreorderIter(c *Commit, ignore []plumbing.Hash) CommitIter {
24+
func NewCommitPreorderIter(
25+
c *Commit,
26+
seenExternal map[plumbing.Hash]bool,
27+
ignore []plumbing.Hash,
28+
) CommitIter {
2429
seen := make(map[plumbing.Hash]bool)
2530
for _, h := range ignore {
2631
seen[h] = true
2732
}
2833

2934
return &commitPreIterator{
30-
seen: seen,
31-
stack: make([]CommitIter, 0),
32-
start: c,
35+
seenExternal: seenExternal,
36+
seen: seen,
37+
stack: make([]CommitIter, 0),
38+
start: c,
3339
}
3440
}
3541

@@ -57,7 +63,7 @@ func (w *commitPreIterator) Next() (*Commit, error) {
5763
}
5864
}
5965

60-
if w.seen[c.Hash] {
66+
if w.seen[c.Hash] || w.seenExternal[c.Hash] {
6167
continue
6268
}
6369

plumbing/object/commit_walker_test.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
1616
commit := s.commit(c, s.Fixture.Head)
1717

1818
var commits []*Commit
19-
NewCommitPreorderIter(commit, nil).ForEach(func(c *Commit) error {
19+
NewCommitPreorderIter(commit, nil, nil).ForEach(func(c *Commit) error {
2020
commits = append(commits, c)
2121
return nil
2222
})
@@ -42,7 +42,7 @@ func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
4242
commit := s.commit(c, s.Fixture.Head)
4343

4444
var commits []*Commit
45-
NewCommitPreorderIter(commit, []plumbing.Hash{
45+
NewCommitPreorderIter(commit, nil, []plumbing.Hash{
4646
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
4747
}).ForEach(func(c *Commit) error {
4848
commits = append(commits, c)
@@ -60,6 +60,30 @@ func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
6060
}
6161
}
6262

63+
func (s *CommitWalkerSuite) TestCommitPreIteratorWithSeenExternal(c *C) {
64+
commit := s.commit(c, s.Fixture.Head)
65+
66+
var commits []*Commit
67+
seenExternal := map[plumbing.Hash]bool{
68+
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"): true,
69+
}
70+
NewCommitPreorderIter(commit, seenExternal, nil).
71+
ForEach(func(c *Commit) error {
72+
commits = append(commits, c)
73+
return nil
74+
})
75+
76+
c.Assert(commits, HasLen, 2)
77+
78+
expected := []string{
79+
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
80+
"918c48b83bd081e863dbe1b80f8998f058cd8294",
81+
}
82+
for i, commit := range commits {
83+
c.Assert(commit.Hash.String(), Equals, expected[i])
84+
}
85+
}
86+
6387
func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
6488
commit := s.commit(c, s.Fixture.Head)
6589

plumbing/revlist/revlist.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func reachableObjects(
108108
ignore []plumbing.Hash,
109109
cb func(h plumbing.Hash),
110110
) error {
111-
i := object.NewCommitPreorderIter(commit, ignore)
111+
i := object.NewCommitPreorderIter(commit, seen, ignore)
112112
for {
113113
commit, err := i.Next()
114114
if err == io.EOF {

remote.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool,
615615
}
616616

617617
found := false
618-
iter := object.NewCommitPreorderIter(c, nil)
618+
iter := object.NewCommitPreorderIter(c, nil, nil)
619619
return found, iter.ForEach(func(c *object.Commit) error {
620620
if c.Hash != old {
621621
return nil

repository.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) {
720720
return nil, err
721721
}
722722

723-
return object.NewCommitPreorderIter(commit, nil), nil
723+
return object.NewCommitPreorderIter(commit, nil, nil), nil
724724
}
725725

726726
// Tags returns all the References from Tags. This method returns all the tag
@@ -949,7 +949,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
949949
commit = c
950950
}
951951
case revision.CaretReg:
952-
history := object.NewCommitPreorderIter(commit, nil)
952+
history := object.NewCommitPreorderIter(commit, nil, nil)
953953

954954
re := item.(revision.CaretReg).Regexp
955955
negate := item.(revision.CaretReg).Negate
@@ -979,7 +979,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
979979

980980
commit = c
981981
case revision.AtDate:
982-
history := object.NewCommitPreorderIter(commit, nil)
982+
history := object.NewCommitPreorderIter(commit, nil, nil)
983983

984984
date := item.(revision.AtDate).Date
985985

0 commit comments

Comments
 (0)