1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package gitcli
4
5import (
6 "context"
7 "sort"
8
9 "bnema.dev/ermite/internal/domain"
10)
11
12// CatFilePIDs returns the process ids of the live long-lived cat-file
13// processes, for the tests of the pool.
14func (g *Git) CatFilePIDs() []int {
15 g.cat.mu.Lock()
16 defer g.cat.mu.Unlock()
17 var pids []int
18 for _, procs := range g.cat.procs {
19 for _, cp := range procs {
20 pids = append(pids, cp.cmd.Process.Pid)
21 }
22 }
23 sort.Ints(pids)
24 return pids
25}
26
27// BlobStreams returns the number of blob streams that are open.
28func (g *Git) BlobStreams() int {
29 g.cat.mu.Lock()
30 defer g.cat.mu.Unlock()
31 return len(g.cat.streams)
32}
33
34// BlobStreamPIDs returns the process ids of the open blob streams.
35func (g *Git) BlobStreamPIDs() []int {
36 g.cat.mu.Lock()
37 defer g.cat.mu.Unlock()
38 var pids []int
39 for s := range g.cat.streams {
40 pids = append(pids, s.cmd.Process.Pid)
41 }
42 return pids
43}
44
45// FireIdleTimers runs, for every idle cat-file process, what its idle timer
46// would do now, so that tests do not wait for real time.
47func (g *Git) FireIdleTimers() {
48 g.cat.mu.Lock()
49 type armed struct {
50 cp *catProc
51 gen uint64
52 }
53 var all []armed
54 for _, procs := range g.cat.procs {
55 for _, cp := range procs {
56 all = append(all, armed{cp, cp.gen})
57 }
58 }
59 g.cat.mu.Unlock()
60 for _, a := range all {
61 g.cat.expire(a.cp, a.gen)
62 }
63}
64
65// FireStaleIdleTimers runs what the idle timers armed before the last use of
66// each process would do: nothing, since the process was used since.
67func (g *Git) FireStaleIdleTimers() {
68 g.cat.mu.Lock()
69 type armed struct {
70 cp *catProc
71 gen uint64
72 }
73 var all []armed
74 for _, procs := range g.cat.procs {
75 for _, cp := range procs {
76 all = append(all, armed{cp, cp.gen - 1})
77 }
78 }
79 g.cat.mu.Unlock()
80 for _, a := range all {
81 g.cat.expire(a.cp, a.gen)
82 }
83}
84
85// ExecSlots returns the size of the one-shot process semaphore and how many
86// slots are taken.
87func (g *Git) ExecSlots() (size, taken int) { return cap(g.exec), len(g.exec) }
88
89// HoldCatFile runs fn while holding a cat-file process of the repository, as
90// a request in flight would.
91func (g *Git) HoldCatFile(ctx context.Context, repo domain.RepoName, fn func()) error {
92 dir, err := g.repoDir(repo)
93 if err != nil {
94 return err
95 }
96 return g.cat.do(ctx, dir, func(*catConn) error { fn(); return nil })
97}
98
99// CatFileWaiting returns the number of requests that wait for a cat-file
100// process.
101func (g *Git) CatFileWaiting() int {
102 g.cat.mu.Lock()
103 defer g.cat.mu.Unlock()
104 n := 0
105 for _, q := range g.cat.waiters {
106 n += len(q)
107 }
108 return n
109}