diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go
index 98a80933..cbf2da76 100644
--- a/cmd/syncthing/gui.go
+++ b/cmd/syncthing/gui.go
@@ -149,6 +149,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
postRestMux.HandleFunc("/rest/shutdown", restPostShutdown)
postRestMux.HandleFunc("/rest/upgrade", restPostUpgrade)
postRestMux.HandleFunc("/rest/scan", withModel(m, restPostScan))
+ postRestMux.HandleFunc("/rest/bump", withModel(m, restPostBump))
// A handler that splits requests between the two above and disables
// caching
@@ -314,19 +315,12 @@ func restGetNeed(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var folder = qs.Get("folder")
- files := m.NeedFolderFilesLimited(folder, 100) // max 100 files
+ progress, queued, rest := m.NeedFolderFiles(folder, 100)
// Convert the struct to a more loose structure, and inject the size.
- output := make([]map[string]interface{}, 0, len(files))
- for _, file := range files {
- output = append(output, map[string]interface{}{
- "Name": file.Name,
- "Flags": file.Flags,
- "Modified": file.Modified,
- "Version": file.Version,
- "LocalVersion": file.LocalVersion,
- "NumBlocks": file.NumBlocks,
- "Size": protocol.BlocksToSize(file.NumBlocks),
- })
+ output := map[string][]map[string]interface{}{
+ "progress": toNeedSlice(progress),
+ "queued": toNeedSlice(queued),
+ "rest": toNeedSlice(rest),
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
@@ -650,6 +644,14 @@ func restPostScan(m *model.Model, w http.ResponseWriter, r *http.Request) {
}
}
+func restPostBump(m *model.Model, w http.ResponseWriter, r *http.Request) {
+ qs := r.URL.Query()
+ folder := qs.Get("folder")
+ file := qs.Get("file")
+ m.BringToFront(folder, file)
+ restGetNeed(m, w, r)
+}
+
func getQR(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var text = qs.Get("text")
@@ -775,3 +777,19 @@ func mimeTypeForFile(file string) string {
return mime.TypeByExtension(ext)
}
}
+
+func toNeedSlice(files []protocol.FileInfoTruncated) []map[string]interface{} {
+ output := make([]map[string]interface{}, len(files))
+ for i, file := range files {
+ output[i] = map[string]interface{}{
+ "Name": file.Name,
+ "Flags": file.Flags,
+ "Modified": file.Modified,
+ "Version": file.Version,
+ "LocalVersion": file.LocalVersion,
+ "NumBlocks": file.NumBlocks,
+ "Size": protocol.BlocksToSize(file.NumBlocks),
+ }
+ }
+ return output
+}
diff --git a/gui/index.html b/gui/index.html
index 890c8da3..b1fb4251 100644
--- a/gui/index.html
+++ b/gui/index.html
@@ -801,21 +801,37 @@
-
+
| {{needActions[a]}} |
{{f.Name | basename}} |
-
-
-
-
-
-
-
-
- {{progress[neededFolder][f.Name].BytesDone | binary}}B / {{progress[neededFolder][f.Name].BytesTotal | binary}}B
-
-
+ |
+
+
+
+
+
+
+
+ {{progress[neededFolder][f.Name].BytesDone | binary}}B / {{progress[neededFolder][f.Name].BytesTotal | binary}}B
+
+
|
+
+ {{f.Size | binary}}B
+ |
+
+
+ | {{needActions[a]}} |
+ {{f.Name | basename}} |
+
+
+ {{f.Size | binary}}B
+ |
+
+
+ | {{needActions[a]}} |
+ {{f.Name | basename}} |
+ {{f.Size | binary}}B |
diff --git a/gui/scripts/syncthing/core/controllers/syncthingController.js b/gui/scripts/syncthing/core/controllers/syncthingController.js
index 14142c1f..387030d3 100644
--- a/gui/scripts/syncthing/core/controllers/syncthingController.js
+++ b/gui/scripts/syncthing/core/controllers/syncthingController.js
@@ -1056,6 +1056,15 @@ angular.module('syncthing.core')
$http.post(urlbase + "/scan?folder=" + encodeURIComponent(folder));
};
+ $scope.bumpFile = function (folder, file) {
+ $http.post(urlbase + "/bump?folder=" + encodeURIComponent(folder) + "&file=" + encodeURIComponent(file)).success(function (data) {
+ if ($scope.neededFolder == folder) {
+ console.log("bumpFile", folder, data);
+ $scope.needed = data;
+ }
+ });
+ };
+
// pseudo main. called on all definitions assigned
initController();
});
diff --git a/internal/auto/gui.files.go b/internal/auto/gui.files.go
index 6f7d1b08..7b5b2ad0 100644
--- a/internal/auto/gui.files.go
+++ b/internal/auto/gui.files.go
@@ -147,7 +147,7 @@ func Assets() map[string][]byte {
bs, _ = ioutil.ReadAll(gr)
assets["assets/lang/valid-langs.js"] = bs
- bs, _ = base64.StdEncoding.DecodeString("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")
+ bs, _ = base64.StdEncoding.DecodeString("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")
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
bs, _ = ioutil.ReadAll(gr)
assets["index.html"] = bs
@@ -167,7 +167,7 @@ func Assets() map[string][]byte {
bs, _ = ioutil.ReadAll(gr)
assets["scripts/syncthing/core/controllers/eventController.js"] = bs
- bs, _ = base64.StdEncoding.DecodeString("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")
+ bs, _ = base64.StdEncoding.DecodeString("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")
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
bs, _ = ioutil.ReadAll(gr)
assets["scripts/syncthing/core/controllers/syncthingController.js"] = bs
diff --git a/internal/model/model.go b/internal/model/model.go
index c1a64d1e..c17bc366 100644
--- a/internal/model/model.go
+++ b/internal/model/model.go
@@ -79,6 +79,8 @@ const (
type service interface {
Serve()
Stop()
+ Jobs() ([]string, []string) // In progress, Queued
+ BringToFront(string)
}
type Model struct {
@@ -189,6 +191,7 @@ func (m *Model) StartFolderRW(folder string) {
copiers: cfg.Copiers,
pullers: cfg.Pullers,
finishers: cfg.Finishers,
+ queue: newJobQueue(),
}
m.folderRunners[folder] = p
m.fmut.Unlock()
@@ -416,22 +419,50 @@ func (m *Model) NeedSize(folder string) (files int, bytes int64) {
return
}
-// NeedFiles returns the list of currently needed files, stopping at maxFiles
-// files. Limit <= 0 is ignored.
-func (m *Model) NeedFolderFilesLimited(folder string, maxFiles int) []protocol.FileInfoTruncated {
+// NeedFiles returns the list of currently needed files in progress, queued,
+// and to be queued on next puller iteration. Also takes a soft cap which is
+// only respected when adding files from the model rather than the runner queue.
+func (m *Model) NeedFolderFiles(folder string, max int) ([]protocol.FileInfoTruncated, []protocol.FileInfoTruncated, []protocol.FileInfoTruncated) {
defer m.leveldbPanicWorkaround()
m.fmut.RLock()
defer m.fmut.RUnlock()
if rf, ok := m.folderFiles[folder]; ok {
- fs := make([]protocol.FileInfoTruncated, 0, maxFiles)
- rf.WithNeedTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
- fs = append(fs, f.(protocol.FileInfoTruncated))
- return maxFiles <= 0 || len(fs) < maxFiles
- })
- return fs
+ var progress, queued, rest []protocol.FileInfoTruncated
+ var seen map[string]bool
+
+ runner, ok := m.folderRunners[folder]
+ if ok {
+ progressNames, queuedNames := runner.Jobs()
+
+ progress = make([]protocol.FileInfoTruncated, len(progressNames))
+ queued = make([]protocol.FileInfoTruncated, len(queuedNames))
+ seen = make(map[string]bool, len(progressNames)+len(queuedNames))
+
+ for i, name := range progressNames {
+ progress[i] = rf.GetGlobal(name).ToTruncated() /// XXX: Should implement GetGlobalTruncated directly
+ seen[name] = true
+ }
+
+ for i, name := range queuedNames {
+ queued[i] = rf.GetGlobal(name).ToTruncated() /// XXX: Should implement GetGlobalTruncated directly
+ seen[name] = true
+ }
+ }
+ left := max - len(progress) - len(queued)
+ if max < 1 || left > 0 {
+ rf.WithNeedTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
+ left--
+ ft := f.(protocol.FileInfoTruncated)
+ if !seen[ft.Name] {
+ rest = append(rest, ft)
+ }
+ return max < 1 || left > 0
+ })
+ }
+ return progress, queued, rest
}
- return nil
+ return nil, nil, nil
}
// Index is called when a new device is connected and we receive their full index.
@@ -1336,7 +1367,7 @@ func (m *Model) RemoteLocalVersion(folder string) uint64 {
return ver
}
-func (m *Model) availability(folder string, file string) []protocol.DeviceID {
+func (m *Model) availability(folder, file string) []protocol.DeviceID {
// Acquire this lock first, as the value returned from foldersFiles can
// gen heavily modified on Close()
m.pmut.RLock()
@@ -1359,6 +1390,17 @@ func (m *Model) availability(folder string, file string) []protocol.DeviceID {
return availableDevices
}
+// Bump the given files priority in the job queue
+func (m *Model) BringToFront(folder, file string) {
+ m.pmut.RLock()
+ defer m.pmut.RUnlock()
+
+ runner, ok := m.folderRunners[folder]
+ if ok {
+ runner.BringToFront(file)
+ }
+}
+
func (m *Model) String() string {
return fmt.Sprintf("model@%p", m)
}
diff --git a/internal/model/puller.go b/internal/model/puller.go
index 1d9fea68..e1d063dd 100644
--- a/internal/model/puller.go
+++ b/internal/model/puller.go
@@ -78,6 +78,7 @@ type Puller struct {
copiers int
pullers int
finishers int
+ queue *jobQueue
}
// Serve will run scans and pulls. It will return when Stop()ed or on a
@@ -337,15 +338,23 @@ func (p *Puller) pullerIteration(checksum bool, ignores *ignore.Matcher) int {
p.handleDir(file)
default:
// A new or changed file or symlink. This is the only case where we
- // do stuff in the background; the other three are done
- // synchronously.
- p.handleFile(file, copyChan, finisherChan)
+ // do stuff concurrently in the background
+ p.queue.Push(file.Name)
}
changed++
return true
})
+ for {
+ fileName, ok := p.queue.Pop()
+ if !ok {
+ break
+ }
+ f := p.model.CurrentGlobalFile(p.folder, fileName)
+ p.handleFile(f, copyChan, finisherChan)
+ }
+
// Signal copy and puller routines that we are done with the in data for
// this iteration. Wait for them to finish.
close(copyChan)
@@ -483,6 +492,7 @@ func (p *Puller) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksSt
if debug {
l.Debugln(p, "taking shortcut on", file.Name)
}
+ p.queue.Done(file.Name)
if file.IsSymlink() {
p.shortcutSymlink(curFile, file)
} else {
@@ -850,6 +860,7 @@ func (p *Puller) finisherRoutine(in <-chan *sharedPullerState) {
continue
}
+ p.queue.Done(state.file.Name)
p.performFinish(state)
p.model.receivedFile(p.folder, state.file.Name)
if p.progressEmitter != nil {
@@ -859,6 +870,15 @@ func (p *Puller) finisherRoutine(in <-chan *sharedPullerState) {
}
}
+// Moves the given filename to the front of the job queue
+func (p *Puller) BringToFront(filename string) {
+ p.queue.BringToFront(filename)
+}
+
+func (p *Puller) Jobs() ([]string, []string) {
+ return p.queue.Jobs()
+}
+
func invalidateFolder(cfg *config.Configuration, folderID string, err error) {
for i := range cfg.Folders {
folder := &cfg.Folders[i]
diff --git a/internal/model/queue.go b/internal/model/queue.go
new file mode 100644
index 00000000..a4f34dab
--- /dev/null
+++ b/internal/model/queue.go
@@ -0,0 +1,94 @@
+// Copyright (C) 2014 The Syncthing Authors.
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see .
+
+package model
+
+import "sync"
+
+type jobQueue struct {
+ progress []string
+ queued []string
+ mut sync.Mutex
+}
+
+func newJobQueue() *jobQueue {
+ return &jobQueue{}
+}
+
+func (q *jobQueue) Push(file string) {
+ q.mut.Lock()
+ q.queued = append(q.queued, file)
+ q.mut.Unlock()
+}
+
+func (q *jobQueue) Pop() (string, bool) {
+ q.mut.Lock()
+ defer q.mut.Unlock()
+
+ if len(q.queued) == 0 {
+ return "", false
+ }
+
+ var f string
+ f = q.queued[0]
+ q.queued = q.queued[1:]
+ q.progress = append(q.progress, f)
+
+ return f, true
+}
+
+func (q *jobQueue) BringToFront(filename string) {
+ q.mut.Lock()
+ defer q.mut.Unlock()
+
+ for i, cur := range q.queued {
+ if cur == filename {
+ if i > 0 {
+ // Shift the elements before the selected element one step to
+ // the right, overwriting the selected element
+ copy(q.queued[1:i+1], q.queued[0:])
+ // Put the selected element at the front
+ q.queued[0] = cur
+ }
+ return
+ }
+ }
+}
+
+func (q *jobQueue) Done(file string) {
+ q.mut.Lock()
+ defer q.mut.Unlock()
+
+ for i := range q.progress {
+ if q.progress[i] == file {
+ copy(q.progress[i:], q.progress[i+1:])
+ q.progress = q.progress[:len(q.progress)-1]
+ return
+ }
+ }
+}
+
+func (q *jobQueue) Jobs() ([]string, []string) {
+ q.mut.Lock()
+ defer q.mut.Unlock()
+
+ progress := make([]string, len(q.progress))
+ copy(progress, q.progress)
+
+ queued := make([]string, len(q.queued))
+ copy(queued, q.queued)
+
+ return progress, queued
+}
diff --git a/internal/model/queue_test.go b/internal/model/queue_test.go
new file mode 100644
index 00000000..37456644
--- /dev/null
+++ b/internal/model/queue_test.go
@@ -0,0 +1,200 @@
+// Copyright (C) 2014 The Syncthing Authors.
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see .
+
+package model
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestJobQueue(t *testing.T) {
+ // Some random actions
+ q := newJobQueue()
+ q.Push("f1")
+ q.Push("f2")
+ q.Push("f3")
+ q.Push("f4")
+
+ progress, queued := q.Jobs()
+ if len(progress) != 0 || len(queued) != 4 {
+ t.Fatal("Wrong length")
+ }
+
+ for i := 1; i < 5; i++ {
+ n, ok := q.Pop()
+ if !ok || n != fmt.Sprintf("f%d", i) {
+ t.Fatal("Wrong element")
+ }
+ progress, queued = q.Jobs()
+ if len(progress) != 1 || len(queued) != 3 {
+ t.Log(progress)
+ t.Log(queued)
+ t.Fatal("Wrong length")
+ }
+
+ q.Done(n)
+ progress, queued = q.Jobs()
+ if len(progress) != 0 || len(queued) != 3 {
+ t.Fatal("Wrong length", len(progress), len(queued))
+ }
+
+ q.Push(n)
+ progress, queued = q.Jobs()
+ if len(progress) != 0 || len(queued) != 4 {
+ t.Fatal("Wrong length")
+ }
+
+ q.Done("f5") // Does not exist
+ progress, queued = q.Jobs()
+ if len(progress) != 0 || len(queued) != 4 {
+ t.Fatal("Wrong length")
+ }
+ }
+
+ if len(q.progress) > 0 || len(q.queued) != 4 {
+ t.Fatal("Wrong length")
+ }
+
+ for i := 4; i > 0; i-- {
+ progress, queued = q.Jobs()
+ if len(progress) != 4-i || len(queued) != i {
+ t.Fatal("Wrong length")
+ }
+
+ s := fmt.Sprintf("f%d", i)
+
+ q.BringToFront(s)
+ progress, queued = q.Jobs()
+ if len(progress) != 4-i || len(queued) != i {
+ t.Fatal("Wrong length")
+ }
+
+ n, ok := q.Pop()
+ if !ok || n != s {
+ t.Fatal("Wrong element")
+ }
+ progress, queued = q.Jobs()
+ if len(progress) != 5-i || len(queued) != i-1 {
+ t.Fatal("Wrong length")
+ }
+
+ q.Done("f5") // Does not exist
+ progress, queued = q.Jobs()
+ if len(progress) != 5-i || len(queued) != i-1 {
+ t.Fatal("Wrong length")
+ }
+ }
+
+ _, ok := q.Pop()
+ if len(q.progress) != 4 || ok {
+ t.Fatal("Wrong length")
+ }
+
+ q.Done("f1")
+ q.Done("f2")
+ q.Done("f3")
+ q.Done("f4")
+ q.Done("f5") // Does not exist
+
+ _, ok = q.Pop()
+ if len(q.progress) != 0 || ok {
+ t.Fatal("Wrong length")
+ }
+
+ progress, queued = q.Jobs()
+ if len(progress) != 0 || len(queued) != 0 {
+ t.Fatal("Wrong length")
+ }
+ q.BringToFront("")
+ q.Done("f5") // Does not exist
+ progress, queued = q.Jobs()
+ if len(progress) != 0 || len(queued) != 0 {
+ t.Fatal("Wrong length")
+ }
+}
+
+func TestBringToFront(t *testing.T) {
+ q := newJobQueue()
+ q.Push("f1")
+ q.Push("f2")
+ q.Push("f3")
+ q.Push("f4")
+
+ _, queued := q.Jobs()
+ if !reflect.DeepEqual(queued, []string{"f1", "f2", "f3", "f4"}) {
+ t.Errorf("Incorrect order %v at start", queued)
+ }
+
+ q.BringToFront("f1") // corner case: does nothing
+
+ _, queued = q.Jobs()
+ if !reflect.DeepEqual(queued, []string{"f1", "f2", "f3", "f4"}) {
+ t.Errorf("Incorrect order %v", queued)
+ }
+
+ q.BringToFront("f3")
+
+ _, queued = q.Jobs()
+ if !reflect.DeepEqual(queued, []string{"f3", "f1", "f2", "f4"}) {
+ t.Errorf("Incorrect order %v", queued)
+ }
+
+ q.BringToFront("f2")
+
+ _, queued = q.Jobs()
+ if !reflect.DeepEqual(queued, []string{"f2", "f3", "f1", "f4"}) {
+ t.Errorf("Incorrect order %v", queued)
+ }
+
+ q.BringToFront("f4") // corner case: last element
+
+ _, queued = q.Jobs()
+ if !reflect.DeepEqual(queued, []string{"f4", "f2", "f3", "f1"}) {
+ t.Errorf("Incorrect order %v", queued)
+ }
+}
+
+func BenchmarkJobQueueBump(b *testing.B) {
+ files := genFiles(b.N)
+
+ q := newJobQueue()
+ for _, f := range files {
+ q.Push(f.Name)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ q.BringToFront(files[i].Name)
+ }
+}
+
+func BenchmarkJobQueuePushPopDone10k(b *testing.B) {
+ files := genFiles(10000)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ q := newJobQueue()
+ for _, f := range files {
+ q.Push(f.Name)
+ }
+ for range files {
+ n, _ := q.Pop()
+ q.Done(n)
+ }
+ }
+
+}
diff --git a/internal/model/scanner.go b/internal/model/scanner.go
index 98c1fc2d..c2824b60 100644
--- a/internal/model/scanner.go
+++ b/internal/model/scanner.go
@@ -75,3 +75,9 @@ func (s *Scanner) Stop() {
func (s *Scanner) String() string {
return fmt.Sprintf("scanner/%s@%p", s.folder, s)
}
+
+func (s *Scanner) BringToFront(string) {}
+
+func (s *Scanner) Jobs() ([]string, []string) {
+ return nil, nil
+}
diff --git a/internal/protocol/message.go b/internal/protocol/message.go
index 8cc191d8..ae04a9da 100644
--- a/internal/protocol/message.go
+++ b/internal/protocol/message.go
@@ -69,6 +69,17 @@ func (f FileInfo) HasPermissionBits() bool {
return f.Flags&FlagNoPermBits == 0
}
+func (f FileInfo) ToTruncated() FileInfoTruncated {
+ return FileInfoTruncated{
+ Name: f.Name,
+ Flags: f.Flags,
+ Modified: f.Modified,
+ Version: f.Version,
+ LocalVersion: f.LocalVersion,
+ NumBlocks: uint32(len(f.Blocks)),
+ }
+}
+
// Used for unmarshalling a FileInfo structure but skipping the actual block list
type FileInfoTruncated struct {
Name string // max:8192