]> Sergey Matveev's repositories - btrtrc.git/blobdiff - conn_stats.go
fix: torrent file real time completed bytes
[btrtrc.git] / conn_stats.go
index 5455b49ad40b432c2eb8bb88127428bd90d90fe2..0c5bfc784e88d4ce142cff68bb552e681cac9e1e 100644 (file)
 package torrent
 
 import (
+       "encoding/json"
+       "fmt"
+       "io"
+       "reflect"
+       "sync/atomic"
+
        pp "github.com/anacrolix/torrent/peer_protocol"
 )
 
+// Various connection-level metrics. At the Torrent level these are aggregates. Chunks are messages
+// with data payloads. Data is actual torrent content without any overhead. Useful is something we
+// needed locally. Unwanted is something we didn't ask for (but may still be useful). Written is
+// things sent to the peer, and Read is stuff received from them. Due to the implementation of
+// Count, must be aligned on some platforms: See https://github.com/anacrolix/torrent/issues/262.
 type ConnStats struct {
-       ChunksSent    int64 // Num piece messages sent.
-       BytesSent     int64 // Total bytes sent.
-       DataBytesSent int64 // Data-only bytes sent.
+       // Total bytes on the wire. Includes handshakes and encryption.
+       BytesWritten     Count
+       BytesWrittenData Count
+
+       BytesRead                   Count
+       BytesReadData               Count
+       BytesReadUsefulData         Count
+       BytesReadUsefulIntendedData Count
+
+       ChunksWritten Count
+
+       ChunksRead       Count
+       ChunksReadUseful Count
+       ChunksReadWasted Count
+
+       MetadataChunksRead Count
+
+       // Number of pieces data was written to, that subsequently passed verification.
+       PiecesDirtiedGood Count
+       // Number of pieces data was written to, that subsequently failed verification. Note that a
+       // connection may not have been the sole dirtier of a piece.
+       PiecesDirtiedBad Count
+}
+
+func (me *ConnStats) Copy() (ret ConnStats) {
+       for i := 0; i < reflect.TypeOf(ConnStats{}).NumField(); i++ {
+               n := reflect.ValueOf(me).Elem().Field(i).Addr().Interface().(*Count).Int64()
+               reflect.ValueOf(&ret).Elem().Field(i).Addr().Interface().(*Count).Add(n)
+       }
+       return
 }
 
-func (cs *ConnStats) wroteMsg(msg pp.Message) {
+type Count struct {
+       n int64
+}
+
+var _ fmt.Stringer = (*Count)(nil)
+
+func (me *Count) Add(n int64) {
+       atomic.AddInt64(&me.n, n)
+}
+
+func (me *Count) Int64() int64 {
+       return atomic.LoadInt64(&me.n)
+}
+
+func (me *Count) String() string {
+       return fmt.Sprintf("%v", me.Int64())
+}
+
+func (me *Count) MarshalJSON() ([]byte, error) {
+       return json.Marshal(me.n)
+}
+
+func (cs *ConnStats) wroteMsg(msg *pp.Message) {
+       // TODO: Track messages and not just chunks.
        switch msg.Type {
        case pp.Piece:
-               cs.ChunksSent++
-               cs.DataBytesSent += int64(len(msg.Piece))
+               cs.ChunksWritten.Add(1)
+               cs.BytesWrittenData.Add(int64(len(msg.Piece)))
+       }
+}
+
+func (cs *ConnStats) receivedChunk(size int64) {
+       cs.ChunksRead.Add(1)
+       cs.BytesReadData.Add(size)
+}
+
+func (cs *ConnStats) incrementPiecesDirtiedGood() {
+       cs.PiecesDirtiedGood.Add(1)
+}
+
+func (cs *ConnStats) incrementPiecesDirtiedBad() {
+       cs.PiecesDirtiedBad.Add(1)
+}
+
+func add(n int64, f func(*ConnStats) *Count) func(*ConnStats) {
+       return func(cs *ConnStats) {
+               p := f(cs)
+               p.Add(n)
        }
 }
 
-func (cs *ConnStats) wroteBytes(b []byte) {
-       cs.BytesSent += int64(len(b))
+type connStatsReadWriter struct {
+       rw io.ReadWriter
+       c  *PeerConn
+}
+
+func (me connStatsReadWriter) Write(b []byte) (n int, err error) {
+       n, err = me.rw.Write(b)
+       me.c.wroteBytes(int64(n))
+       return
+}
+
+func (me connStatsReadWriter) Read(b []byte) (n int, err error) {
+       n, err = me.rw.Read(b)
+       me.c.readBytes(int64(n))
+       return
 }