Allow limiting max conflicts (fixes #2282)

This commit is contained in:
Audrius Butkevicius 2015-10-13 20:50:58 +01:00
parent 2b56961b54
commit 752533489a
6 changed files with 66 additions and 33 deletions

View File

@ -1135,6 +1135,7 @@ angular.module('syncthing.core')
}; };
$scope.currentFolder.rescanIntervalS = 60; $scope.currentFolder.rescanIntervalS = 60;
$scope.currentFolder.minDiskFreePct = 1; $scope.currentFolder.minDiskFreePct = 1;
$scope.currentFolder.maxConflicts = -1;
$scope.currentFolder.order = "random"; $scope.currentFolder.order = "random";
$scope.currentFolder.fileVersioningSelector = "none"; $scope.currentFolder.fileVersioningSelector = "none";
$scope.currentFolder.trashcanClean = 0; $scope.currentFolder.trashcanClean = 0;
@ -1156,6 +1157,7 @@ angular.module('syncthing.core')
selectedDevices: {}, selectedDevices: {},
rescanIntervalS: 60, rescanIntervalS: 60,
minDiskFreePct: 1, minDiskFreePct: 1,
maxConflicts: -1,
order: "random", order: "random",
fileVersioningSelector: "none", fileVersioningSelector: "none",
trashcanClean: 0, trashcanClean: 0,

File diff suppressed because one or more lines are too long

View File

