Initial commit
This commit is contained in:
105
vendor/github.com/cockroachdb/pebble/vfs/syncing_file_linux.go
generated
vendored
Normal file
105
vendor/github.com/cockroachdb/pebble/vfs/syncing_file_linux.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||||
// of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
//go:build linux && !arm
|
||||
// +build linux,!arm
|
||||
|
||||
package vfs
|
||||
|
||||
import "syscall"
|
||||
|
||||
type syncFileRange func(fd int, off int64, n int64, flags int) (err error)
|
||||
|
||||
// sync_file_range depends on both the filesystem, and the broader kernel
|
||||
// support. In particular, Windows Subsystem for Linux does not support
|
||||
// sync_file_range, even when used with ext{2,3,4}. syncRangeSmokeTest performs
|
||||
// a test of of sync_file_range, returning false on ENOSYS, and true otherwise.
|
||||
func syncRangeSmokeTest(fd uintptr, fn syncFileRange) bool {
|
||||
err := fn(int(fd), 0 /* offset */, 0 /* nbytes */, 0 /* flags */)
|
||||
return err != syscall.ENOSYS
|
||||
}
|
||||
|
||||
func isSyncRangeSupported(fd uintptr) bool {
|
||||
var stat syscall.Statfs_t
|
||||
if err := syscall.Fstatfs(int(fd), &stat); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Allowlist which filesystems we allow using sync_file_range with as some
|
||||
// filesystems treat that syscall as a noop (notably ZFS). A allowlist is
|
||||
// used instead of a denylist in order to have a more graceful failure mode
|
||||
// in case a filesystem we haven't tested is encountered. Currently only
|
||||
// ext2/3/4 are known to work properly.
|
||||
const extMagic = 0xef53
|
||||
switch stat.Type {
|
||||
case extMagic:
|
||||
return syncRangeSmokeTest(fd, syscall.SyncFileRange)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *syncingFile) init() {
|
||||
if f.fd == 0 {
|
||||
return
|
||||
}
|
||||
f.timeDiskOp(func() {
|
||||
f.useSyncRange = isSyncRangeSupported(f.fd)
|
||||
})
|
||||
if f.useSyncRange {
|
||||
f.syncTo = f.syncToRange
|
||||
} else {
|
||||
f.syncTo = f.syncToFdatasync
|
||||
}
|
||||
f.syncData = f.syncFdatasync
|
||||
}
|
||||
|
||||
func (f *syncingFile) syncFdatasync() error {
|
||||
if f.fd == 0 {
|
||||
return f.File.Sync()
|
||||
}
|
||||
var err error
|
||||
f.timeDiskOp(func() {
|
||||
err = syscall.Fdatasync(int(f.fd))
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *syncingFile) syncToFdatasync(_ int64) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
func (f *syncingFile) syncToRange(offset int64) error {
|
||||
const (
|
||||
waitBefore = 0x1
|
||||
write = 0x2
|
||||
// waitAfter = 0x4
|
||||
)
|
||||
|
||||
// The flags for the sync_file_range system call. Unless the file has
|
||||
// noSyncOnClose explicitly set and it is being closed, the waitBefore
|
||||
// flag will be set which may block the call.
|
||||
flags := write
|
||||
if !f.noSyncOnClose || !f.closing {
|
||||
flags |= waitBefore
|
||||
}
|
||||
|
||||
// Note that syncToRange is only called with an offset that is guaranteed to
|
||||
// be less than atomic.offset (i.e. the write offset). This implies the
|
||||
// syncingFile.Close will Sync the rest of the data, as well as the file's
|
||||
// metadata.
|
||||
f.ratchetSyncOffset(offset)
|
||||
|
||||
// By specifying write|waitBefore for the flags, we're instructing
|
||||
// SyncFileRange to a) wait for any outstanding data being written to finish,
|
||||
// and b) to queue any other dirty data blocks in the range [0,offset] for
|
||||
// writing. The actual writing of this data will occur asynchronously. The
|
||||
// use of `waitBefore` is to limit how much dirty data is allowed to
|
||||
// accumulate. Linux sometimes behaves poorly when a large amount of dirty
|
||||
// data accumulates, impacting other I/O operations.
|
||||
var err error
|
||||
f.timeDiskOp(func() {
|
||||
err = syscall.SyncFileRange(int(f.fd), 0, offset, flags)
|
||||
})
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user