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.
This commit is contained in:
Simon Frei 2018-08-25 10:16:38 +02:00 committed by Jakob Borg
parent d86d5e8bb2
commit cb0f4ce55a
6 changed files with 33 additions and 24 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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)