]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Add doc comments related to #383
[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
27         ChunksWritten Count
28
29         ChunksRead       Count
30         ChunksReadUseful Count
31         ChunksReadWasted Count
32
33         MetadataChunksRead Count
34
35         // Number of pieces data was written to, that subsequently passed verification.
36         PiecesDirtiedGood Count
37         // Number of pieces data was written to, that subsequently failed verification. Note that a
38         // connection may not have been the sole dirtier of a piece.
39         PiecesDirtiedBad Count
40 }
41
42 func (me *ConnStats) Copy() (ret ConnStats) {
43         for i := 0; i < reflect.TypeOf(ConnStats{}).NumField(); i++ {
44                 n := reflect.ValueOf(me).Elem().Field(i).Addr().Interface().(*Count).Int64()
45                 reflect.ValueOf(&ret).Elem().Field(i).Addr().Interface().(*Count).Add(n)
46         }
47         return
48 }
49
50 type Count struct {
51         n int64
52 }
53
54 var _ fmt.Stringer = (*Count)(nil)
55
56 func (me *Count) Add(n int64) {
57         atomic.AddInt64(&me.n, n)
58 }
59
60 func (me *Count) Int64() int64 {
61         return atomic.LoadInt64(&me.n)
62 }
63
64 func (me *Count) String() string {
65         return fmt.Sprintf("%v", me.Int64())
66 }
67
68 func (me *Count) MarshalJSON() ([]byte, error) {
69         return json.Marshal(me.n)
70 }
71
72 func (cs *ConnStats) wroteMsg(msg *pp.Message) {
73         // TODO: Track messages and not just chunks.
74         switch msg.Type {
75         case pp.Piece:
76                 cs.ChunksWritten.Add(1)
77                 cs.BytesWrittenData.Add(int64(len(msg.Piece)))
78         }
79 }
80
81 func (cs *ConnStats) readMsg(msg *pp.Message) {
82         // We want to also handle extended metadata pieces here, but we wouldn't
83         // have decoded the extended payload yet.
84         switch msg.Type {
85         case pp.Piece:
86                 cs.ChunksRead.Add(1)
87                 cs.BytesReadData.Add(int64(len(msg.Piece)))
88         }
89 }
90
91 func (cs *ConnStats) incrementPiecesDirtiedGood() {
92         cs.PiecesDirtiedGood.Add(1)
93 }
94
95 func (cs *ConnStats) incrementPiecesDirtiedBad() {
96         cs.PiecesDirtiedBad.Add(1)
97 }
98
99 func add(n int64, f func(*ConnStats) *Count) func(*ConnStats) {
100         return func(cs *ConnStats) {
101                 p := f(cs)
102                 p.Add(n)
103         }
104 }
105
106 type connStatsReadWriter struct {
107         rw io.ReadWriter
108         c  *PeerConn
109 }
110
111 func (me connStatsReadWriter) Write(b []byte) (n int, err error) {
112         n, err = me.rw.Write(b)
113         me.c.wroteBytes(int64(n))
114         return
115 }
116
117 func (me connStatsReadWriter) Read(b []byte) (n int, err error) {
118         n, err = me.rw.Read(b)
119         me.c.readBytes(int64(n))
120         return
121 }