Skip to content

Commit 9db8a60

Browse files
zeripathStelios Malathouras
authored and
Stelios Malathouras
committed
Make Requests Processes and create process hierarchy. Associate OpenRepository with context. (go-gitea#17125)
This PR registers requests with the process manager and manages hierarchy within the processes. Git repos are then associated with a context, (usually the request's context) - with sub commands using this context as their base context. Signed-off-by: Andrew Thornton <art27@cantab.net>
1 parent 5fd191f commit 9db8a60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+591
-306
lines changed

Diff for: cmd/hook.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
309309
defer cancel()
310310

311311
// First of all run update-server-info no matter what
312-
if _, err := git.NewCommand("update-server-info").SetParentContext(ctx).Run(); err != nil {
312+
if _, err := git.NewCommandContext(ctx, "update-server-info").Run(); err != nil {
313313
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
314314
}
315315

Diff for: modules/context/repo.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
534534
return
535535
}
536536

537-
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
537+
gitRepo, err := git.OpenRepositoryCtx(ctx, models.RepoPath(userName, repoName))
538538
if err != nil {
539539
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
540540
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
@@ -792,7 +792,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
792792

793793
if ctx.Repo.GitRepo == nil {
794794
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
795-
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
795+
ctx.Repo.GitRepo, err = git.OpenRepositoryCtx(ctx, repoPath)
796796
if err != nil {
797797
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
798798
return

Diff for: modules/git/batch_reader.go

+7-11
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,15 @@ type WriteCloserError interface {
2828
}
2929

3030
// CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
31-
func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()) {
31+
func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
3232
batchStdinReader, batchStdinWriter := io.Pipe()
3333
batchStdoutReader, batchStdoutWriter := io.Pipe()
34-
ctx, ctxCancel := context.WithCancel(DefaultContext)
34+
ctx, ctxCancel := context.WithCancel(ctx)
3535
closed := make(chan struct{})
3636
cancel := func() {
37-
_ = batchStdinReader.Close()
38-
_ = batchStdinWriter.Close()
39-
_ = batchStdoutReader.Close()
40-
_ = batchStdoutWriter.Close()
4137
ctxCancel()
38+
_ = batchStdoutReader.Close()
39+
_ = batchStdinWriter.Close()
4240
<-closed
4341
}
4442

@@ -67,19 +65,17 @@ func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()
6765
}
6866

6967
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
70-
func CatFileBatch(repoPath string) (WriteCloserError, *bufio.Reader, func()) {
68+
func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
7169
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
7270
// so let's create a batch stdin and stdout
7371
batchStdinReader, batchStdinWriter := io.Pipe()
7472
batchStdoutReader, batchStdoutWriter := nio.Pipe(buffer.New(32 * 1024))
75-
ctx, ctxCancel := context.WithCancel(DefaultContext)
73+
ctx, ctxCancel := context.WithCancel(ctx)
7674
closed := make(chan struct{})
7775
cancel := func() {
78-
_ = batchStdinReader.Close()
76+
ctxCancel()
7977
_ = batchStdinWriter.Close()
8078
_ = batchStdoutReader.Close()
81-
_ = batchStdoutWriter.Close()
82-
ctxCancel()
8379
<-closed
8480
}
8581

Diff for: modules/git/blame.go

+19-20
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ type BlamePart struct {
2424

2525
// BlameReader returns part of file blame one by one
2626
type BlameReader struct {
27-
cmd *exec.Cmd
28-
pid int64
29-
output io.ReadCloser
30-
reader *bufio.Reader
31-
lastSha *string
32-
cancel context.CancelFunc
27+
cmd *exec.Cmd
28+
output io.ReadCloser
29+
reader *bufio.Reader
30+
lastSha *string
31+
cancel context.CancelFunc // Cancels the context that this reader runs in
32+
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
3333
}
3434

3535
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
@@ -100,8 +100,8 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
100100

101101
// Close BlameReader - don't run NextPart after invoking that
102102
func (r *BlameReader) Close() error {
103-
defer process.GetManager().Remove(r.pid)
104-
r.cancel()
103+
defer r.finished() // Only remove the process from the process table when the underlying command is closed
104+
r.cancel() // However, first cancel our own context early
105105

106106
_ = r.output.Close()
107107

@@ -114,7 +114,7 @@ func (r *BlameReader) Close() error {
114114

115115
// CreateBlameReader creates reader for given repository, commit and file
116116
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
117-
gitRepo, err := OpenRepository(repoPath)
117+
gitRepo, err := OpenRepositoryCtx(ctx, repoPath)
118118
if err != nil {
119119
return nil, err
120120
}
@@ -125,32 +125,31 @@ func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*B
125125

126126
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
127127
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
128-
ctx, cancel := context.WithCancel(ctx)
128+
ctx, cancel, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("GetBlame [repo_path: %s]", dir))
129+
129130
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
130131
cmd.Dir = dir
131132
cmd.Stderr = os.Stderr
132133

133134
stdout, err := cmd.StdoutPipe()
134135
if err != nil {
135-
defer cancel()
136+
defer finished()
136137
return nil, fmt.Errorf("StdoutPipe: %v", err)
137138
}
138139

139140
if err = cmd.Start(); err != nil {
140-
defer cancel()
141+
defer finished()
142+
_ = stdout.Close()
141143
return nil, fmt.Errorf("Start: %v", err)
142144
}
143145

144-
pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel)
145-
146146
reader := bufio.NewReader(stdout)
147147

148148
return &BlameReader{
149-
cmd,
150-
pid,
151-
stdout,
152-
reader,
153-
nil,
154-
cancel,
149+
cmd: cmd,
150+
output: stdout,
151+
reader: reader,
152+
cancel: cancel,
153+
finished: finished,
155154
}, nil
156155
}

Diff for: modules/git/blob_nogogit.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Blob struct {
2929
// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
3030
// Calling the Close function on the result will discard all unread output.
3131
func (b *Blob) DataAsync() (io.ReadCloser, error) {
32-
wr, rd, cancel := b.repo.CatFileBatch()
32+
wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx)
3333

3434
_, err := wr.Write([]byte(b.ID.String() + "\n"))
3535
if err != nil {
@@ -67,7 +67,7 @@ func (b *Blob) Size() int64 {
6767
return b.size
6868
}
6969

70-
wr, rd, cancel := b.repo.CatFileBatchCheck()
70+
wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx)
7171
defer cancel()
7272
_, err := wr.Write([]byte(b.ID.String() + "\n"))
7373
if err != nil {

Diff for: modules/git/command.go

+7-9
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ func (c *Command) RunWithContext(rc *RunContext) error {
143143
log.Debug("%s: %v", rc.Dir, c)
144144
}
145145

146-
ctx, cancel := context.WithTimeout(c.parentContext, rc.Timeout)
147-
defer cancel()
146+
desc := c.desc
147+
if desc == "" {
148+
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir)
149+
}
150+
151+
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
152+
defer finished()
148153

149154
cmd := exec.CommandContext(ctx, c.name, c.args...)
150155
if rc.Env == nil {
@@ -172,13 +177,6 @@ func (c *Command) RunWithContext(rc *RunContext) error {
172177
return err
173178
}
174179

175-
desc := c.desc
176-
if desc == "" {
177-
desc = fmt.Sprintf("%s %s %s [repo_path: %s]", GitExecutable, c.name, strings.Join(c.args, " "), rc.Dir)
178-
}
179-
pid := process.GetManager().Add(desc, cancel)
180-
defer process.GetManager().Remove(pid)
181-
182180
if rc.PipelineFunc != nil {
183181
err := rc.PipelineFunc(ctx, cancel)
184182
if err != nil {

Diff for: modules/git/commit_info_nogogit.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
100100
}
101101

102102
func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
103-
wr, rd, cancel := cache.repo.CatFileBatch()
103+
wr, rd, cancel := cache.repo.CatFileBatch(ctx)
104104
defer cancel()
105105

106106
var unHitEntryPaths []string
@@ -129,7 +129,7 @@ func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, commit *
129129
return nil, err
130130
}
131131

132-
batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch()
132+
batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch(ctx)
133133
defer cancel()
134134

135135
commitsMap := map[string]*Commit{}

Diff for: modules/git/diff.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
5656
fileArgs = append(fileArgs, "--", file)
5757
}
5858
// FIXME: graceful: These commands should have a timeout
59-
ctx, cancel := context.WithCancel(DefaultContext)
60-
defer cancel()
59+
ctx, _, finished := process.GetManager().AddContext(repo.Ctx, fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path))
60+
defer finished()
6161

6262
var cmd *exec.Cmd
6363
switch diffType {
@@ -90,8 +90,6 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
9090
cmd.Dir = repo.Path
9191
cmd.Stdout = writer
9292
cmd.Stderr = stderr
93-
pid := process.GetManager().Add(fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path), cancel)
94-
defer process.GetManager().Remove(pid)
9593

9694
if err = cmd.Run(); err != nil {
9795
return fmt.Errorf("Run: %v - %s", err, stderr)

Diff for: modules/git/pipeline/lfs_nogogit.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
6363

6464
// Next feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
6565
// so let's create a batch stdin and stdout
66-
batchStdinWriter, batchReader, cancel := repo.CatFileBatch()
66+
batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
6767
defer cancel()
6868

6969
// We'll use a scanner for the revList because it's simpler than a bufio.Reader

Diff for: modules/git/remote.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44

55
package git
66

7-
import "net/url"
7+
import (
8+
"context"
9+
"net/url"
10+
)
811

912
// GetRemoteAddress returns the url of a specific remote of the repository.
10-
func GetRemoteAddress(repoPath, remoteName string) (*url.URL, error) {
13+
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) {
1114
err := LoadGitVersion()
1215
if err != nil {
1316
return nil, err
1417
}
1518
var cmd *Command
1619
if CheckGitVersionAtLeast("2.7") == nil {
17-
cmd = NewCommand("remote", "get-url", remoteName)
20+
cmd = NewCommandContext(ctx, "remote", "get-url", remoteName)
1821
} else {
19-
cmd = NewCommand("config", "--get", "remote."+remoteName+".url")
22+
cmd = NewCommandContext(ctx, "config", "--get", "remote."+remoteName+".url")
2023
}
2124

2225
result, err := cmd.RunInDir(repoPath)

Diff for: modules/git/repo.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ type PushOptions struct {
211211
}
212212

213213
// Push pushs local commits to given remote branch.
214-
func Push(repoPath string, opts PushOptions) error {
215-
cmd := NewCommand("push")
214+
func Push(ctx context.Context, repoPath string, opts PushOptions) error {
215+
cmd := NewCommandContext(ctx, "push")
216216
if opts.Force {
217217
cmd.AddArguments("-f")
218218
}

Diff for: modules/git/repo_attribute.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
7474
}
7575
}
7676

77-
cmd := NewCommand(cmdArgs...)
77+
cmd := NewCommandContext(repo.Ctx, cmdArgs...)
7878

7979
if err := cmd.RunInDirTimeoutEnvPipeline(env, -1, repo.Path, stdOut, stdErr); err != nil {
8080
return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String())

Diff for: modules/git/repo_base_gogit.go

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package git
1010

1111
import (
12+
"context"
1213
"errors"
1314
"path/filepath"
1415

@@ -30,10 +31,17 @@ type Repository struct {
3031
gogitRepo *gogit.Repository
3132
gogitStorage *filesystem.Storage
3233
gpgSettings *GPGSettings
34+
35+
Ctx context.Context
3336
}
3437

3538
// OpenRepository opens the repository at the given path.
3639
func OpenRepository(repoPath string) (*Repository, error) {
40+
return OpenRepositoryCtx(DefaultContext, repoPath)
41+
}
42+
43+
// OpenRepositoryCtx opens the repository at the given path within the context.Context
44+
func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error) {
3745
repoPath, err := filepath.Abs(repoPath)
3846
if err != nil {
3947
return nil, err
@@ -60,6 +68,7 @@ func OpenRepository(repoPath string) (*Repository, error) {
6068
gogitRepo: gogitRepo,
6169
gogitStorage: storage,
6270
tagCache: newObjectCache(),
71+
Ctx: ctx,
6372
}, nil
6473
}
6574

Diff for: modules/git/repo_base_nogogit.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,17 @@ type Repository struct {
3232
checkCancel context.CancelFunc
3333
checkReader *bufio.Reader
3434
checkWriter WriteCloserError
35+
36+
Ctx context.Context
3537
}
3638

3739
// OpenRepository opens the repository at the given path.
3840
func OpenRepository(repoPath string) (*Repository, error) {
41+
return OpenRepositoryCtx(DefaultContext, repoPath)
42+
}
43+
44+
// OpenRepositoryCtx opens the repository at the given path with the provided context.
45+
func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error) {
3946
repoPath, err := filepath.Abs(repoPath)
4047
if err != nil {
4148
return nil, err
@@ -46,28 +53,29 @@ func OpenRepository(repoPath string) (*Repository, error) {
4653
repo := &Repository{
4754
Path: repoPath,
4855
tagCache: newObjectCache(),
56+
Ctx: ctx,
4957
}
5058

51-
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(repoPath)
52-
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(repo.Path)
59+
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
60+
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
5361

5462
return repo, nil
5563
}
5664

5765
// CatFileBatch obtains a CatFileBatch for this repository
58-
func (repo *Repository) CatFileBatch() (WriteCloserError, *bufio.Reader, func()) {
66+
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
5967
if repo.batchCancel == nil || repo.batchReader.Buffered() > 0 {
6068
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
61-
return CatFileBatch(repo.Path)
69+
return CatFileBatch(ctx, repo.Path)
6270
}
6371
return repo.batchWriter, repo.batchReader, func() {}
6472
}
6573

6674
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
67-
func (repo *Repository) CatFileBatchCheck() (WriteCloserError, *bufio.Reader, func()) {
75+
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
6876
if repo.checkCancel == nil || repo.checkReader.Buffered() > 0 {
6977
log.Debug("Opening temporary cat file batch-check: %s", repo.Path)
70-
return CatFileBatchCheck(repo.Path)
78+
return CatFileBatchCheck(ctx, repo.Path)
7179
}
7280
return repo.checkWriter, repo.checkReader, func() {}
7381
}

Diff for: modules/git/repo_blame.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import "fmt"
88

99
// FileBlame return the Blame object of file
1010
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
11-
return NewCommand("blame", "--root", "--", file).RunInDirBytes(path)
11+
return NewCommandContext(repo.Ctx, "blame", "--root", "--", file).RunInDirBytes(path)
1212
}
1313

1414
// LineBlame returns the latest commit at the given line
1515
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
16-
res, err := NewCommand("blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
16+
res, err := NewCommandContext(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
1717
if err != nil {
1818
return nil, err
1919
}

0 commit comments

Comments
 (0)