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.

forge/index/refresh.go +23

@@ -10,6 +10,7 @@ package index
10 10 import (
11 11 "strings"
12 12
13 "github.com/rodent-software/vole/core/git"
13 14 "github.com/rodent-software/vole/forge/repo"
14 15 "github.com/rodent-software/vole/metadata"
15 16 )
@@ -84,6 +85,15 @@ func (s *Store) IndexRepo(m *repo.Meta) error {
84 85 if err != nil {
85 86 return err
86 87 }
88 // State changes are the metadata commits' subjects, so a rebuild reads the
89 // whole branch and takes every one of them. A repository that never pushed
90 // metadata has no branch to read, which is not an error.
91 var stateCommits []git.Commit
92 if commit != "" {
93 if stateCommits, err = g.Log(metadata.Ref, 0); err != nil {
94 return err
95 }
96 }
87 97
88 98 tx, err := s.db.Begin()
89 99 if err != nil {
@@ -121,6 +131,9 @@ func (s *Store) IndexRepo(m *repo.Meta) error {
121 131 if err := replaceArtifacts(tx, m.ID, artifacts); err != nil {
122 132 return err
123 133 }
134 if err := insertStateChanges(tx, m.ID, stateCommits); err != nil {
135 return err
136 }
124 137 if _, err := tx.Exec(`UPDATE repos SET issues_sha=? WHERE id=?`, commit, m.ID); err != nil {
125 138 return err
126 139 }
@@ -187,6 +200,12 @@ func (s *Store) indexFrom(m *repo.Meta, from, to string) error {
187 200 // Numbers are historical: a deleted entity keeps its number, and a creation
188 201 // that was deleted again inside the range still consumed one. The additions
189 202 // are therefore taken from the commit range, not from the current tree.
203 // The commits in the range carry the state changes: a closed issue is a
204 // subject, not a file to diff.
205 stateCommits, err := g.CommitsBetween(from, to, 0)
206 if err != nil {
207 return err
208 }
190 209 groups, err := g.AddedPathsPerCommit(from+".."+to, metadata.IssuesDir, metadata.RequestsDir)
191 210 if err != nil {
192 211 return err
@@ -240,6 +259,9 @@ func (s *Store) indexFrom(m *repo.Meta, from, to string) error {
240 259 return err
241 260 }
242 261 }
262 if err := insertStateChanges(tx, m.ID, stateCommits); err != nil {
263 return err
264 }
243 265 if err := addNumbers(tx, m.ID, metadata.Additions(groups)); err != nil {
244 266 return err
245 267 }
@@ -262,6 +284,7 @@ func deleteRepoRows(tx execer, repoID string) error {
262 284 `DELETE FROM request_approvals WHERE repo_id=?`,
263 285 `DELETE FROM comments WHERE repo_id=?`,
264 286 `DELETE FROM artifacts WHERE repo_id=?`,
287 `DELETE FROM state_changes WHERE repo_id=?`,
265 288 `DELETE FROM entity_numbers WHERE repo_id=?`,
266 289 } {
267 290 if _, err := tx.Exec(q, repoID); err != nil {