lib/model: Use factories for creating folders
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3029
This commit is contained in:
committed by
Jakob Borg
parent
6720906ee5
commit
eabd2fc936
@@ -100,8 +100,11 @@ type Model struct {
|
||||
pmut sync.RWMutex // protects the above
|
||||
}
|
||||
|
||||
type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner) service
|
||||
|
||||
var (
|
||||
symlinkWarning = stdsync.Once{}
|
||||
symlinkWarning = stdsync.Once{}
|
||||
folderFactories = make(map[string]folderFactory, 0)
|
||||
)
|
||||
|
||||
// NewModel creates and starts a new model. The model starts in read-only mode,
|
||||
@@ -158,10 +161,8 @@ func (m *Model) StartDeadlockDetector(timeout time.Duration) {
|
||||
deadlockDetect(m.pmut, timeout)
|
||||
}
|
||||
|
||||
// StartFolderRW starts read/write processing on the current model. When in
|
||||
// read/write mode the model will attempt to keep in sync with the cluster by
|
||||
// pulling needed files from peer devices.
|
||||
func (m *Model) StartFolderRW(folder string) {
|
||||
// StartFolder constrcuts the folder service and starts it.
|
||||
func (m *Model) StartFolder(folder string) {
|
||||
m.fmut.Lock()
|
||||
cfg, ok := m.folderCfgs[folder]
|
||||
if !ok {
|
||||
@@ -172,37 +173,43 @@ func (m *Model) StartFolderRW(folder string) {
|
||||
if ok {
|
||||
panic("cannot start already running folder " + folder)
|
||||
}
|
||||
p := newRWFolder(m, cfg)
|
||||
m.folderRunners[folder] = p
|
||||
|
||||
folderFactory, ok := folderFactories[cfg.Type]
|
||||
if !ok {
|
||||
panic("unknown folder type " + cfg.Type)
|
||||
}
|
||||
|
||||
var ver versioner.Versioner
|
||||
if len(cfg.Versioning.Type) > 0 {
|
||||
factory, ok := versioner.Factories[cfg.Versioning.Type]
|
||||
versionerFactory, ok := versioner.Factories[cfg.Versioning.Type]
|
||||
if !ok {
|
||||
l.Fatalf("Requested versioning type %q that does not exist", cfg.Versioning.Type)
|
||||
}
|
||||
|
||||
versioner := factory(folder, cfg.Path(), cfg.Versioning.Params)
|
||||
if service, ok := versioner.(suture.Service); ok {
|
||||
ver = versionerFactory(folder, cfg.Path(), cfg.Versioning.Params)
|
||||
if service, ok := ver.(suture.Service); ok {
|
||||
// The versioner implements the suture.Service interface, so
|
||||
// expects to be run in the background in addition to being called
|
||||
// when files are going to be archived.
|
||||
token := m.Add(service)
|
||||
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
||||
}
|
||||
p.versioner = versioner
|
||||
}
|
||||
|
||||
p := folderFactory(m, cfg, ver)
|
||||
m.folderRunners[folder] = p
|
||||
|
||||
m.warnAboutOverwritingProtectedFiles(folder)
|
||||
|
||||
token := m.Add(p)
|
||||
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
||||
m.fmut.Unlock()
|
||||
|
||||
l.Infoln("Ready to synchronize", folder, "(read-write)")
|
||||
l.Infoln("Ready to synchronize", folder, fmt.Sprintf("(%s)", cfg.Type))
|
||||
}
|
||||
|
||||
func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
|
||||
if m.folderCfgs[folder].ReadOnly {
|
||||
if m.folderCfgs[folder].Type == config.FolderTypeReadOnly {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -229,30 +236,6 @@ func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
|
||||
}
|
||||
}
|
||||
|
||||
// StartFolderRO starts read only processing on the current model. When in
|
||||
// read only mode the model will announce files to the cluster but not pull in
|
||||
// any external changes.
|
||||
func (m *Model) StartFolderRO(folder string) {
|
||||
m.fmut.Lock()
|
||||
cfg, ok := m.folderCfgs[folder]
|
||||
if !ok {
|
||||
panic("cannot start nonexistent folder " + folder)
|
||||
}
|
||||
|
||||
_, ok = m.folderRunners[folder]
|
||||
if ok {
|
||||
panic("cannot start already running folder " + folder)
|
||||
}
|
||||
s := newROFolder(m, cfg)
|
||||
m.folderRunners[folder] = s
|
||||
|
||||
token := m.Add(s)
|
||||
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
||||
m.fmut.Unlock()
|
||||
|
||||
l.Infoln("Ready to synchronize", folder, "(read only; no external updates accepted)")
|
||||
}
|
||||
|
||||
func (m *Model) RemoveFolder(folder string) {
|
||||
m.fmut.Lock()
|
||||
m.pmut.Lock()
|
||||
@@ -1093,7 +1076,7 @@ func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, update
|
||||
cfg, ok := m.folderCfgs[folder]
|
||||
m.fmut.RUnlock()
|
||||
|
||||
if !ok || cfg.ReadOnly || cfg.DisableTempIndexes {
|
||||
if !ok || cfg.Type == config.FolderTypeReadOnly || cfg.DisableTempIndexes {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1606,7 +1589,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
|
||||
Label: folderCfg.Label,
|
||||
}
|
||||
var flags uint32
|
||||
if folderCfg.ReadOnly {
|
||||
if folderCfg.Type == config.FolderTypeReadOnly {
|
||||
flags |= protocol.FlagFolderReadOnly
|
||||
}
|
||||
if folderCfg.IgnorePerms {
|
||||
@@ -1874,7 +1857,7 @@ func (m *Model) CheckFolderHealth(id string) error {
|
||||
case !folder.HasMarker():
|
||||
err = errors.New("folder marker missing")
|
||||
|
||||
case !folder.ReadOnly:
|
||||
case folder.Type != config.FolderTypeReadOnly:
|
||||
// Check for free space, if it isn't a master folder. We aren't
|
||||
// going to change the contents of master folders, so we don't
|
||||
// care about the amount of free space there.
|
||||
@@ -1951,11 +1934,7 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
// A folder was added.
|
||||
l.Debugln(m, "adding folder", folderID)
|
||||
m.AddFolder(cfg)
|
||||
if cfg.ReadOnly {
|
||||
m.StartFolderRO(folderID)
|
||||
} else {
|
||||
m.StartFolderRW(folderID)
|
||||
}
|
||||
m.StartFolder(folderID)
|
||||
|
||||
// Drop connections to all devices that can now share the new
|
||||
// folder.
|
||||
|
||||
@@ -34,7 +34,7 @@ func init() {
|
||||
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
|
||||
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
|
||||
|
||||
defaultFolderConfig = config.NewFolderConfiguration("default", "testdata")
|
||||
defaultFolderConfig = config.NewFolderConfiguration("default", "testdata", config.FolderTypeReadWrite)
|
||||
defaultFolderConfig.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
|
||||
_defaultConfig := config.Configuration{
|
||||
Folders: []config.FolderConfiguration{defaultFolderConfig},
|
||||
@@ -85,7 +85,7 @@ func TestRequest(t *testing.T) {
|
||||
|
||||
// device1 shares default, but device2 doesn't
|
||||
m.AddFolder(defaultFolderConfig)
|
||||
m.StartFolderRO("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
m.ScanFolder("default")
|
||||
|
||||
@@ -159,7 +159,7 @@ func benchmarkIndex(b *testing.B, nfiles int) {
|
||||
db := db.OpenMemory()
|
||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||
m.AddFolder(defaultFolderConfig)
|
||||
m.StartFolderRO("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
|
||||
files := genFiles(nfiles)
|
||||
@@ -188,7 +188,7 @@ func benchmarkIndexUpdate(b *testing.B, nfiles, nufiles int) {
|
||||
db := db.OpenMemory()
|
||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||
m.AddFolder(defaultFolderConfig)
|
||||
m.StartFolderRO("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
|
||||
files := genFiles(nfiles)
|
||||
@@ -492,7 +492,7 @@ func TestIgnores(t *testing.T) {
|
||||
db := db.OpenMemory()
|
||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||
m.AddFolder(defaultFolderConfig)
|
||||
m.StartFolderRO("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
|
||||
expected := []string{
|
||||
@@ -609,6 +609,7 @@ func TestROScanRecovery(t *testing.T) {
|
||||
fcfg := config.FolderConfiguration{
|
||||
ID: "default",
|
||||
RawPath: "testdata/rotestfolder",
|
||||
Type: config.FolderTypeReadOnly,
|
||||
RescanIntervalS: 1,
|
||||
}
|
||||
cfg := config.Wrap("/tmp/test", config.Configuration{
|
||||
@@ -624,7 +625,7 @@ func TestROScanRecovery(t *testing.T) {
|
||||
|
||||
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
||||
m.AddFolder(fcfg)
|
||||
m.StartFolderRO("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
|
||||
waitFor := func(status string) error {
|
||||
@@ -693,6 +694,7 @@ func TestRWScanRecovery(t *testing.T) {
|
||||
fcfg := config.FolderConfiguration{
|
||||
ID: "default",
|
||||
RawPath: "testdata/rwtestfolder",
|
||||
Type: config.FolderTypeReadWrite,
|
||||
RescanIntervalS: 1,
|
||||
}
|
||||
cfg := config.Wrap("/tmp/test", config.Configuration{
|
||||
@@ -708,7 +710,7 @@ func TestRWScanRecovery(t *testing.T) {
|
||||
|
||||
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
||||
m.AddFolder(fcfg)
|
||||
m.StartFolderRW("default")
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
|
||||
waitFor := func(status string) error {
|
||||
@@ -1219,7 +1221,7 @@ func TestIgnoreDelete(t *testing.T) {
|
||||
|
||||
m.AddFolder(cfg)
|
||||
m.ServeBackground()
|
||||
m.StartFolderRW("default")
|
||||
m.StartFolder("default")
|
||||
m.ScanFolder("default")
|
||||
|
||||
// Get a currently existing file
|
||||
|
||||
@@ -12,13 +12,18 @@ import (
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/versioner"
|
||||
)
|
||||
|
||||
func init() {
|
||||
folderFactories[config.FolderTypeReadOnly] = newROFolder
|
||||
}
|
||||
|
||||
type roFolder struct {
|
||||
folder
|
||||
}
|
||||
|
||||
func newROFolder(model *Model, cfg config.FolderConfiguration) *roFolder {
|
||||
func newROFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner) service {
|
||||
return &roFolder{
|
||||
folder: folder{
|
||||
stateTracker: stateTracker{
|
||||
|
||||
@@ -31,6 +31,10 @@ import (
|
||||
|
||||
// TODO: Stop on errors
|
||||
|
||||
func init() {
|
||||
folderFactories[config.FolderTypeReadWrite] = newRWFolder
|
||||
}
|
||||
|
||||
// A pullBlockState is passed to the puller routine for each block that needs
|
||||
// to be fetched.
|
||||
type pullBlockState struct {
|
||||
@@ -98,7 +102,7 @@ type rwFolder struct {
|
||||
errorsMut sync.Mutex
|
||||
}
|
||||
|
||||
func newRWFolder(model *Model, cfg config.FolderConfiguration) *rwFolder {
|
||||
func newRWFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner) service {
|
||||
f := &rwFolder{
|
||||
folder: folder{
|
||||
stateTracker: stateTracker{
|
||||
@@ -124,6 +128,7 @@ func newRWFolder(model *Model, cfg config.FolderConfiguration) *rwFolder {
|
||||
maxConflicts: cfg.MaxConflicts,
|
||||
allowSparse: !cfg.DisableSparseFiles,
|
||||
checkFreeSpace: cfg.MinDiskFreePct != 0,
|
||||
versioner: ver,
|
||||
|
||||
queue: newJobQueue(),
|
||||
pullTimer: time.NewTimer(time.Second),
|
||||
|
||||
Reference in New Issue
Block a user