]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Fix download rate, status output
[btrtrc.git] / conn_stats.go
1 package torrent
2
3 import (
4         "encoding/json"
5         "fmt"
6         "io"
7         "reflect"
8         "sync/atomic"
9
10         pp "github.com/anacrolix/torrent/peer_protocol"
11 )
12
13 // Various connection-level metrics. At the Torrent level these are aggregates. Chunks are messages
14 // with data payloads. Data is actual torrent content without any overhead. Useful is something we
15 // needed locally. Unwanted is something we didn't ask for (but may still be useful). Written is
16 // things sent to the peer, and Read is stuff received from them. Due to the implementation of
17 // Count, must be aligned on some platforms: See https://github.com/anacrolix/torrent/issues/262.
18 type ConnStats struct {
19         // Total bytes on the wire. Includes handshakes and encryption.
20         BytesWritten     Count
21         BytesWrittenData Count
22
23         BytesRead                   Count
24         BytesReadData               Count
25         BytesReadUsefulData         Count
26         BytesReadUsefulIntendedData Count
27
28         ChunksWritten Count
29
30         ChunksRead       Count
31         ChunksReadUseful Count
32         ChunksReadWasted Count
33
34         MetadataChunksRead Count
35
36         // Number of pieces data was written to, that subsequently passed verification.
37         PiecesDirtiedGood Count
38         // Number of pieces data was written to, that subsequently failed verification. Note that a
39         // connection may not have been the sole dirtier of a piece.
40         PiecesDirtiedBad Count
41 }
42
43 func (me *ConnStats) Copy() (ret ConnStats) {
44         for i := 0; i < reflect.TypeOf(ConnStats{}).NumField(); i++ {
45                 n := reflect.ValueOf(me).Elem().Field(i).Addr().Interface().(*Count).Int64()
46                 reflect.ValueOf(&ret).Elem().Field(i).Addr().Interface().(*Count).Add(n)
47         }
48         return
49 }
50
51 type Count struct {
52         n int64
53 }
54
55 var _ fmt.Stringer = (*Count)(nil)
56
57 func (me *Count) Add(n int64) {
58         atomic.AddInt64(&me.n, n)
59 }
60
61 func (me *Count) Int64() int64 {
62         return atomic.LoadInt64(&me.n)
63 }
64
65 func (me *Count) String() string {
66         return fmt.Sprintf("%v", me.Int64())
67 }
68
69 func (me *Count) MarshalJSON() ([]byte, error) {
70         return json.Marshal(me.n)
71 }
72
73 func (cs *ConnStats) wroteMsg(msg *pp.Message) {
74         // TODO: Track messages and not just chunks.
75         switch msg.Type {
76         case pp.Piece:
77                 cs.ChunksWritten.Add(1)
78                 cs.BytesWrittenData.Add(int64(len(msg.Piece)))
79         }
80 }
81
82 func (cs *ConnStats) readMsg(msg *pp.Message) {
83         // We want to also handle extended metadata pieces here, but we wouldn't
84         // have decoded the extended payload yet.
85         switch msg.Type {
86         case pp.Piece:
87                 cs.ChunksRead.Add(1)
88                 cs.BytesReadData.Add(int64(len(msg.Piece)))
89         }
90 }
91
92 func (cs *ConnStats) incrementPiecesDirtiedGood() {
93         cs.PiecesDirtiedGood.Add(1)
94 }
95
96 func (cs *ConnStats) incrementPiecesDirtiedBad() {
97         cs.PiecesDirtiedBad.Add(1)
98 }
99
100 func add(n int64, f func(*ConnStats) *Count) func(*ConnStats) {
101         return func(cs *ConnStats) {
102                 p := f(cs)
103                 p.Add(n)
104         }
105 }
106
107 type connStatsReadWriter struct {
108         rw io.ReadWriter
109         c  *PeerConn
110 }
111
112 func (me connStatsReadWriter) Write(b []byte) (n int, err error) {
113         n, err = me.rw.Write(b)
114         me.c.wroteBytes(int64(n))
115         return
116 }
117
118 func (me connStatsReadWriter) Read(b []byte) (n int, err error) {
119         n, err = me.rw.Read(b)
120         me.c.readBytes(int64(n))
121         return
122 }