rdkafka 0.29.0-aarch64-linux-gnu → 0.29.1-aarch64-linux-gnu

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.
data/lib/rdkafka/admin.rb CHANGED
@@ -5,6 +5,7 @@ module Rdkafka
5
5
  class Admin
6
6
  include Helpers::OAuth
7
7
  include Helpers::Metadata
8
+ include Helpers::ListOffsets
8
9
 
9
10
  class << self
10
11
  # Allows us to retrieve librdkafka errors with descriptions
@@ -107,10 +108,6 @@ module Rdkafka
107
108
  # @return [nil]
108
109
  # @raise [Rdkafka::ClosedAdminError] if called on a closed admin client
109
110
  #
110
- # @note This method holds the inner lock until the queue is empty or `:stop` is returned.
111
- # Other admin operations will wait until this method returns.
112
- # @note This method is thread-safe as it uses @native_kafka.with_inner synchronization
113
- #
114
111
  # @example Drain all pending events
115
112
  # admin.events_poll_nb_each { |_count| }
116
113
  #
@@ -119,6 +116,9 @@ module Rdkafka
119
116
  # admin.events_poll_nb_each do |_count|
120
117
  # :stop if monotonic_now >= deadline
121
118
  # end
119
+ # @note This method holds the inner lock until the queue is empty or `:stop` is returned.
120
+ # Other admin operations will wait until this method returns.
121
+ # @note This method is thread-safe as it uses @native_kafka.with_inner synchronization
122
122
  def events_poll_nb_each
123
123
  closed_admin_check(__method__)
124
124
 
@@ -282,6 +282,172 @@ module Rdkafka
282
282
  delete_groups_handle
283
283
  end
284
284
 
