Skip to content

Commit 326cb03

Browse files
committed
Defer last commit info
Signed-off-by: Andrew Thornton <[email protected]>
1 parent fb3ffeb commit 326cb03

15 files changed

+422
-42
lines changed

integrations/repo_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"testing"
1313
"time"
1414

15+
"code.gitea.io/gitea/modules/repository"
1516
"code.gitea.io/gitea/modules/setting"
1617

1718
"github.com/PuerkitoBio/goquery"
@@ -92,7 +93,15 @@ func TestViewRepo2(t *testing.T) {
9293
// enable last commit cache for all repositories
9394
oldCommitsCount := setting.CacheService.LastCommit.CommitsCount
9495
setting.CacheService.LastCommit.CommitsCount = 0
95-
// first view will not hit the cache
96+
97+
ccr := &repository.CommitCacheRequest{
98+
Repo: "user3/repo3",
99+
CommitID: "master",
100+
TreePath: "",
101+
}
102+
err := ccr.Do()
103+
assert.NoError(t, err)
104+
// first view should hit the cache
96105
testViewRepo(t)
97106
// second view will hit the cache
98107
testViewRepo(t)

modules/git/commit_info_gogit.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
3737

3838
var revs map[string]*object.Commit
3939
if cache != nil {
40-
var unHitPaths []string
41-
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, cache)
40+
revs, _, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, cache)
4241
if err != nil {
4342
return nil, nil, err
4443
}
45-
if len(unHitPaths) > 0 {
46-
revs2, err := GetLastCommitForPaths(ctx, c, treePath, unHitPaths)
47-
if err != nil {
48-
return nil, nil, err
49-
}
50-
51-
for k, v := range revs2 {
52-
if err := cache.Put(commit.ID.String(), path.Join(treePath, k), v.ID().String()); err != nil {
53-
return nil, nil, err
54-
}
55-
revs[k] = v
56-
}
57-
}
5844
} else {
5945
revs, err = GetLastCommitForPaths(ctx, c, treePath, entryPaths)
6046
}
@@ -88,6 +74,21 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
8874
subModuleFile := NewSubModuleFile(entryCommit, subModuleURL, entry.ID.String())
8975
commitsInfo[i].SubModuleFile = subModuleFile
9076
}
77+
} else if entry.IsSubModule() {
78+
subModuleURL := ""
79+
var fullPath string
80+
if len(treePath) > 0 {
81+
fullPath = treePath + "/" + entry.Name()
82+
} else {
83+
fullPath = entry.Name()
84+
}
85+
if subModule, err := commit.GetSubModule(fullPath); err != nil {
86+
return nil, nil, err
87+
} else if subModule != nil {
88+
subModuleURL = subModule.URL
89+
}
90+
subModuleFile := NewSubModuleFile(nil, subModuleURL, entry.ID.String())
91+
commitsInfo[i].SubModuleFile = subModuleFile
9192
}
9293
}
9394

modules/git/commit_info_nogogit.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
3131

3232
var revs map[string]*Commit
3333
if cache != nil {
34-
var unHitPaths []string
35-
revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, cache)
34+
revs, _, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, cache)
3635
if err != nil {
3736
return nil, nil, err
3837
}
39-
if len(unHitPaths) > 0 {
40-
sort.Strings(unHitPaths)
41-
commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths)
42-
if err != nil {
43-
return nil, nil, err
44-
}
45-
46-
for i, found := range commits {
47-
if err := cache.Put(commit.ID.String(), path.Join(treePath, unHitPaths[i]), found.ID.String()); err != nil {
48-
return nil, nil, err
49-
}
50-
revs[unHitPaths[i]] = found
51-
}
52-
}
5338
} else {
5439
sort.Strings(entryPaths)
5540
revs = map[string]*Commit{}
@@ -86,6 +71,21 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
8671
subModuleFile := NewSubModuleFile(entryCommit, subModuleURL, entry.ID.String())
8772
commitsInfo[i].SubModuleFile = subModuleFile
8873
}
74+
} else if entry.IsSubModule() {
75+
subModuleURL := ""
76+
var fullPath string
77+
if len(treePath) > 0 {
78+
fullPath = treePath + "/" + entry.Name()
79+
} else {
80+
fullPath = entry.Name()
81+
}
82+
if subModule, err := commit.GetSubModule(fullPath); err != nil {
83+
return nil, nil, err
84+
} else if subModule != nil {
85+
subModuleURL = subModule.URL
86+
}
87+
subModuleFile := NewSubModuleFile(entryCommit, subModuleURL, entry.ID.String())
88+
commitsInfo[i].SubModuleFile = subModuleFile
8989
}
9090
}
9191

