posix: Use sync.Pool buffers to copy in large buffers. (#3106)

These fixes are borrowed from the fixes required for GlusterFS i/o throughput.
master
Harshavardhana 8 years ago committed by GitHub
parent 8871eb8e1e
commit e9c45102b0
  1. 3
      .travis.yml
  2. 2
      cmd/object-common.go
  3. 17
      cmd/posix-list-dir-nix.go
  4. 2
      cmd/posix-utils_windows_test.go
  5. 20
      cmd/posix.go

@ -7,9 +7,6 @@ language: go
os: os:
- linux - linux
- osx
osx_image: xcode7.2
env: env:
- ARCH=x86_64 - ARCH=x86_64

@ -27,7 +27,7 @@ const (
blockSizeV1 = 10 * 1024 * 1024 // 10MiB. blockSizeV1 = 10 * 1024 * 1024 // 10MiB.
// Staging buffer read size for all internal operations version 1. // Staging buffer read size for all internal operations version 1.
readSizeV1 = 128 * 1024 // 128KiB. readSizeV1 = 1 * 1024 * 1024 // 1MiB.
// Buckets meta prefix. // Buckets meta prefix.
bucketMetaPrefix = "buckets" bucketMetaPrefix = "buckets"

@ -23,6 +23,7 @@ import (
"path" "path"
"runtime" "runtime"
"strings" "strings"
"sync"
"syscall" "syscall"
"unsafe" "unsafe"
) )
@ -30,9 +31,9 @@ import (
const ( const (
// readDirentBufSize for syscall.ReadDirent() to hold multiple // readDirentBufSize for syscall.ReadDirent() to hold multiple
// directory entries in one buffer. golang source uses 4096 as // directory entries in one buffer. golang source uses 4096 as
// buffer size whereas we want 25 times larger to save lots of // buffer size whereas we want 64 times larger to save lots of
// entries to avoid multiple syscall.ReadDirent() call. // entries to avoid multiple syscall.ReadDirent() call.
readDirentBufSize = 4096 * 25 readDirentBufSize = 4096 * 64
) )
// actual length of the byte array from the c - world. // actual length of the byte array from the c - world.
@ -106,9 +107,19 @@ func parseDirents(dirPath string, buf []byte) (entries []string, err error) {
return entries, nil return entries, nil
} }
var readDirBufPool = sync.Pool{
New: func() interface{} {
b := make([]byte, readDirentBufSize)
return &b
},
}
// Return all the entries at the directory dirPath. // Return all the entries at the directory dirPath.
func readDir(dirPath string) (entries []string, err error) { func readDir(dirPath string) (entries []string, err error) {
buf := make([]byte, readDirentBufSize) bufp := readDirBufPool.Get().(*[]byte)
buf := *bufp
defer readDirBufPool.Put(bufp)
d, err := os.Open(dirPath) d, err := os.Open(dirPath)
if err != nil { if err != nil {
// File is really not found. // File is really not found.

@ -36,7 +36,7 @@ func TestUNCPaths(t *testing.T) {
{string(bytes.Repeat([]byte("界"), 85)), true}, {string(bytes.Repeat([]byte("界"), 85)), true},
// Each path component must be <= 255 bytes long. // Each path component must be <= 255 bytes long.
{string(bytes.Repeat([]byte("界"), 100)), false}, {string(bytes.Repeat([]byte("界"), 100)), false},
{`\\p\q\r\s\t`, true}, {`/p/q/r/s/t`, true},
} }
// Instantiate posix object to manage a disk // Instantiate posix object to manage a disk
var err error var err error

@ -26,6 +26,7 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@ -45,6 +46,7 @@ type posix struct {
suppliedDiskPath string suppliedDiskPath string
minFreeSpace int64 minFreeSpace int64
minFreeInodes int64 minFreeInodes int64
pool sync.Pool
} }
var errFaultyDisk = errors.New("Faulty disk") var errFaultyDisk = errors.New("Faulty disk")
@ -114,6 +116,13 @@ func newPosix(diskPath string) (StorageAPI, error) {
diskPath: diskPath, diskPath: diskPath,
minFreeSpace: fsMinFreeSpace, minFreeSpace: fsMinFreeSpace,
minFreeInodes: fsMinFreeInodesPercent, minFreeInodes: fsMinFreeInodesPercent,
// 1MiB buffer pool for posix internal operations.
pool: sync.Pool{
New: func() interface{} {
b := make([]byte, readSizeV1)
return &b
},
},
} }
st, err := os.Stat(preparePath(diskPath)) st, err := os.Stat(preparePath(diskPath))
if err != nil { if err != nil {
@ -144,7 +153,7 @@ func getDiskInfo(diskPath string) (di disk.Info, err error) {
} }
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files. // checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
func (s posix) checkDiskFree() (err error) { func (s *posix) checkDiskFree() (err error) {
di, err := getDiskInfo(s.diskPath) di, err := getDiskInfo(s.diskPath)
if err != nil { if err != nil {
return err return err
@ -584,7 +593,7 @@ func (s *posix) AppendFile(volume, path string, buf []byte) (err error) {
} }
// Create top level directories if they don't exist. // Create top level directories if they don't exist.
// with mode 0777 mkdir honors system umask. // with mode 0777 mkdir honors system umask.
if err = mkdirAll(filepath.Dir(filePath), 0777); err != nil { if err = mkdirAll(preparePath(slashpath.Dir(filePath)), 0777); err != nil {
// File path cannot be verified since one of the parents is a file. // File path cannot be verified since one of the parents is a file.
if isSysErrNotDir(err) { if isSysErrNotDir(err) {
return errFileAccessDenied return errFileAccessDenied
@ -609,8 +618,13 @@ func (s *posix) AppendFile(volume, path string, buf []byte) (err error) {
// Close upon return. // Close upon return.
defer w.Close() defer w.Close()
bufp := s.pool.Get().(*[]byte)
// Reuse buffer.
defer s.pool.Put(bufp)
// Return io.Copy // Return io.Copy
_, err = io.Copy(w, bytes.NewReader(buf)) _, err = io.CopyBuffer(w, bytes.NewReader(buf), *bufp)
return err return err
} }

Loading…
Cancel
Save