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.

Index state changes for the activity feed

4d938fe894d56ff29b87fa0f2ebec50a744f2993 · Keenan Nemetz · 9d ago · parent e2a58f3a

Index state changes for the activity feed

The activity feed found closed, reopened and merged events by reading the
last 200 metadata commit subjects on every render: one git process per
repository, so the instance home with N repositories ran N of them. It was
the last derived read still going to git.

- A `state_changes` table is fed by the same refresh: a delta reads the
  commits in its range, a rebuild reads the whole metadata branch. Rows are
  keyed by the commit, so a retried or overlapping refresh cannot duplicate
  an event, and an ordinal keeps two changes in one second in branch order
  (commit times are seconds; a close and a reopen often share one).
- `Store.StateChanges` returns the events newest first; the feed reads it
  and keeps the metadata log as the fallback for a server without an index
  or a failed read.
- `git.Repo.Log` and `CommitsBetween` treat a limit of zero as no limit,
  which the rebuild needs, and `metadata.ParseStateSubject` is exported so
  the index derives the events without a second copy of the format.

The activity page now starts no metadata log; the instance home and the
instance activity page lose one process per visible repository. On the
load harness with three repositories: activity 496 req/s (p50 7 ms),
instance activity 230 req/s (p50 17 ms), home 202 req/s (p50 20 ms).

Schema version 7 rebuilds each repository on its first read after upgrade.

metadata/activity.go +5−2

@@ -31,7 +31,7 @@ func LoadStateChanges(g *git.Repo, n int) ([]StateChange, error) {
31 31 }
32 32 out := make([]StateChange, 0, len(commits)/4)
33 33 for _, c := range commits {
34 kind, id, state, ok := parseStateSubject(c.Subject)
34 kind, id, state, ok := ParseStateSubject(c.Subject)
35 35 if !ok {
36 36 continue
37 37 }
@@ -43,7 +43,10 @@ func LoadStateChanges(g *git.Repo, n int) ([]StateChange, error) {
43 43 return out, nil
44 44 }
45 45
46 func parseStateSubject(subject string) (kind, id, state string, ok bool) {
46 // ParseStateSubject reads the canonical subject SetIssueState and SetRequestState
47 // write. It is exported so the index can derive the same events from the commits
48 // it reads without a second copy of the format.
49 func ParseStateSubject(subject string) (kind, id, state string, ok bool) {
47 50 fields := strings.Fields(subject)
48 51 if len(fields) != 3 {
49 52 return "", "", "", false