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