mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 00:59:35 +00:00
chore: still keep ctx in git.Repository struct for cat-file batch command (#38684)
Unfortunately, we can't completely remove the ctx from git.Repository, because the CatFileBatch still heavily depends on a parent context. If we remove the Repository ctx, the CatFileBatch will become a mess and create a lot of unnecessary git processes. http://localhost:3000/-/admin/monitor/perftrace * Before: open a repo home, dozens of git processes (duplicate cat-file) * After: only a few (no duplicate cat-file)
This commit is contained in:
+19
-19
@@ -32,7 +32,15 @@ type RepositoryBase struct {
|
||||
tagCache *ObjectCache[*Tag]
|
||||
objectFormatCache ObjectFormat
|
||||
|
||||
mu sync.Mutex
|
||||
mu sync.Mutex
|
||||
// Unfortunately, we can't completely remove the ctx, because CatFileBatch still heavily depends on a parent context.
|
||||
// If we remove the ctx, then CatFileBatch's process management will become a mess and create a lot of unnecessary git processes.
|
||||
// ref: http://localhost:3000/-/admin/monitor/perftrace
|
||||
// The root problem is that some functions like "GetCommit" need to use CatFileBatch,
|
||||
// if CatFileBatch accepts its own ctx, then every sub-context needs a git process.
|
||||
// e.g.: open a repo home, dozens of git processes (duplicate cat-file)
|
||||
// ATTENTION: this ctx is for cached cat-file process only, don't use it for other purposes.
|
||||
catFileBatchCtx context.Context
|
||||
catFileBatchCloser CatFileBatchCloser
|
||||
catFileBatchInUse bool
|
||||
}
|
||||
@@ -51,7 +59,7 @@ func (repo *Repository) LogString() string {
|
||||
return repo.repoFacade.LogString()
|
||||
}
|
||||
|
||||
func OpenRepository(repo RepositoryFacade) (*Repository, error) {
|
||||
func OpenRepository(catFileBatchCtx context.Context, repo RepositoryFacade) (*Repository, error) {
|
||||
repoPath := gitrepo.RepoLocalPath(repo)
|
||||
exist, err := util.IsDir(repoPath)
|
||||
if err != nil {
|
||||
@@ -61,7 +69,7 @@ func OpenRepository(repo RepositoryFacade) (*Repository, error) {
|
||||
return nil, util.NewNotExistErrorf("no such file or directory")
|
||||
}
|
||||
gitRepo := &Repository{
|
||||
RepositoryBase: RepositoryBase{tagCache: newObjectCache[*Tag](), repoFacade: repo},
|
||||
RepositoryBase: RepositoryBase{tagCache: newObjectCache[*Tag](), repoFacade: repo, catFileBatchCtx: catFileBatchCtx},
|
||||
}
|
||||
if err = openRepositoryInternal(gitRepo); err != nil {
|
||||
return nil, err
|
||||
@@ -71,14 +79,14 @@ func OpenRepository(repo RepositoryFacade) (*Repository, error) {
|
||||
|
||||
// OpenRepositoryLocal opens a local repository that is not managed by Gitea
|
||||
// If the path is relative, it will be converted to an absolute path using filepath.Abs (base on current working path)
|
||||
func OpenRepositoryLocal(localPath string) (_ *Repository, err error) {
|
||||
func OpenRepositoryLocal(catFileBatchCtx context.Context, localPath string) (_ *Repository, err error) {
|
||||
if !filepath.IsAbs(localPath) {
|
||||
localPath, err = filepath.Abs(localPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return OpenRepository(gitrepo.RepositoryUnmanaged(localPath))
|
||||
return OpenRepository(catFileBatchCtx, gitrepo.RepositoryUnmanaged(localPath))
|
||||
}
|
||||
|
||||
func (repo *Repository) Close() error {
|
||||
@@ -276,30 +284,21 @@ func Push(ctx context.Context, localRepoPath string, opts PushOptions) error {
|
||||
|
||||
// CatFileBatch obtains a "batch object provider" for this repository.
|
||||
// It reuses an existing one if available, otherwise creates a new one.
|
||||
func (repo *Repository) CatFileBatch(ctx context.Context) (_ CatFileBatch, closeFunc func(), err error) {
|
||||
func (repo *Repository) CatFileBatch() (_ CatFileBatch, closeFunc func(), err error) {
|
||||
repo.mu.Lock()
|
||||
defer repo.mu.Unlock()
|
||||
|
||||
// clean up the cached but canceled batcher
|
||||
if repo.catFileBatchCloser != nil && repo.catFileBatchCloser.Context().Err() != nil && !repo.catFileBatchInUse {
|
||||
repo.catFileBatchCloser.Close()
|
||||
repo.catFileBatchCloser = nil
|
||||
repo.catFileBatchInUse = false
|
||||
}
|
||||
|
||||
// if no cached batcher, make a new managed one, and cache it
|
||||
if repo.catFileBatchCloser == nil {
|
||||
repo.catFileBatchCloser, err = NewBatch(ctx, repo)
|
||||
repo.catFileBatchCloser, err = NewBatch(repo.catFileBatchCtx, repo)
|
||||
if err != nil {
|
||||
repo.catFileBatchCloser = nil // otherwise it is "interface(nil)" and will cause wrong logic
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// if the cached batcher is in use, or the cached ctx is not the current ctx, then we need a new temp one
|
||||
// for example: the cached one is from request context, the current ctx is a cancelable ctx with timeout
|
||||
needTemp := repo.catFileBatchInUse || repo.catFileBatchCloser.Context() != ctx
|
||||
if !needTemp {
|
||||
// if the cached batcher is not in use, return it
|
||||
if !repo.catFileBatchInUse {
|
||||
repo.catFileBatchInUse = true
|
||||
return CatFileBatch(repo.catFileBatchCloser), func() {
|
||||
repo.mu.Lock()
|
||||
@@ -308,7 +307,8 @@ func (repo *Repository) CatFileBatch(ctx context.Context) (_ CatFileBatch, close
|
||||
}, nil
|
||||
}
|
||||
|
||||
tempBatch, err := NewBatch(ctx, repo)
|
||||
// return a temp one (won't be cached or shared)
|
||||
tempBatch, err := NewBatch(repo.catFileBatchCtx, repo)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user