github.com/streamdal/segmentio-kafka-go@v0.4.47-streamdal/metadata.go (about) 1 package kafka 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "time" 8 9 metadataAPI "github.com/segmentio/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 }