From 30c67caced9aeaa862a1be67c4615507ec69e11f Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Fri, 20 Mar 2015 10:52:55 +1100 Subject: [PATCH] Allow some overlap between piece prioritization classes This probabilistically improves download speeds when doing readaheads --- connection.go | 31 +++++++++++++++++-------------- connection_test.go | 37 +++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/connection.go b/connection.go index 756729ae..675ba57a 100644 --- a/connection.go +++ b/connection.go @@ -100,20 +100,23 @@ func (cn *connection) pendPiece(piece int, priority piecePriority) { cn.pieceRequestOrder.DeletePiece(piece) return } - key := cn.piecePriorities[piece] - // There is overlap here so there's some probabilistic favouring of higher - // priority pieces. - switch priority { - case piecePriorityReadahead: - key -= len(cn.piecePriorities) - case piecePriorityNext: - key -= 2 * len(cn.piecePriorities) - case piecePriorityNow: - key -= 3 * len(cn.piecePriorities) - } - // Favour earlier pieces more than later pieces. - // key -= piece / 2 - + pp := cn.piecePriorities[piece] + // Priority goes to Now, then Next in connection order. Then Readahead in + // by piece index. Then normal again by connection order. + key := func() int { + switch priority { + case piecePriorityNow: + return -3*len(cn.piecePriorities) + 3*pp + case piecePriorityNext: + return -2*len(cn.piecePriorities) + 2*pp + case piecePriorityReadahead: + return -len(cn.piecePriorities) + pp + case piecePriorityNormal: + return pp + default: + panic(priority) + } + }() cn.pieceRequestOrder.SetPiece(piece, key) } diff --git a/connection_test.go b/connection_test.go index 55181a9c..ed26edec 100644 --- a/connection_test.go +++ b/connection_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + . "gopkg.in/check.v1" + "github.com/bradfitz/iter" "bitbucket.org/anacrolix/go.torrent/internal/pieceordering" @@ -53,21 +55,25 @@ func TestCancelRequestOptimized(t *testing.T) { } } -func testRequestOrder(expected []int, ro *pieceordering.Instance, t *testing.T) { - e := ro.First() - for _, i := range expected { - if i != e.Piece() { - t.FailNow() - } - e = e.Next() - } - if e != nil { - t.FailNow() +func pieceOrderingAsSlice(po *pieceordering.Instance) (ret []int) { + for e := po.First(); e != nil; e = e.Next() { + ret = append(ret, e.Piece()) } + return } +func testRequestOrder(expected []int, ro *pieceordering.Instance, t *C) { + t.Assert(pieceOrderingAsSlice(ro), DeepEquals, expected) +} + +type suite struct{} + +var _ = Suite(suite{}) + +func Test(t *testing.T) { TestingT(t) } + // Tests the request ordering based on a connections priorities. -func TestPieceRequestOrder(t *testing.T) { +func (suite) TestPieceRequestOrder(t *C) { c := connection{ pieceRequestOrder: pieceordering.New(), piecePriorities: []int{1, 4, 0, 3, 2}, @@ -83,10 +89,17 @@ func TestPieceRequestOrder(t *testing.T) { c.pendPiece(1, piecePriorityReadahead) testRequestOrder([]int{1, 2, 0}, c.pieceRequestOrder, t) c.pendPiece(4, piecePriorityNow) + // now(4), r(1), normal(0, 2) testRequestOrder([]int{4, 1, 2, 0}, c.pieceRequestOrder, t) c.pendPiece(2, piecePriorityReadahead) // N(4), R(1, 2), N(0) - testRequestOrder([]int{4, 1, 2, 0}, c.pieceRequestOrder, t) + testRequestOrder([]int{4, 2, 1, 0}, c.pieceRequestOrder, t) + c.pendPiece(1, piecePriorityNow) + // 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" + // piece has been placed after a readahead piece. + 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)