Initialize connection piece priorities lazily, and using a pool

This commit is contained in:
Matt Joiner 2015-09-26 17:27:35 +10:00
parent 52b0705956
commit 53259397fc
4 changed files with 39 additions and 12 deletions

View File

@ -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)
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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 {