github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/cluster/rpc.go (about) 1 /* 2 Copyright hechain. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package cluster 8 9 import ( 10 "context" 11 "io" 12 "sync" 13 "time" 14 15 "github.com/hechain20/hechain/common/flogging" 16 "github.com/hyperledger/fabric-protos-go/orderer" 17 "github.com/pkg/errors" 18 "go.uber.org/zap/zapcore" 19 "google.golang.org/grpc" 20 ) 21 22 //go:generate mockery -dir . -name StepClient -case underscore -output ./mocks/ 23 24 // StepClient defines a client that sends and receives Step requests and responses. 25 type StepClient interface { 26 Send(*orderer.StepRequest) error 27 Recv() (*orderer.StepResponse, error) 28 grpc.ClientStream 29 } 30 31 //go:generate mockery -dir . -name ClusterClient -case underscore -output ./mocks/ 32 33 // ClusterClient creates streams that point to a remote cluster member. 34 type ClusterClient interface { 35 Step(ctx context.Context, opts ...grpc.CallOption) (orderer.Cluster_StepClient, error) 36 } 37 38 // RPC performs remote procedure calls to remote cluster nodes. 39 type RPC struct { 40 consensusLock sync.Mutex 41 submitLock sync.Mutex 42 Logger *flogging.FabricLogger 43 Timeout time.Duration 44 Channel string 45 Comm Communicator 46 lock sync.RWMutex 47 StreamsByType map[OperationType]map[uint64]*Stream 48 } 49 50 // NewStreamsByType returns a mapping of operation type to 51 // a mapping of destination to stream. 52 func NewStreamsByType() map[OperationType]map[uint64]*Stream { 53 m := make(map[OperationType]map[uint64]*Stream) 54 m[ConsensusOperation] = make(map[uint64]*Stream) 55 m[SubmitOperation] = make(map[uint64]*Stream) 56 return m 57 } 58 59 // OperationType denotes a type of operation that the RPC can perform 60 // such as sending a transaction, or a consensus related message. 61 type OperationType int 62 63 const ( 64 ConsensusOperation OperationType = iota 65 SubmitOperation 66 ) 67 68 func (ot OperationType) String() string { 69 if ot == SubmitOperation { 70 return "transaction" 71 } 72 73 return "consensus" 74 } 75 76 // SendConsensus passes the given ConsensusRequest message to the raft.Node instance. 77 func (s *RPC) SendConsensus(destination uint64, msg *orderer.ConsensusRequest) error { 78 if s.Logger.IsEnabledFor(zapcore.DebugLevel) { 79 defer s.consensusSent(time.Now(), destination, msg) 80 } 81 82 stream, err := s.getOrCreateStream(destination, ConsensusOperation) 83 if err != nil { 84 return err 85 } 86 87 req := &orderer.StepRequest{ 88 Payload: &orderer.StepRequest_ConsensusRequest{ 89 ConsensusRequest: msg, 90 }, 91 } 92 93 s.consensusLock.Lock() 94 defer s.consensusLock.Unlock() 95 96 err = stream.Send(req) 97 if err != nil { 98 s.unMapStream(destination, ConsensusOperation, stream.ID) 99 } 100 101 return err 102 } 103 104 // SendSubmit sends a SubmitRequest to the given destination node. 105 func (s *RPC) SendSubmit(destination uint64, request *orderer.SubmitRequest, report func(error)) error { 106 if s.Logger.IsEnabledFor(zapcore.DebugLevel) { 107 defer s.submitSent(time.Now(), destination, request) 108 } 109 110 stream, err := s.getOrCreateStream(destination, SubmitOperation) 111 if err != nil { 112 return err 113 } 114 115 req := &orderer.StepRequest{ 116 Payload: &orderer.StepRequest_SubmitRequest{ 117 SubmitRequest: request, 118 }, 119 } 120 121 unmapOnFailure := func(err error) { 122 if err != nil && err.Error() == io.EOF.Error() { 123 s.Logger.Infof("Un-mapping transaction stream to %d because encountered a stale stream", destination) 124 s.unMapStream(destination, SubmitOperation, stream.ID) 125 } 126 report(err) 127 } 128 129 s.submitLock.Lock() 130 defer s.submitLock.Unlock() 131 132 err = stream.SendWithReport(req, unmapOnFailure) 133 if err != nil { 134 s.unMapStream(destination, SubmitOperation, stream.ID) 135 } 136 return err 137 } 138 139 func (s *RPC) submitSent(start time.Time, to uint64, msg *orderer.SubmitRequest) { 140 s.Logger.Debugf("Sending msg of %d bytes to %d on channel %s took %v", submitMsgLength(msg), to, s.Channel, time.Since(start)) 141 } 142 143 func (s *RPC) consensusSent(start time.Time, to uint64, msg *orderer.ConsensusRequest) { 144 s.Logger.Debugf("Sending msg of %d bytes to %d on channel %s took %v", len(msg.Payload), to, s.Channel, time.Since(start)) 145 } 146 147 // getOrCreateStream obtains a Submit stream for the given destination node 148 func (s *RPC) getOrCreateStream(destination uint64, operationType OperationType) (*Stream, error) { 149 stream := s.getStream(destination, operationType) 150 if stream != nil { 151 return stream, nil 152 } 153 stub, err := s.Comm.Remote(s.Channel, destination) 154 if err != nil { 155 return nil, errors.WithStack(err) 156 } 157 stream, err = stub.NewStream(s.Timeout) 158 if err != nil { 159 return nil, err 160 } 161 s.mapStream(destination, stream, operationType) 162 return stream, nil 163 } 164 165 func (s *RPC) getStream(destination uint64, operationType OperationType) *Stream { 166 s.lock.RLock() 167 defer s.lock.RUnlock() 168 return s.StreamsByType[operationType][destination] 169 } 170 171 func (s *RPC) mapStream(destination uint64, stream *Stream, operationType OperationType) { 172 s.lock.Lock() 173 defer s.lock.Unlock() 174 s.StreamsByType[operationType][destination] = stream 175 s.cleanCanceledStreams(operationType) 176 } 177 178 func (s *RPC) unMapStream(destination uint64, operationType OperationType, streamIDToUnmap uint64) { 179 s.lock.Lock() 180 defer s.lock.Unlock() 181 182 stream, exists := s.StreamsByType[operationType][destination] 183 if !exists { 184 s.Logger.Debugf("No %s stream to %d found, nothing to unmap", operationType, destination) 185 return 186 } 187 188 if stream.ID != streamIDToUnmap { 189 s.Logger.Debugf("Stream for %s to %d has an ID of %d, not %d", operationType, destination, stream.ID, streamIDToUnmap) 190 return 191 } 192 193 delete(s.StreamsByType[operationType], destination) 194 } 195 196 func (s *RPC) cleanCanceledStreams(operationType OperationType) { 197 for destination, stream := range s.StreamsByType[operationType] { 198 if !stream.Canceled() { 199 continue 200 } 201 s.Logger.Infof("Removing stream %d to %d for channel %s because it is canceled", stream.ID, destination, s.Channel) 202 delete(s.StreamsByType[operationType], destination) 203 } 204 } 205 206 func submitMsgLength(request *orderer.SubmitRequest) int { 207 if request.Payload == nil { 208 return 0 209 } 210 return len(request.Payload.Payload) 211 }