Skip to content

Commit b31a601

Browse files
committed
internal/function: add cache for history_idx
This commit adds a LRU cache to the history_idx function, caching the indexes in which a commit is from another in the history. Before: BenchmarkHistoryIdx/history_idx-4 2000 789749 ns/op 415896 B/op 1519 allocs/op PASS ok github.com/src-d/gitquery/internal/function 2.189s After: BenchmarkHistoryIdx/history_idx-4 1000000 1063 ns/op 256 B/op 9 allocs/op PASS ok github.com/src-d/gitquery/internal/function 1.607s Signed-off-by: Miguel Molina <[email protected]>
1 parent 9d458be commit b31a601

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

internal/function/history_idx.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"io"
66

7+
"github.com/hashicorp/golang-lru"
8+
79
"github.com/src-d/gitquery"
810
git "gopkg.in/src-d/go-git.v4"
911
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -15,17 +17,25 @@ import (
1517
// of another commit.
1618
type HistoryIdx struct {
1719
expression.BinaryExpression
20+
cache *lru.ARCCache
1821
}
1922

23+
const historyIdxCacheSize = 300
24+
2025
// NewHistoryIdx creates a new HistoryIdx udf.
2126
func NewHistoryIdx(start, target sql.Expression) sql.Expression {
22-
return &HistoryIdx{expression.BinaryExpression{Left: start, Right: target}}
27+
cache, _ := lru.NewARC(historyIdxCacheSize)
28+
return &HistoryIdx{expression.BinaryExpression{Left: start, Right: target}, cache}
2329
}
2430

2531
func (f HistoryIdx) String() string {
2632
return fmt.Sprintf("history_idx(%s, %s)", f.Left, f.Right)
2733
}
2834

35+
type historyKey struct {
36+
start, target plumbing.Hash
37+
}
38+
2939
// Eval implements the Expression interface.
3040
func (f *HistoryIdx) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
3141
s, ok := ctx.Session.(*gitquery.Session)
@@ -64,6 +74,10 @@ func (f *HistoryIdx) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
6474
start := plumbing.NewHash(left.(string))
6575
target := plumbing.NewHash(right.(string))
6676

77+
if val, ok := f.cache.Get(historyKey{start, target}); ok {
78+
return val.(int64), nil
79+
}
80+
6781
// fast path for equal hashes
6882
if start == target {
6983
return int64(0), nil
@@ -131,6 +145,7 @@ func (f *HistoryIdx) repoHistoryIdx(repo *git.Repository, start, target plumbing
131145

132146
for {
133147
if len(stack) == 0 {
148+
f.cache.Add(historyKey{start, target}, int64(-1))
134149
return -1, nil
135150
}
136151

@@ -152,6 +167,8 @@ func (f *HistoryIdx) repoHistoryIdx(repo *git.Repository, start, target plumbing
152167

153168
frame.pos++
154169

170+
f.cache.Add(historyKey{start, c.Hash}, frame.idx)
171+
155172
if c.Hash == target {
156173
return frame.idx, nil
157174
}

internal/function/history_idx_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,57 @@ func TestHistoryIdx(t *testing.T) {
6363
})
6464
}
6565
}
66+
67+
func BenchmarkHistoryIdx(b *testing.B) {
68+
require.NoError(b, fixtures.Init())
69+
defer func() {
70+
require.NoError(b, fixtures.Clean())
71+
}()
72+
73+
f := NewHistoryIdx(
74+
expression.NewGetField(0, sql.Text, "start", true),
75+
expression.NewGetField(1, sql.Text, "target", true),
76+
)
77+
78+
pool := gitquery.NewRepositoryPool()
79+
for _, f := range fixtures.ByTag("worktree") {
80+
pool.AddGit(f.Worktree().Root())
81+
}
82+
83+
session := gitquery.NewSession(&pool)
84+
ctx := sql.NewContext(context.TODO(), session)
85+
86+
cases := []struct {
87+
row sql.Row
88+
idx int64
89+
}{
90+
{
91+
sql.NewRow("b029517f6300c2da0f4b651b8642506cd6aaf45d", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
92+
-1,
93+
},
94+
{
95+
sql.NewRow("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "b029517f6300c2da0f4b651b8642506cd6aaf45d"),
96+
5,
97+
},
98+
{
99+
sql.NewRow("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "b8e471f58bcbca63b07bda20e428190409c2db47"),
100+
5,
101+
},
102+
{
103+
sql.NewRow("b685400c1f9316f350965a5993d350bc746b0bf4", "c7431b5bc9d45fb64a87d4a895ce3d1073c898d2"),
104+
3,
105+
},
106+
}
107+
108+
n := len(cases)
109+
b.Run("history_idx", func(b *testing.B) {
110+
require := require.New(b)
111+
112+
for i := 0; i < b.N; i++ {
113+
cs := cases[i%n]
114+
val, err := f.Eval(ctx, cs.row)
115+
require.NoError(err)
116+
require.Equal(cs.idx, val)
117+
}
118+
})
119+
}

0 commit comments

Comments
 (0)