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 | |