github.com/aergoio/aergo@v1.3.1/p2p/raftsupport/clusterreceiver.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package raftsupport 7 8 import ( 9 "fmt" 10 "github.com/pkg/errors" 11 "sync" 12 "time" 13 14 "github.com/aergoio/aergo/message" 15 "github.com/aergoio/aergo/p2p/p2pcommon" 16 "github.com/aergoio/aergo/types" 17 "github.com/golang/protobuf/proto" 18 ) 19 20 // ClusterInfoReceiver is send p2p getClusterInfo to connected peers and Receive p2p responses one of peers return successful response 21 // The first version will be simplified version. it send and Receive one by one. 22 type ClusterInfoReceiver struct { 23 mf p2pcommon.MoFactory 24 25 peers []p2pcommon.RemotePeer 26 mutex sync.Mutex 27 sents map[p2pcommon.MsgID]p2pcommon.RemotePeer 28 offset int 29 30 req *message.GetCluster 31 actor p2pcommon.ActorService 32 33 ttl time.Duration 34 timeout time.Time 35 finished bool 36 status receiverStatus 37 38 got []*types.Block 39 senderFinished chan interface{} 40 } 41 42 type receiverStatus int32 43 44 const ( 45 receiverStatusWaiting receiverStatus = iota 46 receiverStatusCanceled 47 receiverStatusFinished 48 ) 49 50 func NewClusterInfoReceiver(actor p2pcommon.ActorService, mf p2pcommon.MoFactory, peers []p2pcommon.RemotePeer, ttl time.Duration, req *message.GetCluster) *ClusterInfoReceiver { 51 return &ClusterInfoReceiver{actor: actor, mf: mf, peers: peers, ttl: ttl, req: req, sents: make(map[p2pcommon.MsgID]p2pcommon.RemotePeer)} 52 } 53 54 func (br *ClusterInfoReceiver) StartGet() { 55 br.timeout = time.Now().Add(br.ttl) 56 // create message data 57 // send message to first peer 58 go func() { 59 br.mutex.Lock() 60 defer br.mutex.Unlock() 61 if !br.trySendNextPeer() { 62 br.cancelReceiving(errors.New("no live peers"), false) 63 } 64 }() 65 } 66 67 func (br *ClusterInfoReceiver) trySendNextPeer() bool { 68 for ; br.offset < len(br.peers); br.offset++ { 69 peer := br.peers[br.offset] 70 if peer.State() == types.RUNNING { 71 br.offset++ 72 mo := br.mf.NewMsgBlockRequestOrder(br.ReceiveResp, p2pcommon.GetClusterRequest, &types.GetClusterInfoRequest{BestBlockHash: br.req.BestBlockHash}) 73 peer.SendMessage(mo) 74 br.sents[mo.GetMsgID()] = peer 75 return true 76 } 77 } 78 return false 79 } 80 81 // ReceiveResp must be called just in read go routine 82 func (br *ClusterInfoReceiver) ReceiveResp(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) (ret bool) { 83 // cases in waiting 84 // normal not status => wait 85 // normal status (last response) => finish 86 // abnormal resp (no following resp expected): hasNext is true => cancel 87 // abnormal resp (following resp expected): hasNext is false, or invalid resp data type (maybe remote peer is totally broken) => cancel finish 88 // case in status or status 89 ret = true 90 br.mutex.Lock() 91 defer br.mutex.Unlock() 92 // consuming request id at first 93 peer, exist := br.sents[msg.OriginalID()] 94 if exist { 95 delete(br.sents, msg.OriginalID()) 96 peer.ConsumeRequest(msg.OriginalID()) 97 } 98 99 status := br.status 100 switch status { 101 case receiverStatusWaiting: 102 br.handleInWaiting(msg, msgBody) 103 case receiverStatusCanceled: 104 fallthrough 105 case receiverStatusFinished: 106 fallthrough 107 default: 108 br.ignoreMsg(msg, msgBody) 109 return 110 } 111 return 112 } 113 114 func (br *ClusterInfoReceiver) handleInWaiting(msg p2pcommon.Message, msgBody proto.Message) { 115 // timeout 116 if br.timeout.Before(time.Now()) { 117 // silently ignore already finished job 118 br.finishReceiver() 119 return 120 } 121 122 // remote peer response malformed data. 123 body, ok := msgBody.(*types.GetClusterInfoResponse) 124 if !ok || len(body.MbrAttrs) == 0 || body.Error != "" { 125 // TODO log fail reason? 126 if !br.trySendNextPeer() { 127 br.cancelReceiving(errors.New("no live peers"), false) 128 } 129 return 130 } 131 132 // return the result 133 var err error 134 br.finishReceiver() 135 if len(body.Error) != 0 { 136 err = fmt.Errorf("get cluster info error: %s", body.Error) 137 } 138 result := &message.GetClusterRsp{ClusterID: body.GetClusterID(), ChainID: body.GetChainID(), Members: body.GetMbrAttrs(), 139 Err: err, HardStateInfo: body.HardStateInfo} 140 br.req.ReplyC <- result 141 close(br.req.ReplyC) 142 return 143 } 144 145 // cancelReceiving is cancel wait for receiving and return the failure result. 146 // it wait remaining (and useless) response. It is assumed cancellations are not frequently occur 147 func (br *ClusterInfoReceiver) cancelReceiving(err error, hasNext bool) { 148 br.status = receiverStatusCanceled 149 result := &message.GetClusterRsp{Err: err} 150 br.req.ReplyC <- result 151 close(br.req.ReplyC) 152 br.finishReceiver() 153 } 154 155 // finishReceiver is to cancel works, assuming cancellations are not frequently occur 156 func (br *ClusterInfoReceiver) finishReceiver() { 157 br.status = receiverStatusFinished 158 } 159 160 // ignoreMsg is silently ignore following responses, which is not useless anymore. 161 func (br *ClusterInfoReceiver) ignoreMsg(msg p2pcommon.Message, msgBody proto.Message) { 162 // nothing to do for now 163 }