Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Read one request, or one commit, instead of resolving twice

c9202f7f0ba5904af798e7f55bb91079aa774bf5 · Keenan Nemetz · 10d ago · parent 73ec800b

Read one request, or one commit, instead of resolving twice

The index and the change page both paid for reads they did not need:

- GetRequest read every request on the branch to return one. It now reads
  that request's files.
- The index resolves the metadata commit once and then handed the ref to
  loaders that resolved it again. LoadIssuesAt, LoadNumbersAt and
  LoadRequestAt take the commit they were given.
- Release artifacts get a batched loader: one tree listing and one
  cat-file for the whole set, instead of one process per file per tag.

These are the loaders the index needs to derive its rows from one commit
at a time.

metadata/releases.go +46

@@ -157,3 +157,49 @@ func WriteReleasePointers(g *git.Repo, ref, tag string, arts []Artifact, message
157 157 }, message, author)
158 158 return err
159 159 }
160
161 // LoadArtifactsAt reads every release artifact on the metadata branch at commit,
162 // keyed by tag. It is one tree listing and one blob read for the whole set: a
163 // release with fifty files is not fifty processes, and the index reads the set to
164 // answer the artifact list without touching git.
165 func LoadArtifactsAt(g *git.Repo, commit string) (map[string][]Artifact, error) {
166 out := map[string][]Artifact{}
167 if commit == "" {
168 return out, nil
169 }
170 entries, err := g.LsTreeR(commit)
171 if err != nil {
172 return nil, err
173 }
174 var paths, shas []string
175 for _, e := range entries {
176 if e.Type != "blob" || !strings.HasPrefix(e.Name, ReleasesDir+"/") {
177 continue
178 }
179 // releases/<tag>/<name>; anything deeper is not an artifact.
180 if parts := strings.Split(e.Name, "/"); len(parts) != 3 {
181 continue
182 }
183 paths = append(paths, e.Name)
184 shas = append(shas, e.SHA)
185 }
186 files, err := readBlobs(g, paths, shas)
187 if err != nil {
188 return nil, err
189 }
190 for _, path := range paths {
191 parts := strings.Split(path, "/")
192 p, ok := lfs.ParsePointer([]byte(files[path]))
193 if !ok {
194 // A file that is not a pointer is not an artifact; the release
195 // validator refuses those at push time, and a reader skips one a
196 // human put there by hand.
197 continue
198 }
199 out[parts[1]] = append(out[parts[1]], Artifact{Name: parts[2], OID: p.OID, Size: p.Size})
200 }
201 for _, list := range out {
202 sort.Slice(list, func(i, j int) bool { return list[i].Name < list[j].Name })
203 }
204 return out, nil
205 }