]> Sergey Matveev's repositories - btrtrc.git/blob - conn_stats.go
Drop support for go 1.20
[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         BytesReadUsefulIntendedData Count
27
28         ChunksWritten Count
29
30         ChunksRead       Count
31         ChunksReadUseful Count
32         ChunksReadWasted Count
33
34         MetadataChunksRead Count
35
36         // Number of pieces data was written to, that subsequently passed verification.
37         PiecesDirtiedGood Count
38         // Number of pieces data was written to, that subsequently failed verification. Note that a
39         // connection may not have been the sole dirtier 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) receivedChunk(size int64) {
83         cs.ChunksRead.Add(1)
84         cs.BytesReadData.Add(size)
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  *PeerConn
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 }