From 98f188dcbef1b62cdcd6e91fdc3abf16113b2b5a Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Mon, 13 Dec 2021 12:09:12 +1100
Subject: [PATCH] Update requests after deleting all in some corner cases

Choked by non-fast PeerConn, deleted PeerConn. They're not exactly guarded as strictly as they could be, so there's plenty of room for performance improvements here.
---
 peerconn.go     | 23 ++++++++++++++++++++---
 torrent.go      |  8 +++++++-
 webseed-peer.go |  5 +++++
 3 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/peerconn.go b/peerconn.go
index 4ec0944b..0083a073 100644
--- a/peerconn.go
+++ b/peerconn.go
@@ -1095,7 +1095,13 @@ func (c *PeerConn) mainReadLoop() (err error) {
 				break
 			}
 			if !c.fastEnabled() {
-				c.deleteAllRequests()
+				if !c.deleteAllRequests().IsEmpty() {
+					c.t.iterPeers(func(p *Peer) {
+						if p.isLowOnRequests() {
+							p.updateRequests("choked by non-fast PeerConn")
+						}
+					})
+				}
 			} else {
 				// We don't decrement pending requests here, let's wait for the peer to either
 				// reject or satisfy the outstanding requests. Additionally, some peers may unchoke
@@ -1554,16 +1560,27 @@ func (c *Peer) deleteRequest(r RequestIndex) bool {
 	}
 	delete(c.t.pendingRequests, r)
 	delete(c.t.lastRequested, r)
+	// c.t.iterPeers(func(p *Peer) {
+	// 	if p.isLowOnRequests() {
+	// 		p.updateRequests("Peer.deleteRequest")
+	// 	}
+	// })
 	return true
 }
 
-func (c *Peer) deleteAllRequests() {
-	c.requestState.Requests.Clone().Iterate(func(x uint32) bool {
+func (c *Peer) deleteAllRequests() (deleted *roaring.Bitmap) {
+	deleted = c.requestState.Requests.Clone()
+	deleted.Iterate(func(x uint32) bool {
 		if !c.deleteRequest(x) {
 			panic("request should exist")
 		}
 		return true
 	})
+	c.assertNoRequests()
+	return
+}
+
+func (c *Peer) assertNoRequests() {
 	if !c.requestState.Requests.IsEmpty() {
 		panic(c.requestState.Requests.GetCardinality())
 	}
diff --git a/torrent.go b/torrent.go
index c41b213b..5c8dca25 100644
--- a/torrent.go
+++ b/torrent.go
@@ -1396,7 +1396,13 @@ func (t *Torrent) deletePeerConn(c *PeerConn) (ret bool) {
 		}
 	}
 	torrent.Add("deleted connections", 1)
-	c.deleteAllRequests()
+	if !c.deleteAllRequests().IsEmpty() {
+		t.iterPeers(func(p *Peer) {
+			if p.isLowOnRequests() {
+				p.updateRequests("Torrent.deletePeerConn")
+			}
+		})
+	}
 	t.assertPendingRequests()
 	return
 }
diff --git a/webseed-peer.go b/webseed-peer.go
index 221aa53f..08a7be2c 100644
--- a/webseed-peer.go
+++ b/webseed-peer.go
@@ -133,6 +133,11 @@ func (ws *webseedPeer) onClose() {
 	for _, r := range ws.activeRequests {
 		r.Cancel()
 	}
+	ws.peer.t.iterPeers(func(p *Peer) {
+		if p.isLowOnRequests() {
+			p.updateRequests("webseedPeer.onClose")
+		}
+	})
 	ws.requesterCond.Broadcast()
 }
 
-- 
2.51.0