github.com/hoveychen/kafka-go@v0.4.42/metadata.go (about)

     1  package kafka
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"time"
     8  
     9  	metadataAPI "github.com/hoveychen/kafka-go/protocol/metadata"
    10  )
    11  
    12  // MetadataRequest represents a request sent to a kafka broker to retrieve its
    13  // cluster metadata.
    14  type MetadataRequest struct {
    15  	// Address of the kafka broker to send the request to.
    16  	Addr net.Addr
    17  
    18  	// The list of topics to retrieve metadata for.
    19  	Topics []string
    20  }
    21  
    22  // MetadatResponse represents a response from a kafka broker to a metadata
    23  // request.
    24  type MetadataResponse struct {
    25  	// The amount of time that the broker throttled the request.
    26  	Throttle time.Duration
    27  
    28  	// Name of the kafka cluster that client retrieved metadata from.
    29  	ClusterID string
    30  
    31  	// The broker which is currently the controller for the cluster.
    32  	Controller Broker
    33  
    34  	// The list of brokers registered to the cluster.
    35  	Brokers []Broker
    36  
    37  	// The list of topics available on the cluster.
    38  	Topics []Topic
    39  }
    40  
    41  // Metadata sends a metadata request to a kafka broker and returns the response.
    42  func (c *Client) Metadata(ctx context.Context, req *MetadataRequest) (*MetadataResponse, error) {
    43  	m, err := c.roundTrip(ctx, req.Addr, &metadataAPI.Request{
    44  		TopicNames: req.Topics,
    45  	})
    46  
    47  	if err != nil {
    48  		return nil, fmt.Errorf("kafka.(*Client).Metadata: %w", err)
    49  	}
    50  
    51  	res := m.(*metadataAPI.Response)
    52  	ret := &MetadataResponse{
    53  		Throttle:  makeDuration(res.ThrottleTimeMs),
    54  		Brokers:   make([]Broker, len(res.Brokers)),
    55  		Topics:    make([]Topic, len(res.Topics)),
    56  		ClusterID: res.ClusterID,
    57  	}
    58  
    59  	brokers := make(map[int32]Broker, len(res.Brokers))
    60  
    61  	for i, b := range res.Brokers {
    62  		broker := Broker{
    63  			Host: b.Host,
    64  			Port: int(b.Port),
    65  			ID:   int(b.NodeID),
    66  			Rack: b.Rack,
    67  		}
    68  
    69  		ret.Brokers[i] = broker
    70  		brokers[b.NodeID] = broker
    71  
    72  		if b.NodeID == res.ControllerID {
    73  			ret.Controller = broker
    74  		}
    75  	}
    76  
    77  	for i, t := range res.Topics {
    78  		ret.Topics[i] = Topic{
    79  			Name:       t.Name,
    80  			Internal:   t.IsInternal,
    81  			Partitions: make([]Partition, len(t.Partitions)),
    82  			Error:      makeError(t.ErrorCode, ""),
    83  		}
    84  
    85  		for j, p := range t.Partitions {
    86  			partition := Partition{
    87  				Topic:    t.Name,
    88  				ID:       int(p.PartitionIndex),
    89  				Leader:   brokers[p.LeaderID],
    90  				Replicas: make([]Broker, len(p.ReplicaNodes)),
    91  				Isr:      make([]Broker, len(p.IsrNodes)),
    92  				Error:    makeError(p.ErrorCode, ""),
    93  			}
    94  
    95  			for i, id := range p.ReplicaNodes {
    96  				partition.Replicas[i] = brokers[id]
    97  			}
    98  
    99  			for i, id := range p.IsrNodes {
   100  				partition.Isr[i] = brokers[id]
   101  			}
   102  
   103  			ret.Topics[i].Partitions[j] = partition
   104  		}
   105  	}
   106  
   107  	return ret, nil
   108  }
   109  
   110  type topicMetadataRequestV1 []string
   111  
   112  func (r topicMetadataRequestV1) size() int32 {
   113  	return sizeofStringArray([]string(r))
   114  }
   115  
   116  func (r topicMetadataRequestV1) writeTo(wb *writeBuffer) {
   117  	// communicate nil-ness to the broker by passing -1 as the array length.
   118  	// for this particular request, the broker interpets a zero length array
   119  	// as a request for no topics whereas a nil array is for all topics.
   120  	if r == nil {
   121  		wb.writeArrayLen(-1)
   122  	} else {
   123  		wb.writeStringArray([]string(r))
   124  	}
   125  }
   126  
   127  type metadataResponseV1 struct {
   128  	Brokers      []brokerMetadataV1
   129  	ControllerID int32
   130  	Topics       []topicMetadataV1
   131  }
   132  
   133  func (r metadataResponseV1) size() int32 {
   134  	n1 := sizeofArray(len(r.Brokers), func(i int) int32 { return r.Brokers[i].size() })
   135  	n2 := sizeofArray(len(r.Topics), func(i int) int32 { return r.Topics[i].size() })
   136  	return 4 + n1 + n2
   137  }
   138  
   139  func (r metadataResponseV1) writeTo(wb *writeBuffer) {
   140  	wb.writeArray(len(r.Brokers), func(i int) { r.Brokers[i].writeTo(wb) })
   141  	wb.writeInt32(r.ControllerID)
   142  	wb.writeArray(len(r.Topics), func(i int) { r.Topics[i].writeTo(wb) })
   143  }
   144  
   145  type brokerMetadataV1 struct {
   146  	NodeID int32
   147  	Host   string
   148  	Port   int32
   149  	Rack   string
   150  }
   151  
   152  func (b brokerMetadataV1) size() int32 {
   153  	return 4 + 4 + sizeofString(b.Host) + sizeofString(b.Rack)
   154  }
   155  
   156  func (b brokerMetadataV1) writeTo(wb *writeBuffer) {
   157  	wb.writeInt32(b.NodeID)
   158  	wb.writeString(b.Host)
   159  	wb.writeInt32(b.Port)
   160  	wb.writeString(b.Rack)
   161  }
   162  
   163  type topicMetadataV1 struct {
   164  	TopicErrorCode int16
   165  	TopicName      string
   166  	Internal       bool
   167  	Partitions     []partitionMetadataV1
   168  }
   169  
   170  func (t topicMetadataV1) size() int32 {
   171  	return 2 + 1 +
   172  		sizeofString(t.TopicName) +
   173  		sizeofArray(len(t.Partitions), func(i int) int32 { return t.Partitions[i].size() })
   174  }
   175  
   176  func (t topicMetadataV1) writeTo(wb *writeBuffer) {
   177  	wb.writeInt16(t.TopicErrorCode)
   178  	wb.writeString(t.TopicName)
   179  	wb.writeBool(t.Internal)
   180  	wb.writeArray(len(t.Partitions), func(i int) { t.Partitions[i].writeTo(wb) })
   181  }
   182  
   183  type partitionMetadataV1 struct {
   184  	PartitionErrorCode int16
   185  	PartitionID        int32
   186  	Leader             int32
   187  	Replicas           []int32
   188  	Isr                []int32
   189  }
   190  
   191  func (p partitionMetadataV1) size() int32 {
   192  	return 2 + 4 + 4 + sizeofInt32Array(p.Replicas) + sizeofInt32Array(p.Isr)
   193  }
   194  
   195  func (p partitionMetadataV1) writeTo(wb *writeBuffer) {
   196  	wb.writeInt16(p.PartitionErrorCode)
   197  	wb.writeInt32(p.PartitionID)
   198  	wb.writeInt32(p.Leader)
   199  	wb.writeInt32Array(p.Replicas)
   200  	wb.writeInt32Array(p.Isr)
   201  }
   202  
   203  type topicMetadataRequestV6 struct {
   204  	Topics                 []string
   205  	AllowAutoTopicCreation bool
   206  }
   207  
   208  func (r topicMetadataRequestV6) size() int32 {
   209  	return sizeofStringArray([]string(r.Topics)) + 1
   210  }
   211  
   212  func (r topicMetadataRequestV6) writeTo(wb *writeBuffer) {
   213  	// communicate nil-ness to the broker by passing -1 as the array length.
   214  	// for this particular request, the broker interpets a zero length array
   215  	// as a request for no topics whereas a nil array is for all topics.
   216  	if r.Topics == nil {
   217  		wb.writeArrayLen(-1)
   218  	} else {
   219  		wb.writeStringArray([]string(r.Topics))
   220  	}
   221  	wb.writeBool(r.AllowAutoTopicCreation)
   222  }
   223  
   224  type metadataResponseV6 struct {
   225  	ThrottleTimeMs int32
   226  	Brokers        []brokerMetadataV1
   227  	ClusterId      string
   228  	ControllerID   int32
   229  	Topics         []topicMetadataV6
   230  }
   231  
   232  func (r metadataResponseV6) size() int32 {
   233  	n1 := sizeofArray(len(r.Brokers), func(i int) int32 { return r.Brokers[i].size() })
   234  	n2 := sizeofNullableString(&r.ClusterId)
   235  	n3 := sizeofArray(len(r.Topics), func(i int) int32 { return r.Topics[i].size() })
   236  	return 4 + 4 + n1 + n2 + n3
   237  }
   238  
   239  func (r metadataResponseV6) writeTo(wb *writeBuffer) {
   240  	wb.writeInt32(r.ThrottleTimeMs)
   241  	wb.writeArray(len(r.Brokers), func(i int) { r.Brokers[i].writeTo(wb) })
   242  	wb.writeString(r.ClusterId)
   243  	wb.writeInt32(r.ControllerID)
   244  	wb.writeArray(len(r.Topics), func(i int) { r.Topics[i].writeTo(wb) })
   245  }
   246  
   247  type topicMetadataV6 struct {
   248  	TopicErrorCode int16
   249  	TopicName      string
   250  	Internal       bool
   251  	Partitions     []partitionMetadataV6
   252  }
   253  
   254  func (t topicMetadataV6) size() int32 {
   255  	return 2 + 1 +
   256  		sizeofString(t.TopicName) +
   257  		sizeofArray(len(t.Partitions), func(i int) int32 { return t.Partitions[i].size() })
   258  }
   259  
   260  func (t topicMetadataV6) writeTo(wb *writeBuffer) {
   261  	wb.writeInt16(t.TopicErrorCode)
   262  	wb.writeString(t.TopicName)
   263  	wb.writeBool(t.Internal)
   264  	wb.writeArray(len(t.Partitions), func(i int) { t.Partitions[i].writeTo(wb) })
   265  }
   266  
   267  type partitionMetadataV6 struct {
   268  	PartitionErrorCode int16
   269  	PartitionID        int32
   270  	Leader             int32
   271  	Replicas           []int32
   272  	Isr                []int32
   273  	OfflineReplicas    []int32
   274  }
   275  
   276  func (p partitionMetadataV6) size() int32 {
   277  	return 2 + 4 + 4 + sizeofInt32Array(p.Replicas) + sizeofInt32Array(p.Isr) + sizeofInt32Array(p.OfflineReplicas)
   278  }
   279  
   280  func (p partitionMetadataV6) writeTo(wb *writeBuffer) {
   281  	wb.writeInt16(p.PartitionErrorCode)
   282  	wb.writeInt32(p.PartitionID)
   283  	wb.writeInt32(p.Leader)
   284  	wb.writeInt32Array(p.Replicas)
   285  	wb.writeInt32Array(p.Isr)
   286  	wb.writeInt32Array(p.OfflineReplicas)
   287  }