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 metadata tree in one git call

5cecc6183eadab8147d11438abc64d54c4b0a78f · Keenan Nemetz · 10d ago · parent 5fce878d

Read the metadata tree in one git call

The issue and change-request loaders read the metadata tree with one
`git cat-file` per file, so a page render cost as many processes as the
branch had issues and comments. On a repository with 30 change requests
the overview paid 114 git invocations and 98 ms; the requests list paid
72 and 90 ms.

Read every listed blob through a single `cat-file --batch`. The push
validators share the same helper, so pre-receive stops paying one
process per file as well.

The metadata branch is the whole source of truth for issues and changes,
so this is the read path that grows with use. Nothing about the format or
the size limits changes: an oversized file is still refused before any of
it is allocated.

metadata/releases.go +13−6

@@ -100,6 +100,7 @@ func ReleaseProblems(g *git.Repo, commit string) []string {
100 100 return []string{fmt.Sprintf("cannot read the metadata tree: %v", err)}
101 101 }
102 102 var problems []string
103 var paths, shas []string
103 104 for _, e := range blobs {
104 105 if !strings.HasPrefix(e.Name, ReleasesDir+"/") {
105 106 continue
@@ -119,13 +120,19 @@ func ReleaseProblems(g *git.Repo, commit string) []string {
119 120 problems = append(problems, e.Name+": "+err.Error())
120 121 continue
121 122 }
122 data, err := g.BlobBySHA(e.SHA)
123 if err != nil {
124 return append(problems, fmt.Sprintf("cannot read %s: %v", e.Name, err))
125 }
126 if _, ok := lfs.ParsePointer(data); !ok {
123 paths = append(paths, e.Name)
124 shas = append(shas, e.SHA)
125 }
126 files, err := readBlobs(g, paths, shas)
127 if err != nil {
128 return append(problems, err.Error())
129 }
130 // The pointers are read together: a tree with many artifacts is one call, not
131 // one process per file.
132 for _, path := range paths {
133 if _, ok := lfs.ParsePointer([]byte(files[path])); !ok {
127 134 problems = append(problems, fmt.Sprintf(
128 "%s: an artifact must be a git-lfs pointer; write it with vole release attach", e.Name))
135 "%s: an artifact must be a git-lfs pointer; write it with vole release attach", path))
129 136 }
130 137 }
131 138 return problems