285
+ # Deletes all messages in the given partitions up to (but not including) the given offset.
286
+ #
287
+ # The programmatic equivalent of `kafka-delete-records.sh`. Useful for GDPR/right-to-erasure
288
+ # compliance, clearing out poison messages, or retention cleanup outside of the configured
289
+ # time/size-based retention policy.
290
+ #
291
+ # @param topic_partition_offsets [Hash{String => Array<Hash>}] hash mapping topic names to
292
+ # arrays of partition delete specifications. Each specification is a hash with:
293
+ # - `:partition` [Integer] partition number
294
+ # - `:offset` [Symbol, Integer] delete all messages before this offset (exclusive) - an
295
+ # integer offset, or `:end` to delete all data currently in the partition
296
+ #
297
+ # @return [DeleteRecordsHandle] handle that can be used to wait for the result
298
+ # @raise [RdkafkaError] when deleting records fails
299
+ #
300
+ # @example Delete all messages before offset 100 in one partition, and all data in another
301
+ # report = admin.delete_records(
302
+ # "my_topic" => [
303
+ # { partition: 0, offset: 100 },
304
+ # { partition: 1, offset: :end }
305
+ # ]
306
+ # ).wait(max_wait_timeout_ms: 15_000)
307
+ #
308
+ # report.offsets.to_h
309
+ # # => { "my_topic" => [#<Partition @partition=0, @offset=100, @err=0>, ...] }
310
+ def delete_records(topic_partition_offsets)
311
+ closed_admin_check(__method__)
312
+
313
+ parsed = topic_partition_offsets.flat_map do |topic, partitions|
314
+ partitions.map do |spec|
315
+ offset = spec.fetch(:offset)
316
+
317
+ native_offset = case offset
318
+ when :end then Rdkafka::Bindings::RD_KAFKA_OFFSET_END
319
+ when Integer then offset
320
+ else
321
+ raise ArgumentError, "Unknown offset specification: #{offset.inspect}"
322
+ end
323
+
324
+ [topic, spec.fetch(:partition), native_offset]
325
+ end
326
+ end
327
+
328
+ tpl = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(parsed.size)
329
+
330
+ parsed.each do |topic, partition, native_offset|
331
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_add(tpl, topic, partition)
332
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(tpl, topic, partition, native_offset)
333
+ end
334
+
335
+ # rd_kafka_DeleteRecords_new copies the tpl it is given, so it does not need to (and must
336
+ # not) outlive this call - it is destroyed below, independently of the wrapping
337
+ # DeleteRecords_t object.
338
+ delete_records_ptr = Rdkafka::Bindings.rd_kafka_DeleteRecords_new(tpl)
339
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
340
+
341
+ pointer_array = [delete_records_ptr]
342
+ records_array_ptr = FFI::MemoryPointer.new(:pointer)
343
+ records_array_ptr.write_array_of_pointer(pointer_array)
344
+
345
+ # Get a pointer to the queue that our request will be enqueued on
346
+ queue_ptr = @native_kafka.with_inner do |inner|
347
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
348
+ end
349
+ if queue_ptr.null?
350
+ Rdkafka::Bindings.rd_kafka_DeleteRecords_destroy(delete_records_ptr)
351
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
352
+ end
353
+
354
+ # Create and register the handle we will return to the caller
355
+ handle = DeleteRecordsHandle.new
356
+ handle[:pending] = true
357
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
358
+ DeleteRecordsHandle.register(handle)
359
+
360
+ admin_options_ptr = @native_kafka.with_inner do |inner|
361
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETERECORDS)
362
+ end
363
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
364
+
365
+ begin
366
+ @native_kafka.with_inner do |inner|
367
+ Rdkafka::Bindings.rd_kafka_DeleteRecords(
368
+ inner,
369
+ records_array_ptr,
370
+ 1,
371
+ admin_options_ptr,
372
+ queue_ptr
373
+ )
374
+ end
375
+ rescue Exception
376
+ DeleteRecordsHandle.remove(handle.to_ptr.address)
377
+ raise
378
+ ensure
379
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
380
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
381
+ Rdkafka::Bindings.rd_kafka_DeleteRecords_destroy(delete_records_ptr)
382
+ end
383
+
384
+ handle
385
+ end
386
+
387
+ # Lists consumer groups cluster-wide.
388
+ #
389
+ # librdkafka issues a single `ListConsumerGroups` request that is fanned out to every broker
390
+ # internally, so the result covers all consumer groups in the cluster, not only those
391
+ # coordinated by the connected broker.
392
+ #
393
+ # @return [ListConsumerGroupsHandle] handle that can be used to wait for the result
394
+ # @raise [RdkafkaError] when listing the consumer groups fails
395
+ #
396
+ # @example List every consumer group in the cluster and print its name and attributes
397
+ # report = admin.list_consumer_groups.wait(max_wait_timeout_ms: 15_000)
398
+ #
399
+ # report.groups.each do |group|
400
+ # puts "#{group[:group_id]} - #{group[:state_name]} " \
401
+ # "(simple: #{group[:is_simple_consumer_group]})"
402
+ # end
403
+ #
404
+ # # Any brokers that could not be reached are reported separately
405
+ # report.errors.each { |error| warn "partial listing error: #{error.message}" }
406
+ def list_consumer_groups
407
+ closed_admin_check(__method__)
408
+
409
+ # Get a pointer to the queue that our request will be enqueued on
410
+ queue_ptr = @native_kafka.with_inner do |inner|
411
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
412
+ end
413
+
414
+ if queue_ptr.null?
415
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
416
+ end
417
+
418
+ # Create and register the handle we will return to the caller
419
+ handle = ListConsumerGroupsHandle.new
420
+ handle[:pending] = true
421
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
422
+ ListConsumerGroupsHandle.register(handle)
423
+
424
+ admin_options_ptr = @native_kafka.with_inner do |inner|
425
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(
426
+ inner,
427
+ Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_LISTCONSUMERGROUPS
428
+ )
429
+ end
430
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
431
+
432
+ begin
433
+ @native_kafka.with_inner do |inner|
434
+ Rdkafka::Bindings.rd_kafka_ListConsumerGroups(
435
+ inner,
436
+ admin_options_ptr,
437
+ queue_ptr
438
+ )
439
+ end
440
+ rescue Exception
441
+ ListConsumerGroupsHandle.remove(handle.to_ptr.address)
442
+ raise
443
+ ensure
444
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
445
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
446
+ end
447
+
448
+ handle
449
+ end
450
+
285
451
  # Deletes the named topic
