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 <copilot@github.com>

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>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-14 06:49:29 +00:00
committed by GitHub
parent d284f5c798
commit 4bece1feb4
3 changed files with 12 additions and 48 deletions

View File

@@ -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:
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH>
//
// 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
}

View File

@@ -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

View File

@@ -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
}