]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Rename connection->PeerConn and fix exports
[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
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 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 }