@ -111,6 +111,7 @@ type FolderConfiguration struct {
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value) ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"` PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"` PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
MaxConflicts int `xml:"maxConflicts" json:"maxConflicts"`
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
} }
@ -499,14 +500,6 @@ func ChangeRequiresRestart(from, to Configuration) bool {
return false return false
} }
func convertV10V11(cfg *Configuration) {
// Set minimum disk free of existing folders to 1%
for i := range cfg.Folders {
cfg.Folders[i].MinDiskFreePct = 1
}
cfg.Version = 11
}
func convertV11V12(cfg *Configuration) { func convertV11V12(cfg *Configuration) {
// Change listen address schema // Change listen address schema
for i, addr := range cfg.Options.ListenAddress { for i, addr := range cfg.Options.ListenAddress {
@ -550,9 +543,22 @@ func convertV11V12(cfg *Configuration) {
cfg.Options.LocalAnnPort = 21027 cfg.Options.LocalAnnPort = 21027
} }
// Set MaxConflicts to unlimited
for i := range cfg.Folders {
cfg.Folders[i].MaxConflicts = -1
}
cfg.Version = 12 cfg.Version = 12
} }
func convertV10V11(cfg *Configuration) {
// Set minimum disk free of existing folders to 1%
for i := range cfg.Folders {
cfg.Folders[i].MinDiskFreePct = 1
}
cfg.Version = 11
}
func convertV9V10(cfg *Configuration) { func convertV9V10(cfg *Configuration) {
// Enable auto normalization on existing folders. // Enable auto normalization on existing folders.
for i := range cfg.Folders { for i := range cfg.Folders {

View File

@ -100,6 +100,7 @@ func TestDeviceConfig(t *testing.T) {
Hashers: 0, Hashers: 0,
AutoNormalize: true, AutoNormalize: true,
MinDiskFreePct: 1, MinDiskFreePct: 1,
MaxConflicts: -1,
}, },
} }
expectedDevices := []DeviceConfiguration{ expectedDevices := []DeviceConfiguration{

View File

@ -3,6 +3,7 @@
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device> <device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device> <device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
<minDiskFreePct>1</minDiskFreePct> <minDiskFreePct>1</minDiskFreePct>
<maxConflicts>-1</maxConflicts>
</folder> </folder>
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata"> <device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
<address>tcp://a</address> <address>tcp://a</address>

View File

@ -79,17 +79,18 @@ type rwFolder struct {
progressEmitter *ProgressEmitter progressEmitter *ProgressEmitter
virtualMtimeRepo *db.VirtualMtimeRepo virtualMtimeRepo *db.VirtualMtimeRepo
folder string folder string
dir string dir string
scanIntv time.Duration scanIntv time.Duration
versioner versioner.Versioner versioner versioner.Versioner
ignorePerms bool ignorePerms bool
copiers int copiers int
pullers int pullers int
shortID uint64 shortID uint64
order config.PullOrder order config.PullOrder
sleep time.Duration maxConflicts int
pause time.Duration sleep time.Duration
pause time.Duration
stop chan struct{} stop chan struct{}
queue *jobQueue queue *jobQueue
@ -115,14 +116,15 @@ func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFo
progressEmitter: m.progressEmitter, progressEmitter: m.progressEmitter,
virtualMtimeRepo: db.NewVirtualMtimeRepo(m.db, cfg.ID), virtualMtimeRepo: db.NewVirtualMtimeRepo(m.db, cfg.ID),
folder: cfg.ID, folder: cfg.ID,
dir: cfg.Path(), dir: cfg.Path(),
scanIntv: time.Duration(cfg.RescanIntervalS) * time.Second, scanIntv: time.Duration(cfg.RescanIntervalS) * time.Second,
ignorePerms: cfg.IgnorePerms, ignorePerms: cfg.IgnorePerms,
copiers: cfg.Copiers, copiers: cfg.Copiers,
pullers: cfg.Pullers, pullers: cfg.Pullers,
shortID: shortID, shortID: shortID,
order: cfg.Order, order: cfg.Order,
maxConflicts: cfg.MaxConflicts,
stop: make(chan struct{}), stop: make(chan struct{}),
queue: newJobQueue(), queue: newJobQueue(),
@ -757,7 +759,7 @@ func (p *rwFolder) deleteFile(file protocol.FileInfo) {
// of deleting. Also merge with the version vector we had, to indicate // of deleting. Also merge with the version vector we had, to indicate
// we have resolved the conflict. // we have resolved the conflict.
file.Version = file.Version.Merge(cur.Version) file.Version = file.Version.Merge(cur.Version)
err = osutil.InWritableDir(moveForConflict, realName) err = osutil.InWritableDir(p.moveForConflict, realName)
} else if p.versioner != nil { } else if p.versioner != nil {
err = osutil.InWritableDir(p.versioner.Archive, realName) err = osutil.InWritableDir(p.versioner.Archive, realName)
} else { } else {
@ -1254,7 +1256,7 @@ func (p *rwFolder) performFinish(state *sharedPullerState) error {
// we have resolved the conflict. // we have resolved the conflict.
state.file.Version = state.file.Version.Merge(state.version) state.file.Version = state.file.Version.Merge(state.version)
if err = osutil.InWritableDir(moveForConflict, state.realName); err != nil { if err = osutil.InWritableDir(p.moveForConflict, state.realName); err != nil {
return err return err
} }
@ -1447,7 +1449,14 @@ func removeDevice(devices []protocol.DeviceID, device protocol.DeviceID) []proto
return devices return devices
} }
func moveForConflict(name string) error { func (p *rwFolder) moveForConflict(name string) error {
if p.maxConflicts == 0 {
if err := osutil.Remove(name); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
ext := filepath.Ext(name) ext := filepath.Ext(name)
withoutExt := name[:len(name)-len(ext)] withoutExt := name[:len(name)-len(ext)]
newName := withoutExt + time.Now().Format(".sync-conflict-20060102-150405") + ext newName := withoutExt + time.Now().Format(".sync-conflict-20060102-150405") + ext
@ -1457,7 +1466,21 @@ func moveForConflict(name string) error {
// the user has already moved it away, or the conflict was between a // the user has already moved it away, or the conflict was between a
// remote modification and a local delete. In either way it does not // remote modification and a local delete. In either way it does not
// matter, go ahead as if the move succeeded. // matter, go ahead as if the move succeeded.
return nil err = nil
}
if p.maxConflicts > -1 {
matches, gerr := osutil.Glob(withoutExt + ".sync-conflict-????????-??????" + ext)
if gerr == nil && len(matches) > p.maxConflicts {
sort.Sort(sort.Reverse(sort.StringSlice(matches)))
for _, match := range matches[p.maxConflicts:] {
gerr = osutil.Remove(match)
if gerr != nil {
l.Debugln(p, "removing extra conflict", gerr)
}
}
} else if gerr != nil {
l.Debugln(p, "globbing for conflicts", gerr)
}
} }
return err return err
} }