[NOD-1142] Implement EnqueueWithTimeout and DequeueWithTimeout (#794)

* [NOD-1142] Implement EnqueueWithTimeout and DequeueWithTimeout.

* [NOD-1142] Use DequeueWithTimeout in readMsgBlock.

* [NOD-1142] Add comments about the new methods.
This commit is contained in:
stasatdaglabs 2020-07-14 16:14:27 +03:00 committed by GitHub
parent 6076309b3e
commit f8e53d309c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 27 deletions

View File

@ -1,7 +1,9 @@
package router
import (
"errors"
"github.com/kaspanet/kaspad/wire"
"time"
)
const (
@ -48,6 +50,37 @@ func (r *Route) Dequeue() (message wire.Message, isOpen bool) {
return <-r.channel, true
}
// EnqueueWithTimeout attempts to enqueue a message to the Route
// and returns an error if the given timeout expires first.
func (r *Route) EnqueueWithTimeout(message wire.Message, timeout time.Duration) (isOpen bool, err error) {
if r.closed {
return false, nil
}
if len(r.channel) == maxMessages {
r.onCapacityReachedHandler()
}
select {
case <-time.After(timeout):
return false, errors.New("timeout expired")
case r.channel <- message:
return true, nil
}
}
// DequeueWithTimeout attempts to dequeue a message from the Route
// and returns an error if the given timeout expires first.
func (r *Route) DequeueWithTimeout(timeout time.Duration) (message wire.Message, isOpen bool, err error) {
if r.closed {
return nil, false, nil
}
select {
case <-time.After(timeout):
return nil, false, errors.New("timeout expired")
case message := <-r.channel:
return message, true, nil
}
}
func (r *Route) setOnCapacityReachedHandler(onCapacityReachedHandler onCapacityReachedHandler) {
r.onCapacityReachedHandler = onCapacityReachedHandler
}

View File

@ -138,32 +138,22 @@ func readMsgBlock(incomingRoute *router.Route, invsQueue *[]*wire.MsgInvRelayBlo
msgBlock *wire.MsgBlock, shouldStop bool, err error) {
for {
closeChan := make(chan struct{})
msgChan := make(chan wire.Message)
spawn(func() {
message, isOpen := incomingRoute.Dequeue()
if !isOpen {
closeChan <- struct{}{}
return
}
msgChan <- message
})
const timeout = 30 * time.Second
select {
case <-time.After(timeout):
return nil, false, errors.Errorf("stalled for %s", timeout)
case <-closeChan:
message, isOpen, err := incomingRoute.DequeueWithTimeout(timeout)
if err != nil {
return nil, false, err
}
if !isOpen {
return nil, true, nil
case msg := <-msgChan:
switch msg := msg.(type) {
case *wire.MsgInvRelayBlock:
*invsQueue = append(*invsQueue, msg)
case *wire.MsgBlock:
return msg, false, nil
default:
panic(errors.Errorf("unexpected message %s", msg.Command()))
}
}
switch message := message.(type) {
case *wire.MsgInvRelayBlock:
*invsQueue = append(*invsQueue, message)
case *wire.MsgBlock:
return message, false, nil
default:
panic(errors.Errorf("unexpected message %s", message.Command()))
}
}
}

View File

@ -9,6 +9,8 @@ import (
"time"
)
const pingTimeout = 30 * time.Second
// ReceivePings handles all ping messages coming through incomingRoute.
// This function assumes that incomingRoute will only return MsgPing.
func ReceivePings(incomingRoute *router.Route, outgoingRoute *router.Route) error {
@ -20,7 +22,10 @@ func ReceivePings(incomingRoute *router.Route, outgoingRoute *router.Route) erro
pingMessage := message.(*wire.MsgPing)
pongMessage := wire.NewMsgPong(pingMessage.Nonce)
isOpen = outgoingRoute.Enqueue(pongMessage)
isOpen, err := outgoingRoute.EnqueueWithTimeout(pongMessage, pingTimeout)
if err != nil {
return err
}
if !isOpen {
return nil
}
@ -43,12 +48,18 @@ func SendPings(incomingRoute *router.Route, outgoingRoute *router.Route, peer *p
peer.SetPingPending(nonce)
pingMessage := wire.NewMsgPing(nonce)
isOpen := outgoingRoute.Enqueue(pingMessage)
isOpen, err := outgoingRoute.EnqueueWithTimeout(pingMessage, pingTimeout)
if err != nil {
return err
}
if !isOpen {
return nil
}
message, isOpen := incomingRoute.Dequeue()
message, isOpen, err := incomingRoute.DequeueWithTimeout(pingTimeout)
if err != nil {
return err
}
if !isOpen {
return nil
}