From 53259397fc85c40db06de26b06232f76a43b45f7 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sat, 26 Sep 2015 17:27:35 +1000 Subject: [PATCH] Initialize connection piece priorities lazily, and using a pool --- client.go | 9 +++++++-- connection.go | 5 ++++- connection_test.go | 18 +++++++++--------- torrent.go | 19 +++++++++++++++++++ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/client.go b/client.go index 559bcca9..f11e892b 100644 --- a/client.go +++ b/client.go @@ -360,7 +360,7 @@ func (cl *Client) ConfigDir() string { } func (t *torrent) connPendPiece(c *connection, piece int) { - c.pendPiece(piece, t.Pieces[piece].Priority) + c.pendPiece(piece, t.Pieces[piece].Priority, t) } func (cl *Client) raisePiecePriority(t *torrent, piece int, priority piecePriority) { @@ -1276,7 +1276,6 @@ func (t *torrent) initRequestOrdering(c *connection) { if c.pieceRequestOrder != nil || c.piecePriorities != nil { panic("double init of request ordering") } - c.piecePriorities = mathRand.Perm(t.numPieces()) c.pieceRequestOrder = pieceordering.New() for i := range iter.N(t.Info.NumPieces()) { if !c.PeerHasPiece(i) { @@ -1754,6 +1753,12 @@ func (me *Client) deleteConnection(t *torrent, c *connection) bool { func (me *Client) dropConnection(t *torrent, c *connection) { me.event.Broadcast() c.Close() + if c.piecePriorities != nil { + t.connPiecePriorites.Put(c.piecePriorities) + // I wonder if it's safe to set it to nil. Probably not. Since it's + // only read, it doesn't particularly matter if a closing connection + // shares the slice with another connection. + } if me.deleteConnection(t, c) { me.openNewConns(t) } diff --git a/connection.go b/connection.go index 85df7eb4..bedb1a9b 100644 --- a/connection.go +++ b/connection.go @@ -105,11 +105,14 @@ func (cn *connection) localAddr() net.Addr { // Adjust piece position in the request order for this connection based on the // given piece priority. -func (cn *connection) pendPiece(piece int, priority piecePriority) { +func (cn *connection) pendPiece(piece int, priority piecePriority, t *torrent) { if priority == PiecePriorityNone { cn.pieceRequestOrder.DeletePiece(piece) return } + if cn.piecePriorities == nil { + cn.piecePriorities = t.newConnPiecePriorities() + } pp := cn.piecePriorities[piece] // Priority regions not to scale. Within each region, piece is randomized // according to connection. diff --git a/connection_test.go b/connection_test.go index 3749a6ca..36832b9f 100644 --- a/connection_test.go +++ b/connection_test.go @@ -71,22 +71,22 @@ func TestPieceRequestOrder(t *testing.T) { piecePriorities: []int{1, 4, 0, 3, 2}, } testRequestOrder(nil, c.pieceRequestOrder, t) - c.pendPiece(2, PiecePriorityNone) + c.pendPiece(2, PiecePriorityNone, nil) testRequestOrder(nil, c.pieceRequestOrder, t) - c.pendPiece(1, PiecePriorityNormal) - c.pendPiece(2, PiecePriorityNormal) + c.pendPiece(1, PiecePriorityNormal, nil) + c.pendPiece(2, PiecePriorityNormal, nil) testRequestOrder([]int{2, 1}, c.pieceRequestOrder, t) - c.pendPiece(0, PiecePriorityNormal) + c.pendPiece(0, PiecePriorityNormal, nil) testRequestOrder([]int{2, 0, 1}, c.pieceRequestOrder, t) - c.pendPiece(1, PiecePriorityReadahead) + c.pendPiece(1, PiecePriorityReadahead, nil) testRequestOrder([]int{1, 2, 0}, c.pieceRequestOrder, t) - c.pendPiece(4, PiecePriorityNow) + c.pendPiece(4, PiecePriorityNow, nil) // now(4), r(1), normal(0, 2) testRequestOrder([]int{4, 1, 2, 0}, c.pieceRequestOrder, t) - c.pendPiece(2, PiecePriorityReadahead) + c.pendPiece(2, PiecePriorityReadahead, nil) // N(4), R(1, 2), N(0) testRequestOrder([]int{4, 2, 1, 0}, c.pieceRequestOrder, t) - c.pendPiece(1, PiecePriorityNow) + c.pendPiece(1, PiecePriorityNow, nil) // now(4, 1), readahead(2), normal(0) // in the same order, the keys will be: -15+6, -15+12, -5, 1 // so we test that a very low priority (for this connection), "now" @@ -94,7 +94,7 @@ func TestPieceRequestOrder(t *testing.T) { testRequestOrder([]int{4, 2, 1, 0}, c.pieceRequestOrder, t) // Note this intentially sets to None a piece that's not in the order. for i := range iter.N(5) { - c.pendPiece(i, PiecePriorityNone) + c.pendPiece(i, PiecePriorityNone, nil) } testRequestOrder(nil, c.pieceRequestOrder, t) } diff --git a/torrent.go b/torrent.go index 6498c23e..79a6a159 100644 --- a/torrent.go +++ b/torrent.go @@ -2,9 +2,11 @@ package torrent import ( "container/heap" + "expvar" "fmt" "io" "log" + "math/rand" "net" "sort" "sync" @@ -102,6 +104,23 @@ type torrent struct { // Closed when .Info is set. gotMetainfo chan struct{} + + connPiecePriorites sync.Pool +} + +var ( + piecePrioritiesReused = expvar.NewInt("piecePrioritiesReused") + piecePrioritiesNew = expvar.NewInt("piecePrioritiesNew") +) + +func (t *torrent) newConnPiecePriorities() []int { + _ret := t.connPiecePriorites.Get() + if _ret != nil { + piecePrioritiesReused.Add(1) + return _ret.([]int) + } + piecePrioritiesNew.Add(1) + return rand.Perm(t.numPieces()) } func (t *torrent) pieceComplete(piece int) bool { -- 2.48.1