lib/model: Incremental block stats usage reporting
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4498 LGTM: calmh
This commit is contained in:
parent
a9d422e008
commit
386cb274bd
@ -104,7 +104,7 @@ type modelIntf interface {
|
|||||||
CurrentSequence(folder string) (int64, bool)
|
CurrentSequence(folder string) (int64, bool)
|
||||||
RemoteSequence(folder string) (int64, bool)
|
RemoteSequence(folder string) (int64, bool)
|
||||||
State(folder string) (string, time.Time, error)
|
State(folder string) (string, time.Time, error)
|
||||||
UsageReportingStats(version int) map[string]interface{}
|
UsageReportingStats(version int, preview bool) map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type configIntf interface {
|
type configIntf interface {
|
||||||
@ -980,7 +980,7 @@ func (s *apiService) getReport(w http.ResponseWriter, r *http.Request) {
|
|||||||
if val, _ := strconv.Atoi(r.URL.Query().Get("version")); val > 0 {
|
if val, _ := strconv.Atoi(r.URL.Query().Get("version")); val > 0 {
|
||||||
version = val
|
version = val
|
||||||
}
|
}
|
||||||
sendJSON(w, reportData(s.cfg, s.model, s.connectionsService, version))
|
sendJSON(w, reportData(s.cfg, s.model, s.connectionsService, version, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *apiService) getRandomString(w http.ResponseWriter, r *http.Request) {
|
func (s *apiService) getRandomString(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@ -115,6 +115,6 @@ func (m *mockedModel) State(folder string) (string, time.Time, error) {
|
|||||||
return "", time.Time{}, nil
|
return "", time.Time{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockedModel) UsageReportingStats(version int) map[string]interface{} {
|
func (m *mockedModel) UsageReportingStats(version int, preview bool) map[string]interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ const usageReportVersion = 3
|
|||||||
|
|
||||||
// reportData returns the data to be sent in a usage report. It's used in
|
// reportData returns the data to be sent in a usage report. It's used in
|
||||||
// various places, so not part of the usageReportingManager object.
|
// various places, so not part of the usageReportingManager object.
|
||||||
func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf, version int) map[string]interface{} {
|
func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf, version int, preview bool) map[string]interface{} {
|
||||||
opts := cfg.Options()
|
opts := cfg.Options()
|
||||||
res := make(map[string]interface{})
|
res := make(map[string]interface{})
|
||||||
res["urVersion"] = version
|
res["urVersion"] = version
|
||||||
@ -310,7 +310,7 @@ func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf,
|
|||||||
res["guiStats"] = guiStatsInterface
|
res["guiStats"] = guiStatsInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range m.UsageReportingStats(version) {
|
for key, value := range m.UsageReportingStats(version, preview) {
|
||||||
res[key] = value
|
res[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ func newUsageReportingService(cfg *config.Wrapper, model *model.Model, connectio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *usageReportingService) sendUsageReport() error {
|
func (s *usageReportingService) sendUsageReport() error {
|
||||||
d := reportData(s.cfg, s.model, s.connectionsService, s.cfg.Options().URAccepted)
|
d := reportData(s.cfg, s.model, s.connectionsService, s.cfg.Options().URAccepted, false)
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
json.NewEncoder(&b).Encode(d)
|
json.NewEncoder(&b).Encode(d)
|
||||||
|
|
||||||
|
|||||||
@ -73,10 +73,6 @@ func (f *folder) Stop() {
|
|||||||
f.cancel()
|
f.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *folder) BlockStats() map[string]int {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckHealth checks the folder for common errors, updates the folder state
|
// CheckHealth checks the folder for common errors, updates the folder state
|
||||||
// and returns the current folder error, or nil if the folder is healthy.
|
// and returns the current folder error, or nil if the folder is healthy.
|
||||||
func (f *folder) CheckHealth() error {
|
func (f *folder) CheckHealth() error {
|
||||||
|
|||||||
@ -54,7 +54,6 @@ type service interface {
|
|||||||
Scan(subs []string) error
|
Scan(subs []string) error
|
||||||
Serve()
|
Serve()
|
||||||
Stop()
|
Stop()
|
||||||
BlockStats() map[string]int
|
|
||||||
CheckHealth() error
|
CheckHealth() error
|
||||||
|
|
||||||
getState() (folderState, time.Time, error)
|
getState() (folderState, time.Time, error)
|
||||||
@ -397,19 +396,20 @@ func (m *Model) RestartFolder(cfg config.FolderConfiguration) {
|
|||||||
m.fmut.Unlock()
|
m.fmut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) UsageReportingStats(version int) map[string]interface{} {
|
func (m *Model) UsageReportingStats(version int, preview bool) map[string]interface{} {
|
||||||
stats := make(map[string]interface{})
|
stats := make(map[string]interface{})
|
||||||
if version >= 3 {
|
if version >= 3 {
|
||||||
// Block stats
|
// Block stats
|
||||||
m.fmut.Lock()
|
blockStatsMut.Lock()
|
||||||
blockStats := make(map[string]int)
|
copyBlockStats := make(map[string]int)
|
||||||
for _, folder := range m.folderRunners {
|
for k, v := range blockStats {
|
||||||
for k, v := range folder.BlockStats() {
|
copyBlockStats[k] = v
|
||||||
blockStats[k] += v
|
if !preview {
|
||||||
|
blockStats[k] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.fmut.Unlock()
|
blockStatsMut.Unlock()
|
||||||
stats["blockStats"] = blockStats
|
stats["blockStats"] = copyBlockStats
|
||||||
|
|
||||||
// Transport stats
|
// Transport stats
|
||||||
m.pmut.Lock()
|
m.pmut.Lock()
|
||||||
|
|||||||
@ -29,6 +29,11 @@ import (
|
|||||||
"github.com/syncthing/syncthing/lib/weakhash"
|
"github.com/syncthing/syncthing/lib/weakhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
blockStats = make(map[string]int)
|
||||||
|
blockStatsMut = sync.NewMutex()
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
folderFactories[config.FolderTypeSendReceive] = newSendReceiveFolder
|
folderFactories[config.FolderTypeSendReceive] = newSendReceiveFolder
|
||||||
}
|
}
|
||||||
@ -91,9 +96,6 @@ type sendReceiveFolder struct {
|
|||||||
|
|
||||||
errors map[string]string // path -> error string
|
errors map[string]string // path -> error string
|
||||||
errorsMut sync.Mutex
|
errorsMut sync.Mutex
|
||||||
|
|
||||||
blockStats map[string]int
|
|
||||||
blockStatsMut sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
|
func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
|
||||||
@ -107,9 +109,6 @@ func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver vers
|
|||||||
pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes.
|
pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes.
|
||||||
|
|
||||||
errorsMut: sync.NewMutex(),
|
errorsMut: sync.NewMutex(),
|
||||||
|
|
||||||
blockStats: make(map[string]int),
|
|
||||||
blockStatsMut: sync.NewMutex(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.configureCopiersAndPullers()
|
f.configureCopiersAndPullers()
|
||||||
@ -886,10 +885,10 @@ func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f.blockStatsMut.Lock()
|
blockStatsMut.Lock()
|
||||||
f.blockStats["total"] += len(target.Blocks)
|
blockStats["total"] += len(target.Blocks)
|
||||||
f.blockStats["renamed"] += len(target.Blocks)
|
blockStats["renamed"] += len(target.Blocks)
|
||||||
f.blockStatsMut.Unlock()
|
blockStatsMut.Unlock()
|
||||||
|
|
||||||
// The file was renamed, so we have handled both the necessary delete
|
// The file was renamed, so we have handled both the necessary delete
|
||||||
// of the source and the creation of the target. Fix-up the metadata,
|
// of the source and the creation of the target. Fix-up the metadata,
|
||||||
@ -1457,14 +1456,16 @@ func (f *sendReceiveFolder) finisherRoutine(in <-chan *sharedPullerState) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
f.newError("finisher", state.file.Name, err)
|
f.newError("finisher", state.file.Name, err)
|
||||||
} else {
|
} else {
|
||||||
f.blockStatsMut.Lock()
|
blockStatsMut.Lock()
|
||||||
f.blockStats["total"] += state.reused + state.copyTotal + state.pullTotal
|
blockStats["total"] += state.reused + state.copyTotal + state.pullTotal
|
||||||
f.blockStats["reused"] += state.reused
|
blockStats["reused"] += state.reused
|
||||||
f.blockStats["pulled"] += state.pullTotal
|
blockStats["pulled"] += state.pullTotal
|
||||||
f.blockStats["copyOrigin"] += state.copyOrigin
|
// copyOriginShifted is counted towards copyOrigin due to progress bar reasons
|
||||||
f.blockStats["copyOriginShifted"] += state.copyOriginShifted
|
// for reporting reasons we want to separate these.
|
||||||
f.blockStats["copyElsewhere"] += state.copyTotal - state.copyOrigin
|
blockStats["copyOrigin"] += state.copyOrigin - state.copyOriginShifted
|
||||||
f.blockStatsMut.Unlock()
|
blockStats["copyOriginShifted"] += state.copyOriginShifted
|
||||||
|
blockStats["copyElsewhere"] += state.copyTotal - state.copyOrigin
|
||||||
|
blockStatsMut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
||||||
@ -1482,16 +1483,6 @@ func (f *sendReceiveFolder) finisherRoutine(in <-chan *sharedPullerState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *sendReceiveFolder) BlockStats() map[string]int {
|
|
||||||
f.blockStatsMut.Lock()
|
|
||||||
stats := make(map[string]int)
|
|
||||||
for k, v := range f.blockStats {
|
|
||||||
stats[k] = v
|
|
||||||
}
|
|
||||||
f.blockStatsMut.Unlock()
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moves the given filename to the front of the job queue
|
// Moves the given filename to the front of the job queue
|
||||||
func (f *sendReceiveFolder) BringToFront(filename string) {
|
func (f *sendReceiveFolder) BringToFront(filename string) {
|
||||||
f.queue.BringToFront(filename)
|
f.queue.BringToFront(filename)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user