Skip to content

Commit 4eb360f

Browse files
authored
backport incremental alter configs (#448)
1 parent bfdb0a2 commit 4eb360f

10 files changed

+442
-50
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Rdkafka Changelog
22

33
## 0.16.0 (Unreleased)
4-
- **[Feature]** Introduce ability to discover cluster and topic configuration.
4+
- **[Feature]** Support incremental config describe + alter API.
55
- **[Feature]** Oauthbearer token refresh callback (bruce-szalwinski-he)
66
- [Enhancement] Provide `Rrdkafka::Admin#describe_errors` to get errors descriptions (mensfeld)
77
- [Enhancement] Replace time poll based wait engine with an event based to improve response times on blocking operations and wait (nijikon + mensfeld)

lib/rdkafka.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
require "rdkafka/admin/describe_acl_report"
2727
require "rdkafka/admin/describe_configs_handle"
2828
require "rdkafka/admin/describe_configs_report"
29+
require "rdkafka/admin/incremental_alter_configs_handle"
30+
require "rdkafka/admin/incremental_alter_configs_report"
2931
require "rdkafka/admin/acl_binding_result"
3032
require "rdkafka/admin/config_binding_result"
3133
require "rdkafka/admin/config_resource_binding_result"

lib/rdkafka/admin.rb

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -667,11 +667,6 @@ def describe_acl(resource_type:, resource_name:, resource_pattern_type:, princip
667667

668668
# Describe configs
669669
#
670-
# @param resource_type - values of type rd_kafka_ResourceType_t that support configs
671-
# https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
672-
# valid values are:
673-
# RD_KAFKA_RESOURCE_TOPIC = 2
674-
# RD_KAFKA_RESOURCE_BROKER = 4
675670
# @param resources [Array<Hash>] Array where elements are hashes with two keys:
676671
# - `:resource_type` - numerical resource type based on Kafka API
677672
# - `:resource_name` - string with resource name
@@ -742,6 +737,93 @@ def describe_configs(resources)
742737
handle
743738
end
744739

740+
# Alters in an incremental way all the configs provided for given resources
741+
#
742+
# @param resources_with_configs [Array<Hash>] resources with the configs key that contains
743+
# name, value and the proper op_type to perform on this value.
744+
#
745+
# @return [IncrementalAlterConfigsHandle] Incremental alter configs handle that can be used to
746+
# wait for the result of altering resources with their appropriate configs
747+
#
748+
# @raise [RdkafkaError]
749+
#
750+
# @note Several resources can be requested at one go, but only one broker at a time
751+
# @note The results won't contain altered values but only the altered resources
752+
def incremental_alter_configs(resources_with_configs)
753+
closed_admin_check(__method__)
754+
755+
handle = IncrementalAlterConfigsHandle.new
756+
handle[:pending] = true
757+
handle[:response] = -1
758+
759+
queue_ptr = @native_kafka.with_inner do |inner|
760+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
761+
end
762+
763+
if queue_ptr.null?
764+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
765+
end
766+
767+
admin_options_ptr = @native_kafka.with_inner do |inner|
768+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
769+
inner,
770+
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_INCREMENTALALTERCONFIGS
771+
)
772+
end
773+
774+
IncrementalAlterConfigsHandle.register(handle)
775+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
776+
777+
# Tu poprawnie tworzyc
778+
pointer_array = resources_with_configs.map do |resource_details|
779+
# First build the appropriate resource representation
780+
resource_ptr = Rdkafka::Bindings.rd_kafka_ConfigResource_new(
781+
resource_details.fetch(:resource_type),
782+
FFI::MemoryPointer.from_string(
783+
resource_details.fetch(:resource_name)
784+
)
785+
)
786+
787+
resource_details.fetch(:configs).each do |config|
788+
Bindings.rd_kafka_ConfigResource_add_incremental_config(
789+
resource_ptr,
790+
config.fetch(:name),
791+
config.fetch(:op_type),
792+
config.fetch(:value)
793+
)
794+
end
795+
796+
resource_ptr
797+
end
798+
799+
configs_array_ptr = FFI::MemoryPointer.new(:pointer, pointer_array.size)
800+
configs_array_ptr.write_array_of_pointer(pointer_array)
801+
802+
803+
begin
804+
@native_kafka.with_inner do |inner|
805+
Rdkafka::Bindings.rd_kafka_IncrementalAlterConfigs(
806+
inner,
807+
configs_array_ptr,
808+
pointer_array.size,
809+
admin_options_ptr,
810+
queue_ptr
811+
)
812+
end
813+
rescue Exception
814+
IncrementalAlterConfigsHandle.remove(handle.to_ptr.address)
815+
816+
raise
817+
ensure
818+
Rdkafka::Bindings.rd_kafka_ConfigResource_destroy_array(
819+
configs_array_ptr,
820+
pointer_array.size
821+
) if configs_array_ptr
822+
end
823+
824+
handle
825+
end
826+
745827
private
746828

747829
def closed_admin_check(method)

lib/rdkafka/admin/describe_configs_handle.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ def create_result
2424

2525
def raise_error
2626
raise RdkafkaError.new(
27-
self[:response],
28-
broker_message: self[:response_string].read_string
27+
self[:response],
28+
broker_message: self[:response_string].read_string
2929
)
3030
end
3131
end

lib/rdkafka/admin/describe_configs_report.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ def validate!(config_resource_result_ptr)
4545
raise(
4646
RdkafkaError.new(
4747
code,
48-
nil,
49-
broker_message: Bindings.rd_kafka_ConfigResource_error_string(config_resource_result_ptr)
48+
Bindings.rd_kafka_ConfigResource_error_string(config_resource_result_ptr)
5049
)
5150
)
5251
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
module Rdkafka
4+
class Admin
5+
class IncrementalAlterConfigsHandle < AbstractHandle
6+
layout :pending, :bool,
7+
:response, :int,
8+
:response_string, :pointer,
9+
:config_entries, :pointer,
10+
:entry_count, :int
11+
12+
# @return [String] the name of the operation.
13+
def operation_name
14+
"incremental alter configs"
15+
end
16+
17+
# @return [DescribeAclReport] instance with an array of acls that matches the request filters.
18+
def create_result
19+
IncrementalAlterConfigsReport.new(
20+
config_entries: self[:config_entries],
21+
entry_count: self[:entry_count]
22+
)
23+
end
24+
25+
def raise_error
26+
raise RdkafkaError.new(
27+
self[:response],
28+
broker_message: self[:response_string].read_string
29+
)
30+
end
31+
end
32+
end
33+
end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# frozen_string_literal: true
2+
3+
module Rdkafka
4+
class Admin
5+
class IncrementalAlterConfigsReport
6+
attr_reader :resources
7+
8+
def initialize(config_entries:, entry_count:)
9+
@resources=[]
10+
11+
return if config_entries == FFI::Pointer::NULL
12+
13+
config_entries
14+
.read_array_of_pointer(entry_count)
15+
.each { |config_resource_result_ptr| validate!(config_resource_result_ptr) }
16+
.each do |config_resource_result_ptr|
17+
config_resource_result = ConfigResourceBindingResult.new(config_resource_result_ptr)
18+
19+
pointer_to_size_t = FFI::MemoryPointer.new(:int32)
20+
configs_ptr = Bindings.rd_kafka_ConfigResource_configs(
21+
config_resource_result_ptr,
22+
pointer_to_size_t
23+
)
24+
25+
configs_ptr
26+
.read_array_of_pointer(pointer_to_size_t.read_int)
27+
.map { |config_ptr| ConfigBindingResult.new(config_ptr) }
28+
.each { |config_binding| config_resource_result.configs << config_binding }
29+
30+
@resources << config_resource_result
31+
end
32+
ensure
33+
return if config_entries == FFI::Pointer::NULL
34+
35+
Bindings.rd_kafka_ConfigResource_destroy_array(config_entries, entry_count)
36+
end
37+
38+
private
39+
40+
def validate!(config_resource_result_ptr)
41+
code = Bindings.rd_kafka_ConfigResource_error(config_resource_result_ptr)
42+
43+
return if code.zero?
44+
45+
raise(
46+
RdkafkaError.new(
47+
code,
48+
Bindings.rd_kafka_ConfigResource_error_string(config_resource_result_ptr)
49+
)
50+
)
51+
end
52+
end
53+
end
54+
end

lib/rdkafka/bindings.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,22 @@ class ConfigResource < FFI::Struct
115115
attach_function :rd_kafka_ConfigEntry_synonyms, [:pointer, :pointer], :pointer
116116
attach_function :rd_kafka_ConfigResource_error, [:pointer], :int
117117
attach_function :rd_kafka_ConfigResource_error_string, [:pointer], :string
118+
attach_function :rd_kafka_IncrementalAlterConfigs, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
119+
attach_function :rd_kafka_IncrementalAlterConfigs_result_resources, [:pointer, :pointer], :pointer
120+
attach_function :rd_kafka_ConfigResource_add_incremental_config, [:pointer, :string, :int32, :string], :pointer
121+
attach_function :rd_kafka_event_IncrementalAlterConfigs_result, [:pointer], :pointer
118122

119123
RD_KAFKA_ADMIN_OP_DESCRIBECONFIGS = 5
120124
RD_KAFKA_EVENT_DESCRIBECONFIGS_RESULT = 104
121125

126+
RD_KAFKA_ADMIN_OP_INCREMENTALALTERCONFIGS = 16
127+
RD_KAFKA_EVENT_INCREMENTALALTERCONFIGS_RESULT = 131072
128+
129+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_SET = 0
130+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_DELETE = 1
131+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_APPEND = 2
132+
RD_KAFKA_ALTER_CONFIG_OP_TYPE_SUBTRACT = 3
133+
122134
# Errors
123135
class NativeErrorDesc < FFI::Struct
124136
layout :code, :int,

lib/rdkafka/callbacks.rb

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def initialize(event_ptr)
113113
end
114114
end
115115

116-
class DescribeConfigResult
116+
class DescribeConfigsResult
117117
attr_reader :result_error, :error_string, :results, :results_count
118118

119119
def initialize(event_ptr)
@@ -122,10 +122,28 @@ def initialize(event_ptr)
122122
@error_string = Rdkafka::Bindings.rd_kafka_event_error_string(event_ptr)
123123

124124
if @result_error == 0
125-
acl_describe_result = Rdkafka::Bindings.rd_kafka_event_DescribeConfigs_result(event_ptr)
125+
configs_describe_result = Rdkafka::Bindings.rd_kafka_event_DescribeConfigs_result(event_ptr)
126126
# Get the number of matching acls
127127
pointer_to_size_t = FFI::MemoryPointer.new(:int32)
128-
@results = Rdkafka::Bindings.rd_kafka_DescribeConfigs_result_resources(acl_describe_result, pointer_to_size_t)
128+
@results = Rdkafka::Bindings.rd_kafka_DescribeConfigs_result_resources(configs_describe_result, pointer_to_size_t)
129+
@results_count = pointer_to_size_t.read_int
130+
end
131+
end
132+
end
133+
134+
class IncrementalAlterConfigsResult
135+
attr_reader :result_error, :error_string, :results, :results_count
136+
137+
def initialize(event_ptr)
138+
@results=[]
139+
@result_error = Rdkafka::Bindings.rd_kafka_event_error(event_ptr)
140+
@error_string = Rdkafka::Bindings.rd_kafka_event_error_string(event_ptr)
141+
142+
if @result_error == 0
143+
incremental_alter_result = Rdkafka::Bindings.rd_kafka_event_IncrementalAlterConfigs_result(event_ptr)
144+
# Get the number of matching acls
145+
pointer_to_size_t = FFI::MemoryPointer.new(:int32)
146+
@results = Rdkafka::Bindings.rd_kafka_IncrementalAlterConfigs_result_resources(incremental_alter_result, pointer_to_size_t)
129147
@results_count = pointer_to_size_t.read_int
130148
end
131149
end
@@ -146,6 +164,8 @@ def self.call(_, event_ptr, _)
146164
process_create_topic(event_ptr)
147165
when Rdkafka::Bindings::RD_KAFKA_EVENT_DESCRIBECONFIGS_RESULT
148166
process_describe_configs(event_ptr)
167+
when Rdkafka::Bindings::RD_KAFKA_EVENT_INCREMENTALALTERCONFIGS_RESULT
168+
process_incremental_alter_configs(event_ptr)
149169
when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETETOPICS_RESULT
150170
process_delete_topic(event_ptr)
151171
when Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS_RESULT
@@ -182,7 +202,7 @@ def self.process_create_topic(event_ptr)
182202
end
183203

184204
def self.process_describe_configs(event_ptr)
185-
describe_configs = DescribeConfigResult.new(event_ptr)
205+
describe_configs = DescribeConfigsResult.new(event_ptr)
186206
describe_configs_handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
187207

188208
if describe_configs_handle = Rdkafka::Admin::DescribeConfigsHandle.remove(describe_configs_handle_ptr.address)
@@ -199,6 +219,24 @@ def self.process_describe_configs(event_ptr)
199219
end
200220
end
201221

222+
def self.process_incremental_alter_configs(event_ptr)
223+
incremental_alter = IncrementalAlterConfigsResult.new(event_ptr)
224+
incremental_alter_handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
225+
226+
if incremental_alter_handle = Rdkafka::Admin::IncrementalAlterConfigsHandle.remove(incremental_alter_handle_ptr.address)
227+
incremental_alter_handle[:response] = incremental_alter.result_error
228+
incremental_alter_handle[:response_string] = incremental_alter.error_string
229+
incremental_alter_handle[:pending] = false
230+
231+
if incremental_alter.result_error == 0
232+
incremental_alter_handle[:config_entries] = incremental_alter.results
233+
incremental_alter_handle[:entry_count] = incremental_alter.results_count
234+
end
235+
236+
incremental_alter_handle.unlock
237+
end
238+
end
239+
202240
def self.process_delete_groups(event_ptr)
203241
delete_groups_result = Rdkafka::Bindings.rd_kafka_event_DeleteGroups_result(event_ptr)
204242

0 commit comments

Comments
 (0)