rdkafka 0.29.2 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -15
- data/README.md +2 -0
- data/dist/librdkafka-2.15.1.tar.gz +0 -0
- data/docker-compose-ssl.yml +1 -0
- data/docker-compose.yml +1 -0
- data/lib/rdkafka/admin/alter_consumer_group_offsets_handle.rb +31 -0
- data/lib/rdkafka/admin/alter_consumer_group_offsets_report.rb +50 -0
- data/lib/rdkafka/admin/delete_consumer_group_offsets_handle.rb +31 -0
- data/lib/rdkafka/admin/delete_consumer_group_offsets_report.rb +50 -0
- data/lib/rdkafka/admin/describe_cluster_handle.rb +31 -0
- data/lib/rdkafka/admin/describe_cluster_report.rb +48 -0
- data/lib/rdkafka/admin/describe_consumer_groups_handle.rb +31 -0
- data/lib/rdkafka/admin/describe_consumer_groups_report.rb +151 -0
- data/lib/rdkafka/admin/describe_result_parsing.rb +47 -0
- data/lib/rdkafka/admin/describe_topics_handle.rb +31 -0
- data/lib/rdkafka/admin/describe_topics_report.rb +118 -0
- data/lib/rdkafka/admin.rb +365 -0
- data/lib/rdkafka/bindings/admin/acls.rb +85 -0
- data/lib/rdkafka/bindings/admin/configs.rb +37 -0
- data/lib/rdkafka/bindings/admin/list_offsets.rb +26 -0
- data/lib/rdkafka/bindings/admin.rb +197 -0
- data/lib/rdkafka/bindings/callbacks.rb +100 -0
- data/lib/rdkafka/bindings/configuration.rb +50 -0
- data/lib/rdkafka/bindings/consumer.rb +83 -0
- data/lib/rdkafka/bindings/errors.rb +15 -0
- data/lib/rdkafka/bindings/handle.rb +16 -0
- data/lib/rdkafka/bindings/messages.rb +28 -0
- data/lib/rdkafka/bindings/metadata.rb +14 -0
- data/lib/rdkafka/bindings/polling.rb +17 -0
- data/lib/rdkafka/bindings/producer.rb +77 -0
- data/lib/rdkafka/bindings/structs.rb +62 -0
- data/lib/rdkafka/bindings.rb +12 -612
- data/lib/rdkafka/callbacks/alter_consumer_group_offsets_handler.rb +65 -0
- data/lib/rdkafka/callbacks/delete_consumer_group_offsets_handler.rb +65 -0
- data/lib/rdkafka/callbacks/describe_cluster_handler.rb +36 -0
- data/lib/rdkafka/callbacks/describe_consumer_groups_handler.rb +36 -0
- data/lib/rdkafka/callbacks/describe_topics_handler.rb +36 -0
- data/lib/rdkafka/callbacks.rb +24 -17
- data/lib/rdkafka/clients.rb +13 -46
- data/lib/rdkafka/config.rb +34 -0
- data/lib/rdkafka/consumer/message.rb +6 -9
- data/lib/rdkafka/producer/delivery_handle.rb +8 -2
- data/lib/rdkafka/producer/delivery_report.rb +51 -1
- data/lib/rdkafka/version.rb +3 -3
- data/lib/rdkafka.rb +16 -0
- data/package-lock.json +9 -9
- data/rdkafka.gemspec +1 -1
- data/renovate.json +3 -0
- metadata +34 -4
- data/dist/librdkafka-2.14.2.tar.gz +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
class Admin
|
|
5
|
+
# Handle for describe topics operation
|
|
6
|
+
class DescribeTopicsHandle < AbstractHandle
|
|
7
|
+
layout :pending, :bool,
|
|
8
|
+
:response, :int
|
|
9
|
+
|
|
10
|
+
# @return [String] the name of the operation
|
|
11
|
+
def operation_name
|
|
12
|
+
"describe topics"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [DescribeTopicsReport] report prepared by the background event callback, with
|
|
16
|
+
# the described topics.
|
|
17
|
+
def create_result
|
|
18
|
+
prepared_result
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Raises an error if the operation failed
|
|
22
|
+
# @raise [RdkafkaError]
|
|
23
|
+
def raise_error
|
|
24
|
+
raise RdkafkaError.new(
|
|
25
|
+
self[:response],
|
|
26
|
+
broker_message: broker_message
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
class Admin
|
|
5
|
+
# Report for describe topics operation result
|
|
6
|
+
class DescribeTopicsReport
|
|
7
|
+
include DescribeResultParsing
|
|
8
|
+
|
|
9
|
+
# Described topics, one per requested topic name. Each entry is a hash with:
|
|
10
|
+
# - `:name` [String] the topic name
|
|
11
|
+
# - `:topic_id` [String, nil] the topic id (KIP-516), base64 encoded, or `nil` when the
|
|
12
|
+
# topic could not be described
|
|
13
|
+
# - `:is_internal` [Boolean] whether the topic is internal (e.g. `__consumer_offsets`)
|
|
14
|
+
# - `:partitions` [Array<Hash>] each with `:partition` [Integer], `:leader` [Hash, nil] and
|
|
15
|
+
# `:replicas` / `:isr` [Array<Hash>]; nodes have `:id`, `:host`, `:port` and `:rack`
|
|
16
|
+
# - `:authorized_operations` [Array<Integer>, nil] `Bindings::RD_KAFKA_ACL_OPERATION_*`
|
|
17
|
+
# codes, `nil` unless requested with `include_authorized_operations: true`
|
|
18
|
+
# - `:error` [RdkafkaError, nil] per-topic error (e.g. `unknown_topic_or_part`), `nil`
|
|
19
|
+
# on success
|
|
20
|
+
# @return [Array<Hash>]
|
|
21
|
+
attr_reader :topics
|
|
22
|
+
|
|
23
|
+
# @param result_ptr [FFI::Pointer] pointer to the `rd_kafka_DescribeTopics_result_t`
|
|
24
|
+
def initialize(result_ptr)
|
|
25
|
+
@topics = []
|
|
26
|
+
|
|
27
|
+
return if result_ptr.null?
|
|
28
|
+
|
|
29
|
+
count_ptr = FFI::MemoryPointer.new(:size_t)
|
|
30
|
+
array_ptr = Bindings.rd_kafka_DescribeTopics_result_topics(result_ptr, count_ptr)
|
|
31
|
+
|
|
32
|
+
return if array_ptr.null?
|
|
33
|
+
|
|
34
|
+
array_ptr.read_array_of_pointer(count_ptr.read(:size_t)).each do |topic_ptr|
|
|
35
|
+
@topics << extract_topic(topic_ptr)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# @param topic_ptr [FFI::Pointer] pointer to a `rd_kafka_TopicDescription_t`
|
|
42
|
+
# @return [Hash]
|
|
43
|
+
def extract_topic(topic_ptr)
|
|
44
|
+
name_ptr = Bindings.rd_kafka_TopicDescription_name(topic_ptr)
|
|
45
|
+
operations_count_ptr = FFI::MemoryPointer.new(:size_t)
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
name: name_ptr.null? ? nil : name_ptr.read_string,
|
|
49
|
+
topic_id: extract_topic_id(topic_ptr),
|
|
50
|
+
is_internal: Bindings.rd_kafka_TopicDescription_is_internal(topic_ptr) != 0,
|
|
51
|
+
partitions: extract_partitions(topic_ptr),
|
|
52
|
+
authorized_operations: extract_authorized_operations(
|
|
53
|
+
Bindings.rd_kafka_TopicDescription_authorized_operations(topic_ptr, operations_count_ptr),
|
|
54
|
+
operations_count_ptr
|
|
55
|
+
),
|
|
56
|
+
error: extract_error(topic_ptr)
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# librdkafka reports the zero UUID for a topic it could not describe
|
|
61
|
+
# @param topic_ptr [FFI::Pointer] pointer to a `rd_kafka_TopicDescription_t`
|
|
62
|
+
# @return [String, nil]
|
|
63
|
+
def extract_topic_id(topic_ptr)
|
|
64
|
+
uuid_ptr = Bindings.rd_kafka_TopicDescription_topic_id(topic_ptr)
|
|
65
|
+
|
|
66
|
+
return nil if uuid_ptr.null?
|
|
67
|
+
return nil if Bindings.rd_kafka_Uuid_most_significant_bits(uuid_ptr).zero? &&
|
|
68
|
+
Bindings.rd_kafka_Uuid_least_significant_bits(uuid_ptr).zero?
|
|
69
|
+
|
|
70
|
+
string_ptr = Bindings.rd_kafka_Uuid_base64str(uuid_ptr)
|
|
71
|
+
string_ptr.null? ? nil : string_ptr.read_string
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param topic_ptr [FFI::Pointer] pointer to a `rd_kafka_TopicDescription_t`
|
|
75
|
+
# @return [Array<Hash>]
|
|
76
|
+
def extract_partitions(topic_ptr)
|
|
77
|
+
count_ptr = FFI::MemoryPointer.new(:size_t)
|
|
78
|
+
array_ptr = Bindings.rd_kafka_TopicDescription_partitions(topic_ptr, count_ptr)
|
|
79
|
+
|
|
80
|
+
return [] if array_ptr.null?
|
|
81
|
+
|
|
82
|
+
array_ptr.read_array_of_pointer(count_ptr.read(:size_t)).map do |partition_ptr|
|
|
83
|
+
replicas_count_ptr = FFI::MemoryPointer.new(:size_t)
|
|
84
|
+
isr_count_ptr = FFI::MemoryPointer.new(:size_t)
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
partition: Bindings.rd_kafka_TopicPartitionInfo_partition(partition_ptr),
|
|
88
|
+
leader: extract_node(Bindings.rd_kafka_TopicPartitionInfo_leader(partition_ptr)),
|
|
89
|
+
replicas: extract_nodes(
|
|
90
|
+
Bindings.rd_kafka_TopicPartitionInfo_replicas(partition_ptr, replicas_count_ptr),
|
|
91
|
+
replicas_count_ptr
|
|
92
|
+
),
|
|
93
|
+
isr: extract_nodes(
|
|
94
|
+
Bindings.rd_kafka_TopicPartitionInfo_isr(partition_ptr, isr_count_ptr),
|
|
95
|
+
isr_count_ptr
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The error is owned by the result, so it is copied and not destroyed here.
|
|
102
|
+
# @param topic_ptr [FFI::Pointer] pointer to a `rd_kafka_TopicDescription_t`
|
|
103
|
+
# @return [RdkafkaError, nil]
|
|
104
|
+
def extract_error(topic_ptr)
|
|
105
|
+
error_ptr = Bindings.rd_kafka_TopicDescription_error(topic_ptr)
|
|
106
|
+
|
|
107
|
+
return nil if error_ptr.null?
|
|
108
|
+
|
|
109
|
+
code = Bindings.rd_kafka_error_code(error_ptr)
|
|
110
|
+
|
|
111
|
+
return nil if code == Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
|
112
|
+
|
|
113
|
+
string_ptr = Bindings.rd_kafka_error_string(error_ptr)
|
|
114
|
+
RdkafkaError.new(code, broker_message: string_ptr.null? ? nil : string_ptr.read_string)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/rdkafka/admin.rb
CHANGED
|
@@ -224,6 +224,78 @@ module Rdkafka
|
|
|
224
224
|
create_topic_handle
|
|
225
225
|
end
|
|
226
226
|
|
|
227
|
+
# Sets the committed offsets of a consumer group from outside the group.
|
|
228
|
+
#
|
|
229
|
+
# Kafka requires the group to be empty (no active members) for this to be accepted; when it
|
|
230
|
+
# is not, the broker rejects the request and the handle raises with `group_not_empty` rather
|
|
231
|
+
# than reporting success.
|
|
232
|
+
#
|
|
233
|
+
# @param group_id [String] the group whose offsets we want to set
|
|
234
|
+
# @param topic_partition_list [TopicPartitionList] partitions with the offsets to commit
|
|
235
|
+
# @return [AlterConsumerGroupOffsetsHandle] handle that can be used to wait for the result
|
|
236
|
+
# @raise [RdkafkaError] when altering the offsets fails
|
|
237
|
+
def alter_consumer_group_offsets(group_id, topic_partition_list)
|
|
238
|
+
closed_admin_check(__method__)
|
|
239
|
+
|
|
240
|
+
native_tpl = topic_partition_list.to_native_tpl
|
|
241
|
+
|
|
242
|
+
begin
|
|
243
|
+
alter_ptr = Rdkafka::Bindings.rd_kafka_AlterConsumerGroupOffsets_new(
|
|
244
|
+
FFI::MemoryPointer.from_string(group_id),
|
|
245
|
+
native_tpl
|
|
246
|
+
)
|
|
247
|
+
rescue Exception
|
|
248
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
|
|
249
|
+
raise
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# librdkafka copies the list into the request object, so ours is no longer needed
|
|
253
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
|
|
254
|
+
|
|
255
|
+
enqueue_group_offsets_op(
|
|
256
|
+
request_ptr: alter_ptr,
|
|
257
|
+
handle: AlterConsumerGroupOffsetsHandle.new,
|
|
258
|
+
admin_op: Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_ALTERCONSUMERGROUPOFFSETS,
|
|
259
|
+
destroy: Rdkafka::Bindings.method(:rd_kafka_AlterConsumerGroupOffsets_destroy),
|
|
260
|
+
enqueue: Rdkafka::Bindings.method(:rd_kafka_AlterConsumerGroupOffsets)
|
|
261
|
+
)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Deletes the committed offsets of specific partitions of a consumer group, leaving the
|
|
265
|
+
# group and its remaining offsets in place.
|
|
266
|
+
#
|
|
267
|
+
# This is the partition scoped counterpart of {#delete_group}, which removes the whole group.
|
|
268
|
+
#
|
|
269
|
+
# @param group_id [String] the group whose offsets we want to delete
|
|
270
|
+
# @param topic_partition_list [TopicPartitionList] partitions whose offsets to delete
|
|
271
|
+
# @return [DeleteConsumerGroupOffsetsHandle] handle that can be used to wait for the result
|
|
272
|
+
# @raise [RdkafkaError] when deleting the offsets fails
|
|
273
|
+
def delete_consumer_group_offsets(group_id, topic_partition_list)
|
|
274
|
+
closed_admin_check(__method__)
|
|
275
|
+
|
|
276
|
+
native_tpl = topic_partition_list.to_native_tpl
|
|
277
|
+
|
|
278
|
+
begin
|
|
279
|
+
delete_ptr = Rdkafka::Bindings.rd_kafka_DeleteConsumerGroupOffsets_new(
|
|
280
|
+
FFI::MemoryPointer.from_string(group_id),
|
|
281
|
+
native_tpl
|
|
282
|
+
)
|
|
283
|
+
rescue Exception
|
|
284
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
|
|
285
|
+
raise
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
|
|
289
|
+
|
|
290
|
+
enqueue_group_offsets_op(
|
|
291
|
+
request_ptr: delete_ptr,
|
|
292
|
+
handle: DeleteConsumerGroupOffsetsHandle.new,
|
|
293
|
+
admin_op: Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETECONSUMERGROUPOFFSETS,
|
|
294
|
+
destroy: Rdkafka::Bindings.method(:rd_kafka_DeleteConsumerGroupOffsets_destroy),
|
|
295
|
+
enqueue: Rdkafka::Bindings.method(:rd_kafka_DeleteConsumerGroupOffsets)
|
|
296
|
+
)
|
|
297
|
+
end
|
|
298
|
+
|
|
227
299
|
# Deletes a consumer group
|
|
228
300
|
#
|
|
229
301
|
# @param group_id [String] the group id to delete
|
|
@@ -448,6 +520,231 @@ module Rdkafka
|
|
|
448
520
|
handle
|
|
449
521
|
end
|
|
450
522
|
|
|
523
|
+
# Describes the cluster: its id, the current controller and the broker nodes (with racks).
|
|
524
|
+
#
|
|
525
|
+
# Unlike {#metadata}, this does not fetch any topic metadata.
|
|
526
|
+
#
|
|
527
|
+
# @param include_authorized_operations [Boolean] when true, also return the operations this
|
|
528
|
+
# client is authorized to perform on the cluster
|
|
529
|
+
# @return [DescribeClusterHandle] handle that can be used to wait for the result
|
|
530
|
+
# @raise [RdkafkaError] when describing the cluster fails
|
|
531
|
+
#
|
|
532
|
+
# @example Print the cluster id, the controller and every broker
|
|
533
|
+
# report = admin.describe_cluster.wait(max_wait_timeout_ms: 15_000)
|
|
534
|
+
#
|
|
535
|
+
# puts "cluster: #{report.cluster_id}, controller: #{report.controller[:id]}"
|
|
536
|
+
# report.nodes.each do |node|
|
|
537
|
+
# puts "#{node[:id]} #{node[:host]}:#{node[:port]} #{node[:rack]}"
|
|
538
|
+
# end
|
|
539
|
+
def describe_cluster(include_authorized_operations: false)
|
|
540
|
+
closed_admin_check(__method__)
|
|
541
|
+
|
|
542
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
543
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
if queue_ptr.null?
|
|
547
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
handle = DescribeClusterHandle.new
|
|
551
|
+
handle[:pending] = true
|
|
552
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
553
|
+
DescribeClusterHandle.register(handle)
|
|
554
|
+
|
|
555
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
556
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
|
|
557
|
+
inner,
|
|
558
|
+
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DESCRIBECLUSTER
|
|
559
|
+
)
|
|
560
|
+
end
|
|
561
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
562
|
+
|
|
563
|
+
begin
|
|
564
|
+
set_include_authorized_operations(admin_options_ptr) if include_authorized_operations
|
|
565
|
+
|
|
566
|
+
@native_kafka.with_inner do |inner|
|
|
567
|
+
Rdkafka::Bindings.rd_kafka_DescribeCluster(
|
|
568
|
+
inner,
|
|
569
|
+
admin_options_ptr,
|
|
570
|
+
queue_ptr
|
|
571
|
+
)
|
|
572
|
+
end
|
|
573
|
+
rescue Exception
|
|
574
|
+
DescribeClusterHandle.remove(handle.to_ptr.address)
|
|
575
|
+
raise
|
|
576
|
+
ensure
|
|
577
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
578
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
handle
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Describes the given topics: their topic ids, partitions (leader, replicas and in-sync
|
|
585
|
+
# replicas, with racks) and, optionally, the operations this client is authorized to perform.
|
|
586
|
+
#
|
|
587
|
+
# A topic that cannot be described (e.g. it does not exist) does not fail the whole request;
|
|
588
|
+
# its entry in the report carries an `:error` instead.
|
|
589
|
+
#
|
|
590
|
+
# @param topic_names [Array<String>] names of the topics to describe
|
|
591
|
+
# @param include_authorized_operations [Boolean] when true, also return the operations this
|
|
592
|
+
# client is authorized to perform on each topic
|
|
593
|
+
# @return [DescribeTopicsHandle] handle that can be used to wait for the result
|
|
594
|
+
# @raise [ArgumentError] when topic_names is not an Array of Strings
|
|
595
|
+
# @raise [RdkafkaError] when describing the topics fails
|
|
596
|
+
#
|
|
597
|
+
# @example Print the topic id and partition leaders of a topic
|
|
598
|
+
# report = admin.describe_topics(["events"]).wait(max_wait_timeout_ms: 15_000)
|
|
599
|
+
#
|
|
600
|
+
# report.topics.each do |topic|
|
|
601
|
+
# next warn("#{topic[:name]}: #{topic[:error].message}") if topic[:error]
|
|
602
|
+
#
|
|
603
|
+
# puts "#{topic[:name]} (#{topic[:topic_id]})"
|
|
604
|
+
# topic[:partitions].each do |partition|
|
|
605
|
+
# puts " #{partition[:partition]} -> #{partition[:leader]&.fetch(:id)}"
|
|
606
|
+
# end
|
|
607
|
+
# end
|
|
608
|
+
def describe_topics(topic_names, include_authorized_operations: false)
|
|
609
|
+
closed_admin_check(__method__)
|
|
610
|
+
|
|
611
|
+
unless topic_names.is_a?(Array) && topic_names.all?(String)
|
|
612
|
+
raise ArgumentError, "topic_names must be an Array of Strings"
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
616
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
if queue_ptr.null?
|
|
620
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
handle = DescribeTopicsHandle.new
|
|
624
|
+
handle[:pending] = true
|
|
625
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
626
|
+
DescribeTopicsHandle.register(handle)
|
|
627
|
+
|
|
628
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
629
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
|
|
630
|
+
inner,
|
|
631
|
+
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DESCRIBETOPICS
|
|
632
|
+
)
|
|
633
|
+
end
|
|
634
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
635
|
+
|
|
636
|
+
topic_collection_ptr = nil
|
|
637
|
+
|
|
638
|
+
begin
|
|
639
|
+
set_include_authorized_operations(admin_options_ptr) if include_authorized_operations
|
|
640
|
+
|
|
641
|
+
# librdkafka copies the names, so the Ruby-owned strings only need to outlive this call
|
|
642
|
+
name_ptrs = topic_names.map { |name| FFI::MemoryPointer.from_string(name) }
|
|
643
|
+
names_array_ptr = FFI::MemoryPointer.new(:pointer, [name_ptrs.size, 1].max)
|
|
644
|
+
names_array_ptr.write_array_of_pointer(name_ptrs)
|
|
645
|
+
|
|
646
|
+
topic_collection_ptr = Rdkafka::Bindings.rd_kafka_TopicCollection_of_topic_names(
|
|
647
|
+
names_array_ptr,
|
|
648
|
+
name_ptrs.size
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
@native_kafka.with_inner do |inner|
|
|
652
|
+
Rdkafka::Bindings.rd_kafka_DescribeTopics(
|
|
653
|
+
inner,
|
|
654
|
+
topic_collection_ptr,
|
|
655
|
+
admin_options_ptr,
|
|
656
|
+
queue_ptr
|
|
657
|
+
)
|
|
658
|
+
end
|
|
659
|
+
rescue Exception
|
|
660
|
+
DescribeTopicsHandle.remove(handle.to_ptr.address)
|
|
661
|
+
raise
|
|
662
|
+
ensure
|
|
663
|
+
Rdkafka::Bindings.rd_kafka_TopicCollection_destroy(topic_collection_ptr) if topic_collection_ptr
|
|
664
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
665
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
handle
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
# Describes the given consumer groups: their state, partition assignor, coordinator and
|
|
672
|
+
# members with their partition assignments.
|
|
673
|
+
#
|
|
674
|
+
# Each requested group is reported separately, with its own `:error`. A group id the cluster
|
|
675
|
+
# does not know is not an error: it is reported in the `Dead` state with no members.
|
|
676
|
+
#
|
|
677
|
+
# @param group_ids [Array<String>] ids of the consumer groups to describe
|
|
678
|
+
# @param include_authorized_operations [Boolean] whether to also fetch the ACL operations the
|
|
679
|
+
# client is authorized to perform on each group (reported as `:authorized_operations`)
|
|
680
|
+
# @return [DescribeConsumerGroupsHandle] handle that can be used to wait for the result
|
|
681
|
+
# @raise [RdkafkaError] when describing the consumer groups fails as a whole
|
|
682
|
+
#
|
|
683
|
+
# @example Describe a consumer group and print its members and their assignments
|
|
684
|
+
# report = admin.describe_consumer_groups(["example-group"]).wait(max_wait_timeout_ms: 15_000)
|
|
685
|
+
#
|
|
686
|
+
# report.groups.each do |group|
|
|
687
|
+
# next warn "#{group[:group_id]}: #{group[:error].message}" if group[:error]
|
|
688
|
+
#
|
|
689
|
+
# puts "#{group[:group_id]} - #{group[:state_name]} (#{group[:members].size} members)"
|
|
690
|
+
#
|
|
691
|
+
# group[:members].each do |member|
|
|
692
|
+
# puts " #{member[:client_id]}@#{member[:host]}: #{member[:assignment]}"
|
|
693
|
+
# end
|
|
694
|
+
# end
|
|
695
|
+
def describe_consumer_groups(group_ids, include_authorized_operations: false)
|
|
696
|
+
closed_admin_check(__method__)
|
|
697
|
+
|
|
698
|
+
group_id_ptrs = group_ids.map { |group_id| FFI::MemoryPointer.from_string(group_id) }
|
|
699
|
+
group_ids_ptr = FFI::MemoryPointer.new(:pointer, group_id_ptrs.size)
|
|
700
|
+
group_ids_ptr.write_array_of_pointer(group_id_ptrs)
|
|
701
|
+
|
|
702
|
+
# Get a pointer to the queue that our request will be enqueued on
|
|
703
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
704
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
if queue_ptr.null?
|
|
708
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
# Create and register the handle we will return to the caller
|
|
712
|
+
handle = DescribeConsumerGroupsHandle.new
|
|
713
|
+
handle[:pending] = true
|
|
714
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
715
|
+
DescribeConsumerGroupsHandle.register(handle)
|
|
716
|
+
|
|
717
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
718
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
|
|
719
|
+
inner,
|
|
720
|
+
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DESCRIBECONSUMERGROUPS
|
|
721
|
+
)
|
|
722
|
+
end
|
|
723
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
724
|
+
|
|
725
|
+
begin
|
|
726
|
+
set_include_authorized_operations(admin_options_ptr) if include_authorized_operations
|
|
727
|
+
|
|
728
|
+
@native_kafka.with_inner do |inner|
|
|
729
|
+
Rdkafka::Bindings.rd_kafka_DescribeConsumerGroups(
|
|
730
|
+
inner,
|
|
731
|
+
group_ids_ptr,
|
|
732
|
+
group_id_ptrs.size,
|
|
733
|
+
admin_options_ptr,
|
|
734
|
+
queue_ptr
|
|
735
|
+
)
|
|
736
|
+
end
|
|
737
|
+
rescue Exception
|
|
738
|
+
DescribeConsumerGroupsHandle.remove(handle.to_ptr.address)
|
|
739
|
+
raise
|
|
740
|
+
ensure
|
|
741
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
742
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
handle
|
|
746
|
+
end
|
|
747
|
+
|
|
451
748
|
# Deletes the named topic
|
|
452
749
|
#
|
|
453
750
|
# @param topic_name [String] name of the topic to delete
|
|
@@ -1139,6 +1436,74 @@ module Rdkafka
|
|
|
1139
1436
|
|
|
1140
1437
|
private
|
|
1141
1438
|
|
|
1439
|
+
# Shared enqueue path for the two consumer group offset admin operations. They differ only
|
|
1440
|
+
# in their C entry points, so keeping one body avoids two near identical copies of the
|
|
1441
|
+
# queue/handle/options dance and its cleanup.
|
|
1442
|
+
#
|
|
1443
|
+
# @param request_ptr [FFI::Pointer] the op specific request object
|
|
1444
|
+
# @param handle [AbstractHandle] the handle to register and return
|
|
1445
|
+
# @param admin_op [Integer] the RD_KAFKA_ADMIN_OP_* constant for this operation
|
|
1446
|
+
# @param destroy [Method] bound function used to free the request object
|
|
1447
|
+
# @param enqueue [Method] bound function used to enqueue the request
|
|
1448
|
+
# @return [AbstractHandle] the registered handle
|
|
1449
|
+
def enqueue_group_offsets_op(request_ptr:, handle:, admin_op:, destroy:, enqueue:)
|
|
1450
|
+
array_ptr = FFI::MemoryPointer.new(:pointer)
|
|
1451
|
+
array_ptr.write_array_of_pointer([request_ptr])
|
|
1452
|
+
|
|
1453
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
1454
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
if queue_ptr.null?
|
|
1458
|
+
destroy.call(request_ptr)
|
|
1459
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
1460
|
+
end
|
|
1461
|
+
|
|
1462
|
+
handle[:pending] = true
|
|
1463
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
1464
|
+
handle.class.register(handle)
|
|
1465
|
+
|
|
1466
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
1467
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, admin_op)
|
|
1468
|
+
end
|
|
1469
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
1470
|
+
|
|
1471
|
+
begin
|
|
1472
|
+
@native_kafka.with_inner do |inner|
|
|
1473
|
+
enqueue.call(inner, array_ptr, 1, admin_options_ptr, queue_ptr)
|
|
1474
|
+
end
|
|
1475
|
+
rescue Exception
|
|
1476
|
+
handle.class.remove(handle.to_ptr.address)
|
|
1477
|
+
raise
|
|
1478
|
+
ensure
|
|
1479
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
1480
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
1481
|
+
destroy.call(request_ptr)
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
handle
|
|
1485
|
+
end
|
|
1486
|
+
|
|
1487
|
+
# Asks librdkafka to include authorized operations in a describe result
|
|
1488
|
+
# @param admin_options_ptr [FFI::Pointer] the admin options to update
|
|
1489
|
+
# @raise [RdkafkaError] when librdkafka rejects the option
|
|
1490
|
+
def set_include_authorized_operations(admin_options_ptr)
|
|
1491
|
+
error_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_set_include_authorized_operations(admin_options_ptr, 1)
|
|
1492
|
+
|
|
1493
|
+
return if error_ptr.null?
|
|
1494
|
+
|
|
1495
|
+
begin
|
|
1496
|
+
string_ptr = Rdkafka::Bindings.rd_kafka_error_string(error_ptr)
|
|
1497
|
+
|
|
1498
|
+
raise RdkafkaError.new(
|
|
1499
|
+
Rdkafka::Bindings.rd_kafka_error_code(error_ptr),
|
|
1500
|
+
broker_message: string_ptr.null? ? nil : string_ptr.read_string
|
|
1501
|
+
)
|
|
1502
|
+
ensure
|
|
1503
|
+
Rdkafka::Bindings.rd_kafka_error_destroy(error_ptr)
|
|
1504
|
+
end
|
|
1505
|
+
end
|
|
1506
|
+
|
|
1142
1507
|
# Checks if the admin is closed and raises an error if so
|
|
1143
1508
|
# @param method [Symbol] name of the calling method for error context
|
|
1144
1509
|
# @raise [ClosedAdminError] when the admin is closed
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
module Bindings
|
|
5
|
+
# Create Acls
|
|
6
|
+
RD_KAFKA_ADMIN_OP_CREATEACLS = 9
|
|
7
|
+
RD_KAFKA_EVENT_CREATEACLS_RESULT = 1024
|
|
8
|
+
|
|
9
|
+
attach_function :rd_kafka_CreateAcls, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
|
|
10
|
+
attach_function :rd_kafka_event_CreateAcls_result, [:pointer], :pointer
|
|
11
|
+
attach_function :rd_kafka_CreateAcls_result_acls, [:pointer, :pointer], :pointer
|
|
12
|
+
|
|
13
|
+
# Delete Acls
|
|
14
|
+
RD_KAFKA_ADMIN_OP_DELETEACLS = 11
|
|
15
|
+
RD_KAFKA_EVENT_DELETEACLS_RESULT = 4096
|
|
16
|
+
|
|
17
|
+
attach_function :rd_kafka_DeleteAcls, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
|
|
18
|
+
attach_function :rd_kafka_event_DeleteAcls_result, [:pointer], :pointer
|
|
19
|
+
attach_function :rd_kafka_DeleteAcls_result_responses, [:pointer, :pointer], :pointer
|
|
20
|
+
attach_function :rd_kafka_DeleteAcls_result_response_error, [:pointer], :pointer
|
|
21
|
+
attach_function :rd_kafka_DeleteAcls_result_response_matching_acls, [:pointer, :pointer], :pointer
|
|
22
|
+
|
|
23
|
+
# Describe Acls
|
|
24
|
+
RD_KAFKA_ADMIN_OP_DESCRIBEACLS = 10
|
|
25
|
+
RD_KAFKA_EVENT_DESCRIBEACLS_RESULT = 2048
|
|
26
|
+
|
|
27
|
+
attach_function :rd_kafka_DescribeAcls, [:pointer, :pointer, :pointer, :pointer], :void
|
|
28
|
+
attach_function :rd_kafka_event_DescribeAcls_result, [:pointer], :pointer
|
|
29
|
+
attach_function :rd_kafka_DescribeAcls_result_acls, [:pointer, :pointer], :pointer
|
|
30
|
+
|
|
31
|
+
# Acl Bindings
|
|
32
|
+
|
|
33
|
+
attach_function :rd_kafka_AclBinding_restype, [:pointer], :int32
|
|
34
|
+
attach_function :rd_kafka_AclBinding_name, [:pointer], :pointer
|
|
35
|
+
attach_function :rd_kafka_AclBinding_resource_pattern_type, [:pointer], :int32
|
|
36
|
+
attach_function :rd_kafka_AclBinding_principal, [:pointer], :pointer
|
|
37
|
+
attach_function :rd_kafka_AclBinding_host, [:pointer], :pointer
|
|
38
|
+
attach_function :rd_kafka_AclBinding_operation, [:pointer], :int32
|
|
39
|
+
attach_function :rd_kafka_AclBinding_permission_type, [:pointer], :int32
|
|
40
|
+
attach_function :rd_kafka_AclBinding_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t], :pointer
|
|
41
|
+
attach_function :rd_kafka_AclBindingFilter_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t], :pointer
|
|
42
|
+
attach_function :rd_kafka_AclBinding_destroy, [:pointer], :void
|
|
43
|
+
|
|
44
|
+
# rd_kafka_ResourceType_t -
|
|
45
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7307
|
|
46
|
+
RD_KAFKA_RESOURCE_ANY = 1
|
|
47
|
+
RD_KAFKA_RESOURCE_TOPIC = 2
|
|
48
|
+
RD_KAFKA_RESOURCE_GROUP = 3
|
|
49
|
+
RD_KAFKA_RESOURCE_BROKER = 4
|
|
50
|
+
RD_KAFKA_RESOURCE_TRANSACTIONAL_ID = 5
|
|
51
|
+
|
|
52
|
+
# rd_kafka_ResourcePatternType_t -
|
|
53
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7320
|
|
54
|
+
RD_KAFKA_RESOURCE_PATTERN_UNKNOWN = 0
|
|
55
|
+
RD_KAFKA_RESOURCE_PATTERN_ANY = 1
|
|
56
|
+
RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
|
|
57
|
+
RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
|
|
58
|
+
RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
|
|
59
|
+
|
|
60
|
+
# rd_kafka_AclOperation_t -
|
|
61
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8403
|
|
62
|
+
RD_KAFKA_ACL_OPERATION_ANY = 1
|
|
63
|
+
RD_KAFKA_ACL_OPERATION_ALL = 2
|
|
64
|
+
RD_KAFKA_ACL_OPERATION_READ = 3
|
|
65
|
+
RD_KAFKA_ACL_OPERATION_WRITE = 4
|
|
66
|
+
RD_KAFKA_ACL_OPERATION_CREATE = 5
|
|
67
|
+
RD_KAFKA_ACL_OPERATION_DELETE = 6
|
|
68
|
+
RD_KAFKA_ACL_OPERATION_ALTER = 7
|
|
69
|
+
RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
|
|
70
|
+
RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
|
|
71
|
+
RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
|
|
72
|
+
RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
|
|
73
|
+
RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
|
|
74
|
+
|
|
75
|
+
# rd_kafka_AclPermissionType_t -
|
|
76
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8435
|
|
77
|
+
RD_KAFKA_ACL_PERMISSION_TYPE_ANY = 1
|
|
78
|
+
RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
|
|
79
|
+
RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
|
|
80
|
+
|
|
81
|
+
# Extracting error details from Acl results
|
|
82
|
+
attach_function :rd_kafka_acl_result_error, [:pointer], :pointer
|
|
83
|
+
attach_function :rd_kafka_AclBinding_error, [:pointer], :pointer
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
module Bindings
|
|
5
|
+
attach_function :rd_kafka_DescribeConfigs, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
|
|
6
|
+
attach_function :rd_kafka_ConfigResource_new, [:int32, :pointer], :pointer
|
|
7
|
+
attach_function :rd_kafka_ConfigResource_destroy, [:pointer], :void
|
|
8
|
+
attach_function :rd_kafka_ConfigResource_destroy_array, [:pointer, :int32], :void
|
|
9
|
+
attach_function :rd_kafka_event_DescribeConfigs_result, [:pointer], :pointer
|
|
10
|
+
attach_function :rd_kafka_DescribeConfigs_result_resources, [:pointer, :pointer], :pointer
|
|
11
|
+
attach_function :rd_kafka_ConfigResource_configs, [:pointer, :pointer], :pointer
|
|
12
|
+
attach_function :rd_kafka_ConfigEntry_name, [:pointer], :string
|
|
13
|
+
attach_function :rd_kafka_ConfigEntry_value, [:pointer], :string
|
|
14
|
+
attach_function :rd_kafka_ConfigEntry_is_read_only, [:pointer], :int
|
|
15
|
+
attach_function :rd_kafka_ConfigEntry_is_default, [:pointer], :int
|
|
16
|
+
attach_function :rd_kafka_ConfigEntry_is_sensitive, [:pointer], :int
|
|
17
|
+
attach_function :rd_kafka_ConfigEntry_is_synonym, [:pointer], :int
|
|
18
|
+
attach_function :rd_kafka_ConfigEntry_synonyms, [:pointer, :pointer], :pointer
|
|
19
|
+
attach_function :rd_kafka_ConfigResource_error, [:pointer], :int
|
|
20
|
+
attach_function :rd_kafka_ConfigResource_error_string, [:pointer], :string
|
|
21
|
+
attach_function :rd_kafka_IncrementalAlterConfigs, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
|
|
22
|
+
attach_function :rd_kafka_IncrementalAlterConfigs_result_resources, [:pointer, :pointer], :pointer
|
|
23
|
+
attach_function :rd_kafka_ConfigResource_add_incremental_config, [:pointer, :string, :int32, :string], :pointer
|
|
24
|
+
attach_function :rd_kafka_event_IncrementalAlterConfigs_result, [:pointer], :pointer
|
|
25
|
+
|
|
26
|
+
RD_KAFKA_ADMIN_OP_DESCRIBECONFIGS = 5
|
|
27
|
+
RD_KAFKA_EVENT_DESCRIBECONFIGS_RESULT = 104
|
|
28
|
+
|
|
29
|
+
RD_KAFKA_ADMIN_OP_INCREMENTALALTERCONFIGS = 16
|
|
30
|
+
RD_KAFKA_EVENT_INCREMENTALALTERCONFIGS_RESULT = 131072
|
|
31
|
+
|
|
32
|
+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_SET = 0
|
|
33
|
+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_DELETE = 1
|
|
34
|
+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_APPEND = 2
|
|
35
|
+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_SUBTRACT = 3
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
module Bindings
|
|
5
|
+
# List Offsets
|
|
6
|
+
RD_KAFKA_ADMIN_OP_LISTOFFSETS = 21
|
|
7
|
+
RD_KAFKA_EVENT_LISTOFFSETS_RESULT = 0x400000
|
|
8
|
+
|
|
9
|
+
# rd_kafka_IsolationLevel_t
|
|
10
|
+
RD_KAFKA_ISOLATION_LEVEL_READ_UNCOMMITTED = 0
|
|
11
|
+
RD_KAFKA_ISOLATION_LEVEL_READ_COMMITTED = 1
|
|
12
|
+
|
|
13
|
+
# rd_kafka_OffsetSpec_t
|
|
14
|
+
RD_KAFKA_OFFSET_SPEC_MAX_TIMESTAMP = -3
|
|
15
|
+
RD_KAFKA_OFFSET_SPEC_EARLIEST = -2
|
|
16
|
+
RD_KAFKA_OFFSET_SPEC_LATEST = -1
|
|
17
|
+
|
|
18
|
+
attach_function :rd_kafka_ListOffsets, [:pointer, :pointer, :pointer, :pointer], :void, blocking: true
|
|
19
|
+
attach_function :rd_kafka_event_ListOffsets_result, [:pointer], :pointer
|
|
20
|
+
attach_function :rd_kafka_ListOffsets_result_infos, [:pointer, :pointer], :pointer
|
|
21
|
+
attach_function :rd_kafka_ListOffsetsResultInfo_topic_partition, [:pointer], :pointer
|
|
22
|
+
attach_function :rd_kafka_ListOffsetsResultInfo_timestamp, [:pointer], :int64
|
|
23
|
+
attach_function :rd_kafka_AdminOptions_set_isolation_level, [:pointer, :int], :pointer
|
|
24
|
+
attach_function :rd_kafka_topic_partition_get_leader_epoch, [:pointer], :int32
|
|
25
|
+
end
|
|
26
|
+
end
|