github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/gossip/election/adapter.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package election 18 19 import ( 20 "bytes" 21 "sync" 22 "time" 23 24 "github.com/hyperledger/fabric/gossip/common" 25 "github.com/hyperledger/fabric/gossip/discovery" 26 "github.com/hyperledger/fabric/gossip/util" 27 proto "github.com/hyperledger/fabric/protos/gossip" 28 "github.com/op/go-logging" 29 ) 30 31 type msgImpl struct { 32 msg *proto.GossipMessage 33 } 34 35 func (mi *msgImpl) SenderID() peerID { 36 return mi.msg.GetLeadershipMsg().PkiId 37 } 38 39 func (mi *msgImpl) IsProposal() bool { 40 return !mi.IsDeclaration() 41 } 42 43 func (mi *msgImpl) IsDeclaration() bool { 44 return mi.msg.GetLeadershipMsg().IsDeclaration 45 } 46 47 type peerImpl struct { 48 member discovery.NetworkMember 49 } 50 51 func (pi *peerImpl) ID() peerID { 52 return peerID(pi.member.PKIid) 53 } 54 55 type gossip interface { 56 // Peers returns the NetworkMembers considered alive 57 Peers() []discovery.NetworkMember 58 59 // Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate. 60 // If passThrough is false, the messages are processed by the gossip layer beforehand. 61 // If passThrough is true, the gossip layer doesn't intervene and the messages 62 // can be used to send a reply back to the sender 63 Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage) 64 65 // Gossip sends a message to other peers to the network 66 Gossip(msg *proto.GossipMessage) 67 } 68 69 type adapterImpl struct { 70 gossip gossip 71 selfPKIid common.PKIidType 72 73 incTime uint64 74 seqNum uint64 75 76 channel common.ChainID 77 78 logger *logging.Logger 79 80 doneCh chan struct{} 81 stopOnce *sync.Once 82 } 83 84 // NewAdapter creates new leader election adapter 85 func NewAdapter(gossip gossip, pkiid common.PKIidType, channel common.ChainID) LeaderElectionAdapter { 86 return &adapterImpl{ 87 gossip: gossip, 88 selfPKIid: pkiid, 89 90 incTime: uint64(time.Now().UnixNano()), 91 seqNum: uint64(0), 92 93 channel: channel, 94 95 logger: util.GetLogger(util.LoggingElectionModule, ""), 96 97 doneCh: make(chan struct{}), 98 stopOnce: &sync.Once{}, 99 } 100 } 101 102 func (ai *adapterImpl) Gossip(msg Msg) { 103 ai.gossip.Gossip(msg.(*msgImpl).msg) 104 } 105 106 func (ai *adapterImpl) Accept() <-chan Msg { 107 adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool { 108 // Get only leadership org and channel messages 109 return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG && 110 message.(*proto.GossipMessage).IsLeadershipMsg() && 111 bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel) 112 }, false) 113 114 msgCh := make(chan Msg) 115 116 go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) { 117 for { 118 select { 119 case <-stopCh: 120 return 121 case gossipMsg, ok := <-inCh: 122 if ok { 123 outCh <- &msgImpl{gossipMsg} 124 } else { 125 return 126 } 127 } 128 } 129 }(adapterCh, msgCh, ai.doneCh) 130 return msgCh 131 } 132 133 func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg { 134 ai.seqNum++ 135 seqNum := ai.seqNum 136 137 leadershipMsg := &proto.LeadershipMessage{ 138 PkiId: ai.selfPKIid, 139 IsDeclaration: isDeclaration, 140 Timestamp: &proto.PeerTime{ 141 IncNum: ai.incTime, 142 SeqNum: seqNum, 143 }, 144 } 145 146 msg := &proto.GossipMessage{ 147 Nonce: 0, 148 Tag: proto.GossipMessage_CHAN_AND_ORG, 149 Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg}, 150 Channel: ai.channel, 151 } 152 return &msgImpl{msg} 153 } 154 155 func (ai *adapterImpl) Peers() []Peer { 156 peers := ai.gossip.Peers() 157 158 var res []Peer 159 for _, peer := range peers { 160 res = append(res, &peerImpl{peer}) 161 } 162 163 return res 164 } 165 166 func (ai *adapterImpl) Stop() { 167 stopFunc := func() { 168 close(ai.doneCh) 169 } 170 ai.stopOnce.Do(stopFunc) 171 }