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 the change list and its counts from the index

b739915c0941be0f97cef8b96fd28d8f4c4685ae · Keenan Nemetz · 10d ago · parent 7f547ca3

Read the change list and its counts from the index

The header, the change list and the release artifact list now come from
the derived rows instead of the metadata branch:

- The header's open-changes badge is one COUNT, so a page that only shows
  the badge no longer reads `ls-tree`, `batch-check` and `batch` on every
  view. That is the read that grew with the repository's issues and
  comments.
- The change list, its state chips and its approval counts are queries.
  An approval still only counts when it names the request's current head
  and base, and eligibility is still the ACL's decision, so a stale
  approval is shown as history exactly as before.
- The release page's artifact list is the indexed pointer set.
- A change page reads its one request rather than every request; the
  conversation page keeps reading git, so the record it renders is
  authoritative rather than a copy.

On the fixture (40 files, 30 issues, 30 changes), git calls per page:

  issues list    5 -> 2        change list   6 -> 3
  releases       6 -> 3        commits       7 -> 4
  overview      19 -> 6 (repeat)  code       12 -> 9
  change view   14 -> 12

The remaining calls are the one `rev-parse` the refresh needs, the branch
and tree reads the page itself shows, and the detail pages' own git read.

server/web/releases.go +19−6

@@ -16,9 +16,25 @@ import (
16 16 "time"
17 17
18 18 "github.com/rodent-software/vole/core/git"
19 "github.com/rodent-software/vole/forge/repo"
19 20 "github.com/rodent-software/vole/metadata"
20 21 )
21 22
23 // releaseArtifacts returns the files attached to a tag. The index answers from
24 // the metadata branch it was built from; a server without an index, or one whose
25 // refresh failed, reads the pointers directly.
26 func (w *Web) releaseArtifacts(r *http.Request, m *repo.Meta, tag string) []metadata.Artifact {
27 if w.Index != nil {
28 if err := w.ensureIndex(memoOf(r), m); err == nil {
29 if list, err := w.Index.Artifacts(m.ID, tag); err == nil {
30 return list
31 }
32 }
33 }
34 list, _ := metadata.ListReleaseArtifacts(m.Git(), tag)
35 return list
36 }
37
22 38 // archiveConc bounds concurrent archives. Plain tar streams at ~1 GiB/s while gzip
23 39 // is single-threaded per stream, and eight concurrent gzipped archives of a 100 MiB
24 40 // tree cost 13 s of CPU. Both spawn git and stream for as long as the client reads,
@@ -82,7 +98,8 @@ func (w *Web) ReleaseView(rw http.ResponseWriter, r *http.Request) {
82 98
83 99 // The artifact list is the pointer directory on the metadata branch, not a
84 100 // stored manifest: the same pointers the sweep marks and the hook validates.
85 artifacts, _ := metadata.ListReleaseArtifacts(g, t.Name)
101 // The index holds the same set, read from the branch it was built from.
102 artifacts := w.releaseArtifacts(r, m, t.Name)
86 103 var artifactBytes int64
87 104 for _, a := range artifacts {
88 105 artifactBytes += a.Size
@@ -148,11 +165,7 @@ func (w *Web) ReleaseArtifact(rw http.ResponseWriter, r *http.Request) {
148 165 return
149 166 }
150 167 name := r.PathValue("artifact")
151 artifacts, err := metadata.ListReleaseArtifacts(g, t.Name)
152 if err != nil {
153 w.serverError(rw, r, "cannot read that release: "+err.Error())
154 return
155 }
168 artifacts := w.releaseArtifacts(r, m, t.Name)
156 169 var art *metadata.Artifact
157 170 for i := range artifacts {
158 171 if artifacts[i].Name == name {