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

Commit 7d1595f

Browse files
authored
Merge pull request #588 from erizocosmico/perf/revlist-norevisit-ancestors-fixed
revlist: do not revisit ancestors as long as all branches are visited
2 parents 8cb0215 + 5bb64f6 commit 7d1595f

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

plumbing/revlist/revlist.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func objects(
3737
) ([]plumbing.Hash, error) {
3838
seen := hashListToSet(ignore)
3939
result := make(map[plumbing.Hash]bool)
40+
visited := make(map[plumbing.Hash]bool)
4041

4142
walkerFunc := func(h plumbing.Hash) {
4243
if !seen[h] {
@@ -46,7 +47,7 @@ func objects(
4647
}
4748

4849
for _, h := range objects {
49-
if err := processObject(s, h, seen, ignore, walkerFunc); err != nil {
50+
if err := processObject(s, h, seen, visited, ignore, walkerFunc); err != nil {
5051
if allowMissingObjects && err == plumbing.ErrObjectNotFound {
5152
continue
5253
}
@@ -63,6 +64,7 @@ func processObject(
6364
s storer.EncodedObjectStorer,
6465
h plumbing.Hash,
6566
seen map[plumbing.Hash]bool,
67+
visited map[plumbing.Hash]bool,
6668
ignore []plumbing.Hash,
6769
walkerFunc func(h plumbing.Hash),
6870
) error {
@@ -82,12 +84,12 @@ func processObject(
8284

8385
switch do := do.(type) {
8486
case *object.Commit:
85-
return reachableObjects(do, seen, ignore, walkerFunc)
87+
return reachableObjects(do, seen, visited, ignore, walkerFunc)
8688
case *object.Tree:
8789
return iterateCommitTrees(seen, do, walkerFunc)
8890
case *object.Tag:
8991
walkerFunc(do.Hash)
90-
return processObject(s, do.Target, seen, ignore, walkerFunc)
92+
return processObject(s, do.Target, seen, visited, ignore, walkerFunc)
9193
case *object.Blob:
9294
walkerFunc(do.Hash)
9395
default:
@@ -105,10 +107,14 @@ func processObject(
105107
func reachableObjects(
106108
commit *object.Commit,
107109
seen map[plumbing.Hash]bool,
110+
visited map[plumbing.Hash]bool,
108111
ignore []plumbing.Hash,
109112
cb func(h plumbing.Hash),
110113
) error {
111114
i := object.NewCommitPreorderIter(commit, seen, ignore)
115+
pending := make(map[plumbing.Hash]bool)
116+
addPendingParents(pending, visited, commit)
117+
112118
for {
113119
commit, err := i.Next()
114120
if err == io.EOF {
@@ -119,6 +125,16 @@ func reachableObjects(
119125
return err
120126
}
121127

128+
if pending[commit.Hash] {
129+
delete(pending, commit.Hash)
130+
}
131+
132+
addPendingParents(pending, visited, commit)
133+
134+
if visited[commit.Hash] && len(pending) == 0 {
135+
break
136+
}
137+
122138
if seen[commit.Hash] {
123139
continue
124140
}
@@ -138,6 +154,14 @@ func reachableObjects(
138154
return nil
139155
}
140156

157+
func addPendingParents(pending, visited map[plumbing.Hash]bool, commit *object.Commit) {
158+
for _, p := range commit.ParentHashes {
159+
if !visited[p] {
160+
pending[p] = true
161+
}
162+
}
163+
}
164+
141165
// iterateCommitTrees iterate all reachable trees from the given commit
142166
func iterateCommitTrees(
143167
seen map[plumbing.Hash]bool,

plumbing/revlist/revlist_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,60 @@ func (s *RevListSuite) TestRevListObjectsNewBranch(c *C) {
217217
}
218218
c.Assert(len(remoteHist), Equals, len(revList))
219219
}
220+
221+
// This tests will ensure that a5b8b09 and b8e471f will be visited even if
222+
// 35e8510 has already been visited and will not stop iterating until they
223+
// have been as well.
224+
//
225+
// * af2d6a6 some json
226+
// * 1669dce Merge branch 'master'
227+
// |\
228+
// | * a5b8b09 Merge pull request #1
229+
// | |\
230+
// | | * b8e471f Creating changelog
231+
// | |/
232+
// * | 35e8510 binary file
233+
// |/
234+
// * b029517 Initial commit
235+
func (s *RevListSuite) TestReachableObjectsNoRevisit(c *C) {
236+
obj, err := s.Storer.EncodedObject(plumbing.CommitObject, plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"))
237+
c.Assert(err, IsNil)
238+
239+
do, err := object.DecodeObject(s.Storer, obj)
240+
c.Assert(err, IsNil)
241+
242+
commit, ok := do.(*object.Commit)
243+
c.Assert(ok, Equals, true)
244+
245+
var visited []plumbing.Hash
246+
err = reachableObjects(
247+
commit,
248+
map[plumbing.Hash]bool{
249+
plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"): true,
250+
},
251+
map[plumbing.Hash]bool{
252+
plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"): true,
253+
},
254+
nil,
255+
func(h plumbing.Hash) {
256+
obj, err := s.Storer.EncodedObject(plumbing.AnyObject, h)
257+
c.Assert(err, IsNil)
258+
259+
do, err := object.DecodeObject(s.Storer, obj)
260+
c.Assert(err, IsNil)
261+
262+
if _, ok := do.(*object.Commit); ok {
263+
visited = append(visited, h)
264+
}
265+
},
266+
)
267+
c.Assert(err, IsNil)
268+
269+
c.Assert(visited, DeepEquals, []plumbing.Hash{
270+
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
271+
plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"),
272+
plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"),
273+
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
274+
plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
275+
})
276+
}

0 commit comments

Comments
 (0)