github.com/divyam234/rclone@v1.64.1/fs/accounting/transfermap.go (about) 1 package accounting 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "strings" 8 "sync" 9 10 "github.com/divyam234/rclone/fs" 11 "github.com/divyam234/rclone/fs/rc" 12 ) 13 14 // transferMap holds name to transfer map 15 type transferMap struct { 16 mu sync.RWMutex 17 items map[string]*Transfer 18 name string 19 } 20 21 // newTransferMap creates a new empty transfer map of capacity size 22 func newTransferMap(size int, name string) *transferMap { 23 return &transferMap{ 24 items: make(map[string]*Transfer, size), 25 name: name, 26 } 27 } 28 29 // add adds a new transfer to the map 30 func (tm *transferMap) add(tr *Transfer) { 31 tm.mu.Lock() 32 tm.items[tr.remote] = tr 33 tm.mu.Unlock() 34 } 35 36 // del removes a transfer from the map by name 37 func (tm *transferMap) del(remote string) bool { 38 tm.mu.Lock() 39 _, exists := tm.items[remote] 40 delete(tm.items, remote) 41 tm.mu.Unlock() 42 43 return exists 44 } 45 46 // merge adds items from another map 47 func (tm *transferMap) merge(m *transferMap) { 48 tm.mu.Lock() 49 m.mu.Lock() 50 for name, tr := range m.items { 51 tm.items[name] = tr 52 } 53 m.mu.Unlock() 54 tm.mu.Unlock() 55 } 56 57 // empty returns whether the map has any items 58 func (tm *transferMap) empty() bool { 59 tm.mu.RLock() 60 defer tm.mu.RUnlock() 61 return len(tm.items) == 0 62 } 63 64 // count returns the number of items in the map 65 func (tm *transferMap) count() int { 66 tm.mu.RLock() 67 defer tm.mu.RUnlock() 68 return len(tm.items) 69 } 70 71 // _sortedSlice returns all transfers sorted by start time 72 // 73 // Call with mu.Rlock held 74 func (tm *transferMap) _sortedSlice() []*Transfer { 75 s := make([]*Transfer, 0, len(tm.items)) 76 for _, tr := range tm.items { 77 s = append(s, tr) 78 } 79 // sort by time first and if equal by name. Note that the relatively 80 // low time resolution on Windows can cause equal times. 81 sort.Slice(s, func(i, j int) bool { 82 a, b := s[i], s[j] 83 if a.startedAt.Before(b.startedAt) { 84 return true 85 } else if !a.startedAt.Equal(b.startedAt) { 86 return false 87 } 88 return a.remote < b.remote 89 }) 90 return s 91 } 92 93 // String returns string representation of map items excluding any in 94 // exclude (if set). 95 func (tm *transferMap) String(ctx context.Context, progress *inProgress, exclude *transferMap) string { 96 tm.mu.RLock() 97 defer tm.mu.RUnlock() 98 ci := fs.GetConfig(ctx) 99 stringList := make([]string, 0, len(tm.items)) 100 for _, tr := range tm._sortedSlice() { 101 var what = tr.what 102 if exclude != nil { 103 exclude.mu.RLock() 104 _, found := exclude.items[tr.remote] 105 exclude.mu.RUnlock() 106 if found { 107 continue 108 } 109 } 110 var out string 111 if acc := progress.get(tr.remote); acc != nil { 112 out = acc.String() 113 if what != "" { 114 out += ", " + what 115 } 116 } else { 117 if what == "" { 118 what = tm.name 119 } 120 out = fmt.Sprintf("%*s: %s", 121 ci.StatsFileNameLength, 122 shortenName(tr.remote, ci.StatsFileNameLength), 123 what, 124 ) 125 } 126 stringList = append(stringList, " * "+out) 127 } 128 return strings.Join(stringList, "\n") 129 } 130 131 // progress returns total bytes read as well as the size. 132 func (tm *transferMap) progress(stats *StatsInfo) (totalBytes, totalSize int64) { 133 tm.mu.RLock() 134 defer tm.mu.RUnlock() 135 for name := range tm.items { 136 if acc := stats.inProgress.get(name); acc != nil { 137 bytes, size := acc.progress() 138 if size >= 0 && bytes >= 0 { 139 totalBytes += bytes 140 totalSize += size 141 } 142 } 143 } 144 return totalBytes, totalSize 145 } 146 147 // remotes returns a []string of the remote names for the transferMap 148 func (tm *transferMap) remotes() (c []string) { 149 tm.mu.RLock() 150 defer tm.mu.RUnlock() 151 for _, tr := range tm._sortedSlice() { 152 c = append(c, tr.remote) 153 } 154 return c 155 } 156 157 // rcStats returns a []rc.Params of the stats for the transferMap 158 func (tm *transferMap) rcStats(progress *inProgress) (t []rc.Params) { 159 tm.mu.RLock() 160 defer tm.mu.RUnlock() 161 for _, tr := range tm._sortedSlice() { 162 if acc := progress.get(tr.remote); acc != nil { 163 t = append(t, acc.rcStats()) 164 } else { 165 t = append(t, tr.rcStats()) 166 } 167 } 168 return t 169 }