4
4
"fmt"
5
5
"io"
6
6
7
+ "github.com/hashicorp/golang-lru"
8
+
7
9
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
8
10
"gopkg.in/src-d/go-git.v4/plumbing/object"
9
11
@@ -18,14 +20,21 @@ import (
18
20
// or not.
19
21
type CommitHasTree struct {
20
22
expression.BinaryExpression
23
+ cache * lru.ARCCache
21
24
}
22
25
26
+ // TODO: set as config
27
+ const commitHasTreeCacheSize = 100
28
+
23
29
// NewCommitHasTree creates a new CommitHasTree function.
24
30
func NewCommitHasTree (commit , tree sql.Expression ) sql.Expression {
31
+ // NewARC can only fail if size is negative, and we know it is not,
32
+ // so it is safe to ignore the error here.
33
+ cache , _ := lru .NewARC (commitHasTreeCacheSize )
25
34
return & CommitHasTree {expression.BinaryExpression {
26
35
Left : commit ,
27
36
Right : tree ,
28
- }}
37
+ }, cache }
29
38
}
30
39
31
40
func (f CommitHasTree ) String () string {
@@ -73,6 +82,10 @@ func (f *CommitHasTree) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
73
82
commitHash := plumbing .NewHash (left .(string ))
74
83
treeHash := plumbing .NewHash (right .(string ))
75
84
85
+ if val , ok := f .cache .Get (cacheKey {commitHash , treeHash }); ok {
86
+ return val .(bool ), nil
87
+ }
88
+
76
89
iter , err := s .Pool .RepoIter ()
77
90
if err != nil {
78
91
return nil , err
@@ -88,7 +101,7 @@ func (f *CommitHasTree) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
88
101
return nil , err
89
102
}
90
103
91
- ok , err := commitHasTree (repo .Repo , commitHash , treeHash )
104
+ ok , err := f . commitHasTree (repo .Repo , commitHash , treeHash )
92
105
if err == plumbing .ErrObjectNotFound {
93
106
continue
94
107
}
@@ -97,7 +110,12 @@ func (f *CommitHasTree) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
97
110
}
98
111
}
99
112
100
- func commitHasTree (
113
+ type cacheKey struct {
114
+ commit plumbing.Hash
115
+ tree plumbing.Hash
116
+ }
117
+
118
+ func (f * CommitHasTree ) commitHasTree (
101
119
repo * git.Repository ,
102
120
commitHash , treeHash plumbing.Hash ,
103
121
) (bool , error ) {
@@ -106,6 +124,8 @@ func commitHasTree(
106
124
return false , err
107
125
}
108
126
127
+ f .cache .Add (cacheKey {commitHash , commit .TreeHash }, true )
128
+
109
129
if commit .TreeHash == treeHash {
110
130
return true , nil
111
131
}
@@ -115,13 +135,13 @@ func commitHasTree(
115
135
return false , err
116
136
}
117
137
118
- return treeInEntries (repo , tree .Entries , treeHash )
138
+ return f . treeInEntries (repo , tree .Entries , commitHash , treeHash )
119
139
}
120
140
121
- func treeInEntries (
141
+ func ( f * CommitHasTree ) treeInEntries (
122
142
repo * git.Repository ,
123
143
entries []object.TreeEntry ,
124
- hash plumbing.Hash ,
144
+ commitHash , hash plumbing.Hash ,
125
145
) (bool , error ) {
126
146
type stackFrame struct {
127
147
pos int
@@ -131,6 +151,7 @@ func treeInEntries(
131
151
132
152
for {
133
153
if len (stack ) == 0 {
154
+ f .cache .Add (cacheKey {commitHash , hash }, false )
134
155
return false , nil
135
156
}
136
157
@@ -143,6 +164,7 @@ func treeInEntries(
143
164
entry := frame .entries [frame .pos ]
144
165
frame .pos ++
145
166
if entry .Mode == filemode .Dir {
167
+ f .cache .Add (cacheKey {commitHash , entry .Hash }, true )
146
168
if entry .Hash == hash {
147
169
return true , nil
148
170
}
0 commit comments