mirror of
https://github.com/rclone/rclone.git
synced 2024-11-07 17:14:44 +01:00
8243ff8bc8
Introduce stats groups that will isolate accounting for logically different transferring operations. That way multiple accounting operations can be done in parallel without interfering with each other stats. Using groups is optional. There is dedicated global stats that will be used by default if no group is specified. This is operating mode for CLI usage which is just fire and forget operation. For running rclone as rc http server each request will create it's own group. Also there is an option to specify your own group.
104 lines
2.1 KiB
Go
104 lines
2.1 KiB
Go
package accounting
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/ncw/rclone/fs"
|
|
)
|
|
|
|
// stringSet holds a set of strings
|
|
type stringSet struct {
|
|
mu sync.RWMutex
|
|
items map[string]struct{}
|
|
name string
|
|
}
|
|
|
|
// newStringSet creates a new empty string set of capacity size
|
|
func newStringSet(size int, name string) *stringSet {
|
|
return &stringSet{
|
|
items: make(map[string]struct{}, size),
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
// add adds remote to the set
|
|
func (ss *stringSet) add(remote string) {
|
|
ss.mu.Lock()
|
|
ss.items[remote] = struct{}{}
|
|
ss.mu.Unlock()
|
|
}
|
|
|
|
// del removes remote from the set
|
|
func (ss *stringSet) del(remote string) {
|
|
ss.mu.Lock()
|
|
delete(ss.items, remote)
|
|
ss.mu.Unlock()
|
|
}
|
|
|
|
// merge adds items from another set
|
|
func (ss *stringSet) merge(m *stringSet) {
|
|
ss.mu.Lock()
|
|
m.mu.Lock()
|
|
for item := range m.items {
|
|
ss.items[item] = struct{}{}
|
|
}
|
|
m.mu.Unlock()
|
|
ss.mu.Unlock()
|
|
}
|
|
|
|
// empty returns whether the set has any items
|
|
func (ss *stringSet) empty() bool {
|
|
ss.mu.RLock()
|
|
defer ss.mu.RUnlock()
|
|
return len(ss.items) == 0
|
|
}
|
|
|
|
// count returns the number of items in the set
|
|
func (ss *stringSet) count() int {
|
|
ss.mu.RLock()
|
|
defer ss.mu.RUnlock()
|
|
return len(ss.items)
|
|
}
|
|
|
|
// String returns string representation of set items.
|
|
func (ss *stringSet) String(progress *inProgress) string {
|
|
ss.mu.RLock()
|
|
defer ss.mu.RUnlock()
|
|
strngs := make([]string, 0, len(ss.items))
|
|
for name := range ss.items {
|
|
var out string
|
|
if acc := progress.get(name); acc != nil {
|
|
out = acc.String()
|
|
} else {
|
|
out = fmt.Sprintf("%*s: %s",
|
|
fs.Config.StatsFileNameLength,
|
|
shortenName(name, fs.Config.StatsFileNameLength),
|
|
ss.name,
|
|
)
|
|
}
|
|
strngs = append(strngs, " * "+out)
|
|
}
|
|
sorted := sort.StringSlice(strngs)
|
|
sorted.Sort()
|
|
return strings.Join(sorted, "\n")
|
|
}
|
|
|
|
// progress returns total bytes read as well as the size.
|
|
func (ss *stringSet) progress(stats *StatsInfo) (totalBytes, totalSize int64) {
|
|
ss.mu.RLock()
|
|
defer ss.mu.RUnlock()
|
|
for name := range ss.items {
|
|
if acc := stats.inProgress.get(name); acc != nil {
|
|
bytes, size := acc.progress()
|
|
if size >= 0 && bytes >= 0 {
|
|
totalBytes += bytes
|
|
totalSize += size
|
|
}
|
|
}
|
|
}
|
|
return totalBytes, totalSize
|
|
}
|