From 2c03f4263f7b9415eacb09a56828c818cbaef7fb Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Thu, 29 May 2025 09:08:18 +0100 Subject: [PATCH] knotserver: calculate repoindex items in parallel performing rev-list and filetree in sequential occupy a large amount of the client budget. we can parallelize all these expensive operations. Signed-off-by: oppiliappan --- knotserver/routes.go | 99 +++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/knotserver/routes.go b/knotserver/routes.go index 160e8da..7424c99 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -17,6 +17,7 @@ import ( "path/filepath" "strconv" "strings" + "sync" securejoin "github.com/cyphar/filepath-securejoin" "github.com/gliderlabs/ssh" @@ -88,33 +89,82 @@ func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { } } - commits, err := gr.Commits(0, 60) // a good preview of commits in this repo - if err != nil { - writeError(w, err.Error(), http.StatusInternalServerError) - l.Error("fetching commits", "error", err.Error()) - return - } + var ( + commits []*object.Commit + total int + branches []types.Branch + files []types.NiceTree + tags []*git.TagReference + ) - total, err := gr.TotalCommits() - if err != nil { - writeError(w, err.Error(), http.StatusInternalServerError) - l.Error("fetching commits", "error", err.Error()) - return - } + var wg sync.WaitGroup + errorsCh := make(chan error, 5) - branches, err := gr.Branches() - if err != nil { - l.Error("getting branches", "error", err.Error()) + wg.Add(1) + go func() { + defer wg.Done() + cs, err := gr.Commits(0, 60) + if err != nil { + errorsCh <- fmt.Errorf("commits: %w", err) + return + } + commits = cs + }() + + wg.Add(1) + go func() { + defer wg.Done() + t, err := gr.TotalCommits() + if err != nil { + errorsCh <- fmt.Errorf("calculating total: %w", err) + return + } + total = t + }() + + wg.Add(1) + go func() { + defer wg.Done() + bs, err := gr.Branches() + if err != nil { + errorsCh <- fmt.Errorf("fetching branches: %w", err) + return + } + branches = bs + }() + + wg.Add(1) + go func() { + defer wg.Done() + ts, err := gr.Tags() + if err != nil { + errorsCh <- fmt.Errorf("fetching tags: %w", err) + return + } + tags = ts + }() + + wg.Add(1) + go func() { + defer wg.Done() + fs, err := gr.FileTree(r.Context(), "") + if err != nil { + errorsCh <- fmt.Errorf("fetching filetree: %w", err) + return + } + files = fs + }() + + wg.Wait() + close(errorsCh) + + // show any errors + for err := range errorsCh { + l.Error("loading repo", "error", err.Error()) writeError(w, err.Error(), http.StatusInternalServerError) return } - tags, err := gr.Tags() - if err != nil { - // Non-fatal, we *should* have at least one branch to show. - l.Warn("getting tags", "error", err.Error()) - } - rtags := []*types.TagReference{} for _, tag := range tags { tr := types.TagReference{ @@ -143,13 +193,6 @@ func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { } } - files, err := gr.FileTree(r.Context(), "") - if err != nil { - writeError(w, err.Error(), http.StatusInternalServerError) - l.Error("file tree", "error", err.Error()) - return - } - if ref == "" { mainBranch, err := gr.FindMainBranch() if err != nil { -- 2.51.2