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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

Read what a page needs once per request

5d440e37f16d06790ce87e2f8b7dcc7d9bf0532c · Keenan Nemetz · 10d ago · parent 34cbc99f

Read what a page needs once per request

A page and its header are built from the same facts, and each of them was
read separately: the repository (twice, each resolving HEAD's branch with
a git call), the open change requests (once for the header's count, once
for the page), and a change request looked up by reading every request.
On a repository with 30 change requests the overview paid 21 git
invocations after the metadata batching, and the requests list still paid
8.

Give each read request one memo, installed by the middleware, and have the
handlers and the header read through it. It lasts one request and covers
reads only: a request that writes metadata gets no memo, so there is no
TTL, no cross-request cache, and no invalidation protocol, and a push is
still visible on the next page load.

The header now takes the page it is rendering (`nav .Page "issues"`)
instead of six fields the view already carries, which is also why the memo
can reach it at all. Templates are unchanged in what they output.

server/web/writes.go +6−6

@@ -173,7 +173,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
173 173 return
174 174 }
175 175 id := r.PathValue("id")
176 req, err := metadata.GetRequest(m.Git(), id)
176 req, err := w.requestAt(memoOf(r), m, id)
177 177 if err != nil {
178 178 w.notFound(rw, r)
179 179 return
@@ -208,7 +208,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
208 208 w.Logger("web: approval left the request tree invalid: %v", problems)
209 209 }
210 210 if htmxRequest(r) {
211 updated, err := metadata.GetRequest(m.Git(), id)
211 updated, err := w.requestAt(memoOf(r), m, id)
212 212 if err != nil {
213 213 w.render(rw, "request_live_write", w.requestLiveWrite(r, m, req, err.Error()), 0)
214 214 return
@@ -339,7 +339,7 @@ func (w *Web) ChangeRequestState(rw http.ResponseWriter, r *http.Request) {
339 339 }
340 340 m := ctx.Repo
341 341 id := r.PathValue("id")
342 req, err := metadata.GetRequest(m.Git(), id)
342 req, err := w.requestAt(memoOf(r), m, id)
343 343 if err != nil {
344 344 w.notFound(rw, r)
345 345 return
@@ -379,7 +379,7 @@ func (w *Web) UpdateRequestTarget(rw http.ResponseWriter, r *http.Request) {
379 379 }
380 380 m := ctx.Repo
381 381 id := r.PathValue("id")
382 req, err := metadata.GetRequest(m.Git(), id)
382 req, err := w.requestAt(memoOf(r), m, id)
383 383 if err != nil {
384 384 w.notFound(rw, r)
385 385 return
@@ -460,7 +460,7 @@ func (w *Web) UpdateRequestIssues(rw http.ResponseWriter, r *http.Request) {
460 460 }
461 461 m := ctx.Repo
462 462 id := r.PathValue("id")
463 req, err := metadata.GetRequest(m.Git(), id)
463 req, err := w.requestAt(memoOf(r), m, id)
464 464 if err != nil {
465 465 w.notFound(rw, r)
466 466 return
@@ -566,7 +566,7 @@ func (w *Web) MergeRequest(rw http.ResponseWriter, r *http.Request) {
566 566 return
567 567 }
568 568 id := r.PathValue("id")
569 req, err := metadata.GetRequest(m.Git(), id)
569 req, err := w.requestAt(memoOf(r), m, id)
570 570 if err != nil {
571 571 w.notFound(rw, r)
572 572 return