Immediately recalculate summary when folder state changes syncing->idle

This commit is contained in:
Jakob Borg 2015-03-29 10:25:41 +02:00
parent 454e688c3d
commit e4dba99cc0

View File

@ -21,6 +21,7 @@ type folderSummarySvc struct {
model *model.Model
srv suture.Service
stop chan struct{}
immediate chan string
// For keeping track of folders to recalculate for
foldersMut sync.Mutex
@ -32,6 +33,7 @@ func (c *folderSummarySvc) Serve() {
srv.Add(serviceFunc(c.listenForUpdates))
srv.Add(serviceFunc(c.calculateSummaries))
c.immediate = make(chan string)
c.stop = make(chan struct{})
c.folders = make(map[string]struct{})
c.srv = srv
@ -50,7 +52,7 @@ func (c *folderSummarySvc) Stop() {
// listenForUpdates subscribes to the event bus and makes note of folders that
// need their data recalculated.
func (c *folderSummarySvc) listenForUpdates() {
sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated)
sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged)
defer events.Default.Unsubscribe(sub)
for {
@ -63,9 +65,29 @@ func (c *folderSummarySvc) listenForUpdates() {
data := ev.Data.(map[string]interface{})
folder := data["folder"].(string)
if ev.Type == events.StateChanged && data["to"].(string) == "idle" && data["from"].(string) == "syncing" {
// The folder changed to idle from syncing. We should do an
// immediate refresh to update the GUI. The send to
// c.immediate must be nonblocking so that we can continue
// handling events.
select {
case c.immediate <- folder:
c.foldersMut.Lock()
delete(c.folders, folder)
c.foldersMut.Unlock()
default:
}
} else {
// This folder needs to be refreshed whenever we do the next
// refresh.
c.foldersMut.Lock()
c.folders[folder] = struct{}{}
c.foldersMut.Unlock()
}
case <-c.stop:
return
@ -82,6 +104,29 @@ func (c *folderSummarySvc) calculateSummaries() {
for {
select {
case <-pump.C:
t0 := time.Now()
for _, folder := range c.foldersToHandle() {
c.sendSummary(folder)
}
// We don't want to spend all our time calculating summaries. Lets
// set an arbitrary limit at not spending more than about 30% of
// our time here...
wait := 2*time.Since(t0) + pumpInterval
pump.Reset(wait)
case folder := <-c.immediate:
c.sendSummary(folder)
case <-c.stop:
return
}
}
}
// foldersToHandle returns the list of folders needing a summary update, and
// clears the list.
func (c *folderSummarySvc) foldersToHandle() []string {
// We only recalculate sumamries if someone is listening to events
// (a request to /rest/events has been made within the last
// pingEventInterval).
@ -92,10 +137,22 @@ func (c *folderSummarySvc) calculateSummaries() {
// we can query about this kind of thing?
last := lastEventRequest
lastEventRequestMut.Unlock()
t0 := time.Now()
if time.Since(last) < pingEventInterval {
for _, folder := range c.foldersToHandle() {
return nil
}
c.foldersMut.Lock()
res := make([]string, 0, len(c.folders))
for folder := range c.folders {
res = append(res, folder)
delete(c.folders, folder)
}
c.foldersMut.Unlock()
return res
}
// sendSummary send the summary events for a single folder
func (c *folderSummarySvc) sendSummary(folder string) {
// The folder summary contains how many bytes, files etc
// are in the folder and how in sync we are.
data := folderSummary(c.model, folder)
@ -124,32 +181,6 @@ func (c *folderSummarySvc) calculateSummaries() {
})
}
}
}
// We don't want to spend all our time calculating summaries. Lets
// set an arbitrary limit at not spending more than about 30% of
// our time here...
wait := 2*time.Since(t0) + pumpInterval
pump.Reset(wait)
case <-c.stop:
return
}
}
}
// foldersToHandle returns the list of folders needing a summary update, and
// clears the list.
func (c *folderSummarySvc) foldersToHandle() []string {
c.foldersMut.Lock()
res := make([]string, 0, len(c.folders))
for folder := range c.folders {
res = append(res, folder)
delete(c.folders, folder)
}
c.foldersMut.Unlock()
return res
}
// serviceFunc wraps a function to create a suture.Service without stop
// functionality.