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  }