client.go | 11 +++++++++++ peerconn.go | 4 ++++ requesting.go | 12 +++++++++--- diff --git a/client.go b/client.go index 3afe64a25be7c676c42fad408132c26f27afe1df..af18b6d0604187cee61aa0652ff4b10b92acd3a8 100644 --- a/client.go +++ b/client.go @@ -9,6 +9,7 @@ "errors" "expvar" "fmt" "io" + "math" "net" "net/http" "sort" @@ -956,6 +957,16 @@ } defer t.dropConnection(c) c.startWriter() cl.sendInitialMessages(c, t) + c.updateRequestsTimer = time.AfterFunc(math.MaxInt64, func() { + if c.needRequestUpdate != "" { + return + } + if c.actualRequestState.Requests.IsEmpty() { + panic("updateRequestsTimer should have been stopped") + } + c.updateRequests("updateRequestsTimer") + }) + c.updateRequestsTimer.Stop() err := c.mainReadLoop() if err != nil { return fmt.Errorf("main read loop: %w", err) diff --git a/peerconn.go b/peerconn.go index eebfc029c7a4b1a3af449ffa8e7c4b3f1e4550c6..545e29f1faff716e11c640ef57c623a647641e05 100644 --- a/peerconn.go +++ b/peerconn.go @@ -84,6 +84,7 @@ // Stuff controlled by the local peer. needRequestUpdate string actualRequestState requestState + updateRequestsTimer *time.Timer cancelledRequests roaring.Bitmap lastBecameInterested time.Time priorInterest time.Duration @@ -413,6 +414,9 @@ func (cn *PeerConn) onClose() { if cn.pex.IsEnabled() { cn.pex.Close() + } + if cn.updateRequestsTimer != nil { + cn.updateRequestsTimer.Stop() } cn.tickleWriter() if cn.conn != nil { diff --git a/requesting.go b/requesting.go index 1da229007f55c9c2d27dc6aaf9f8d035fc9547f9..7d0c8f2fb3b8b75897a46cd37ddcac5550b6f30e 100644 --- a/requesting.go +++ b/requesting.go @@ -253,7 +253,7 @@ return more } func (p *Peer) applyRequestState(next requestState) bool { - current := p.actualRequestState + current := &p.actualRequestState if !p.setInterested(next.Interested) { return false } @@ -268,8 +268,9 @@ return false } next.Requests.Iterate(func(req uint32) bool { if p.cancelledRequests.Contains(req) { - log.Printf("waiting for cancelled request %v", req) - return false + // Waiting for a reject or piece message, which will suitably trigger us to update our + // requests, so we can skip this one with no additional consideration. + return true } if maxRequests(current.Requests.GetCardinality()) >= p.nominalMaxRequests() { log.Printf("not assigning all requests [desired=%v, cancelled=%v, max=%v]", @@ -288,6 +289,11 @@ return more }) if more { p.needRequestUpdate = "" + if current.Requests.IsEmpty() { + p.updateRequestsTimer.Stop() + } else { + p.updateRequestsTimer.Reset(time.Second) + } } return more }