github.com/yimialmonte/fabric@v2.1.1+incompatible/gossip/election/adapter.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package election 8 9 import ( 10 "bytes" 11 "sync" 12 "time" 13 14 proto "github.com/hyperledger/fabric-protos-go/gossip" 15 "github.com/hyperledger/fabric/gossip/common" 16 "github.com/hyperledger/fabric/gossip/discovery" 17 "github.com/hyperledger/fabric/gossip/metrics" 18 "github.com/hyperledger/fabric/gossip/protoext" 19 "github.com/hyperledger/fabric/gossip/util" 20 ) 21 22 type msgImpl struct { 23 msg *proto.GossipMessage 24 } 25 26 func (mi *msgImpl) SenderID() peerID { 27 return mi.msg.GetLeadershipMsg().PkiId 28 } 29 30 func (mi *msgImpl) IsProposal() bool { 31 return !mi.IsDeclaration() 32 } 33 34 func (mi *msgImpl) IsDeclaration() bool { 35 return mi.msg.GetLeadershipMsg().IsDeclaration 36 } 37 38 type peerImpl struct { 39 member discovery.NetworkMember 40 } 41 42 func (pi *peerImpl) ID() peerID { 43 return peerID(pi.member.PKIid) 44 } 45 46 type gossip interface { 47 // PeersOfChannel returns the NetworkMembers considered alive in a channel 48 PeersOfChannel(channel common.ChannelID) []discovery.NetworkMember 49 50 // Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate. 51 // If passThrough is false, the messages are processed by the gossip layer beforehand. 52 // If passThrough is true, the gossip layer doesn't intervene and the messages 53 // can be used to send a reply back to the sender 54 Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan protoext.ReceivedMessage) 55 56 // Gossip sends a message to other peers to the network 57 Gossip(msg *proto.GossipMessage) 58 59 // IsInMyOrg checks whether a network member is in this peer's org 60 IsInMyOrg(member discovery.NetworkMember) bool 61 } 62 63 type adapterImpl struct { 64 gossip gossip 65 selfPKIid common.PKIidType 66 67 incTime uint64 68 seqNum uint64 69 70 channel common.ChannelID 71 72 logger util.Logger 73 74 doneCh chan struct{} 75 stopOnce *sync.Once 76 metrics *metrics.ElectionMetrics 77 } 78 79 // NewAdapter creates new leader election adapter 80 func NewAdapter(gossip gossip, pkiid common.PKIidType, channel common.ChannelID, 81 metrics *metrics.ElectionMetrics) LeaderElectionAdapter { 82 return &adapterImpl{ 83 gossip: gossip, 84 selfPKIid: pkiid, 85 86 incTime: uint64(time.Now().UnixNano()), 87 seqNum: uint64(0), 88 89 channel: channel, 90 91 logger: util.GetLogger(util.ElectionLogger, ""), 92 93 doneCh: make(chan struct{}), 94 stopOnce: &sync.Once{}, 95 metrics: metrics, 96 } 97 } 98 99 func (ai *adapterImpl) Gossip(msg Msg) { 100 ai.gossip.Gossip(msg.(*msgImpl).msg) 101 } 102 103 func (ai *adapterImpl) Accept() <-chan Msg { 104 adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool { 105 // Get only leadership org and channel messages 106 return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG && 107 protoext.IsLeadershipMsg(message.(*proto.GossipMessage)) && 108 bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel) 109 }, false) 110 111 msgCh := make(chan Msg) 112 113 go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) { 114 for { 115 select { 116 case <-stopCh: 117 return 118 case gossipMsg, ok := <-inCh: 119 if ok { 120 outCh <- &msgImpl{gossipMsg} 121 } else { 122 return 123 } 124 } 125 } 126 }(adapterCh, msgCh, ai.doneCh) 127 return msgCh 128 } 129 130 func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg { 131 ai.seqNum++ 132 seqNum := ai.seqNum 133 134 leadershipMsg := &proto.LeadershipMessage{ 135 PkiId: ai.selfPKIid, 136 IsDeclaration: isDeclaration, 137 Timestamp: &proto.PeerTime{ 138 IncNum: ai.incTime, 139 SeqNum: seqNum, 140 }, 141 } 142 143 msg := &proto.GossipMessage{ 144 Nonce: 0, 145 Tag: proto.GossipMessage_CHAN_AND_ORG, 146 Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg}, 147 Channel: ai.channel, 148 } 149 return &msgImpl{msg} 150 } 151 152 func (ai *adapterImpl) Peers() []Peer { 153 peers := ai.gossip.PeersOfChannel(ai.channel) 154 155 var res []Peer 156 for _, peer := range peers { 157 if ai.gossip.IsInMyOrg(peer) { 158 res = append(res, &peerImpl{peer}) 159 } 160 } 161 162 return res 163 } 164 165 func (ai *adapterImpl) ReportMetrics(isLeader bool) { 166 var leadershipBit float64 167 if isLeader { 168 leadershipBit = 1 169 } 170 ai.metrics.Declaration.With("channel", string(ai.channel)).Set(leadershipBit) 171 } 172 173 func (ai *adapterImpl) Stop() { 174 stopFunc := func() { 175 close(ai.doneCh) 176 } 177 ai.stopOnce.Do(stopFunc) 178 }