286
452
  #
287
453
  # @param topic_name [String] name of the topic to delete
@@ -344,7 +510,8 @@ module Rdkafka
344
510
  #
345
511
  # @param topic_name [String] name of the topic
346
512
  # @param partition_count [Integer] how many partitions we want to end up with for given topic
347
- # @return [CreatePartitionsHandle] Create partitions handle that can be used to wait for the result
513
+ # @return [CreatePartitionsHandle] Create partitions handle that can be used to wait for the
514
+ # result
348
515
  # @raise [ConfigError] When the partition count or replication factor are out of valid range
349
516
  # @raise [RdkafkaError] When the topic name is invalid or the topic already exists
350
517
  # @raise [RdkafkaError] When the topic configuration is invalid
@@ -433,7 +600,8 @@ module Rdkafka
433
600
  # @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
434
601
  # - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
435
602
  # - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
436
- # @return [CreateAclHandle] Create acl handle that can be used to wait for the result of creating the acl
603
+ # @return [CreateAclHandle] Create acl handle that can be used to wait for the result of
604
+ # creating the acl
437
605
  # @raise [RdkafkaError]
438
606
  def create_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
439
607
  closed_admin_check(__method__)
@@ -534,7 +702,8 @@ module Rdkafka
534
702
  # @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
535
703
  # - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
536
704
  # - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
537
- # @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of deleting the acl
705
+ # @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of
706
+ # deleting the acl
538
707
  # @raise [RdkafkaError]
539
708
  def delete_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
540
709
  closed_admin_check(__method__)
@@ -637,7 +806,8 @@ module Rdkafka
637
806
  # @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
638
807
  # - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
639
808
  # - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
640
- # @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of fetching acls
809
+ # @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of
810
+ # fetching acls
641
811
  # @raise [RdkafkaError]
642
812
  def describe_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
643
813
  closed_admin_check(__method__)
@@ -909,115 +1079,6 @@ module Rdkafka
909
1079
  handle
910
1080
  end
911
1081
 
