From d4788882316354d3e44bd1926faed5f48449974a Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Tue, 9 Apr 2019 12:57:54 +1000
Subject: [PATCH] When failing to read stored data, try updating only the
 completion state for the failed piece

On rare occasions, reads are failing in a loop, exhausting all the available file descriptors. It's not clear why, it could be an error in the filecache storage backend I'm using, or some logic error regarding when it's okay to try to read.
---
 reader.go  | 5 +++--
 torrent.go | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/reader.go b/reader.go
index 648228be..24403dc1 100644
--- a/reader.go
+++ b/reader.go
@@ -226,8 +226,9 @@ func (r *reader) readOnceAt(b []byte, pos int64, ctxErr *error) (n int, err erro
 		// prevent thrashing with small caches and file and piece priorities.
 		log.Printf("error reading torrent %s piece %d offset %d, %d bytes: %v",
 			r.t.infoHash.HexString(), pi, po, len(b1), err)
-		r.t.updateAllPieceCompletions()
-		r.t.updateAllPiecePriorities()
+		if !r.t.updatePieceCompletion(pi) {
+			log.Printf("piece %d completion unchanged", pi)
+		}
 		r.t.cl.unlock()
 	}
 }
diff --git a/torrent.go b/torrent.go
index c9ccaa9f..4a519d34 100644
--- a/torrent.go
+++ b/torrent.go
@@ -1054,7 +1054,7 @@ func (t *Torrent) putPieceInclination(pi []int) {
 	pieceInclinationsPut.Add(1)
 }
 
-func (t *Torrent) updatePieceCompletion(piece pieceIndex) {
+func (t *Torrent) updatePieceCompletion(piece pieceIndex) bool {
 	pcu := t.pieceCompleteUncached(piece)
 	p := &t.pieces[piece]
 	changed := t.completedPieces.Get(bitmap.BitIndex(piece)) != pcu.Complete || p.storageCompletionOk != pcu.Ok
@@ -1067,6 +1067,7 @@ func (t *Torrent) updatePieceCompletion(piece pieceIndex) {
 	if changed {
 		t.pieceCompletionChanged(piece)
 	}
+	return changed
 }
 
 // Non-blocking read. Client lock is not required.
-- 
2.51.0