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  }