912
- # Queries partition offsets by specification (earliest, latest, max_timestamp, or by
913
- # timestamp) without requiring a consumer group.
914
- #
915
- # @param topic_partition_offsets [Hash{String => Array<Hash>}] hash mapping topic names to
916
- # arrays of partition offset specifications. Each specification is a hash with:
917
- # - `:partition` [Integer] partition number
918
- # - `:offset` [Symbol, Integer] offset specification - `:earliest`, `:latest`,
919
- # `:max_timestamp`, or an integer timestamp in milliseconds
920
- # @param isolation_level [Integer, nil] optional isolation level:
921
- # - `RD_KAFKA_ISOLATION_LEVEL_READ_UNCOMMITTED` (0) - default
922
- # - `RD_KAFKA_ISOLATION_LEVEL_READ_COMMITTED` (1)
923
- #
924
- # @return [ListOffsetsHandle] handle that can be used to wait for the result
925
- #
926
- # @raise [ClosedAdminError] when the admin is closed
927
- # @raise [ConfigError] when the background queue is unavailable
928
- #
929
- # @example Query earliest and latest offsets
930
- # handle = admin.list_offsets(
931
- # { "my_topic" => [
932
- # { partition: 0, offset: :earliest },
933
- # { partition: 1, offset: :latest }
934
- # ] }
935
- # )
936
- # report = handle.wait(max_wait_timeout_ms: 15_000)
937
- # report.offsets
938
- # # => [{ topic: "my_topic", partition: 0, offset: 0, ... }, ...]
939
- def list_offsets(topic_partition_offsets, isolation_level: nil)
940
- closed_admin_check(__method__)
941
-
942
- # Parse and validate every offset spec before allocating the native list, so a missing key or
943
- # an unknown offset specification raises with nothing to clean up. Previously the
944
- # ArgumentError (or KeyError) was raised after `rd_kafka_topic_partition_list_new`, leaking
945
- # the native list.
946
- parsed = topic_partition_offsets.flat_map do |topic, partitions|
947
- partitions.map do |spec|
948
- offset = spec.fetch(:offset)
949
-
950
- native_offset = case offset
951
- when :earliest then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_EARLIEST
952
- when :latest then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_LATEST
953
- when :max_timestamp then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_MAX_TIMESTAMP
954
- when Integer then offset
955
- else
956
- raise ArgumentError, "Unknown offset specification: #{offset.inspect}"
957
- end
958
-
959
- [topic, spec.fetch(:partition), native_offset]
960
- end
961
- end
962
-
963
- # Build native topic partition list
964
- tpl = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(parsed.size)
965
-
966
- parsed.each do |topic, partition, native_offset|
967
- Rdkafka::Bindings.rd_kafka_topic_partition_list_add(tpl, topic, partition)
968
- Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(tpl, topic, partition, native_offset)
969
- end
970
-
971
- # Get a pointer to the queue that our request will be enqueued on
972
- queue_ptr = @native_kafka.with_inner do |inner|
973
- Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
974
- end
975
-
976
- if queue_ptr.null?
977
- Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
978
- raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
979
- end
980
-
981
- # Create and register the handle we will return to the caller
982
- handle = ListOffsetsHandle.new
983
- handle[:pending] = true
984
- handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
985
-
986
- admin_options_ptr = @native_kafka.with_inner do |inner|
987
- Rdkafka::Bindings.rd_kafka_AdminOptions_new(
988
- inner,
989
- Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_LISTOFFSETS
990
- )
991
- end
992
-
993
- if isolation_level
994
- Rdkafka::Bindings.rd_kafka_AdminOptions_set_isolation_level(admin_options_ptr, isolation_level)
995
- end
996
-
997
- ListOffsetsHandle.register(handle)
998
- Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
999
-
1000
- begin
1001
- @native_kafka.with_inner do |inner|
1002
- Rdkafka::Bindings.rd_kafka_ListOffsets(
1003
- inner,
1004
- tpl,
1005
- admin_options_ptr,
1006
- queue_ptr
1007
- )
1008
- end
1009
- rescue Exception
1010
- ListOffsetsHandle.remove(handle.to_ptr.address)
1011
- raise
1012
- ensure
1013
- Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
1014
- Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
1015
- Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
1016
- end
1017
-
1018
- handle
1019
- end
1020
-
1021
1082
  private
1022
1083
 
1023
1084
  # Checks if the admin is closed and raises an error if so
@@ -58,6 +58,7 @@ module Rdkafka
58
58
  end
59
59
  end
60
60
 
61
+ RD_KAFKA_RESP_ERR__TIMED_OUT = -185
61
62
  RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS = -175
62
63
  RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS = -174
63
64
  RD_KAFKA_RESP_ERR__STATE = -172
@@ -81,7 +82,7 @@ module Rdkafka
81
82
 
82
83
  # This function comes from our patch on top of librdkafka. It allows os to load all the
83
84
  # librdkafka components without initializing the client
84
- # @see https://github.com/confluentinc/librdkafka/issues/4590
85
+ # See: https://github.com/confluentinc/librdkafka/issues/4590
85
86
  attach_function :rd_kafka_global_init, [], :void
86
87
 
87
88
  # Polling
@@ -235,6 +236,8 @@ module Rdkafka
235
236
 
236
237
  attach_function :rd_kafka_conf_new, [], :pointer
237
238
  attach_function :rd_kafka_conf_set, [:pointer, :string, :string, :pointer, :int], :kafka_config_response