modules/git/last_commit_cache_gogit.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64,
3737
}
3838
}
3939

40+
// GetCachedCommitID returns if there is a cached commit for the ref and entryPath
41+
func (c *LastCommitCache) GetCachedCommitID(ref, entryPath string) (string, bool) {
42+
v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
43+
vs, ok := v.(string)
44+
return vs, ok
45+
}
46+
4047
// Get get the last commit information by commit id and entry path
4148
func (c *LastCommitCache) Get(ref, entryPath string) (interface{}, error) {
4249
v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))

modules/git/last_commit_cache_nogogit.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64,
3535
}
3636
}
3737

38+
// GetCachedCommitID returns if there is a cached commit for the ref and entryPath
39+
func (c *LastCommitCache) GetCachedCommitID(ref, entryPath string) (string, bool) {
40+
v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
41+
vs, ok := v.(string)
42+
return vs, ok
43+
}
44+
3845
// Get get the last commit information by commit id and entry path
3946
func (c *LastCommitCache) Get(ref, entryPath string, wr WriteCloserError, rd *bufio.Reader) (interface{}, error) {
4047
v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))

modules/git/notes_nogogit.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
6868
if err != nil {
6969
return err
7070
}
71-
note.Commit = lastCommits[0]
72-
71+
if len(lastCommits) > 0 {
72+
note.Commit = lastCommits[0]
73+
}
7374
return nil
7475
}

modules/repository/cache.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ func CacheRef(ctx context.Context, repo *models.Repository, gitRepo *git.Reposit
4242
return nil
4343
}
4444

45-
commitCache := git.NewLastCommitCache(repo.FullName(), gitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache())
45+
repoFullName := repo.FullName()
46+
commitID := commit.ID.String()
4647

