261017.12 · 7d3aa432cb8e6ec51aa21d24e3344d38f6d68c48
Git answers are cached within a memory budget
Most pages ran two git subprocesses, about 3 ms of a 3.3 ms doc page. The server now keeps which repo each directory lies in and the histories it shows, and reads HEAD from the repo's files. A history is kept under the commit HEAD names, so a new commit misses the cache. A doc page renders in about 0.6 ms on a repeat view.
--cache sets the memory for it, default 32M; 0 caches nothing.
reading declarations
Changes to cache_test.go. All files
@@ -0,0 +1,72 @@+package main++import (+ "context"+ "os"+ "path/filepath"+ "testing"+)++// The cache drops the least recently used value past its budget, and a+// budget of 0 keeps nothing.+func TestCacheBudget(t *testing.T) {+ c := newCache(25) // two of the 10-byte entries, keys included+ c.put("a", 1, 9)+ c.put("b", 2, 9)+ c.get("a")+ c.put("c", 3, 9)+ if _, ok := c.get("b"); ok {+ t.Error("b, the least recently used, was kept")+ }+ for _, k := range []string{"a", "c"} {+ if _, ok := c.get(k); !ok {+ t.Errorf("%s was dropped", k)+ }+ }+ none := newCache(0)+ none.put("a", 1, 0)+ if _, ok := none.get("a"); ok {+ t.Error("a budget of 0 kept a value")+ }+}++func TestParseSize(t *testing.T) {+ for s, want := range map[string]int64{"0": 0, "512": 512, "64K": 64 << 10, "32M": 32 << 20, "1g": 1 << 30} {+ if got, err := parseSize(s); err != nil || got != want {+ t.Errorf("%s: %d %v, want %d", s, got, err, want)+ }+ }+ for _, s := range []string{"", "M", "lots", "-1", "1T"} {+ if _, err := parseSize(s); err == nil {+ t.Errorf("%q: no error", s)+ }+ }+}++// HEAD read from the repo's files follows each commit, so a cached+// history never outlives it; a repo made in a directory that had none is+// found.+func TestCachedHeadFollowsCommits(t *testing.T) {+ needGit(t)+ s, dir := repoTree(t)+ tr := s.list()[0]+ ctx := context.Background()+ _, first := tr.gitHead("index.md")+ before := tr.lastCommit(ctx, "index.md")+ os.WriteFile(filepath.Join(dir, "index.md"), []byte("# Changed\n"), 0o644)+ commitAll(t, dir, "Change the index")+ _, second := tr.gitHead("index.md")+ after := tr.lastCommit(ctx, "index.md")+ if first == second || before == nil || after == nil || after.subject != "Change the index" {+ t.Errorf("HEAD %q then %q; last commit %v then %v", first, second, before, after)+ }++ plain := t.TempDir()+ if r := repoAt(ctx, plain); r.complaint == "" {+ t.Fatalf("%s is in a repo: %+v", plain, r)+ }+ git(ctx, plain, "init", "-q")+ if r := repoAt(ctx, plain); r.complaint != "" {+ t.Errorf("new repo not found: %s", r.complaint)+ }+}