From cb0f4ce55ac626f273f8d8f7176a40aa2d6ed036 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Sat, 25 Aug 2018 10:16:38 +0200 Subject: [PATCH] lib/model: Don't stop folder if out of disk space (fixes #2370) (#5099) This removes the out of disk space check from CheckHealth. The disk space is now only checked if there are files to pull, in which case pulling those files is stopped, but everything else (dirs, links, deletes) keeps running -> can recover disk space through pulling. --- lib/config/folderconfiguration.go | 15 +++++++++++++-- lib/config/size.go | 13 +++++-------- lib/config/wrapper.go | 5 ++++- lib/model/folder.go | 4 ---- lib/model/folder_sendrecv.go | 16 ++++++++-------- lib/model/folder_sendrecv_test.go | 4 +++- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go index d8f8666c6..2f06b6951 100644 --- a/lib/config/folderconfiguration.go +++ b/lib/config/folderconfiguration.go @@ -282,8 +282,19 @@ func (l FolderDeviceConfigurationList) Len() int { return len(l) } -func (f *FolderConfiguration) CheckFreeSpace() error { - return checkFreeSpace(f.MinDiskFree, f.Filesystem()) +func (f *FolderConfiguration) CheckAvailableSpace(req int64) error { + fs := f.Filesystem() + usage, err := fs.Usage(".") + if err != nil { + return nil + } + usage.Free -= req + if usage.Free > 0 { + if err := checkFreeSpace(f.MinDiskFree, usage); err == nil { + return nil + } + } + return fmt.Errorf("insufficient space in %v %v", fs.Type(), fs.URI()) } type FolderConfigurationList []FolderConfiguration diff --git a/lib/config/size.go b/lib/config/size.go index 5c6fe5b7e..20c3f38d1 100644 --- a/lib/config/size.go +++ b/lib/config/size.go @@ -76,22 +76,19 @@ func (Size) ParseDefault(s string) (interface{}, error) { return ParseSize(s) } -func checkFreeSpace(req Size, fs fs.Filesystem) error { +func checkFreeSpace(req Size, usage fs.Usage) error { val := req.BaseValue() if val <= 0 { return nil } - usage, err := fs.Usage(".") if req.Percentage() { freePct := (float64(usage.Free) / float64(usage.Total)) * 100 - if err == nil && freePct < val { - return fmt.Errorf("insufficient space in %v %v: %f %% < %v", fs.Type(), fs.URI(), freePct, req) - } - } else { - if err == nil && float64(usage.Free) < val { - return fmt.Errorf("insufficient space in %v %v: %v < %v", fs.Type(), fs.URI(), usage.Free, req) + if freePct < val { + return fmt.Errorf("%f %% < %v", freePct, req) } + } else if float64(usage.Free) < val { + return fmt.Errorf("%v < %v", usage.Free, req) } return nil diff --git a/lib/config/wrapper.go b/lib/config/wrapper.go index 1cbd6beba..17c1f5fdf 100644 --- a/lib/config/wrapper.go +++ b/lib/config/wrapper.go @@ -445,5 +445,8 @@ func (w *Wrapper) MyName() string { // CheckHomeFreeSpace returns nil if the home disk has the required amount of // free space, or if home disk free space checking is disabled. func (w *Wrapper) CheckHomeFreeSpace() error { - return checkFreeSpace(w.Options().MinHomeDiskFree, fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Dir(w.ConfigPath()))) + if usage, err := fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Dir(w.ConfigPath())).Usage("."); err == nil { + return checkFreeSpace(w.Options().MinHomeDiskFree, usage) + } + return nil } diff --git a/lib/model/folder.go b/lib/model/folder.go index 9716e272e..add212e68 100644 --- a/lib/model/folder.go +++ b/lib/model/folder.go @@ -254,10 +254,6 @@ func (f *folder) getHealthError() error { return err } - if err := f.CheckFreeSpace(); err != nil { - return err - } - if err := f.model.cfg.CheckHomeFreeSpace(); err != nil { return err } diff --git a/lib/model/folder_sendrecv.go b/lib/model/folder_sendrecv.go index 9fd530f18..06029cdd7 100644 --- a/lib/model/folder_sendrecv.go +++ b/lib/model/folder_sendrecv.go @@ -839,9 +839,12 @@ func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo, dbUpdat l.Debugln(f, "taking rename shortcut", source.Name, "->", target.Name) if f.versioner != nil { - err = osutil.Copy(f.fs, source.Name, target.Name) + err = f.CheckAvailableSpace(source.Size) if err == nil { - err = osutil.InWritableDir(f.versioner.Archive, f.fs, source.Name) + err = osutil.Copy(f.fs, source.Name, target.Name) + if err == nil { + err = osutil.InWritableDir(f.versioner.Archive, f.fs, source.Name) + } } } else { err = osutil.TryRename(f.fs, source.Name, target.Name) @@ -1003,12 +1006,9 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c blocksSize = file.Size } - if f.MinDiskFree.BaseValue() > 0 { - if usage, err := f.fs.Usage("."); err == nil && usage.Free < blocksSize { - l.Warnf(`Folder "%s": insufficient disk space in %s for %s: have %.2f MiB, need %.2f MiB`, f.folderID, f.fs.URI(), file.Name, float64(usage.Free)/1024/1024, float64(blocksSize)/1024/1024) - f.newError("disk space", file.Name, errors.New("insufficient space")) - return - } + if err := f.CheckAvailableSpace(blocksSize); err != nil { + f.newError("pulling file", file.Name, err) + return } // Shuffle the blocks diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go index b3b007836..d074d50dd 100644 --- a/lib/model/folder_sendrecv_test.go +++ b/lib/model/folder_sendrecv_test.go @@ -91,15 +91,17 @@ func setUpSendReceiveFolder(model *Model) *sendReceiveFolder { initialScanFinished: make(chan struct{}), ctx: context.TODO(), FolderConfiguration: config.FolderConfiguration{ + FilesystemType: fs.FilesystemTypeBasic, + Path: "testdata", PullerMaxPendingKiB: defaultPullerPendingKiB, }, }, - fs: fs.NewMtimeFS(fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata"), db.NewNamespacedKV(model.db, "mtime")), queue: newJobQueue(), errors: make(map[string]string), errorsMut: sync.NewMutex(), } + f.fs = fs.NewMtimeFS(f.Filesystem(), db.NewNamespacedKV(model.db, "mtime")) // Folders are never actually started, so no initial scan will be done close(f.initialScanFinished)