239
+ attach_function :rd_kafka_conf_get, [:pointer, :string, :pointer, :pointer], :kafka_config_response
240
+ attach_function :rd_kafka_conf, [:pointer], :pointer
238
241
  attach_function :rd_kafka_conf_dump, [:pointer, :pointer], :pointer
239
242
  attach_function :rd_kafka_conf_dump_free, [:pointer, :size_t], :void
240
243
  attach_function :rd_kafka_conf_destroy, [:pointer], :void
@@ -257,10 +260,11 @@ module Rdkafka
257
260
 
258
261
  # Queue IO Event Support - for fiber scheduler integration
259
262
  # Enables notifications to a custom FD when queue transitions from empty to non-empty
260
- # @param queue rd_kafka_queue_t* - the queue to monitor
261
- # @param fd int - file descriptor to write to (provide your own pipe/eventfd)
262
- # @param payload const void* - data to write to fd
263
- # @param size size_t - size of payload
263
+ # Arguments:
264
+ # - queue (rd_kafka_queue_t*) - the queue to monitor
265
+ # - fd (int) - file descriptor to write to (provide your own pipe/eventfd)
266
+ # - payload (const void*) - data to write to fd
267
+ # - size (size_t) - size of payload
264
268
  attach_function :rd_kafka_queue_io_event_enable, [:pointer, :int, :pointer, :size_t], :void
265
269
  # Per topic configs
266
270
  attach_function :rd_kafka_topic_conf_new, [], :pointer
@@ -335,9 +339,10 @@ module Rdkafka
335
339
  end
336
340
  end
337
341
 
338
- # The OAuth callback is currently global and contextless.
339
- # This means that the callback will be called for all instances, and the callback must be able to determine to which instance it is associated.
340
- # The instance name will be provided in the callback, allowing the callback to reference the correct instance.
342
+ # The OAuth callback is currently global and contextless. This means that the callback will be
343
+ # called for all instances, and the callback must be able to determine to which instance it is
344
+ # associated. The instance name will be provided in the callback, allowing the callback to
345
+ # reference the correct instance.
341
346
  #
342
347
  # An example of how to use the instance name in the callback is given below.
343
348
  # The `refresh_token` is configured as the `oauthbearer_token_refresh_callback`.
@@ -541,6 +546,37 @@ module Rdkafka
541
546
  attach_function :rd_kafka_event_DeleteGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteGroups_result_t*
542
547
  attach_function :rd_kafka_DeleteGroups_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_DeleteGroups_result_t*, size_t* => rd_kafka_group_result_t**
543
548
 
