From 0d10a1b53afb425d1cabf3a0ebd5ebb56e550822 Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Fri, 10 Sep 2021 21:48:44 +1000
Subject: [PATCH] Optimize Torrent.worstBadConn

---
 go.mod     |  2 +-
 go.sum     |  2 ++
 torrent.go | 27 ++++++++++++++++++++-------
 3 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/go.mod b/go.mod
index 144bc7fd..dcbe602c 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ require (
 	crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508
 	github.com/RoaringBitmap/roaring v0.9.4
 	github.com/alexflint/go-arg v1.4.2
-	github.com/anacrolix/chansync v0.1.1-0.20210904130811-9cd7139c8dd9
+	github.com/anacrolix/chansync v0.2.1-0.20210910114620-14955c95ded9
 	github.com/anacrolix/confluence v1.8.0 // indirect
 	github.com/anacrolix/dht/v2 v2.10.5-0.20210902001729-06cc4fe90e53
 	github.com/anacrolix/envpprof v1.1.1
diff --git a/go.sum b/go.sum
index af23d4b5..4dc4fcef 100644
--- a/go.sum
+++ b/go.sum
@@ -49,6 +49,8 @@ github.com/anacrolix/chansync v0.1.0 h1:4cIfJmEV8sYkSEMW2AXnPjX6iQT4plqELJ65pLna
 github.com/anacrolix/chansync v0.1.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
 github.com/anacrolix/chansync v0.1.1-0.20210904130811-9cd7139c8dd9 h1:Jk3Mdr+XbO1uvf/+nUXjb/M1dPDNPQThxKmS5MLGE+w=
 github.com/anacrolix/chansync v0.1.1-0.20210904130811-9cd7139c8dd9/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
+github.com/anacrolix/chansync v0.2.1-0.20210910114620-14955c95ded9 h1:jfSupvl9p7Bkd9snD6DrjxDmsYjJeYxSqhQa/I9wV3I=
+github.com/anacrolix/chansync v0.2.1-0.20210910114620-14955c95ded9/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
 github.com/anacrolix/confluence v1.7.1-0.20210221224747-9cb14aa2c53a/go.mod h1:T0JHvSaf9UfoiUdCtCOUuRroHm/tauUJTbLc6/vd5YA=
 github.com/anacrolix/confluence v1.7.1-0.20210221225853-90405640e928/go.mod h1:NoLcfoRet+kYttjLXJRmh4qBVrylJsfIItik5GGj21A=
 github.com/anacrolix/confluence v1.7.1-0.20210311004351-d642adb8546c/go.mod h1:KCZ3eObqKECNeZg0ekAoJVakHMP3gAdR8i0bQ26IkzM=
diff --git a/torrent.go b/torrent.go
index b719529f..27ad3e1e 100644
--- a/torrent.go
+++ b/torrent.go
@@ -263,14 +263,13 @@ func (t *Torrent) addrActive(addr string) bool {
 	return false
 }
 
-func (t *Torrent) unclosedConnsAsSlice() (ret []*PeerConn) {
-	ret = make([]*PeerConn, 0, len(t.conns))
+func (t *Torrent) appendUnclosedConns(ret []*PeerConn) []*PeerConn {
 	for c := range t.conns {
 		if !c.closed.IsSet() {
 			ret = append(ret, c)
 		}
 	}
-	return
+	return ret
 }
 
 func (t *Torrent) addPeer(p PeerInfo) (added bool) {
@@ -974,11 +973,25 @@ func (t *Torrent) wantPieceIndex(index pieceIndex) bool {
 	})
 }
 
+// A pool of []*PeerConn, to reduce allocations in functions that need to index or sort Torrent
+// conns (which is a map).
+var peerConnSlices sync.Pool
+
 // The worst connection is one that hasn't been sent, or sent anything useful for the longest. A bad
-// connection is one that usually sends us unwanted pieces, or has been in worser half of the
-// established connections for more than a minute.
-func (t *Torrent) worstBadConn() *PeerConn {
-	wcs := worseConnSlice{t.unclosedConnsAsSlice()}
+// connection is one that usually sends us unwanted pieces, or has been in the worse half of the
+// established connections for more than a minute. This is O(n log n). If there was a way to not
+// consider the position of a conn relative to the total number, it could be reduced to O(n).
+func (t *Torrent) worstBadConn() (ret *PeerConn) {
+	var sl []*PeerConn
+	getInterface := peerConnSlices.Get()
+	if getInterface == nil {
+		sl = make([]*PeerConn, 0, len(t.conns))
+	} else {
+		sl = getInterface.([]*PeerConn)[:0]
+	}
+	sl = t.appendUnclosedConns(sl)
+	defer peerConnSlices.Put(sl)
+	wcs := worseConnSlice{sl}
 	heap.Init(&wcs)
 	for wcs.Len() != 0 {
 		c := heap.Pop(&wcs).(*PeerConn)
-- 
2.51.0