forked from tangled.org/core
Monorepo for Tangled

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 <me@oppi.li>

Changed files
+71 -28
knotserver
+71 -28
knotserver/routes.go
··· 17 17 "path/filepath" 18 18 "strconv" 19 19 "strings" 20 + "sync" 20 21 21 22 securejoin "github.com/cyphar/filepath-securejoin" 22 23 "github.com/gliderlabs/ssh" ··· 88 89 } 89 90 } 90 91 91 - commits, err := gr.Commits(0, 60) // a good preview of commits in this repo 92 - if err != nil { 93 - writeError(w, err.Error(), http.StatusInternalServerError) 94 - l.Error("fetching commits", "error", err.Error()) 95 - return 96 - } 92 + var ( 93 + commits []*object.Commit 94 + total int 95 + branches []types.Branch 96 + files []types.NiceTree 97 + tags []*git.TagReference 98 + ) 99 + 100 + var wg sync.WaitGroup 101 + errorsCh := make(chan error, 5) 102 + 103 + wg.Add(1) 104 + go func() { 105 + defer wg.Done() 106 + cs, err := gr.Commits(0, 60) 107 + if err != nil { 108 + errorsCh <- fmt.Errorf("commits: %w", err) 109 + return 110 + } 111 + commits = cs 112 + }() 113 + 114 + wg.Add(1) 115 + go func() { 116 + defer wg.Done() 117 + t, err := gr.TotalCommits() 118 + if err != nil { 119 + errorsCh <- fmt.Errorf("calculating total: %w", err) 120 + return 121 + } 122 + total = t 123 + }() 124 + 125 + wg.Add(1) 126 + go func() { 127 + defer wg.Done() 128 + bs, err := gr.Branches() 129 + if err != nil { 130 + errorsCh <- fmt.Errorf("fetching branches: %w", err) 131 + return 132 + } 133 + branches = bs 134 + }() 135 + 136 + wg.Add(1) 137 + go func() { 138 + defer wg.Done() 139 + ts, err := gr.Tags() 140 + if err != nil { 141 + errorsCh <- fmt.Errorf("fetching tags: %w", err) 142 + return 143 + } 144 + tags = ts 145 + }() 146 + 147 + wg.Add(1) 148 + go func() { 149 + defer wg.Done() 150 + fs, err := gr.FileTree(r.Context(), "") 151 + if err != nil { 152 + errorsCh <- fmt.Errorf("fetching filetree: %w", err) 153 + return 154 + } 155 + files = fs 156 + }() 97 157 98 - total, err := gr.TotalCommits() 99 - if err != nil { 100 - writeError(w, err.Error(), http.StatusInternalServerError) 101 - l.Error("fetching commits", "error", err.Error()) 102 - return 103 - } 158 + wg.Wait() 159 + close(errorsCh) 104 160 105 - branches, err := gr.Branches() 106 - if err != nil { 107 - l.Error("getting branches", "error", err.Error()) 161 + // show any errors 162 + for err := range errorsCh { 163 + l.Error("loading repo", "error", err.Error()) 108 164 writeError(w, err.Error(), http.StatusInternalServerError) 109 165 return 110 - } 111 - 112 - tags, err := gr.Tags() 113 - if err != nil { 114 - // Non-fatal, we *should* have at least one branch to show. 115 - l.Warn("getting tags", "error", err.Error()) 116 166 } 117 167 118 168 rtags := []*types.TagReference{} ··· 141 191 readmeContent = string(content) 142 192 readmeFile = readme 143 193 } 144 - } 145 - 146 - files, err := gr.FileTree(r.Context(), "") 147 - if err != nil { 148 - writeError(w, err.Error(), http.StatusInternalServerError) 149 - l.Error("file tree", "error", err.Error()) 150 - return 151 194 } 152 195 153 196 if ref == "" {