Browse Source

lib/model: Add option to disable fsync (#6588)

* lib/model: Add option to disable fsync

* Fix test

* Dont open stuff for no reason
Audrius Butkevicius 5 years ago
parent
commit
782bd08aad

+ 1 - 0
lib/config/folderconfiguration.go

@@ -58,6 +58,7 @@ type FolderConfiguration struct {
 	CopyOwnershipFromParent bool                        `xml:"copyOwnershipFromParent" json:"copyOwnershipFromParent"`
 	RawModTimeWindowS       int                         `xml:"modTimeWindowS" json:"modTimeWindowS"`
 	MaxConcurrentWrites     int                         `xml:"maxConcurrentWrites" json:"maxConcurrentWrites" default:"2"`
+	DisableFsync            bool                        `xml:"disableFsync" json:"disableFsync"`
 
 	cachedFilesystem    fs.Filesystem
 	cachedModTimeWindow time.Duration

+ 11 - 9
lib/model/folder_sendrecv.go

@@ -1082,7 +1082,7 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, snap *db.Snapshot
 		"action": "update",
 	})
 
-	s := newSharedPullerState(file, f.fs, f.folderID, tempName, blocks, reused, f.IgnorePerms || file.NoPermissions, hasCurFile, curFile, !f.DisableSparseFiles)
+	s := newSharedPullerState(file, f.fs, f.folderID, tempName, blocks, reused, f.IgnorePerms || file.NoPermissions, hasCurFile, curFile, !f.DisableSparseFiles, !f.DisableFsync)
 
 	l.Debugf("%v need file %s; copy %d, reused %v", f, file.Name, len(blocks), len(reused))
 
@@ -1581,15 +1581,17 @@ func (f *sendReceiveFolder) dbUpdaterRoutine(dbUpdateChan <-chan dbUpdateJob) {
 		// sync directories
 		for dir := range changedDirs {
 			delete(changedDirs, dir)
-			fd, err := f.fs.Open(dir)
-			if err != nil {
-				l.Debugf("fsync %q failed: %v", dir, err)
-				continue
-			}
-			if err := fd.Sync(); err != nil {
-				l.Debugf("fsync %q failed: %v", dir, err)
+			if !f.FolderConfiguration.DisableFsync {
+				fd, err := f.fs.Open(dir)
+				if err != nil {
+					l.Debugf("fsync %q failed: %v", dir, err)
+					continue
+				}
+				if err := fd.Sync(); err != nil {
+					l.Debugf("fsync %q failed: %v", dir, err)
+				}
+				fd.Close()
 			}
-			fd.Close()
 		}
 
 		// All updates to file/folder objects that originated remotely

+ 1 - 1
lib/model/folder_sendrecv_test.go

@@ -1031,7 +1031,7 @@ func TestPullCtxCancel(t *testing.T) {
 
 	emptyState := func() pullBlockState {
 		return pullBlockState{
-			sharedPullerState: newSharedPullerState(protocol.FileInfo{}, nil, f.folderID, "", nil, nil, false, false, protocol.FileInfo{}, false),
+			sharedPullerState: newSharedPullerState(protocol.FileInfo{}, nil, f.folderID, "", nil, nil, false, false, protocol.FileInfo{}, false, false),
 			block:             protocol.BlockInfo{},
 		}
 	}

+ 11 - 7
lib/model/sharedpullerstate.go

@@ -32,6 +32,7 @@ type sharedPullerState struct {
 	curFile     protocol.FileInfo // The file as it exists now in our database
 	sparse      bool
 	created     time.Time
+	fsync       bool
 
 	// Mutable, must be locked for access
 	err               error           // The first error we hit
@@ -49,7 +50,7 @@ type sharedPullerState struct {
 	mut               sync.RWMutex    // Protects the above
 }
 
-func newSharedPullerState(file protocol.FileInfo, fs fs.Filesystem, folderID, tempName string, blocks []protocol.BlockInfo, reused []int32, ignorePerms, hasCurFile bool, curFile protocol.FileInfo, sparse bool) *sharedPullerState {
+func newSharedPullerState(file protocol.FileInfo, fs fs.Filesystem, folderID, tempName string, blocks []protocol.BlockInfo, reused []int32, ignorePerms, hasCurFile bool, curFile protocol.FileInfo, sparse bool, fsync bool) *sharedPullerState {
 	return &sharedPullerState{
 		file:             file,
 		fs:               fs,
@@ -67,6 +68,7 @@ func newSharedPullerState(file protocol.FileInfo, fs fs.Filesystem, folderID, te
 		curFile:          curFile,
 		mut:              sync.NewRWMutex(),
 		sparse:           sparse,
+		fsync:            fsync,
 		created:          time.Now(),
 	}
 }
@@ -101,13 +103,15 @@ func (w *lockedWriterAt) WriteAt(p []byte, off int64) (n int, err error) {
 
 // SyncClose ensures that no more writes are happening before going ahead and
 // syncing and closing the fd, thus needs to acquire a write-lock.
-func (w *lockedWriterAt) SyncClose() error {
+func (w *lockedWriterAt) SyncClose(fsync bool) error {
 	w.mut.Lock()
 	defer w.mut.Unlock()
-	if err := w.fd.Sync(); err != nil {
-		// Sync() is nice if it works but not worth failing the
-		// operation over if it fails.
-		l.Debugf("fsync failed: %v", err)
+	if fsync {
+		if err := w.fd.Sync(); err != nil {
+			// Sync() is nice if it works but not worth failing the
+			// operation over if it fails.
+			l.Debugf("fsync failed: %v", err)
+		}
 	}
 	return w.fd.Close()
 }
@@ -303,7 +307,7 @@ func (s *sharedPullerState) finalClose() (bool, error) {
 	}
 
 	if s.writer != nil {
-		if err := s.writer.SyncClose(); err != nil && s.err == nil {
+		if err := s.writer.SyncClose(s.fsync); err != nil && s.err == nil {
 			// This is our error as we weren't errored before.
 			s.err = err
 		}