fix: git cache (#38763)

1. always use "last commit cache"
2. correctly build the cache key for any input (SafeCacheKey)
3. fix the git note "last commit cache FIXME" and avoid OOM
This commit is contained in:
wxiaoguang
2026-08-05 00:17:07 +08:00
committed by GitHub
parent 6347a33b34
commit deccd53c24
26 changed files with 213 additions and 298 deletions
+2 -15
View File
@@ -251,18 +251,6 @@ func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_
return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull)
}
// GetCommitsCount returns cached commit count for current view
func (r *Repository) GetCommitsCount(ctx context.Context) (int64, error) {
if r.Commit == nil {
return 0, nil
}
contextName := r.RefFullName.ShortName()
isRef := r.RefFullName.IsBranch() || r.RefFullName.IsTag()
return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, isRef), func() (int64, error) {
return git.CommitsCountOfCommit(ctx, r.Repository, r.Commit.ID.String())
})
}
// GetCommitGraphsCount returns cached commit count for current view
func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool, branches, files []string) (int64, error) {
cacheKey := fmt.Sprintf("commits-count-%d-graph-%t-%s-%s", r.Repository.ID, hidePRRefs, branches, files)
@@ -906,7 +894,7 @@ func RepoRefByDefaultBranch() func(*Context) {
ctx.Repo.RefFullName = git.RefNameFromBranch(ctx.Repo.Repository.DefaultBranch)
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
ctx.Repo.Commit, _ = ctx.Repo.GitRepo.GetBranchCommit(ctx, ctx.Repo.BranchName)
ctx.Repo.CommitsCount, _ = ctx.Repo.GetCommitsCount(ctx)
ctx.Repo.CommitsCount, _ = git.GetCommitsCountCache(ctx, ctx.Repo.Repository, ctx.Repo.RefFullName, ctx.Repo.Commit)
ctx.Data["RefFullName"] = ctx.Repo.RefFullName
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
@@ -1053,7 +1041,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) {
ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch() // only used by the branch selector dropdown: AllowCreateNewRef
ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount(ctx)
ctx.Repo.CommitsCount, err = git.GetCommitsCountCache(ctx, ctx.Repo.Repository, ctx.Repo.RefFullName, ctx.Repo.Commit)
if err != nil {
ctx.ServerError("GetCommitsCount", err)
return
@@ -1068,7 +1056,6 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) {
}
}
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
ctx.Repo.GitRepo.LastCommitCache = git.NewLastCommitCache(ctx.Repo.CommitsCount, ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, cache.GetCache())
}
}
+1 -2
View File
@@ -11,7 +11,6 @@ import (
repo_model "gitea.dev/models/repo"
system_model "gitea.dev/models/system"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd"
giturl "gitea.dev/modules/git/url"
@@ -266,7 +265,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu
}
for _, branch := range branches {
cache.Remove(m.Repo.GetCommitsCountCacheKey(branch, true))
git.RemoveCommitsCountCache(m.Repo, git.RefNameFromBranch(branch))
}
m.UpdatedUnix = timeutil.TimeStampNow()
+1 -3
View File
@@ -24,7 +24,6 @@ import (
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/globallock"
@@ -294,8 +293,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
}
// Reset cached commit count
cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true))
git.RemoveCommitsCountCache(pr.Issue.Repo, git.RefNameFromBranch(pr.BaseBranch))
return handleCloseCrossReferences(ctx, pr, doer)
}
+2 -15
View File
@@ -6,27 +6,14 @@ package repository
import (
"context"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
)
// CacheRef cachhe last commit information of the branch or the tag
func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error {
// CacheRef caches last commit information of the branch or the tag
func CacheRef(ctx context.Context, gitRepo *git.Repository, fullRefName git.RefName) error {
commit, err := gitRepo.GetCommit(ctx, fullRefName.String())
if err != nil {
return err
}
if gitRepo.LastCommitCache == nil {
commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(fullRefName.ShortName(), true), func() (int64, error) {
return git.CommitsCountOfCommit(ctx, repo, commit.ID.String())
})
if err != nil {
return err
}
gitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, repo.FullName(), gitRepo, cache.GetCache())
}
return commit.CacheCommit(ctx, gitRepo)
}
-20
View File
@@ -11,7 +11,6 @@ import (
"strings"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
"gitea.dev/modules/lfs"
"gitea.dev/modules/setting"
@@ -121,21 +120,7 @@ func GetFileContents(ctx context.Context, repo *repo_model.Repository, gitRepo *
return getFileContentsByEntryInternal(ctx, repo, gitRepo, refCommit, entry, opts)
}
func addLastCommitCache(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, cacheKey, fullName, sha string) error {
if gitRepo.LastCommitCache == nil {
commitsCount, err := cache.GetInt64(cacheKey, func() (int64, error) {
return git.CommitsCountOfCommit(ctx, repo, sha)
})
if err != nil {
return err
}
gitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, fullName, gitRepo, cache.GetCache())
}
return nil
}
func getFileContentsByEntryInternal(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, entry *git.TreeEntry, opts GetContentsOrListOptions) (*api.ContentsResponse, error) {
refType := refCommit.RefName.RefType()
commit := refCommit.Commit
selfURL, err := url.Parse(repo.APIURL() + "/contents/" + util.PathEscapeSegments(opts.TreePath) + "?ref=" + url.QueryEscape(refCommit.InputRef))
if err != nil {
@@ -157,11 +142,6 @@ func getFileContentsByEntryInternal(ctx context.Context, repo *repo_model.Reposi
}
if opts.IncludeCommitMetadata || opts.IncludeCommitMessage {
err = addLastCommitCache(ctx, repo, gitRepo, repo.GetCommitsCountCacheKey(refCommit.InputRef, refType != git.RefTypeCommit), repo.FullName(), refCommit.CommitID)
if err != nil {
return nil, err
}
lastCommit, err := refCommit.Commit.GetCommitByPath(ctx, gitRepo, opts.TreePath)
if err != nil {
return nil, err
+2 -12
View File
@@ -13,7 +13,6 @@ import (
"gitea.dev/models/db"
repo_model "gitea.dev/models/repo"
user_model "gitea.dev/models/user"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
"gitea.dev/modules/graceful"
"gitea.dev/modules/log"
@@ -205,7 +204,7 @@ func pushQueueHandleUpdates(optsList []*repo_module.PushUpdateOptions) error {
notify_service.PushCommits(ctx, pusher, repo, opts, commits)
// Cache for big repository
if err := CacheRef(graceful.GetManager().HammerContext(), repo, gitRepo, opts.RefFullName); err != nil {
if err := CacheRef(graceful.GetManager().HammerContext(), gitRepo, opts.RefFullName); err != nil {
log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err)
}
} else {
@@ -309,16 +308,7 @@ func pushUpdateBranch(ctx context.Context, repo *repo_model.Repository, gitRepo
OldCommitID: opts.OldCommitID,
NewCommitID: opts.NewCommitID,
})
if isForcePush {
log.Trace("Push %s is a force push", opts.NewCommitID)
cache.Remove(repo.GetCommitsCountCacheKey(opts.RefName(), true))
} else {
// TODO: increment update the commit count cache but not remove
cache.Remove(repo.GetCommitsCountCacheKey(opts.RefName(), true))
}
git.RemoveCommitsCountCache(repo, opts.RefFullName)
return l, nil
}