github.com/lzy4123/fabric@v2.1.1+incompatible/orderer/consensus/kafka/consenter.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kafka
     8  
     9  import (
    10  	"github.com/Shopify/sarama"
    11  	"github.com/hyperledger/fabric-lib-go/healthz"
    12  	cb "github.com/hyperledger/fabric-protos-go/common"
    13  	"github.com/hyperledger/fabric/common/flogging"
    14  	"github.com/hyperledger/fabric/common/metrics"
    15  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    16  	"github.com/hyperledger/fabric/orderer/consensus"
    17  	"github.com/hyperledger/fabric/orderer/consensus/inactive"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  //go:generate counterfeiter -o mock/health_checker.go -fake-name HealthChecker . healthChecker
    22  
    23  // healthChecker defines the contract for health checker
    24  type healthChecker interface {
    25  	RegisterChecker(component string, checker healthz.HealthChecker) error
    26  }
    27  
    28  // New creates a Kafka-based consenter. Called by orderer's main.go.
    29  func New(config localconfig.Kafka, mp metrics.Provider, healthChecker healthChecker, icr InactiveChainRegistry, mkChain func(string)) (consensus.Consenter, *Metrics) {
    30  	if config.Verbose {
    31  		flogging.ActivateSpec(flogging.Global.Spec() + ":orderer.consensus.kafka.sarama=debug")
    32  	}
    33  
    34  	brokerConfig := newBrokerConfig(
    35  		config.TLS,
    36  		config.SASLPlain,
    37  		config.Retry,
    38  		config.Version,
    39  		defaultPartition)
    40  
    41  	metrics := NewMetrics(mp, brokerConfig.MetricRegistry)
    42  
    43  	return &consenterImpl{
    44  		mkChain:               mkChain,
    45  		inactiveChainRegistry: icr,
    46  		brokerConfigVal:       brokerConfig,
    47  		tlsConfigVal:          config.TLS,
    48  		retryOptionsVal:       config.Retry,
    49  		kafkaVersionVal:       config.Version,
    50  		topicDetailVal: &sarama.TopicDetail{
    51  			NumPartitions:     1,
    52  			ReplicationFactor: config.Topic.ReplicationFactor,
    53  		},
    54  		healthChecker: healthChecker,
    55  		metrics:       metrics,
    56  	}, metrics
    57  }
    58  
    59  // InactiveChainRegistry registers chains that are inactive
    60  type InactiveChainRegistry interface {
    61  	// TrackChain tracks a chain with the given name, and calls the given callback
    62  	// when this chain should be created.
    63  	TrackChain(chainName string, genesisBlock *cb.Block, createChain func())
    64  }
    65  
    66  // consenterImpl holds the implementation of type that satisfies the
    67  // consensus.Consenter interface --as the HandleChain contract requires-- and
    68  // the commonConsenter one.
    69  type consenterImpl struct {
    70  	mkChain               func(string)
    71  	brokerConfigVal       *sarama.Config
    72  	tlsConfigVal          localconfig.TLS
    73  	retryOptionsVal       localconfig.Retry
    74  	kafkaVersionVal       sarama.KafkaVersion
    75  	topicDetailVal        *sarama.TopicDetail
    76  	healthChecker         healthChecker
    77  	metrics               *Metrics
    78  	inactiveChainRegistry InactiveChainRegistry
    79  }
    80  
    81  // HandleChain creates/returns a reference to a consensus.Chain object for the
    82  // given set of support resources. Implements the consensus.Consenter
    83  // interface. Called by consensus.newChainSupport(), which is itself called by
    84  // multichannel.NewManagerImpl() when ranging over the ledgerFactory's
    85  // existingChains.
    86  func (consenter *consenterImpl) HandleChain(support consensus.ConsenterSupport, metadata *cb.Metadata) (consensus.Chain, error) {
    87  
    88  	// Check if this node was migrated from Raft
    89  	if consenter.inactiveChainRegistry != nil {
    90  		logger.Infof("This node was migrated from Kafka to Raft, skipping activation of Kafka chain")
    91  		consenter.inactiveChainRegistry.TrackChain(support.ChannelID(), support.Block(0), func() {
    92  			consenter.mkChain(support.ChannelID())
    93  		})
    94  		return &inactive.Chain{Err: errors.Errorf("channel %s is not serviced by me", support.ChannelID())}, nil
    95  	}
    96  
    97  	lastOffsetPersisted, lastOriginalOffsetProcessed, lastResubmittedConfigOffset := getOffsets(metadata.Value, support.ChannelID())
    98  	ch, err := newChain(consenter, support, lastOffsetPersisted, lastOriginalOffsetProcessed, lastResubmittedConfigOffset)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	consenter.healthChecker.RegisterChecker(ch.channel.String(), ch)
   103  	return ch, nil
   104  }
   105  
   106  // commonConsenter allows us to retrieve the configuration options set on the
   107  // consenter object. These will be common across all chain objects derived by
   108  // this consenter. They are set using local configuration settings. This
   109  // interface is satisfied by consenterImpl.
   110  type commonConsenter interface {
   111  	brokerConfig() *sarama.Config
   112  	retryOptions() localconfig.Retry
   113  	topicDetail() *sarama.TopicDetail
   114  	Metrics() *Metrics
   115  }
   116  
   117  func (consenter *consenterImpl) Metrics() *Metrics {
   118  	return consenter.metrics
   119  }
   120  
   121  func (consenter *consenterImpl) brokerConfig() *sarama.Config {
   122  	return consenter.brokerConfigVal
   123  }
   124  
   125  func (consenter *consenterImpl) retryOptions() localconfig.Retry {
   126  	return consenter.retryOptionsVal
   127  }
   128  
   129  func (consenter *consenterImpl) topicDetail() *sarama.TopicDetail {
   130  	return consenter.topicDetailVal
   131  }