From 930bae2300be1c62a56d6f019e519b6752d41ad1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Mar 2024 18:21:24 +0800 Subject: [PATCH] Add cache for branch divergence on branch list page (#29577) The branch page for blender project will take 6s because calculating divergence is very slow. This PR will add a cache for the branch divergence calculation. So when the second visit the branch list, it will take only less 200ms. --- services/repository/branch.go | 55 +++++++++++++++++++++++++++++++---- services/repository/push.go | 5 ++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index 763fb966c58b8..8d8cfa2d19d82 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -16,9 +16,11 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/queue" @@ -99,7 +101,6 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - branches = append(branches, branch) } @@ -109,10 +110,44 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - return defaultBranch, branches, totalNumOfBranches, nil } +func getDivergenceCacheKey(repoID int64, branchName string) string { + return fmt.Sprintf("%d-%s", repoID, branchName) +} + +// getDivergenceFromCache gets the divergence from cache +func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) { + data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) + res := git.DivergeObject{ + Ahead: -1, + Behind: -1, + } + s, ok := data.([]byte) + if !ok || len(s) == 0 { + return &res, false + } + + if err := json.Unmarshal(s, &res); err != nil { + log.Error("json.UnMarshal failed: %v", err) + return &res, false + } + return &res, true +} + +func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) error { + bs, err := json.Marshal(divergence) + if err != nil { + return err + } + return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) +} + +func DelDivergenceFromCache(repoID int64, branchName string) error { + return cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName)) +} + func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *git_model.Branch, protectedBranches *git_model.ProtectedBranchRules, repoIDToRepo map[int64]*repo_model.Repository, repoIDToGitRepo map[int64]*git.Repository, @@ -130,10 +165,18 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g // it's not default branch if repo.DefaultBranch != dbBranch.Name && !dbBranch.IsDeleted { - var err error - divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) - if err != nil { - log.Error("CountDivergingCommits: %v", err) + var cached bool + divergence, cached = getDivergenceFromCache(repo.ID, dbBranch.Name) + if !cached { + var err error + divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) + if err != nil { + log.Error("CountDivergingCommits: %v", err) + } else { + if err = putDivergenceFromCache(repo.ID, dbBranch.Name, divergence); err != nil { + log.Error("putDivergenceFromCache: %v", err) + } + } } } diff --git a/services/repository/push.go b/services/repository/push.go index 0aeb4c830b721..39843249a53a7 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -220,6 +220,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } + // delete cache for divergence + if err := DelDivergenceFromCache(repo.ID, branch); err != nil { + log.Error("DelDivergenceFromCache: %v", err) + } + commits := repo_module.GitToPushCommits(l) commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)