2
0
mirror of synced 2025-02-23 22:28:11 +00:00

Move uploading to the connection writer

This commit is contained in:
Matt Joiner 2017-09-18 12:09:08 +10:00
parent ed0fa62340
commit bb53c97d38
3 changed files with 42 additions and 46 deletions

View File

@ -1142,7 +1142,7 @@ func (cl *Client) gotMetadataExtensionMsg(payload []byte, t *Torrent, c *connect
} }
} }
func (cl *Client) sendChunk(t *Torrent, c *connection, r request) error { func (cl *Client) sendChunk(t *Torrent, c *connection, r request, msg func(pp.Message) bool) (more bool, err error) {
// Count the chunk being sent, even if it isn't. // Count the chunk being sent, even if it isn't.
b := make([]byte, r.Length) b := make([]byte, r.Length)
p := t.info.Piece(int(r.Index)) p := t.info.Piece(int(r.Index))
@ -1151,9 +1151,9 @@ func (cl *Client) sendChunk(t *Torrent, c *connection, r request) error {
if err == nil { if err == nil {
panic("expected error") panic("expected error")
} }
return err return
} }
c.Post(pp.Message{ more = msg(pp.Message{
Type: pp.Piece, Type: pp.Piece,
Index: r.Index, Index: r.Index,
Begin: r.Begin, Begin: r.Begin,
@ -1162,7 +1162,7 @@ func (cl *Client) sendChunk(t *Torrent, c *connection, r request) error {
c.chunksSent++ c.chunksSent++
uploadChunksPosted.Add(1) uploadChunksPosted.Add(1)
c.lastChunkSent = time.Now() c.lastChunkSent = time.Now()
return nil return
} }
func (cl *Client) openNewConns(t *Torrent) { func (cl *Client) openNewConns(t *Torrent) {

View File

@ -99,6 +99,7 @@ type connection struct {
pieceRequestOrder prioritybitmap.PriorityBitmap pieceRequestOrder prioritybitmap.PriorityBitmap
postedBuffer bytes.Buffer postedBuffer bytes.Buffer
uploadTimer *time.Timer
writerCond sync.Cond writerCond sync.Cond
} }
@ -297,25 +298,25 @@ func (cn *connection) PeerCancel(r request) bool {
return true return true
} }
func (cn *connection) Choke() { func (cn *connection) Choke(msg func(pp.Message) bool) bool {
if cn.Choked { if cn.Choked {
return return true
} }
cn.Post(pp.Message{
Type: pp.Choke,
})
cn.PeerRequests = nil cn.PeerRequests = nil
cn.Choked = true cn.Choked = true
return msg(pp.Message{
Type: pp.Choke,
})
} }
func (cn *connection) Unchoke() { func (cn *connection) Unchoke(msg func(pp.Message) bool) bool {
if !cn.Choked { if !cn.Choked {
return return true
} }
cn.Post(pp.Message{ cn.Choked = false
return msg(pp.Message{
Type: pp.Unchoke, Type: pp.Unchoke,
}) })
cn.Choked = false
} }
func (cn *connection) SetInterested(interested bool, msg func(pp.Message) bool) bool { func (cn *connection) SetInterested(interested bool, msg func(pp.Message) bool) bool {
@ -378,6 +379,7 @@ func (cn *connection) fillWriteBuffer(msg func(pp.Message) bool) {
// have more write buffer space. // have more write buffer space.
cn.requestsLowWater = len(cn.requests) / 2 cn.requestsLowWater = len(cn.requests) / 2
} }
cn.upload(msg)
} }
// Writes buffers to the socket from the write channel. // Writes buffers to the socket from the write channel.
@ -757,33 +759,24 @@ func (c *connection) mainReadLoop() error {
c.tickleWriter() c.tickleWriter()
case pp.Interested: case pp.Interested:
c.PeerInterested = true c.PeerInterested = true
c.upload() c.tickleWriter()
case pp.NotInterested: case pp.NotInterested:
c.PeerInterested = false c.PeerInterested = false
c.Choke() c.PeerRequests = nil
case pp.Have: case pp.Have:
err = c.peerSentHave(int(msg.Index)) err = c.peerSentHave(int(msg.Index))
case pp.Request: case pp.Request:
if c.Choked { if c.Choked {
break break
} }
if !c.PeerInterested { if len(c.PeerRequests) >= maxRequests {
err = errors.New("peer sent request but isn't interested")
break
}
if !t.havePiece(msg.Index.Int()) {
// This isn't necessarily them screwing up. We can drop pieces
// from our storage, and can't communicate this to peers
// except by reconnecting.
requestsReceivedForMissingPieces.Add(1)
err = errors.New("peer requested piece we don't have")
break break
} }
if c.PeerRequests == nil { if c.PeerRequests == nil {
c.PeerRequests = make(map[request]struct{}, maxRequests) c.PeerRequests = make(map[request]struct{}, maxRequests)
} }
c.PeerRequests[newRequest(msg.Index, msg.Begin, msg.Length)] = struct{}{} c.PeerRequests[newRequest(msg.Index, msg.Begin, msg.Length)] = struct{}{}
c.upload() c.tickleWriter()
case pp.Cancel: case pp.Cancel:
req := newRequest(msg.Index, msg.Begin, msg.Length) req := newRequest(msg.Index, msg.Begin, msg.Length)
if !c.PeerCancel(req) { if !c.PeerCancel(req) {
@ -971,8 +964,6 @@ func (c *connection) receiveChunk(msg *pp.Message) {
c.UsefulChunksReceived++ c.UsefulChunksReceived++
c.lastUsefulChunkReceived = time.Now() c.lastUsefulChunkReceived = time.Now()
c.upload()
// Need to record that it hasn't been written yet, before we attempt to do // Need to record that it hasn't been written yet, before we attempt to do
// anything with it. // anything with it.
piece.incrementPendingWrites() piece.incrementPendingWrites()
@ -1016,40 +1007,45 @@ func (c *connection) receiveChunk(msg *pp.Message) {
} }
// Also handles choking and unchoking of the remote peer. // Also handles choking and unchoking of the remote peer.
func (c *connection) upload() { func (c *connection) upload(msg func(pp.Message) bool) bool {
t := c.t t := c.t
cl := t.cl cl := t.cl
if cl.config.NoUpload { if cl.config.NoUpload {
return return true
} }
if !c.PeerInterested { if !c.PeerInterested {
return return true
} }
seeding := t.seeding() seeding := t.seeding()
if !seeding && !c.peerHasWantedPieces() { if !seeding && !c.peerHasWantedPieces() {
// There's no reason to upload to this peer. // There's no reason to upload to this peer.
return return true
} }
// Breaking or completing this loop means we don't want to upload to the // Breaking or completing this loop means we don't want to upload to the
// peer anymore, and we choke them. // peer anymore, and we choke them.
another: another:
for seeding || c.chunksSent < c.UsefulChunksReceived+6 { for seeding || c.chunksSent < c.UsefulChunksReceived+6 {
// We want to upload to the peer. // We want to upload to the peer.
c.Unchoke() if !c.Unchoke(msg) {
return false
}
for r := range c.PeerRequests { for r := range c.PeerRequests {
res := cl.uploadLimit.ReserveN(time.Now(), int(r.Length)) res := cl.uploadLimit.ReserveN(time.Now(), int(r.Length))
if !res.OK() {
panic(res)
}
delay := res.Delay() delay := res.Delay()
if delay > 0 { if delay > 0 {
res.Cancel() res.Cancel()
go func() { if c.uploadTimer == nil {
time.Sleep(delay) c.uploadTimer = time.AfterFunc(delay, c.writerCond.Broadcast)
cl.mu.Lock() } else {
defer cl.mu.Unlock() c.uploadTimer.Reset(delay)
c.upload() }
}() // Hard to say what to return here.
return return true
} }
err := cl.sendChunk(t, c, r) more, err := cl.sendChunk(t, c, r, msg)
if err != nil { if err != nil {
i := int(r.Index) i := int(r.Index)
if t.pieceComplete(i) { if t.pieceComplete(i) {
@ -1068,11 +1064,14 @@ another:
break another break another
} }
delete(c.PeerRequests, r) delete(c.PeerRequests, r)
if !more {
return false
}
goto another goto another
} }
return return true
} }
c.Choke() return c.Choke(msg)
} }
func (cn *connection) Drop() { func (cn *connection) Drop() {

View File

@ -1481,9 +1481,6 @@ func (t *Torrent) onPieceCompleted(piece int) {
t.cancelRequestsForPiece(piece) t.cancelRequestsForPiece(piece)
for conn := range t.conns { for conn := range t.conns {
conn.Have(piece) conn.Have(piece)
// Could check here if peer doesn't have piece, but due to caching
// some peers may have said they have a piece but they don't.
conn.upload()
} }
} }