mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Performance improvement for last commit cache and show-ref (#15455)
* Improve performance when there are multiple commits in the last commit cache * read refs directly if we can Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		@@ -102,10 +102,13 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache *LastCo
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
 | 
					func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
 | 
				
			||||||
 | 
						wr, rd, cancel := CatFileBatch(cache.repo.Path)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var unHitEntryPaths []string
 | 
						var unHitEntryPaths []string
 | 
				
			||||||
	var results = make(map[string]*Commit)
 | 
						var results = make(map[string]*Commit)
 | 
				
			||||||
	for _, p := range paths {
 | 
						for _, p := range paths {
 | 
				
			||||||
		lastCommit, err := cache.Get(commitID, path.Join(treePath, p))
 | 
							lastCommit, err := cache.Get(commitID, path.Join(treePath, p), wr, rd)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, nil, err
 | 
								return nil, nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
package git
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +36,7 @@ func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get get the last commit information by commit id and entry path
 | 
					// Get get the last commit information by commit id and entry path
 | 
				
			||||||
func (c *LastCommitCache) Get(ref, entryPath string) (interface{}, error) {
 | 
					func (c *LastCommitCache) Get(ref, entryPath string, wr *io.PipeWriter, rd *bufio.Reader) (interface{}, error) {
 | 
				
			||||||
	v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
 | 
						v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
 | 
				
			||||||
	if vs, ok := v.(string); ok {
 | 
						if vs, ok := v.(string); ok {
 | 
				
			||||||
		log("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs)
 | 
							log("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs)
 | 
				
			||||||
@@ -46,7 +48,10 @@ func (c *LastCommitCache) Get(ref, entryPath string) (interface{}, error) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		commit, err := c.repo.getCommit(id)
 | 
							if _, err := wr.Write([]byte(vs + "\n")); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							commit, err := c.repo.getCommitFromBatchReader(rd, id)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,9 +9,10 @@ package git
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,6 +35,18 @@ func (repo *Repository) ResolveReference(name string) (string, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
 | 
					// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
 | 
				
			||||||
func (repo *Repository) GetRefCommitID(name string) (string, error) {
 | 
					func (repo *Repository) GetRefCommitID(name string) (string, error) {
 | 
				
			||||||
 | 
						if strings.HasPrefix(name, "refs/") {
 | 
				
			||||||
 | 
							// We're gonna try just reading the ref file as this is likely to be quicker than other options
 | 
				
			||||||
 | 
							fileInfo, err := os.Lstat(filepath.Join(repo.Path, name))
 | 
				
			||||||
 | 
							if err == nil && fileInfo.Mode().IsRegular() && fileInfo.Size() == 41 {
 | 
				
			||||||
 | 
								ref, err := ioutil.ReadFile(filepath.Join(repo.Path, name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if err == nil && SHAPattern.Match(ref[:40]) && ref[40] == '\n' {
 | 
				
			||||||
 | 
									return string(ref[:40]), nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stdout, err := NewCommand("show-ref", "--verify", "--hash", name).RunInDir(repo.Path)
 | 
						stdout, err := NewCommand("show-ref", "--verify", "--hash", name).RunInDir(repo.Path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if strings.Contains(err.Error(), "not a valid ref") {
 | 
							if strings.Contains(err.Error(), "not a valid ref") {
 | 
				
			||||||
@@ -69,6 +82,11 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bufReader := bufio.NewReader(stdoutReader)
 | 
						bufReader := bufio.NewReader(stdoutReader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return repo.getCommitFromBatchReader(bufReader, id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (repo *Repository) getCommitFromBatchReader(bufReader *bufio.Reader, id SHA1) (*Commit, error) {
 | 
				
			||||||
	_, typ, size, err := ReadBatchLine(bufReader)
 | 
						_, typ, size, err := ReadBatchLine(bufReader)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if errors.Is(err, io.EOF) {
 | 
							if errors.Is(err, io.EOF) {
 | 
				
			||||||
@@ -106,7 +124,6 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
				
			|||||||
	case "commit":
 | 
						case "commit":
 | 
				
			||||||
		return CommitFromReader(repo, id, io.LimitReader(bufReader, size))
 | 
							return CommitFromReader(repo, id, io.LimitReader(bufReader, size))
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		_ = stdoutReader.CloseWithError(fmt.Errorf("unknown typ: %s", typ))
 | 
					 | 
				
			||||||
		log("Unknown typ: %s", typ)
 | 
							log("Unknown typ: %s", typ)
 | 
				
			||||||
		return nil, ErrNotExist{
 | 
							return nil, ErrNotExist{
 | 
				
			||||||
			ID: id.String(),
 | 
								ID: id.String(),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user