47-
return commitCache.CacheCommit(ctx, commit)
48+
return UpdateCache(repoFullName, commitID, "", true)
4849
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright 2019 Gitea. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build gogit
6+
7+
package repository
8+
9+
import (
10+
"path"
11+
"path/filepath"
12+
"sync"
13+
14+
"code.gitea.io/gitea/modules/cache"
15+
"code.gitea.io/gitea/modules/git"
16+
"code.gitea.io/gitea/modules/graceful"
17+
"code.gitea.io/gitea/modules/log"
18+
"code.gitea.io/gitea/modules/queue"
19+
"code.gitea.io/gitea/modules/setting"
20+
)
21+
22+
var lock = sync.Mutex{}
23+
var table = map[CommitCacheRequest]bool{}
24+
var lastCommitQueue queue.UniqueQueue
25+
26+
// CommitCacheRequest represents a cache request
27+
type CommitCacheRequest struct {
28+
Repo string
29+
CommitID string
30+
TreePath string
31+
Recursive bool
32+
}
33+
34+
// Do runs the cache request uniquely ensuring that only one cache request is running for this request triple
35+
func (req *CommitCacheRequest) Do() error {
36+
recursive := req.Recursive
37+
req.Recursive = false
38+
39+
repo, err := git.OpenRepository(filepath.Join(setting.RepoRootPath, req.Repo+".git"))
40+
if err != nil {
41+
return err
42+
}
43+
commit, err := repo.GetCommit(req.CommitID)
44+
if err != nil {
45+
if git.IsErrNotExist(err) {
46+
return nil
47+
}
48+
return err
49+
}
50+
51+
lccache := git.NewLastCommitCache(req.Repo, repo, setting.LastCommitCacheTTLSeconds, cache.GetCache())
52+
53+
directories := []string{req.TreePath}
54+
for len(directories) > 0 {
55+
req.TreePath = directories[len(directories)-1]
56+
next, err := req.doTree(repo, commit, recursive, lccache)
57+
if err != nil {
58+
return err
59+
}
60+
directories = append(next, directories[:len(directories)-1]...)
61+
}
62+
return nil
63+
}
64+
65+
func (req *CommitCacheRequest) doTree(repo *git.Repository, commit *git.Commit, recursive bool, lccache *git.LastCommitCache) ([]string, error) {
66+
67+
tree, err := commit.Tree.SubTree(req.TreePath)
68+
if err != nil {
69+
if git.IsErrNotExist(err) {
70+
return nil, nil
71+
}
72+
return nil, err
73+
}
74+
entries, err := tree.ListEntries()
75+
if err != nil {
76+
if git.IsErrNotExist(err) {
77+
return nil, nil
78+
}
79+
return nil, err
80+
}
81+
directories := make([]string, 0, len(entries))
82+
83+
commitNodeIndex, commitGraphFile := repo.CommitNodeIndex()
84+
if commitGraphFile != nil {
85+
defer commitGraphFile.Close()
86+
}
87+
88+
commitNode, err := commitNodeIndex.Get(commit.ID)
89+
if err != nil {
90+
return nil, err
91+
}
92+
93+
lock.Lock()
94+
if has := table[*req]; has {
95+
lock.Unlock()
96+
if recursive {
97+
for _, entry := range entries {
98+
if entry.IsDir() {
99+
directories = append(directories, path.Join(req.TreePath, entry.Name()))
100+
}
101+
}
102+
}
103+
return directories, nil
104+
}
105+
table[*req] = true
106+
lock.Unlock()
107+
defer func() {
108+
lock.Lock()
109+
delete(table, *req)
110+
lock.Unlock()
111+
}()
112+
113+
entryPaths := make([]string, 0, len(entries))
114+
for _, entry := range entries {
115+
if recursive && entry.IsDir() {
116+
directories = append(directories, path.Join(req.TreePath, entry.Name()))
117+
}
118+
_, ok := lccache.GetCachedCommitID(req.CommitID, path.Join(req.TreePath, entry.Name()))
119+
if !ok {
120+
entryPaths = append(entryPaths, entry.Name())
121+
}
122+
}
123+
124+
if len(entryPaths) == 0 {
125+
return directories, nil
126+
}
127+
128+
commits, err := git.GetLastCommitForPaths(graceful.GetManager().HammerContext(), commitNode, req.TreePath, entryPaths)
129+
if err != nil {
130+
return nil, err
131+
}
132+
133+
for entryPath, entryCommit := range commits {
134+
if err := lccache.Put(commit.ID.String(), path.Join(req.TreePath, entryPath), entryCommit.ID().String()); err != nil {
135+
return nil, err
136+
}
137+
}
138+
139+
return directories, nil
140+
}
141+
142+
func handle(data ...queue.Data) {
143+
for _, datum := range data {
144+
req := datum.(*CommitCacheRequest)
145+
if err := req.Do(); err != nil {
146+
log.Error("Unable to process commit cache request for %s:%s:%s:%t: %v", req.Repo, req.CommitID, req.TreePath, req.Recursive, err)
147+
}
148+
}
149+
}
150+
151+
// Init initialises the queue
152+
func Init() error {
153+
lastCommitQueue = queue.CreateUniqueQueue("last_commit_queue", handle, &CommitCacheRequest{}).(queue.UniqueQueue)
154+
155+
return nil
156+
}
157+
158+
// UpdateCache queues the the request
159+
func UpdateCache(repo, commitID, treePath string, recursive bool) error {
160+
return lastCommitQueue.Push(&CommitCacheRequest{
161+
Repo: repo,
162+
CommitID: commitID,
163+
TreePath: treePath,
164+
Recursive: recursive,
165+
})
166+
}

0 commit comments

Comments
 (0)