mirror of
https://gitee.com/gitea/gitea
synced 2025-12-05 15:50:26 +08:00
It may be prudent to add runtime finalizers to the git.Repository and git.blobReader objects to absolutely ensure that these are both properly cancelled, cleaned and closed out. This commit is a backport of an extract from #19448 Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
@@ -13,8 +13,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
)
|
||||
|
||||
// Repository represents a Git repository.
|
||||
@@ -25,6 +28,10 @@ type Repository struct {
|
||||
|
||||
gpgSettings *GPGSettings
|
||||
|
||||
lock sync.Mutex
|
||||
|
||||
closed bool
|
||||
|
||||
batchCancel context.CancelFunc
|
||||
batchReader *bufio.Reader
|
||||
batchWriter WriteCloserError
|
||||
@@ -64,29 +71,57 @@ func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).finalizer)
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// CatFileBatch obtains a CatFileBatch for this repository
|
||||
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.batchCancel == nil || repo.batchReader.Buffered() > 0 {
|
||||
repo.lock.Lock()
|
||||
defer repo.lock.Unlock()
|
||||
|
||||
if repo.closed || repo.batchReader.Buffered() > 0 {
|
||||
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
|
||||
return CatFileBatch(ctx, repo.Path)
|
||||
}
|
||||
|
||||
if repo.batchCancel == nil {
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repo.Path)
|
||||
}
|
||||
|
||||
return repo.batchWriter, repo.batchReader, func() {}
|
||||
}
|
||||
|
||||
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
|
||||
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.checkCancel == nil || repo.checkReader.Buffered() > 0 {
|
||||
repo.lock.Lock()
|
||||
defer repo.lock.Unlock()
|
||||
|
||||
if repo.closed || repo.checkReader.Buffered() > 0 {
|
||||
log.Debug("Opening temporary cat file batch-check: %s", repo.Path)
|
||||
return CatFileBatchCheck(ctx, repo.Path)
|
||||
}
|
||||
|
||||
if repo.checkCancel == nil {
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
|
||||
}
|
||||
|
||||
return repo.checkWriter, repo.checkReader, func() {}
|
||||
}
|
||||
|
||||
// Close this repository, in particular close the underlying gogitStorage if this is not nil
|
||||
func (repo *Repository) Close() {
|
||||
func (repo *Repository) Close() (err error) {
|
||||
if repo == nil {
|
||||
return
|
||||
}
|
||||
repo.lock.Lock()
|
||||
defer repo.lock.Unlock()
|
||||
|
||||
return repo.close()
|
||||
}
|
||||
|
||||
func (repo *Repository) close() (err error) {
|
||||
if repo == nil {
|
||||
return
|
||||
}
|
||||
@@ -102,4 +137,26 @@ func (repo *Repository) Close() {
|
||||
repo.checkReader = nil
|
||||
repo.checkWriter = nil
|
||||
}
|
||||
repo.closed = true
|
||||
return
|
||||
}
|
||||
|
||||
func (repo *Repository) finalizer() (err error) {
|
||||
if repo == nil {
|
||||
return
|
||||
}
|
||||
repo.lock.Lock()
|
||||
defer repo.lock.Unlock()
|
||||
if repo.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
if repo.batchCancel != nil || repo.checkCancel != nil {
|
||||
pid := ""
|
||||
if repo.Ctx != nil {
|
||||
pid = " from PID: " + string(process.GetPID(repo.Ctx))
|
||||
}
|
||||
log.Error("Finalizer running on unclosed repository%s: %s%s", pid, repo.Path)
|
||||
}
|
||||
return repo.close()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user