]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
allow ConnStats being marsheled to json
[btrtrc.git] / conn_stats.go
1 package torrent
2
3 import (
4         "fmt"
5         "io"
6         "reflect"
7         "sync/atomic"
8         "encoding/json"
9
10         pp "github.com/anacrolix/torrent/peer_protocol"
11 )
12
13 // Various connection-level metrics. At the Torrent level these are
14 // aggregates. Chunks are messages with data payloads. Data is actual torrent
15 // content without any overhead. Useful is something we needed locally.
16 // Unwanted is something we didn't ask for (but may still be useful). Written
17 // is things sent to the peer, and Read is stuff received from them.
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
38         // verification. Note that a connection may not have been the sole dirtier
39         // 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  *connection
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 }