]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Track metadata chunks read with its own Count
[btrtrc.git] / conn_stats.go
1 package torrent
2
3 import (
4         "fmt"
5         "io"
6         "reflect"
7         "sync/atomic"
8
9         pp "github.com/anacrolix/torrent/peer_protocol"
10 )
11
12 // Various connection-level metrics. At the Torrent level these are
13 // aggregates. Chunks are messages with data payloads. Data is actual torrent
14 // content without any overhead. Useful is something we needed locally.
15 // Unwanted is something we didn't ask for (but may still be useful). Written
16 // is things sent to the peer, and Read is stuff received from them.
17 type ConnStats struct {
18         // Total bytes on the wire. Includes handshakes and encryption.
19         BytesWritten     Count
20         BytesWrittenData Count
21
22         BytesRead           Count
23         BytesReadData       Count
24         BytesReadUsefulData Count
25
26         ChunksWritten Count
27
28         ChunksRead       Count
29         ChunksReadUseful Count
30         ChunksReadWasted Count
31
32         MetadataChunksRead Count
33
34         // Number of pieces data was written to, that subsequently passed verification.
35         PiecesDirtiedGood Count
36         // Number of pieces data was written to, that subsequently failed
37         // verification. Note that a connection may not have been the sole dirtier
38         // 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 (cs *ConnStats) wroteMsg(msg *pp.Message) {
69         // TODO: Track messages and not just chunks.
70         switch msg.Type {
71         case pp.Piece:
72                 cs.ChunksWritten.Add(1)
73                 cs.BytesWrittenData.Add(int64(len(msg.Piece)))
74         }
75 }
76
77 func (cs *ConnStats) readMsg(msg *pp.Message) {
78         // We want to also handle extended metadata pieces here, but we wouldn't
79         // have decoded the extended payload yet.
80         switch msg.Type {
81         case pp.Piece:
82                 cs.ChunksRead.Add(1)
83                 cs.BytesReadData.Add(int64(len(msg.Piece)))
84         }
85 }
86
87 func (cs *ConnStats) incrementPiecesDirtiedGood() {
88         cs.PiecesDirtiedGood.Add(1)
89 }
90
91 func (cs *ConnStats) incrementPiecesDirtiedBad() {
92         cs.PiecesDirtiedBad.Add(1)
93 }
94
95 func add(n int64, f func(*ConnStats) *Count) func(*ConnStats) {
96         return func(cs *ConnStats) {
97                 p := f(cs)
98                 p.Add(n)
99         }
100 }
101
102 type connStatsReadWriter struct {
103         rw io.ReadWriter
104         c  *connection
105 }
106
107 func (me connStatsReadWriter) Write(b []byte) (n int, err error) {
108         n, err = me.rw.Write(b)
109         me.c.wroteBytes(int64(n))
110         return
111 }
112
113 func (me connStatsReadWriter) Read(b []byte) (n int, err error) {
114         n, err = me.rw.Read(b)
115         me.c.readBytes(int64(n))
116         return
117 }