Skip to content

Commit

Permalink
perf: add file pool to reduce allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
ybirader committed Sep 8, 2023
1 parent 05b62ee commit 7d89111
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 7 deletions.
4 changes: 3 additions & 1 deletion archiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (a *Archiver) archive(file *pool.File) error {
return errors.Errorf("ERROR: could not write raw header for %s", file.Path)
}

_, err = io.Copy(fileWriter, &file.CompressedData)
_, err = io.Copy(fileWriter, file.CompressedData)
if err != nil {
return errors.Errorf("ERROR: could not write content for %s", file.Path)
}
Expand All @@ -281,6 +281,8 @@ func (a *Archiver) archive(file *pool.File) error {
os.Remove(file.Overflow.Name())
}

pool.FilePool.Put(file)

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion archiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func TestCompress(t *testing.T) {
file, err := pool.NewFile(helloTxtFileFixture, info, "")
assert.NoError(t, err)
bufCap := 5
file.CompressedData = *bytes.NewBuffer(make([]byte, 0, bufCap))
file.CompressedData = bytes.NewBuffer(make([]byte, 0, bufCap))

err = archiver.compress(file)
assert.NoError(t, err)
Expand Down
28 changes: 23 additions & 5 deletions pool/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,51 @@ import (
"io/fs"
"os"
"path/filepath"
"sync"

"github.com/pkg/errors"
)

const defaultBufferSize = 2 * 1024 * 1024
const DefaultBufferSize = 2 * 1024 * 1024

var FilePool = sync.Pool{
New: func() any {
return &File{CompressedData: bytes.NewBuffer(make([]byte, DefaultBufferSize))}
},
}

type File struct {
Path string
Info fs.FileInfo
Header *zip.FileHeader
CompressedData bytes.Buffer
CompressedData *bytes.Buffer
Overflow *os.File
written int64
}

func NewFile(path string, info fs.FileInfo, relativeTo string) (*File, error) {
f := FilePool.Get().(*File)
err := f.Reset(path, info, relativeTo)
return f, err
}

func (f *File) Reset(path string, info fs.FileInfo, relativeTo string) error {
hdr, err := zip.FileInfoHeader(info)
if err != nil {
return nil, errors.Errorf("ERROR: could not get file info header for %s: %v", path, err)
errors.Errorf("ERROR: could not get file info header for %s: %v", path, err)
}
f.Path = path
f.Info = info
f.Header = hdr
f.CompressedData.Reset()
f.Overflow = nil
f.written = 0

f := &File{Path: path, Info: info, Header: hdr, CompressedData: *bytes.NewBuffer(make([]byte, 0, defaultBufferSize))}
if relativeTo != "" {
f.setNameRelativeTo(relativeTo)
}

return f, nil
return nil
}

func (f *File) Write(p []byte) (n int, err error) {
Expand Down
18 changes: 18 additions & 0 deletions pool/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,22 @@ func TestNewFile(t *testing.T) {

assert.Equal(t, "hello/nested/hello.md", file.Header.Name)
})

t.Run("resets file as new", func(t *testing.T) {
filePath := filepath.Join(helloDirectoryFixture, "nested/hello.md")
info := testutils.GetFileInfo(t, filePath)

file, err := pool.NewFile(filePath, info, helloDirectoryFixture)
assert.NoError(t, err)

newInfo := testutils.GetFileInfo(t, helloTxtFileFixture)
err = file.Reset(helloTxtFileFixture, newInfo, "")
assert.NoError(t, err)

assert.Equal(t, helloTxtFileFixture, file.Path)
assert.Equal(t, newInfo, file.Info)
assert.Equal(t, "hello.txt", file.Header.Name)
assert.Equal(t, 0, file.CompressedData.Len())
assert.Equal(t, pool.DefaultBufferSize, file.CompressedData.Cap())
})
}

0 comments on commit 7d89111

Please sign in to comment.