github.com/aergoio/aergo@v1.3.1/p2p/raftsupport/rafttransport.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package raftsupport 7 8 import ( 9 "github.com/aergoio/aergo-lib/log" 10 "github.com/aergoio/aergo/consensus" 11 "github.com/aergoio/aergo/consensus/impl/raftv2" 12 "github.com/aergoio/aergo/p2p/p2pcommon" 13 "github.com/aergoio/aergo/p2p/p2putil" 14 "github.com/aergoio/aergo/types" 15 "github.com/aergoio/etcd/etcdserver/stats" 16 rtypes "github.com/aergoio/etcd/pkg/types" 17 "github.com/aergoio/etcd/raft" 18 "github.com/aergoio/etcd/raft/raftpb" 19 "github.com/aergoio/etcd/snap" 20 "github.com/libp2p/go-libp2p-core/network" 21 "github.com/pkg/errors" 22 "io" 23 "net/http" 24 "strconv" 25 "sync" 26 "time" 27 ) 28 29 // errors 30 var ( 31 errInvalidMember = errors.New("invalid member id") 32 errCanNotFoundMember = errors.New("cannot find member") 33 errRemovedMember = errors.New("member was removed") 34 errUnreachableMember = errors.New("member is unreachable") 35 ) 36 // AergoRaftTransport is wrapper of p2p module 37 type AergoRaftTransport struct { 38 logger *log.Logger 39 mutex sync.RWMutex 40 41 nt p2pcommon.NetworkTransport 42 pm p2pcommon.PeerManager 43 mf p2pcommon.MoFactory 44 consAcc consensus.ConsensusAccessor 45 raftAcc consensus.AergoRaftAccessor 46 snapF SnapshotIOFactory 47 48 cluster *raftv2.Cluster 49 50 // statuses have connection status of memeber peers 51 statuses map[rtypes.ID]*rPeerStatus 52 stByPID map[types.PeerID]*rPeerStatus 53 54 // copied from original transport 55 ServerStats *stats.ServerStats 56 LeaderStats *stats.LeaderStats 57 } 58 59 var _ raftv2.Transporter = (*AergoRaftTransport)(nil) 60 61 func NewAergoRaftTransport(logger *log.Logger, nt p2pcommon.NetworkTransport, pm p2pcommon.PeerManager, mf p2pcommon.MoFactory, consAcc consensus.ConsensusAccessor, cluster interface{}) *AergoRaftTransport { 62 t := &AergoRaftTransport{logger: logger, nt: nt, pm: pm, mf: mf, consAcc: consAcc, raftAcc: consAcc.RaftAccessor(), cluster: cluster.(*raftv2.Cluster), 63 statuses: make(map[rtypes.ID]*rPeerStatus), 64 stByPID: make(map[types.PeerID]*rPeerStatus), 65 ServerStats: stats.NewServerStats("", ""), 66 } 67 // TODO need check real id type 68 t.LeaderStats = stats.NewLeaderStats(strconv.Itoa(int(t.cluster.NodeID()))) 69 t.snapF = t 70 pm.AddPeerEventListener(t) 71 logger.Info().Msg("aergo raft transport is created") 72 return t 73 } 74 75 func (t *AergoRaftTransport) Start() error { 76 t.nt.AddStreamHandler(p2pcommon.RaftSnapSubAddr, t.OnRaftSnapshot) 77 78 // do nothing for now 79 return nil 80 } 81 82 func (t *AergoRaftTransport) Handler() http.Handler { 83 // 84 return http.NewServeMux() 85 } 86 87 // Send must send message to target peer or report unreachable if sending peer is failed. 88 func (t *AergoRaftTransport) Send(msgs []raftpb.Message) { 89 for _, m := range msgs { 90 if m.To == 0 { 91 // ignore intentionally dropped message 92 continue 93 } 94 95 member := t.raftAcc.GetMemberByID(m.To) 96 if member == nil { 97 t.logger.Info().Object("raftMsg", &RaftMsgMarshaller{&m}).Msg("ignored message to no raft member") 98 99 continue 100 } 101 peer, _ := t.pm.GetPeer(member.GetPeerID()) 102 if peer != nil { 103 peer.SendMessage(t.mf.NewRaftMsgOrder(m.Type, &m)) 104 continue 105 } else { 106 t.logger.Debug().Str(p2putil.LogPeerID, p2putil.ShortForm(member.GetPeerID())).Msg("peer is unreachable") 107 t.raftAcc.ReportUnreachable(member.GetPeerID()) 108 continue 109 } 110 111 t.logger.Debug().Str(p2putil.LogPeerID, p2putil.ShortForm(member.GetPeerID())).Object("raftMsg", &RaftMsgMarshaller{&m}).Msg("can't send message to unconnected peer") 112 } 113 } 114 115 func (t *AergoRaftTransport) SendSnapshot(m snap.Message) { 116 if m.To == 0 { 117 // ignore intentionally dropped message 118 t.logger.Warn().Msg("drop snap message: to invalid target") 119 m.CloseWithError(errInvalidMember) 120 return 121 } 122 member := t.raftAcc.GetMemberByID(m.To) 123 if member == nil { 124 // TODO is it ok to ignore? 125 t.logger.Warn().Msg("drop snap message: no member") 126 m.CloseWithError(errCanNotFoundMember) 127 return 128 } 129 // TODO: member is exists but unreachable should return message to change peer state 130 peer, _ := t.pm.GetPeer(member.GetPeerID()) 131 if peer == nil { 132 t.logger.Warn().Msg("drop snap message:no peer") 133 t.raftAcc.ReportUnreachable(member.GetPeerID()) 134 t.raftAcc.ReportSnapshot(member.GetPeerID(), raft.SnapshotFailure) 135 m.CloseWithError(errUnreachableMember) 136 return 137 } 138 139 sender := t.snapF.NewSnapshotSender(peer) 140 go sender.Send(&m) 141 } 142 143 func (t *AergoRaftTransport) AddRemote(id rtypes.ID, urls []string) { 144 panic("implement me") 145 } 146 147 func (t *AergoRaftTransport) AddPeer(id rtypes.ID, peerID types.PeerID, urls []string) { 148 t.mutex.Lock() 149 defer t.mutex.Unlock() 150 t.logger.Debug().Str(p2putil.LogPeerID, p2putil.ShortForm(peerID)).Str("id", id.String()).Msg("Adding member peer") 151 152 member := t.raftAcc.GetMemberByID(uint64(id)) 153 if member == nil { 154 t.logger.Info().Str(p2putil.LogPeerID, p2putil.ShortForm(peerID)).Str("id", id.String()).Msg("can't find member") 155 return 156 } 157 st, exist := t.statuses[id] 158 if exist { 159 if _, exist := t.pm.GetPeer(member.GetPeerID()); exist { 160 t.logger.Info().Str(p2putil.LogPeerID, p2putil.ShortForm(peerID)).Str("id", id.String()).Msg("peer already exists") 161 st.activate() 162 return 163 } else { 164 st.deactivate("disconnected") 165 t.connectToPeer(member) 166 } 167 } else { 168 // register new status and try to connect 169 t.statuses[id] = newPeerStatus(id, peerID, t.logger) 170 t.stByPID[peerID] = t.statuses[id] 171 t.connectToPeer(member) 172 } 173 } 174 175 func (t *AergoRaftTransport) connectToPeer(member *consensus.Member) { 176 pid, err := types.IDFromBytes(member.PeerID) 177 peerMeta, err := p2putil.FromMultiAddrStringWithPID(member.Address, pid) 178 if err != nil { 179 t.logger.Panic().Err(err).Str("addr", member.Address).Msg("Address must be valid") 180 } 181 182 // member should be add to designated peer 183 meta := peerMeta 184 meta.Outbound = true 185 meta.Designated = true 186 t.pm.AddDesignatedPeer(meta) 187 t.pm.AddNewPeer(meta) 188 } 189 190 func (t *AergoRaftTransport) RemovePeer(id rtypes.ID) { 191 t.mutex.Lock() 192 defer t.mutex.Unlock() 193 194 st := t.statuses[id] 195 if st == nil { 196 return 197 } 198 t.pm.RemoveDesignatedPeer(st.pid) 199 delete(t.statuses, id) 200 delete(t.stByPID, st.pid) 201 if peer, exist := t.pm.GetPeer(st.pid); exist { 202 peer.Stop() 203 } 204 t.logger.Info().Str(p2putil.LogPeerID, p2putil.ShortForm(st.pid)).Uint64("raftID", uint64(id)).Msg("removed raft peer") 205 } 206 207 func (t *AergoRaftTransport) RemoveAllPeers() { 208 t.mutex.Lock() 209 defer t.mutex.Unlock() 210 for _, peer := range t.pm.GetPeers() { 211 peer.Stop() 212 } 213 } 214 215 func (t *AergoRaftTransport) UpdatePeer(id rtypes.ID, urls []string) { 216 t.mutex.Lock() 217 defer t.mutex.Unlock() 218 // To Nothing for now 219 } 220 221 func (t *AergoRaftTransport) ActiveSince(id rtypes.ID) time.Time { 222 t.mutex.Lock() 223 defer t.mutex.Unlock() 224 if p, ok := t.statuses[id]; ok { 225 return p.activeSince() 226 } 227 return time.Time{} 228 229 } 230 231 func (t *AergoRaftTransport) ActivePeers() int { 232 return len(t.pm.GetPeers()) 233 } 234 235 func (t *AergoRaftTransport) Stop() { 236 t.mutex.Lock() 237 defer t.mutex.Unlock() 238 // Lots of works will be done by p2p modules 239 t.nt.RemoveStreamHandler(p2pcommon.RaftSnapSubAddr) 240 } 241 242 func (t *AergoRaftTransport) OnRaftSnapshot(s network.Stream) { 243 hsresp := p2pcommon.HSHeadResp{Magic: p2pcommon.MAGICRaftSnap} 244 peerID := s.Conn().RemotePeer() 245 246 // check validation 247 // check if sender is the leader node 248 peer, found := t.pm.GetPeer(peerID) 249 if !found { 250 addr := s.Conn().RemoteMultiaddr() 251 t.logger.Info().Str(p2putil.LogPeerID, p2putil.ShortForm(peerID)).Str("multiaddr", addr.String()).Msg("snapshot stream from leader node") 252 hsresp.RespCode = p2pcommon.HSCodeAuthFail 253 s.Write(hsresp.Marshal()) 254 s.Close() 255 return 256 } 257 //// TODO raft role is not properly set yet. 258 //if peer.Role() != p2pcommon.RaftLeader { 259 // t.logger.Warn().Str(p2putil.LogPeerName, peer.Name()).Msg("Closing snapshot stream from follower node") 260 // hsresp.RespCode = p2pcommon.HSCodeNoPermission 261 // s.Write(hsresp.Marshal()) 262 // s.Close() 263 // return 264 //} 265 // 266 t.logger.Debug().Str(p2putil.LogPeerName, peerID.Pretty()).Msg("snapshot stream from leader node") 267 268 // read stream and send it to raft 269 sr := t.snapF.NewSnapshotReceiver(peer, s) 270 sr.Receive() 271 t.logger.Debug().Str(p2putil.LogPeerName, peerID.Pretty()).Msg("snapshot receiving finished") 272 s.Close() 273 } 274 275 func (t *AergoRaftTransport) OnPeerConnect(pid types.PeerID) { 276 go func() { 277 t.mutex.Lock() 278 defer t.mutex.Unlock() 279 if st, exist := t.stByPID[pid]; exist { 280 st.activate() 281 } 282 }() 283 } 284 285 func (t *AergoRaftTransport) OnPeerDisconnect(peer p2pcommon.RemotePeer) { 286 go func(peerID types.PeerID) { 287 t.mutex.Lock() 288 defer t.mutex.Unlock() 289 if st, exist := t.stByPID[peer.ID()]; exist { 290 st.deactivate("disconnect") 291 } 292 }(peer.ID()) 293 } 294 295 func (t *AergoRaftTransport) NewSnapshotSender(peer p2pcommon.RemotePeer) SnapshotSender { 296 return newSnapshotSender(t.logger, t.nt, t.raftAcc, peer) 297 } 298 299 func (t *AergoRaftTransport) NewSnapshotReceiver(peer p2pcommon.RemotePeer, rwc io.ReadWriteCloser) SnapshotReceiver { 300 return newSnapshotReceiver(t.logger, t.pm, t.raftAcc, peer, rwc) 301 }