From 4bece1feb447d4718a02fcae7d97022d6dd09f93 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 06:49:29 +0000 Subject: [PATCH] refactor: ParseCatFileTreeLine returns slices from ReadBytes, remove pre-provided buffers Replace the three caller-provided buffer parameters (modeBuf, fnameBuf, shaBuf) with internal allocation. Use rd.ReadBytes('\x00') to read mode+fname in one call and slice the result directly. Allocate sha internally. Update both callers (catBatchParseTreeEntries and lfs_nogogit.go) to drop the buffer setup. Co-Authored-By: GitHub Copilot Agent-Logs-Url: https://github.com/go-gitea/gitea/sessions/43dab9a5-8c12-41c7-8da6-77c268a65ada Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com> --- modules/git/catfile_batch_reader.go | 49 ++++++----------------------- modules/git/parse_treeentry.go | 5 +-- modules/git/pipeline/lfs_nogogit.go | 6 +--- 3 files changed, 12 insertions(+), 48 deletions(-) diff --git a/modules/git/catfile_batch_reader.go b/modules/git/catfile_batch_reader.go index 5727c4a8ac..79a0c758f1 100644 --- a/modules/git/catfile_batch_reader.go +++ b/modules/git/catfile_batch_reader.go @@ -179,18 +179,14 @@ headerLoop: // Therefore we need some method to convert these binary hashes to hex hashes // ParseCatFileTreeLine reads an entry from a tree in a cat-file --batch stream -// This carefully avoids allocations - except where fnameBuf is too small. -// It is recommended therefore to pass in an fnameBuf large enough to avoid almost all allocations // // Each line is composed of: // SP NUL // // We don't attempt to convert the raw HASH to save a lot of time -func ParseCatFileTreeLine(objectFormat ObjectFormat, rd BufferedReader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) { - var readBytes []byte - - // Read the Mode & fname - readBytes, err = rd.ReadSlice('\x00') +func ParseCatFileTreeLine(objectFormat ObjectFormat, rd BufferedReader) (mode, fname, sha []byte, n int, err error) { + // Read the mode and fname up to and including the NUL separator + readBytes, err := rd.ReadBytes('\x00') if err != nil { return mode, fname, sha, n, err } @@ -200,48 +196,23 @@ func ParseCatFileTreeLine(objectFormat ObjectFormat, rd BufferedReader, modeBuf, return mode, fname, sha, n, &ErrNotExist{} } - n += idx + 1 - copy(modeBuf, readBytes[:idx]) - if len(modeBuf) >= idx { - modeBuf = modeBuf[:idx] - } else { - modeBuf = append(modeBuf, readBytes[len(modeBuf):idx]...) - } - mode = modeBuf + mode = readBytes[:idx] + fname = readBytes[idx+1 : len(readBytes)-1] // trim the NUL terminator + n = len(readBytes) - readBytes = readBytes[idx+1:] - - // Deal with the fname - copy(fnameBuf, readBytes) - if len(fnameBuf) > len(readBytes) { - fnameBuf = fnameBuf[:len(readBytes)] - } else { - fnameBuf = append(fnameBuf, readBytes[len(fnameBuf):]...) - } - for err == bufio.ErrBufferFull { - readBytes, err = rd.ReadSlice('\x00') - fnameBuf = append(fnameBuf, readBytes...) - } - n += len(fnameBuf) - if err != nil { - return mode, fname, sha, n, err - } - fnameBuf = fnameBuf[:len(fnameBuf)-1] - fname = fnameBuf - - // Deal with the binary hash - idx = 0 + // Read the binary hash length := objectFormat.FullLength() / 2 + sha = make([]byte, length) + idx = 0 for idx < length { var read int - read, err = rd.Read(shaBuf[idx:length]) + read, err = rd.Read(sha[idx:length]) n += read if err != nil { return mode, fname, sha, n, err } idx += read } - sha = shaBuf return mode, fname, sha, n, err } diff --git a/modules/git/parse_treeentry.go b/modules/git/parse_treeentry.go index 8d8deb5b3d..cc1cb1fdc1 100644 --- a/modules/git/parse_treeentry.go +++ b/modules/git/parse_treeentry.go @@ -47,14 +47,11 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { } func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd BufferedReader, sz int64) ([]*TreeEntry, error) { - fnameBuf := make([]byte, 4096) - modeBuf := make([]byte, 40) - shaBuf := make([]byte, objectFormat.FullLength()) entries := make([]*TreeEntry, 0, 10) loop: for sz > 0 { - mode, fname, sha, count, err := ParseCatFileTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf) + mode, fname, sha, count, err := ParseCatFileTreeLine(objectFormat, rd) if err != nil { if err == io.EOF { break loop diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go index 91bda0d0e5..50bbf9f1f7 100644 --- a/modules/git/pipeline/lfs_nogogit.go +++ b/modules/git/pipeline/lfs_nogogit.go @@ -46,10 +46,6 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader trees := []string{} paths := []string{} - fnameBuf := make([]byte, 4096) - modeBuf := make([]byte, 40) - workingShaBuf := make([]byte, objectID.Type().FullLength()/2) - for scan.Scan() { // Get the next commit ID commitID := scan.Text() @@ -93,7 +89,7 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader case "tree": var n int64 for n < info.Size { - mode, fname, binObjectID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf) + mode, fname, binObjectID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader) if err != nil { return nil, err }