]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Fix harmless race conditions in Client.WriteStatus introduced way back
authorMatt Joiner <anacrolix@gmail.com>
Sun, 27 Nov 2016 03:26:45 +0000 (14:26 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Sun, 27 Nov 2016 03:26:45 +0000 (14:26 +1100)
client.go
torrent.go

index 2e6ded8b6b213df33febba064b8b0761351133a1..5dfb465efc72e5c91f3fb4c4173ad3b9d76fe749 100644 (file)
--- a/client.go
+++ b/client.go
@@ -79,6 +79,10 @@ type Client struct {
 func (cl *Client) BadPeerIPs() []string {
        cl.mu.RLock()
        defer cl.mu.RUnlock()
+       return cl.badPeerIPsLocked()
+}
+
+func (cl *Client) badPeerIPsLocked() []string {
        return slices.FromMapKeys(cl.badPeerIPs).([]string)
 }
 
@@ -123,6 +127,8 @@ func (cl *Client) sortedTorrents() (ret []*Torrent) {
 // Writes out a human readable status of the client, such as for writing to a
 // HTTP status page.
 func (cl *Client) WriteStatus(_w io.Writer) {
+       cl.mu.Lock()
+       defer cl.mu.Unlock()
        w := bufio.NewWriter(_w)
        defer w.Flush()
        if addr := cl.ListenAddr(); addr != nil {
@@ -131,7 +137,7 @@ func (cl *Client) WriteStatus(_w io.Writer) {
                fmt.Fprintln(w, "Not listening!")
        }
        fmt.Fprintf(w, "Peer ID: %+q\n", cl.PeerID())
-       fmt.Fprintf(w, "Banned IPs: %d\n", len(cl.BadPeerIPs()))
+       fmt.Fprintf(w, "Banned IPs: %d\n", len(cl.badPeerIPsLocked()))
        if dht := cl.DHT(); dht != nil {
                dhtStats := dht.Stats()
                fmt.Fprintf(w, "DHT nodes: %d (%d good, %d banned)\n", dhtStats.Nodes, dhtStats.GoodNodes, dhtStats.BadNodes)
@@ -140,19 +146,19 @@ func (cl *Client) WriteStatus(_w io.Writer) {
                fmt.Fprintf(w, "DHT announces: %d\n", dhtStats.ConfirmedAnnounces)
                fmt.Fprintf(w, "Outstanding transactions: %d\n", dhtStats.OutstandingTransactions)
        }
-       fmt.Fprintf(w, "# Torrents: %d\n", len(cl.Torrents()))
+       fmt.Fprintf(w, "# Torrents: %d\n", len(cl.torrentsAsSlice()))
        fmt.Fprintln(w)
-       for _, t := range slices.Sort(append([]*Torrent(nil), cl.Torrents()...), func(l, r *Torrent) bool {
+       for _, t := range slices.Sort(cl.torrentsAsSlice(), func(l, r *Torrent) bool {
                return l.InfoHash().AsString() < r.InfoHash().AsString()
        }).([]*Torrent) {
-               if t.Name() == "" {
+               if t.name() == "" {
                        fmt.Fprint(w, "<unknown name>")
                } else {
-                       fmt.Fprint(w, t.Name())
+                       fmt.Fprint(w, t.name())
                }
                fmt.Fprint(w, "\n")
                if t.Info() != nil {
-                       fmt.Fprintf(w, "%f%% of %d bytes (%s)", 100*(1-float64(t.BytesMissing())/float64(t.Info().TotalLength())), t.length, humanize.Bytes(uint64(t.Info().TotalLength())))
+                       fmt.Fprintf(w, "%f%% of %d bytes (%s)", 100*(1-float64(t.bytesMissingLocked())/float64(t.Info().TotalLength())), t.length, humanize.Bytes(uint64(t.Info().TotalLength())))
                } else {
                        w.WriteString("<missing metainfo>")
                }
@@ -1269,12 +1275,16 @@ func (cl *Client) WaitAll() bool {
 }
 
 // Returns handles to all the torrents loaded in the Client.
-func (cl *Client) Torrents() (ret []*Torrent) {
+func (cl *Client) Torrents() []*Torrent {
        cl.mu.Lock()
+       defer cl.mu.Unlock()
+       return cl.torrentsAsSlice()
+}
+
+func (cl *Client) torrentsAsSlice() (ret []*Torrent) {
        for _, t := range cl.torrents {
                ret = append(ret, t)
        }
-       cl.mu.Unlock()
        return
 }
 
index 3fd3f0b2b2396780f5f2b0a434c3a8321abf05ab..ed58da1418a37f2985f1b07982e16362026de8c1 100644 (file)
@@ -447,7 +447,7 @@ func (t *Torrent) writeStatus(w io.Writer) {
        if t.Info() != nil {
                fmt.Fprintf(w, "Num Pieces: %d\n", t.numPieces())
                fmt.Fprint(w, "Piece States:")
-               for _, psr := range t.PieceStateRuns() {
+               for _, psr := range t.pieceStateRuns() {
                        w.Write([]byte(" "))
                        w.Write([]byte(pieceStateRunStatusChars(psr)))
                }
@@ -509,6 +509,10 @@ func (t *Torrent) newMetaInfo() metainfo.MetaInfo {
 func (t *Torrent) BytesMissing() int64 {
        t.mu().RLock()
        defer t.mu().RUnlock()
+       return t.bytesMissingLocked()
+}
+
+func (t *Torrent) bytesMissingLocked() int64 {
        return t.bytesLeft()
 }