write() to disk in 4MB blocks for better performance (#7888)

This commit is contained in:
Krishna Srinivas 2019-08-23 15:36:46 -07:00 committed by Harshavardhana
parent 48bc3f1d53
commit c38ada1a26
2 changed files with 38 additions and 40 deletions

View File

@ -47,7 +47,7 @@ const (
diskMinFreeSpace = 900 * humanize.MiByte // Min 900MiB free space. diskMinFreeSpace = 900 * humanize.MiByte // Min 900MiB free space.
diskMinTotalSpace = diskMinFreeSpace // Min 900MiB total space. diskMinTotalSpace = diskMinFreeSpace // Min 900MiB total space.
maxAllowedIOError = 5 maxAllowedIOError = 5
readBlockSize = humanize.KiByte * 32 // Default read block size 32KiB. readBlockSize = 4 * humanize.MiByte // Default read block size 4MiB.
) )
// isValidVolname verifies a volname name in accordance with object // isValidVolname verifies a volname name in accordance with object
@ -1230,7 +1230,7 @@ func (s *posix) CreateFile(volume, path string, fileSize int64, r io.Reader) (er
bufp := s.pool.Get().(*[]byte) bufp := s.pool.Get().(*[]byte)
defer s.pool.Put(bufp) defer s.pool.Put(bufp)
written, err := xioutil.CopyAligned(w, r, *bufp) written, err := xioutil.CopyAligned(w, r, *bufp, fileSize)
if err != nil { if err != nil {
return err return err
} }

View File

@ -173,7 +173,7 @@ const directioAlignSize = 4096
// used with DIRECT I/O based file descriptor and it is expected that // used with DIRECT I/O based file descriptor and it is expected that
// input writer *os.File not a generic io.Writer. Make sure to have // input writer *os.File not a generic io.Writer. Make sure to have
// the file opened for writes with syscall.O_DIRECT flag. // the file opened for writes with syscall.O_DIRECT flag.
func CopyAligned(w *os.File, r io.Reader, alignedBuf []byte) (int64, error) { func CopyAligned(w *os.File, r io.Reader, alignedBuf []byte, totalSize int64) (int64, error) {
// Writes remaining bytes in the buffer. // Writes remaining bytes in the buffer.
writeUnaligned := func(w *os.File, buf []byte) (remainingWritten int, err error) { writeUnaligned := func(w *os.File, buf []byte) (remainingWritten int, err error) {
var n int var n int
@ -205,47 +205,45 @@ func CopyAligned(w *os.File, r io.Reader, alignedBuf []byte) (int64, error) {
} }
var written int64 var written int64
var err error
for { for {
nr, er := r.Read(alignedBuf) buf := alignedBuf
if nr == len(alignedBuf) { if totalSize != -1 {
// Buffer read is aligned with input buffer, proceed to write. remaining := totalSize - written
nw, ew := w.Write(alignedBuf) if remaining < int64(len(buf)) {
buf = buf[:remaining]
}
}
nr, err := io.ReadFull(r, buf)
eof := err == io.EOF || err == io.ErrUnexpectedEOF
if err != nil && !eof {
return written, err
}
buf = buf[:nr]
var nw int
if len(buf)%directioAlignSize == 0 {
// buf is aligned for directio write()
nw, err = w.Write(buf)
} else {
// buf is not aligned, hence use writeUnaligned()
nw, err = writeUnaligned(w, buf)
}
if nw > 0 { if nw > 0 {
written += int64(nw) written += int64(nw)
} }
if ew != nil { if err != nil {
err = ew return written, err
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
} else if nr > 0 {
// Buffer read is not aligned with input buffer, proceed to write
// whatever possible as aligned and turn off direct I/O.
nw, ew := writeUnaligned(w, alignedBuf[:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
// For any read errors break out and return error.
if er != nil {
if er != io.EOF {
err = er
}
break
} }
if nw != len(buf) {
return written, io.ErrShortWrite
} }
return written, err if totalSize != -1 {
if written == totalSize {
return written, nil
}
}
if eof {
return written, nil
}
}
} }