aboutsummaryrefslogtreecommitdiffstats
path: root/modules/git/blob_nogogit.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-05-10 02:27:03 +0100
committerGitHub <noreply@github.com>2021-05-10 03:27:03 +0200
commit270aab429ef025df9a0b9bf9e3982729ae8df449 (patch)
tree215550ee5938876d4caf8516777d6f4bcaa91b40 /modules/git/blob_nogogit.go
parent038e1db4dfc7a7fc0a8675f66f6be9a3dd5f10c2 (diff)
downloadgitea-270aab429ef025df9a0b9bf9e3982729ae8df449.tar.gz
gitea-270aab429ef025df9a0b9bf9e3982729ae8df449.zip
On open repository open common cat file batch and batch-check (#15667)
Use common git cat-file --batch and git cat-file --batch-check to significantly reduce calls to git. Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'modules/git/blob_nogogit.go')
-rw-r--r--modules/git/blob_nogogit.go114
1 files changed, 84 insertions, 30 deletions
diff --git a/modules/git/blob_nogogit.go b/modules/git/blob_nogogit.go
index e917a31619..cdaeb636a9 100644
--- a/modules/git/blob_nogogit.go
+++ b/modules/git/blob_nogogit.go
@@ -8,48 +8,54 @@ package git
import (
"bufio"
+ "bytes"
"io"
- "strconv"
- "strings"
+ "io/ioutil"
+ "math"
)
// Blob represents a Git object.
type Blob struct {
ID SHA1
- gotSize bool
- size int64
- repoPath string
- name string
+ gotSize bool
+ size int64
+ name string
+ repo *Repository
}
// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
// Calling the Close function on the result will discard all unread output.
func (b *Blob) DataAsync() (io.ReadCloser, error) {
- stdoutReader, stdoutWriter := io.Pipe()
+ wr, rd, cancel := b.repo.CatFileBatch()
- go func() {
- stderr := &strings.Builder{}
- err := NewCommand("cat-file", "--batch").RunInDirFullPipeline(b.repoPath, stdoutWriter, stderr, strings.NewReader(b.ID.String()+"\n"))
- if err != nil {
- err = ConcatenateError(err, stderr.String())
- _ = stdoutWriter.CloseWithError(err)
- } else {
- _ = stdoutWriter.Close()
- }
- }()
-
- bufReader := bufio.NewReader(stdoutReader)
- _, _, size, err := ReadBatchLine(bufReader)
+ _, err := wr.Write([]byte(b.ID.String() + "\n"))
if err != nil {
- stdoutReader.Close()
+ cancel()
return nil, err
}
+ _, _, size, err := ReadBatchLine(rd)
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+ b.gotSize = true
+ b.size = size
- return &LimitedReaderCloser{
- R: bufReader,
- C: stdoutReader,
- N: size,
+ if size < 4096 {
+ bs, err := ioutil.ReadAll(io.LimitReader(rd, size))
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+ _, err = rd.Discard(1)
+ return ioutil.NopCloser(bytes.NewReader(bs)), err
+ }
+
+ return &blobReader{
+ rd: rd,
+ n: size,
+ cancel: cancel,
}, nil
}
@@ -59,18 +65,66 @@ func (b *Blob) Size() int64 {
return b.size
}
- size, err := NewCommand("cat-file", "-s", b.ID.String()).RunInDir(b.repoPath)
+ wr, rd, cancel := b.repo.CatFileBatchCheck()
+ defer cancel()
+ _, err := wr.Write([]byte(b.ID.String() + "\n"))
if err != nil {
- log("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repoPath, err)
+ log("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
return 0
}
-
- b.size, err = strconv.ParseInt(size[:len(size)-1], 10, 64)
+ _, _, b.size, err = ReadBatchLine(rd)
if err != nil {
- log("error whilst parsing size %s for %s in %s. Error: %v", size, b.ID.String(), b.repoPath, err)
+ log("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
return 0
}
+
b.gotSize = true
return b.size
}
+
+type blobReader struct {
+ rd *bufio.Reader
+ n int64
+ cancel func()
+}
+
+func (b *blobReader) Read(p []byte) (n int, err error) {
+ if b.n <= 0 {
+ return 0, io.EOF
+ }
+ if int64(len(p)) > b.n {
+ p = p[0:b.n]
+ }
+ n, err = b.rd.Read(p)
+ b.n -= int64(n)
+ return
+}
+
+// Close implements io.Closer
+func (b *blobReader) Close() error {
+ if b.n > 0 {
+ for b.n > math.MaxInt32 {
+ n, err := b.rd.Discard(math.MaxInt32)
+ b.n -= int64(n)
+ if err != nil {
+ b.cancel()
+ return err
+ }
+ b.n -= math.MaxInt32
+ }
+ n, err := b.rd.Discard(int(b.n))
+ b.n -= int64(n)
+ if err != nil {
+ b.cancel()
+ return err
+ }
+ }
+ if b.n == 0 {
+ _, err := b.rd.Discard(1)
+ b.n--
+ b.cancel()
+ return err
+ }
+ return nil
+}