]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Track ConnStats with atomics
[btrtrc.git] / conn_stats.go
1 package torrent
2
3 import (
4         "io"
5         "log"
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         ChunksReadUnwanted Count
31
32         // Number of pieces data was written to, that subsequently passed verification.
33         PiecesDirtiedGood Count
34         // Number of pieces data was written to, that subsequently failed
35         // verification. Note that a connection may not have been the sole dirtier
36         // of a piece.
37         PiecesDirtiedBad Count
38 }
39
40 func (me *ConnStats) Copy() (ret ConnStats) {
41         for i := 0; i < reflect.TypeOf(ConnStats{}).NumField(); i++ {
42                 n := reflect.ValueOf(me).Elem().Field(i).Addr().Interface().(*Count).Int64()
43                 reflect.ValueOf(&ret).Elem().Field(i).Addr().Interface().(*Count).Add(n)
44         }
45         return
46 }
47
48 type Count struct {
49         n int64
50 }
51
52 func (me *Count) Add(n int64) {
53         atomic.AddInt64(&me.n, n)
54 }
55
56 func (me *Count) Int64() int64 {
57         return atomic.LoadInt64(&me.n)
58 }
59
60 func (cs *ConnStats) wroteMsg(msg *pp.Message) {
61         // TODO: Track messages and not just chunks.
62         switch msg.Type {
63         case pp.Piece:
64                 cs.ChunksWritten.Add(1)
65                 cs.BytesWrittenData.Add(int64(len(msg.Piece)))
66         }
67 }
68
69 func (cs *ConnStats) readMsg(msg *pp.Message) {
70         switch msg.Type {
71         case pp.Piece:
72                 cs.ChunksRead.Add(1)
73                 cs.BytesReadData.Add(int64(len(msg.Piece)))
74         }
75 }
76
77 func (cs *ConnStats) incrementPiecesDirtiedGood() {
78         cs.PiecesDirtiedGood.Add(1)
79 }
80
81 func (cs *ConnStats) incrementPiecesDirtiedBad() {
82         cs.PiecesDirtiedBad.Add(1)
83 }
84
85 func add(n int64, f func(*ConnStats) *Count) func(*ConnStats) {
86         return func(cs *ConnStats) {
87                 p := f(cs)
88                 p.Add(n)
89         }
90 }
91
92 type connStatsReadWriter struct {
93         rw io.ReadWriter
94         c  *connection
95 }
96
97 func (me connStatsReadWriter) Write(b []byte) (n int, err error) {
98         n, err = me.rw.Write(b)
99         me.c.wroteBytes(int64(n))
100         return
101 }
102
103 func (me connStatsReadWriter) Read(b []byte) (n int, err error) {
104         n, err = me.rw.Read(b)
105         me.c.readBytes(int64(n))
106         return
107 }