549
+ # Delete Records
550
+ RD_KAFKA_ADMIN_OP_DELETERECORDS = 6 # rd_kafka_admin_op_t
551
+ RD_KAFKA_EVENT_DELETERECORDS_RESULT = 105 # rd_kafka_event_type_t
552
+
553
+ attach_function :rd_kafka_DeleteRecords, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
554
+ attach_function :rd_kafka_DeleteRecords_new, [:pointer], :pointer, blocking: true
555
+ attach_function :rd_kafka_DeleteRecords_destroy, [:pointer], :void, blocking: true
556
+ attach_function :rd_kafka_event_DeleteRecords_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteRecords_result_t*
557
+ attach_function :rd_kafka_DeleteRecords_result_offsets, [:pointer], :pointer, blocking: true # rd_kafka_DeleteRecords_result_t* => rd_kafka_topic_partition_list_t*
558
+
559
+ # List Consumer Groups
560
+ RD_KAFKA_ADMIN_OP_LISTCONSUMERGROUPS = 12 # rd_kafka_admin_op_t
561
+ RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT = 0x2000 # rd_kafka_event_type_t
562
+
563
+ # Consumer group states (rd_kafka_consumer_group_state_t)
564
+ RD_KAFKA_CONSUMER_GROUP_STATE_UNKNOWN = 0
565
+ RD_KAFKA_CONSUMER_GROUP_STATE_PREPARING_REBALANCE = 1
566
+ RD_KAFKA_CONSUMER_GROUP_STATE_COMPLETING_REBALANCE = 2
567
+ RD_KAFKA_CONSUMER_GROUP_STATE_STABLE = 3
568
+ RD_KAFKA_CONSUMER_GROUP_STATE_DEAD = 4
569
+ RD_KAFKA_CONSUMER_GROUP_STATE_EMPTY = 5
570
+
571
+ attach_function :rd_kafka_ListConsumerGroups, [:pointer, :pointer, :pointer], :void, blocking: true
572
+ attach_function :rd_kafka_event_ListConsumerGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_ListConsumerGroups_result_t*
573
+ attach_function :rd_kafka_ListConsumerGroups_result_valid, [:pointer, :pointer], :pointer, blocking: true # result*, size_t* => rd_kafka_ConsumerGroupListing_t**
574
+ attach_function :rd_kafka_ListConsumerGroups_result_errors, [:pointer, :pointer], :pointer, blocking: true # result*, size_t* => rd_kafka_error_t**
575
+ attach_function :rd_kafka_ConsumerGroupListing_group_id, [:pointer], :pointer, blocking: true # => const char*
576
+ attach_function :rd_kafka_ConsumerGroupListing_is_simple_consumer_group, [:pointer], :int, blocking: true
577
+ attach_function :rd_kafka_ConsumerGroupListing_state, [:pointer], :int, blocking: true
578
+ attach_function :rd_kafka_consumer_group_state_name, [:int], :pointer, blocking: true # => const char*
579
+
544
580
  # Background Queue and Callback
545
581
 
546
582
  attach_function :rd_kafka_conf_set_background_event_cb, [:pointer, :pointer], :void
@@ -603,21 +639,24 @@ module Rdkafka
603
639
  attach_function :rd_kafka_AclBindingFilter_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t], :pointer
604
640
  attach_function :rd_kafka_AclBinding_destroy, [:pointer], :void
605
641
 
606
- # rd_kafka_ResourceType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
642
+ # rd_kafka_ResourceType_t -
643
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7307
607
644
  RD_KAFKA_RESOURCE_ANY = 1
608
645
  RD_KAFKA_RESOURCE_TOPIC = 2
609
646
  RD_KAFKA_RESOURCE_GROUP = 3
610
647
  RD_KAFKA_RESOURCE_BROKER = 4
611
648
  RD_KAFKA_RESOURCE_TRANSACTIONAL_ID = 5
612
649
 
613
- # rd_kafka_ResourcePatternType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
650
+ # rd_kafka_ResourcePatternType_t -
651
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7320
614
652
  RD_KAFKA_RESOURCE_PATTERN_UNKNOWN = 0
615
653
  RD_KAFKA_RESOURCE_PATTERN_ANY = 1
616
654
  RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
617
655
  RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
618
656
  RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
619
657
 
620
- # rd_kafka_AclOperation_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
658
+ # rd_kafka_AclOperation_t -
659
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8403
621
660
  RD_KAFKA_ACL_OPERATION_ANY = 1
622
661
  RD_KAFKA_ACL_OPERATION_ALL = 2
623
662
  RD_KAFKA_ACL_OPERATION_READ = 3
@@ -631,7 +670,8 @@ module Rdkafka
631
670
  RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
632
671
  RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
633
672
 
634
- # rd_kafka_AclPermissionType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
673
+ # rd_kafka_AclPermissionType_t -
674
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8435
635
675
  RD_KAFKA_ACL_PERMISSION_TYPE_ANY = 1
636
676
  RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
637
677
  RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ module Callbacks
