github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 proto "github.com/hyperledger/fabric/protos/gossip" 27 "github.com/op/go-logging" 28 ) 29 30 type msgImpl struct { 31 msg *proto.GossipMessage 32 } 33 34 func (mi *msgImpl) SenderID() string { 35 return string(mi.msg.GetLeadershipMsg().PkiID) 36 } 37 38 func (mi *msgImpl) IsProposal() bool { 39 return !mi.IsDeclaration() 40 } 41 42 func (mi *msgImpl) IsDeclaration() bool { 43 return mi.msg.GetLeadershipMsg().IsDeclaration 44 } 45 46 type peerImpl struct { 47 member *discovery.NetworkMember 48 } 49 50 func (pi *peerImpl) ID() string { 51 return string(pi.member.PKIid) 52 } 53 54 type gossip interface { 55 // Peers returns the NetworkMembers considered alive 56 Peers() []discovery.NetworkMember 57 58 // Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate. 59 // If passThrough is false, the messages are processed by the gossip layer beforehand. 60 // If passThrough is true, the gossip layer doesn't intervene and the messages 61 // can be used to send a reply back to the sender 62 Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage) 63 64 // Gossip sends a message to other peers to the network 65 Gossip(msg *proto.GossipMessage) 66 } 67 68 type adapterImpl struct { 69 gossip gossip 70 self *discovery.NetworkMember 71 72 incTime uint64 73 seqNum uint64 74 75 channel common.ChainID 76 77 logger *logging.Logger 78 79 doneCh chan struct{} 80 stopOnce *sync.Once 81 } 82 83 // NewAdapter creates new leader election adapter 84 func NewAdapter(gossip gossip, self *discovery.NetworkMember, channel common.ChainID) LeaderElectionAdapter { 85 return &adapterImpl{ 86 gossip: gossip, 87 self: self, 88 89 incTime: uint64(time.Now().UnixNano()), 90 seqNum: uint64(0), 91 92 channel: channel, 93 94 logger: logging.MustGetLogger("LeaderElectionAdapter"), 95 96 doneCh: make(chan struct{}), 97 stopOnce: &sync.Once{}, 98 } 99 } 100 101 func (ai *adapterImpl) Gossip(msg Msg) { 102 ai.gossip.Gossip(msg.(*msgImpl).msg) 103 } 104 105 func (ai *adapterImpl) Accept() <-chan Msg { 106 adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool { 107 // Get only leadership org and channel messages 108 return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG && 109 message.(*proto.GossipMessage).IsLeadershipMsg() && 110 bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel) 111 }, false) 112 113 msgCh := make(chan Msg) 114 115 go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) { 116 for { 117 select { 118 case <-stopCh: 119 return 120 case gossipMsg, ok := <-inCh: 121 if ok { 122 outCh <- &msgImpl{gossipMsg} 123 } else { 124 return 125 } 126 } 127 } 128 }(adapterCh, msgCh, ai.doneCh) 129 return msgCh 130 } 131 132 func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg { 133 ai.seqNum++ 134 seqNum := ai.seqNum 135 136 leadershipMsg := &proto.LeadershipMessage{ 137 PkiID: ai.self.PKIid, 138 IsDeclaration: isDeclaration, 139 Timestamp: &proto.PeerTime{ 140 IncNumber: ai.incTime, 141 SeqNum: seqNum, 142 }, 143 } 144 145 msg := &proto.GossipMessage{ 146 Nonce: 0, 147 Tag: proto.GossipMessage_CHAN_AND_ORG, 148 Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg}, 149 Channel: ai.channel, 150 } 151 return &msgImpl{msg} 152 } 153 154 func (ai *adapterImpl) Peers() []Peer { 155 peers := ai.gossip.Peers() 156 157 var res []Peer 158 for _, peer := range peers { 159 res = append(res, &peerImpl{&peer}) 160 } 161 162 return res 163 } 164 165 func (ai *adapterImpl) Stop() { 166 stopFunc := func() { 167 close(ai.doneCh) 168 } 169 ai.stopOnce.Do(stopFunc) 170 }