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  }