5
+ # Handles `RD_KAFKA_EVENT_DELETERECORDS_RESULT` events
6
+ # @private
7
+ class DeleteRecordsHandler < BaseHandler
8
+ class << self
9
+ # Resolves the delete-records handle from its result event
10
+ # @param event_ptr [FFI::Pointer] pointer to the event
11
+ # @return [void]
12
+ def call(event_ptr)
13
+ result_ptr = Rdkafka::Bindings.rd_kafka_event_DeleteRecords_result(event_ptr)
14
+ handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
15
+
16
+ return unless (handle = Rdkafka::Admin::DeleteRecordsHandle.remove(handle_ptr.address))
17
+
18
+ # An operation-level error (e.g. timeout or a closed client) is delivered on the event
19
+ # itself, with no per-partition result to parse.
20
+ return if resolve_operation_error(event_ptr, handle)
21
+
22
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
23
+
24
+ # Parsing must copy everything out of event-owned memory before the event is destroyed.
25
+ # An exception here is captured and re-raised on the waiting thread, since it cannot
26
+ # unwind through librdkafka native frames.
27
+ handle.result = begin
28
+ Rdkafka::Admin::DeleteRecordsReport.new(result_ptr)
29
+ rescue => e
30
+ e
31
+ end
32
+
33
+ handle.unlock
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ module Callbacks
5
+ # Handles `RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT` events
6
+ # @private
7
+ class ListConsumerGroupsHandler < BaseHandler
8
+ class << self
9
+ # Resolves the list-consumer-groups handle from its result event
10
+ # @param event_ptr [FFI::Pointer] pointer to the event
11
+ # @return [void]
12
+ def call(event_ptr)
13
+ result_ptr = Rdkafka::Bindings.rd_kafka_event_ListConsumerGroups_result(event_ptr)
14
+ handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
15
+
16
+ return unless (handle = Rdkafka::Admin::ListConsumerGroupsHandle.remove(handle_ptr.address))
17
+
18
+ # An operation-level error (e.g. timeout or a closed client) is delivered on the event
19
+ # itself; per the source feature's all-or-nothing contract we surface it as the result
20
+ # rather than returning a partial listing.
21
+ return if resolve_operation_error(event_ptr, handle)
22
+
23
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
24
+
25
+ # Parsing must copy everything out of event-owned memory before the event is destroyed.
26
+ # An exception here is captured and re-raised on the waiting thread, since it cannot
27
+ # unwind through librdkafka native frames.
28
+ handle.result = begin
29
+ Rdkafka::Admin::ListConsumerGroupsReport.new(result_ptr)
30
+ rescue => e
31
+ e
32
+ end
33
+
34
+ handle.unlock
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -213,12 +213,14 @@ module Rdkafka
213
213
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETETOPICS_RESULT then DeleteTopicHandler
214
214
  when Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS_RESULT then CreatePartitionsHandler
215
215
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEGROUPS_RESULT then DeleteGroupsHandler
216
+ when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETERECORDS_RESULT then DeleteRecordsHandler
216
217
  when Rdkafka::Bindings::RD_KAFKA_EVENT_CREATEACLS_RESULT then CreateAclHandler
217
218
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEACLS_RESULT then DeleteAclHandler
218
219
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DESCRIBEACLS_RESULT then DescribeAclHandler
219
220
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DESCRIBECONFIGS_RESULT then DescribeConfigsHandler
220
221
  when Rdkafka::Bindings::RD_KAFKA_EVENT_INCREMENTALALTERCONFIGS_RESULT then IncrementalAlterConfigsHandler
221
222
  when Rdkafka::Bindings::RD_KAFKA_EVENT_LISTOFFSETS_RESULT then ListOffsetsHandler
223
+ when Rdkafka::Bindings::RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT then ListConsumerGroupsHandler
222
224
  end
223
225
 
224
226
  handler&.call(event_ptr)
@@ -280,9 +282,9 @@ module Rdkafka
280
282
  end
281
283
  end
282
284
 
283
- # @private
285
+ # @!visibility private
284
286
  @@mutex = Mutex.new
285
- # @private
287
+ # @!visibility private
286
288
  @@current_pid = nil
287
289
 
288
290
  class << self