]> Sergey Matveev's repositories - btrtrc.git/commitdiff
When piece checks fail only ban untrusted peers and only when the entire piece is...
authorMatt Joiner <anacrolix@gmail.com>
Tue, 7 Jan 2020 04:13:28 +0000 (15:13 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Mon, 13 Jan 2020 23:51:09 +0000 (10:51 +1100)
This should help with addressing https://github.com/anacrolix/torrent/issues/364.

piece.go
torrent.go

index 61c0cf442c2cc64f8b0123c68fcc5fb0c56077e2..2ebe3f8b49d7402993d925bb34c2074f306b2d96 100644 (file)
--- a/piece.go
+++ b/piece.go
@@ -243,3 +243,7 @@ func (p *Piece) completion() (ret storage.Completion) {
        ret.Ok = p.storageCompletionOk
        return
 }
+
+func (p *Piece) allChunksDirty() bool {
+       return p.dirtyChunks.Len() == int(p.numChunks())
+}
index caeb8c234104f17350f82ad3346b65ed8b09b19e..8ef5f0fc7ab0cad8f863f480f5f81299ae13ce05 100644 (file)
@@ -1520,51 +1520,64 @@ func (t *Torrent) pieceHashed(piece pieceIndex, correct bool) {
        if t.closed.IsSet() {
                return
        }
-       touchers := t.reapPieceTouchers(piece)
+
+       // Don't score the first time a piece is hashed, it could be an initial check.
        if p.storageCompletionOk {
-               // Don't score the first time a piece is hashed, it could be an
-               // initial check.
                if correct {
                        pieceHashedCorrect.Add(1)
                } else {
-                       log.Fmsg("piece %d failed hash: %d connections contributed", piece, len(touchers)).AddValues(t, p).Log(t.logger)
+                       log.Fmsg("piece %d failed hash: %d connections contributed", piece, len(p.dirtiers)).AddValues(t, p).Log(t.logger)
                        pieceHashedNotCorrect.Add(1)
                }
        }
+
        if correct {
-               if len(touchers) != 0 {
-                       // Don't increment stats above connection-level for every involved
-                       // connection.
+               if len(p.dirtiers) != 0 {
+                       // Don't increment stats above connection-level for every involved connection.
                        t.allStats((*ConnStats).incrementPiecesDirtiedGood)
                }
-               for _, c := range touchers {
+               for c := range p.dirtiers {
                        c.stats.incrementPiecesDirtiedGood()
                }
+               t.clearPieceTouchers(piece)
                err := p.Storage().MarkComplete()
                if err != nil {
                        t.logger.Printf("%T: error marking piece complete %d: %s", t.storage, piece, err)
                }
        } else {
-               if len(touchers) != 0 {
-                       // Don't increment stats above connection-level for every involved connection.
+               if len(p.dirtiers) != 0 && p.allChunksDirty() {
+
+                       // Increment Torrent and above stats, and then specific connections.
                        t.allStats((*ConnStats).incrementPiecesDirtiedBad)
-                       for _, c := range touchers {
+                       for c := range p.dirtiers {
                                // Y u do dis peer?!
                                c.stats.incrementPiecesDirtiedBad()
                        }
-                       slices.Sort(touchers, connLessTrusted)
+
+                       bannableTouchers := make([]*connection, 0, len(p.dirtiers))
+                       for c := range p.dirtiers {
+                               if !c.trusted {
+                                       bannableTouchers = append(bannableTouchers, c)
+                               }
+                       }
+                       t.clearPieceTouchers(piece)
+                       slices.Sort(bannableTouchers, connLessTrusted)
+
                        if t.cl.config.Debug {
-                               t.logger.Printf("conns by trust for piece %d: %v",
+                               t.logger.Printf(
+                                       "bannable conns by trust for piece %d: %v",
                                        piece,
                                        func() (ret []connectionTrust) {
-                                               for _, c := range touchers {
+                                               for _, c := range bannableTouchers {
                                                        ret = append(ret, c.trust())
                                                }
                                                return
-                                       }())
+                                       }(),
+                               )
                        }
-                       c := touchers[0]
-                       if !c.trust().Implicit {
+
+                       if len(bannableTouchers) >= 1 {
+                               c := bannableTouchers[0]
                                t.cl.banPeerIP(c.remoteAddr.IP)
                                c.Drop()
                        }
@@ -1671,15 +1684,13 @@ func (t *Torrent) pieceHasher(index pieceIndex) {
        t.tryCreateMorePieceHashers()
 }
 
-// Return the connections that touched a piece, and clear the entries while
-// doing it.
-func (t *Torrent) reapPieceTouchers(piece pieceIndex) (ret []*connection) {
-       for c := range t.pieces[piece].dirtiers {
-               delete(c.peerTouchedPieces, piece)
-               ret = append(ret, c)
+// Return the connections that touched a piece, and clear the entries while doing it.
+func (t *Torrent) clearPieceTouchers(pi pieceIndex) {
+       p := t.piece(pi)
+       for c := range p.dirtiers {
+               delete(c.peerTouchedPieces, pi)
+               delete(p.dirtiers, c)
        }
-       t.pieces[piece].dirtiers = nil
-       return
 }
 
 func (t *Torrent) connsAsSlice() (ret []*connection) {