mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
Manual fixup
This commit is contained in:
parent
5ec95086f2
commit
fdf8ee7015
@ -7,10 +7,10 @@ syncthing
|
|||||||
|
|
||||||
This is the `syncthing` project. The following are the project goals:
|
This is the `syncthing` project. The following are the project goals:
|
||||||
|
|
||||||
1. Define a protocol for synchronization of a file folder between a
|
1. Define a protocol for synchronization of a folder between a number of
|
||||||
number of collaborating devices. The protocol should be well defined,
|
collaborating devices. The protocol should be well defined, unambiguous,
|
||||||
unambiguous, easily understood, free to use, efficient, secure and
|
easily understood, free to use, efficient, secure and language neutral.
|
||||||
language neutral. This is the [Block Exchange
|
This is the [Block Exchange
|
||||||
Protocol](https://github.com/syncthing/syncthing/blob/master/protocol/PROTOCOL.md).
|
Protocol](https://github.com/syncthing/syncthing/blob/master/protocol/PROTOCOL.md).
|
||||||
|
|
||||||
2. Provide the reference implementation to demonstrate the usability of
|
2. Provide the reference implementation to demonstrate the usability of
|
||||||
|
@ -277,7 +277,7 @@ func restGetNeed(m *model.Model, w http.ResponseWriter, r *http.Request) {
|
|||||||
var qs = r.URL.Query()
|
var qs = r.URL.Query()
|
||||||
var folder = qs.Get("folder")
|
var folder = qs.Get("folder")
|
||||||
|
|
||||||
files := m.NeedFilesFolderLimited(folder, 100, 2500) // max 100 files or 2500 blocks
|
files := m.NeedFolderFilesLimited(folder, 100, 2500) // max 100 files or 2500 blocks
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
json.NewEncoder(w).Encode(files)
|
json.NewEncoder(w).Encode(files)
|
||||||
|
@ -448,8 +448,8 @@ nextFolder:
|
|||||||
// that all files have been deleted which might not be the case,
|
// that all files have been deleted which might not be the case,
|
||||||
// so mark it as invalid instead.
|
// so mark it as invalid instead.
|
||||||
if err != nil || !fi.IsDir() {
|
if err != nil || !fi.IsDir() {
|
||||||
l.Warnf("Stopping folder %q - directory missing, but has files in index", folder.ID)
|
l.Warnf("Stopping folder %q - path does not exist, but has files in index", folder.ID)
|
||||||
cfg.Folders[i].Invalid = "folder directory missing"
|
cfg.Folders[i].Invalid = "folder path missing"
|
||||||
continue nextFolder
|
continue nextFolder
|
||||||
}
|
}
|
||||||
} else if os.IsNotExist(err) {
|
} else if os.IsNotExist(err) {
|
||||||
@ -460,7 +460,7 @@ nextFolder:
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If there was another error or we could not create the
|
// If there was another error or we could not create the
|
||||||
// directory, the folder is invalid.
|
// path, the folder is invalid.
|
||||||
l.Warnf("Stopping folder %q - %v", err)
|
l.Warnf("Stopping folder %q - %v", err)
|
||||||
cfg.Folders[i].Invalid = err.Error()
|
cfg.Folders[i].Invalid = err.Error()
|
||||||
continue nextFolder
|
continue nextFolder
|
||||||
|
@ -509,8 +509,9 @@ func convertV2V3(cfg *Configuration) {
|
|||||||
|
|
||||||
func convertV1V2(cfg *Configuration) {
|
func convertV1V2(cfg *Configuration) {
|
||||||
// Collect the list of devices.
|
// Collect the list of devices.
|
||||||
// Replace device configs inside folders with only a reference to the nide ID.
|
// Replace device configs inside folders with only a reference to the
|
||||||
// Set all folders to read only if the global read only flag is set.
|
// device ID. Set all folders to read only if the global read only flag is
|
||||||
|
// set.
|
||||||
var devices = map[string]FolderDeviceConfiguration{}
|
var devices = map[string]FolderDeviceConfiguration{}
|
||||||
for i, folder := range cfg.Folders {
|
for i, folder := range cfg.Folders {
|
||||||
cfg.Folders[i].ReadOnly = cfg.Options.Deprecated_ReadOnly
|
cfg.Folders[i].ReadOnly = cfg.Options.Deprecated_ReadOnly
|
||||||
|
@ -79,7 +79,7 @@ type Model struct {
|
|||||||
deviceFolders map[protocol.DeviceID][]string // deviceID -> folders
|
deviceFolders map[protocol.DeviceID][]string // deviceID -> folders
|
||||||
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
|
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
|
||||||
folderIgnores map[string]ignore.Patterns // folder -> list of ignore patterns
|
folderIgnores map[string]ignore.Patterns // folder -> list of ignore patterns
|
||||||
rmut sync.RWMutex // protects the above
|
fmut sync.RWMutex // protects the above
|
||||||
|
|
||||||
folderState map[string]folderState // folder -> state
|
folderState map[string]folderState // folder -> state
|
||||||
folderStateChanged map[string]time.Time // folder -> time when state changed
|
folderStateChanged map[string]time.Time // folder -> time when state changed
|
||||||
@ -130,7 +130,7 @@ func NewModel(indexDir string, cfg *config.Configuration, deviceName, clientName
|
|||||||
timeout = it
|
timeout = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deadlockDetect(&m.rmut, time.Duration(timeout)*time.Second)
|
deadlockDetect(&m.fmut, time.Duration(timeout)*time.Second)
|
||||||
deadlockDetect(&m.smut, time.Duration(timeout)*time.Second)
|
deadlockDetect(&m.smut, time.Duration(timeout)*time.Second)
|
||||||
deadlockDetect(&m.pmut, time.Duration(timeout)*time.Second)
|
deadlockDetect(&m.pmut, time.Duration(timeout)*time.Second)
|
||||||
return m
|
return m
|
||||||
@ -140,9 +140,9 @@ func NewModel(indexDir string, cfg *config.Configuration, deviceName, clientName
|
|||||||
// read/write mode the model will attempt to keep in sync with the cluster by
|
// read/write mode the model will attempt to keep in sync with the cluster by
|
||||||
// pulling needed files from peer devices.
|
// pulling needed files from peer devices.
|
||||||
func (m *Model) StartFolderRW(folder string) {
|
func (m *Model) StartFolderRW(folder string) {
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
cfg, ok := m.folderCfgs[folder]
|
cfg, ok := m.folderCfgs[folder]
|
||||||
m.rmut.Unlock()
|
m.fmut.Unlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("cannot start nonexistent folder " + folder)
|
panic("cannot start nonexistent folder " + folder)
|
||||||
@ -202,7 +202,7 @@ func (m *Model) ConnectionStats() map[string]ConnectionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.pmut.RLock()
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
|
|
||||||
var res = make(map[string]ConnectionInfo)
|
var res = make(map[string]ConnectionInfo)
|
||||||
for device, conn := range m.protoConn {
|
for device, conn := range m.protoConn {
|
||||||
@ -217,7 +217,7 @@ func (m *Model) ConnectionStats() map[string]ConnectionInfo {
|
|||||||
res[device.String()] = ci
|
res[device.String()] = ci
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
m.pmut.RUnlock()
|
m.pmut.RUnlock()
|
||||||
|
|
||||||
in, out := protocol.TotalInOut()
|
in, out := protocol.TotalInOut()
|
||||||
@ -245,9 +245,9 @@ func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
|
|||||||
func (m *Model) Completion(device protocol.DeviceID, folder string) float64 {
|
func (m *Model) Completion(device protocol.DeviceID, folder string) float64 {
|
||||||
var tot int64
|
var tot int64
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
rf, ok := m.folderFiles[folder]
|
rf, ok := m.folderFiles[folder]
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0 // Folder doesn't exist, so we hardly have any of it
|
return 0 // Folder doesn't exist, so we hardly have any of it
|
||||||
}
|
}
|
||||||
@ -302,8 +302,8 @@ func sizeOfFile(f protocol.FileIntf) (files, deleted int, bytes int64) {
|
|||||||
// GlobalSize returns the number of files, deleted files and total bytes for all
|
// GlobalSize returns the number of files, deleted files and total bytes for all
|
||||||
// files in the global model.
|
// files in the global model.
|
||||||
func (m *Model) GlobalSize(folder string) (files, deleted int, bytes int64) {
|
func (m *Model) GlobalSize(folder string) (files, deleted int, bytes int64) {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.rmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
if rf, ok := m.folderFiles[folder]; ok {
|
if rf, ok := m.folderFiles[folder]; ok {
|
||||||
rf.WithGlobalTruncated(func(f protocol.FileIntf) bool {
|
rf.WithGlobalTruncated(func(f protocol.FileIntf) bool {
|
||||||
fs, de, by := sizeOfFile(f)
|
fs, de, by := sizeOfFile(f)
|
||||||
@ -319,8 +319,8 @@ func (m *Model) GlobalSize(folder string) (files, deleted int, bytes int64) {
|
|||||||
// LocalSize returns the number of files, deleted files and total bytes for all
|
// LocalSize returns the number of files, deleted files and total bytes for all
|
||||||
// files in the local folder.
|
// files in the local folder.
|
||||||
func (m *Model) LocalSize(folder string) (files, deleted int, bytes int64) {
|
func (m *Model) LocalSize(folder string) (files, deleted int, bytes int64) {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.rmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
if rf, ok := m.folderFiles[folder]; ok {
|
if rf, ok := m.folderFiles[folder]; ok {
|
||||||
rf.WithHaveTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
|
rf.WithHaveTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
|
||||||
if f.IsInvalid() {
|
if f.IsInvalid() {
|
||||||
@ -338,8 +338,8 @@ func (m *Model) LocalSize(folder string) (files, deleted int, bytes int64) {
|
|||||||
|
|
||||||
// NeedSize returns the number and total size of currently needed files.
|
// NeedSize returns the number and total size of currently needed files.
|
||||||
func (m *Model) NeedSize(folder string) (files int, bytes int64) {
|
func (m *Model) NeedSize(folder string) (files int, bytes int64) {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.rmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
if rf, ok := m.folderFiles[folder]; ok {
|
if rf, ok := m.folderFiles[folder]; ok {
|
||||||
rf.WithNeedTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
|
rf.WithNeedTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
|
||||||
fs, de, by := sizeOfFile(f)
|
fs, de, by := sizeOfFile(f)
|
||||||
@ -356,9 +356,9 @@ func (m *Model) NeedSize(folder string) (files int, bytes int64) {
|
|||||||
|
|
||||||
// NeedFiles returns the list of currently needed files, stopping at maxFiles
|
// NeedFiles returns the list of currently needed files, stopping at maxFiles
|
||||||
// files or maxBlocks blocks. Limits <= 0 are ignored.
|
// files or maxBlocks blocks. Limits <= 0 are ignored.
|
||||||
func (m *Model) NeedFilesFolderLimited(folder string, maxFiles, maxBlocks int) []protocol.FileInfo {
|
func (m *Model) NeedFolderFilesLimited(folder string, maxFiles, maxBlocks int) []protocol.FileInfo {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.rmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
nblocks := 0
|
nblocks := 0
|
||||||
if rf, ok := m.folderFiles[folder]; ok {
|
if rf, ok := m.folderFiles[folder]; ok {
|
||||||
fs := make([]protocol.FileInfo, 0, maxFiles)
|
fs := make([]protocol.FileInfo, 0, maxFiles)
|
||||||
@ -389,10 +389,10 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
files, ok := m.folderFiles[folder]
|
files, ok := m.folderFiles[folder]
|
||||||
ignores, _ := m.folderIgnores[folder]
|
ignores, _ := m.folderIgnores[folder]
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
l.Fatalf("Index for nonexistant folder %q", folder)
|
l.Fatalf("Index for nonexistant folder %q", folder)
|
||||||
@ -430,10 +430,10 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
files, ok := m.folderFiles[folder]
|
files, ok := m.folderFiles[folder]
|
||||||
ignores, _ := m.folderIgnores[folder]
|
ignores, _ := m.folderIgnores[folder]
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
l.Fatalf("IndexUpdate for nonexistant folder %q", folder)
|
l.Fatalf("IndexUpdate for nonexistant folder %q", folder)
|
||||||
@ -460,8 +460,8 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) folderSharedWith(folder string, deviceID protocol.DeviceID) bool {
|
func (m *Model) folderSharedWith(folder string, deviceID protocol.DeviceID) bool {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.rmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
for _, nfolder := range m.deviceFolders[deviceID] {
|
for _, nfolder := range m.deviceFolders[deviceID] {
|
||||||
if nfolder == folder {
|
if nfolder == folder {
|
||||||
return true
|
return true
|
||||||
@ -568,11 +568,11 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
m.pmut.Lock()
|
m.pmut.Lock()
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, folder := range m.deviceFolders[device] {
|
for _, folder := range m.deviceFolders[device] {
|
||||||
m.folderFiles[folder].Replace(device, nil)
|
m.folderFiles[folder].Replace(device, nil)
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
conn, ok := m.rawConn[device]
|
conn, ok := m.rawConn[device]
|
||||||
if ok {
|
if ok {
|
||||||
@ -595,9 +595,9 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
|
|||||||
// Implements the protocol.Model interface.
|
// Implements the protocol.Model interface.
|
||||||
func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int) ([]byte, error) {
|
func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int) ([]byte, error) {
|
||||||
// Verify that the requested file exists in the local model.
|
// Verify that the requested file exists in the local model.
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
r, ok := m.folderFiles[folder]
|
r, ok := m.folderFiles[folder]
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
l.Warnf("Request from %s for file %s in nonexistent folder %q", deviceID, name, folder)
|
l.Warnf("Request from %s for file %s in nonexistent folder %q", deviceID, name, folder)
|
||||||
@ -622,9 +622,9 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
|
|||||||
if debug && deviceID != protocol.LocalDeviceID {
|
if debug && deviceID != protocol.LocalDeviceID {
|
||||||
l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
|
l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
|
||||||
}
|
}
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
fn := filepath.Join(m.folderCfgs[folder].Directory, name)
|
fn := filepath.Join(m.folderCfgs[folder].Directory, name)
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
fd, err := os.Open(fn) // XXX: Inefficient, should cache fd?
|
fd, err := os.Open(fn) // XXX: Inefficient, should cache fd?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -642,22 +642,22 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
|
|||||||
|
|
||||||
// ReplaceLocal replaces the local folder index with the given list of files.
|
// ReplaceLocal replaces the local folder index with the given list of files.
|
||||||
func (m *Model) ReplaceLocal(folder string, fs []protocol.FileInfo) {
|
func (m *Model) ReplaceLocal(folder string, fs []protocol.FileInfo) {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
m.folderFiles[folder].ReplaceWithDelete(protocol.LocalDeviceID, fs)
|
m.folderFiles[folder].ReplaceWithDelete(protocol.LocalDeviceID, fs)
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) CurrentFolderFile(folder string, file string) protocol.FileInfo {
|
func (m *Model) CurrentFolderFile(folder string, file string) protocol.FileInfo {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
f := m.folderFiles[folder].Get(protocol.LocalDeviceID, file)
|
f := m.folderFiles[folder].Get(protocol.LocalDeviceID, file)
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) CurrentGlobalFile(folder string, file string) protocol.FileInfo {
|
func (m *Model) CurrentGlobalFile(folder string, file string) protocol.FileInfo {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
f := m.folderFiles[folder].GetGlobal(file)
|
f := m.folderFiles[folder].GetGlobal(file)
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,8 +690,8 @@ func (m *Model) GetIgnores(folder string) ([]string, error) {
|
|||||||
return lines, fmt.Errorf("Folder %s does not exist", folder)
|
return lines, fmt.Errorf("Folder %s does not exist", folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
defer m.rmut.Unlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
fd, err := os.Open(filepath.Join(cfg.Directory, ".stignore"))
|
fd, err := os.Open(filepath.Join(cfg.Directory, ".stignore"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -767,20 +767,20 @@ func (m *Model) AddConnection(rawConn io.Closer, protoConn protocol.Connection)
|
|||||||
cm := m.clusterConfig(deviceID)
|
cm := m.clusterConfig(deviceID)
|
||||||
protoConn.ClusterConfig(cm)
|
protoConn.ClusterConfig(cm)
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, folder := range m.deviceFolders[deviceID] {
|
for _, folder := range m.deviceFolders[deviceID] {
|
||||||
fs := m.folderFiles[folder]
|
fs := m.folderFiles[folder]
|
||||||
go sendIndexes(protoConn, folder, fs, m.folderIgnores[folder])
|
go sendIndexes(protoConn, folder, fs, m.folderIgnores[folder])
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
m.pmut.Unlock()
|
m.pmut.Unlock()
|
||||||
|
|
||||||
m.deviceWasSeen(deviceID)
|
m.deviceWasSeen(deviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
|
func (m *Model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
defer m.rmut.Unlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
if sr, ok := m.deviceStatRefs[deviceID]; ok {
|
if sr, ok := m.deviceStatRefs[deviceID]; ok {
|
||||||
return sr
|
return sr
|
||||||
@ -886,9 +886,9 @@ func sendIndexTo(initial bool, minLocalVer uint64, conn protocol.Connection, fol
|
|||||||
|
|
||||||
func (m *Model) updateLocal(folder string, f protocol.FileInfo) {
|
func (m *Model) updateLocal(folder string, f protocol.FileInfo) {
|
||||||
f.LocalVersion = 0
|
f.LocalVersion = 0
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
m.folderFiles[folder].Update(protocol.LocalDeviceID, []protocol.FileInfo{f})
|
m.folderFiles[folder].Update(protocol.LocalDeviceID, []protocol.FileInfo{f})
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{
|
events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{
|
||||||
"folder": folder,
|
"folder": folder,
|
||||||
"name": f.Name,
|
"name": f.Name,
|
||||||
@ -922,7 +922,7 @@ func (m *Model) AddFolder(cfg config.FolderConfiguration) {
|
|||||||
panic("cannot add empty folder id")
|
panic("cannot add empty folder id")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
m.folderCfgs[cfg.ID] = cfg
|
m.folderCfgs[cfg.ID] = cfg
|
||||||
m.folderFiles[cfg.ID] = files.NewSet(cfg.ID, m.db)
|
m.folderFiles[cfg.ID] = files.NewSet(cfg.ID, m.db)
|
||||||
|
|
||||||
@ -933,16 +933,16 @@ func (m *Model) AddFolder(cfg config.FolderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.addedFolder = true
|
m.addedFolder = true
|
||||||
m.rmut.Unlock()
|
m.fmut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) ScanFolders() {
|
func (m *Model) ScanFolders() {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
var folders = make([]string, 0, len(m.folderCfgs))
|
var folders = make([]string, 0, len(m.folderCfgs))
|
||||||
for folder := range m.folderCfgs {
|
for folder := range m.folderCfgs {
|
||||||
folders = append(folders, folder)
|
folders = append(folders, folder)
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(folders))
|
wg.Add(len(folders))
|
||||||
@ -960,12 +960,12 @@ func (m *Model) ScanFolders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) CleanFolders() {
|
func (m *Model) CleanFolders() {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
var dirs = make([]string, 0, len(m.folderCfgs))
|
var dirs = make([]string, 0, len(m.folderCfgs))
|
||||||
for _, cfg := range m.folderCfgs {
|
for _, cfg := range m.folderCfgs {
|
||||||
dirs = append(dirs, cfg.Directory)
|
dirs = append(dirs, cfg.Directory)
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(dirs))
|
wg.Add(len(dirs))
|
||||||
@ -991,7 +991,7 @@ func (m *Model) ScanFolderSub(folder, sub string) error {
|
|||||||
return errors.New("invalid subpath")
|
return errors.New("invalid subpath")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
fs, ok := m.folderFiles[folder]
|
fs, ok := m.folderFiles[folder]
|
||||||
dir := m.folderCfgs[folder].Directory
|
dir := m.folderCfgs[folder].Directory
|
||||||
|
|
||||||
@ -1007,7 +1007,7 @@ func (m *Model) ScanFolderSub(folder, sub string) error {
|
|||||||
CurrentFiler: cFiler{m, folder},
|
CurrentFiler: cFiler{m, folder},
|
||||||
IgnorePerms: m.folderCfgs[folder].IgnorePerms,
|
IgnorePerms: m.folderCfgs[folder].IgnorePerms,
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("no such folder")
|
return errors.New("no such folder")
|
||||||
}
|
}
|
||||||
@ -1118,7 +1118,7 @@ func (m *Model) clusterConfig(device protocol.DeviceID) protocol.ClusterConfigMe
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, folder := range m.deviceFolders[device] {
|
for _, folder := range m.deviceFolders[device] {
|
||||||
cr := protocol.Folder{
|
cr := protocol.Folder{
|
||||||
ID: folder,
|
ID: folder,
|
||||||
@ -1139,7 +1139,7 @@ func (m *Model) clusterConfig(device protocol.DeviceID) protocol.ClusterConfigMe
|
|||||||
}
|
}
|
||||||
cm.Folders = append(cm.Folders, cr)
|
cm.Folders = append(cm.Folders, cr)
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
return cm
|
return cm
|
||||||
}
|
}
|
||||||
@ -1173,9 +1173,9 @@ func (m *Model) State(folder string) (string, time.Time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Override(folder string) {
|
func (m *Model) Override(folder string) {
|
||||||
m.rmut.RLock()
|
m.fmut.RLock()
|
||||||
fs := m.folderFiles[folder]
|
fs := m.folderFiles[folder]
|
||||||
m.rmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
m.setState(folder, FolderScanning)
|
m.setState(folder, FolderScanning)
|
||||||
batch := make([]protocol.FileInfo, 0, indexBatchSize)
|
batch := make([]protocol.FileInfo, 0, indexBatchSize)
|
||||||
@ -1210,8 +1210,8 @@ func (m *Model) Override(folder string) {
|
|||||||
// This is guaranteed to increment if the contents of the local folder has
|
// This is guaranteed to increment if the contents of the local folder has
|
||||||
// changed.
|
// changed.
|
||||||
func (m *Model) CurrentLocalVersion(folder string) uint64 {
|
func (m *Model) CurrentLocalVersion(folder string) uint64 {
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
defer m.rmut.Unlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
fs, ok := m.folderFiles[folder]
|
fs, ok := m.folderFiles[folder]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1225,8 +1225,8 @@ func (m *Model) CurrentLocalVersion(folder string) uint64 {
|
|||||||
// sent by remote peers. This is guaranteed to increment if the contents of
|
// sent by remote peers. This is guaranteed to increment if the contents of
|
||||||
// the remote or global folder has changed.
|
// the remote or global folder has changed.
|
||||||
func (m *Model) RemoteLocalVersion(folder string) uint64 {
|
func (m *Model) RemoteLocalVersion(folder string) uint64 {
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
defer m.rmut.Unlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
fs, ok := m.folderFiles[folder]
|
fs, ok := m.folderFiles[folder]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1242,8 +1242,8 @@ func (m *Model) RemoteLocalVersion(folder string) uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) availability(folder string, file string) []protocol.DeviceID {
|
func (m *Model) availability(folder string, file string) []protocol.DeviceID {
|
||||||
m.rmut.Lock()
|
m.fmut.Lock()
|
||||||
defer m.rmut.Unlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
fs, ok := m.folderFiles[folder]
|
fs, ok := m.folderFiles[folder]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -217,9 +217,9 @@ func (p *Puller) pullerIteration(ncopiers, npullers, nfinishers int) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
p.model.rmut.RLock()
|
p.model.fmut.RLock()
|
||||||
files := p.model.folderFiles[p.folder]
|
files := p.model.folderFiles[p.folder]
|
||||||
p.model.rmut.RUnlock()
|
p.model.fmut.RUnlock()
|
||||||
|
|
||||||
// !!!
|
// !!!
|
||||||
// WithNeed takes a database snapshot (by necessity). By the time we've
|
// WithNeed takes a database snapshot (by necessity). By the time we've
|
||||||
|
@ -39,13 +39,13 @@ The Announcement packet has the following structure:
|
|||||||
| Magic (0x9D79BC39) |
|
| Magic (0x9D79BC39) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Device Structure \
|
\ Device Structure \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Extra Devices |
|
| Number of Extra Devices |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Zero or more Device Structures \
|
\ Zero or more Device Structures \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
@ -123,10 +123,10 @@ The Query packet has the following structure:
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Magic Number (0x2CA856F5) |
|
| Magic Number (0x2CA856F5) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Length of Device ID |
|
| Length of Device ID |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Device ID (variable length) \
|
\ Device ID (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
@ -158,10 +158,10 @@ Cluster Config messages MUST NOT be sent after the initial exchange.
|
|||||||
\ ClientVersion (variable length) \
|
\ ClientVersion (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Folders |
|
| Number of Folders |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Zero or more Folder Structures \
|
\ Zero or more Folder Structures \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Options |
|
| Number of Options |
|
||||||
@ -183,10 +183,10 @@ Cluster Config messages MUST NOT be sent after the initial exchange.
|
|||||||
\ ID (variable length) \
|
\ ID (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Devices |
|
| Number of Devices |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Zero or more Device Structures \
|
\ Zero or more Device Structures \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
@ -350,10 +350,10 @@ Index message MUST be sent. There is no response to the Index message.
|
|||||||
0 1 2 3
|
0 1 2 3
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Length of Folder |
|
| Length of Folder |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Folder (variable length) \
|
\ Folder (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Files |
|
| Number of Files |
|
||||||
@ -513,10 +513,10 @@ corresponding to a part of a certain file in the peer's folder.
|
|||||||
0 1 2 3
|
0 1 2 3
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Length of Folder |
|
| Length of Folder |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Folder (variable length) \
|
\ Folder (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Length of Name |
|
| Length of Name |
|
||||||
@ -624,7 +624,7 @@ directions.
|
|||||||
|
|
||||||
+------------+ Updates /---------\
|
+------------+ Updates /---------\
|
||||||
| | -----------> / \
|
| | -----------> / \
|
||||||
| Device | | Cluster |
|
| Device | | Cluster |
|
||||||
| | <----------- \ /
|
| | <----------- \ /
|
||||||
+------------+ Updates \---------/
|
+------------+ Updates \---------/
|
||||||
|
|
||||||
@ -637,7 +637,7 @@ affected by the actions of other cluster devices.
|
|||||||
|
|
||||||
+------------+ Updates /---------\
|
+------------+ Updates /---------\
|
||||||
| | -----------> / \
|
| | -----------> / \
|
||||||
| Device | | Cluster |
|
| Device | | Cluster |
|
||||||
| | \ /
|
| | \ /
|
||||||
+------------+ \---------/
|
+------------+ \---------/
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user