@platformatic/rdkafka 4.0.1 → 4.1.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.
Files changed (294) hide show
  1. package/README.md +5 -5
  2. package/bench/seed.sh +0 -0
  3. package/binding.gyp +8 -1
  4. package/ci/prepublish.js +0 -1
  5. package/config.d.ts +126 -10
  6. package/configure +0 -0
  7. package/deps/librdkafka/.semaphore/run-all-tests.yml +77 -0
  8. package/deps/librdkafka/.semaphore/semaphore-integration.yml +250 -0
  9. package/deps/librdkafka/.semaphore/semaphore.yml +67 -44
  10. package/deps/librdkafka/.semaphore/verify-linux-packages.yml +41 -0
  11. package/deps/librdkafka/CHANGELOG.md +471 -1
  12. package/deps/librdkafka/CONFIGURATION.md +29 -9
  13. package/deps/librdkafka/INTRODUCTION.md +909 -601
  14. package/deps/librdkafka/LICENSES.txt +592 -1
  15. package/deps/librdkafka/Makefile +2 -1
  16. package/deps/librdkafka/_mkltmpuuWEwa.c +13 -0
  17. package/deps/librdkafka/configure +0 -0
  18. package/deps/librdkafka/debian/rules +0 -0
  19. package/deps/librdkafka/dev-conf.sh +0 -0
  20. package/deps/librdkafka/examples/consumer.c +18 -8
  21. package/deps/librdkafka/examples/describe_consumer_groups.c +25 -6
  22. package/deps/librdkafka/examples/incremental_alter_configs.c +4 -5
  23. package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +26 -42
  24. package/deps/librdkafka/examples/openssl_engine_example.cpp +3 -4
  25. package/deps/librdkafka/examples/producer.cpp +2 -2
  26. package/deps/librdkafka/examples/user_scram.c +4 -5
  27. package/deps/librdkafka/examples/win_ssl_cert_store.cpp +4 -3
  28. package/deps/librdkafka/lds-gen.py +0 -0
  29. package/deps/librdkafka/mklove/Makefile.base +0 -0
  30. package/deps/librdkafka/packaging/RELEASE.md +8 -0
  31. package/deps/librdkafka/packaging/alpine/build-alpine.sh +0 -0
  32. package/deps/librdkafka/packaging/cp/README.md +4 -1
  33. package/deps/librdkafka/packaging/cp/check_features.c +12 -4
  34. package/deps/librdkafka/packaging/cp/verify-deb.sh +6 -6
  35. package/deps/librdkafka/packaging/cp/verify-packages.sh +52 -31
  36. package/deps/librdkafka/packaging/cp/verify-rpm.sh +6 -13
  37. package/deps/librdkafka/packaging/debian/rules +0 -0
  38. package/deps/librdkafka/packaging/get_version.py +0 -0
  39. package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +0 -0
  40. package/deps/librdkafka/packaging/mingw-w64/{travis-before-install.sh → export-variables.sh} +0 -7
  41. package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +1 -1
  42. package/deps/librdkafka/packaging/nuget/artifact.py +0 -0
  43. package/deps/librdkafka/packaging/nuget/cleanup-s3.py +0 -0
  44. package/deps/librdkafka/packaging/nuget/nuget.sh +0 -0
  45. package/deps/librdkafka/packaging/nuget/packaging.py +0 -0
  46. package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +0 -0
  47. package/deps/librdkafka/packaging/nuget/release.py +0 -0
  48. package/deps/librdkafka/packaging/nuget/requirements.txt +3 -3
  49. package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +0 -0
  50. package/deps/librdkafka/packaging/rpm/tests/run-test.sh +0 -0
  51. package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +0 -0
  52. package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +3 -1
  53. package/deps/librdkafka/packaging/tools/build-deb-package.sh +0 -0
  54. package/deps/librdkafka/packaging/tools/build-debian.sh +0 -0
  55. package/deps/librdkafka/packaging/tools/build-manylinux.sh +0 -0
  56. package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +0 -0
  57. package/deps/librdkafka/packaging/tools/distro-build.sh +0 -0
  58. package/deps/librdkafka/packaging/tools/gh-release-checksums.py +0 -0
  59. package/deps/librdkafka/packaging/tools/rdutcoverage.sh +0 -0
  60. package/deps/librdkafka/packaging/tools/run-in-docker.sh +28 -0
  61. package/deps/librdkafka/packaging/tools/run-integration-tests.sh +31 -0
  62. package/deps/librdkafka/packaging/tools/run-style-check.sh +4 -0
  63. package/deps/librdkafka/packaging/tools/style-format.sh +6 -5
  64. package/deps/librdkafka/packaging/tools/update_rpcs_max_versions.py +100 -0
  65. package/deps/librdkafka/service.yml +154 -0
  66. package/deps/librdkafka/src/generate_proto.sh +0 -0
  67. package/deps/librdkafka/src/rd.h +145 -2
  68. package/deps/librdkafka/src/rdaddr.h +6 -7
  69. package/deps/librdkafka/src/rdatomic.h +15 -11
  70. package/deps/librdkafka/src/rdavg.h +3 -2
  71. package/deps/librdkafka/src/rdbase64.c +33 -2
  72. package/deps/librdkafka/src/rdbase64.h +2 -0
  73. package/deps/librdkafka/src/rdendian.h +10 -9
  74. package/deps/librdkafka/src/rdhttp.c +418 -100
  75. package/deps/librdkafka/src/rdhttp.h +23 -5
  76. package/deps/librdkafka/src/rdkafka.c +299 -145
  77. package/deps/librdkafka/src/rdkafka.h +89 -6
  78. package/deps/librdkafka/src/rdkafka_admin.c +482 -105
  79. package/deps/librdkafka/src/rdkafka_admin.h +42 -0
  80. package/deps/librdkafka/src/rdkafka_broker.c +463 -312
  81. package/deps/librdkafka/src/rdkafka_broker.h +68 -10
  82. package/deps/librdkafka/src/rdkafka_buf.c +8 -5
  83. package/deps/librdkafka/src/rdkafka_buf.h +4 -3
  84. package/deps/librdkafka/src/rdkafka_cert.c +25 -1
  85. package/deps/librdkafka/src/rdkafka_cert.h +4 -3
  86. package/deps/librdkafka/src/rdkafka_cgrp.c +468 -143
  87. package/deps/librdkafka/src/rdkafka_cgrp.h +36 -2
  88. package/deps/librdkafka/src/rdkafka_conf.c +526 -102
  89. package/deps/librdkafka/src/rdkafka_conf.h +68 -4
  90. package/deps/librdkafka/src/rdkafka_feature.c +472 -35
  91. package/deps/librdkafka/src/rdkafka_feature.h +2 -0
  92. package/deps/librdkafka/src/rdkafka_fetcher.c +22 -2
  93. package/deps/librdkafka/src/rdkafka_fetcher.h +2 -2
  94. package/deps/librdkafka/src/rdkafka_int.h +84 -46
  95. package/deps/librdkafka/src/rdkafka_metadata.c +221 -136
  96. package/deps/librdkafka/src/rdkafka_metadata.h +15 -11
  97. package/deps/librdkafka/src/rdkafka_metadata_cache.c +279 -73
  98. package/deps/librdkafka/src/rdkafka_mock.c +795 -19
  99. package/deps/librdkafka/src/rdkafka_mock.h +119 -0
  100. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1298 -132
  101. package/deps/librdkafka/src/rdkafka_mock_handlers.c +345 -49
  102. package/deps/librdkafka/src/rdkafka_mock_int.h +180 -61
  103. package/deps/librdkafka/src/rdkafka_msg.c +35 -19
  104. package/deps/librdkafka/src/rdkafka_msg.h +3 -3
  105. package/deps/librdkafka/src/rdkafka_msgset_writer.c +14 -10
  106. package/deps/librdkafka/src/rdkafka_offset.c +33 -5
  107. package/deps/librdkafka/src/rdkafka_op.c +1 -1
  108. package/deps/librdkafka/src/rdkafka_op.h +45 -21
  109. package/deps/librdkafka/src/rdkafka_partition.c +118 -23
  110. package/deps/librdkafka/src/rdkafka_partition.h +16 -7
  111. package/deps/librdkafka/src/rdkafka_proto.h +4 -1
  112. package/deps/librdkafka/src/rdkafka_protocol.h +1 -0
  113. package/deps/librdkafka/src/rdkafka_queue.c +125 -48
  114. package/deps/librdkafka/src/rdkafka_queue.h +19 -0
  115. package/deps/librdkafka/src/rdkafka_range_assignor.c +1 -1
  116. package/deps/librdkafka/src/rdkafka_request.c +336 -64
  117. package/deps/librdkafka/src/rdkafka_request.h +24 -1
  118. package/deps/librdkafka/src/rdkafka_sasl.c +5 -3
  119. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +14 -10
  120. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1166 -89
  121. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +13 -3
  122. package/deps/librdkafka/src/rdkafka_sasl_plain.c +3 -3
  123. package/deps/librdkafka/src/rdkafka_sasl_scram.c +4 -3
  124. package/deps/librdkafka/src/rdkafka_ssl.c +306 -81
  125. package/deps/librdkafka/src/rdkafka_ssl.h +22 -0
  126. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4 -0
  127. package/deps/librdkafka/src/rdkafka_telemetry.c +80 -23
  128. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +5 -1
  129. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +20 -20
  130. package/deps/librdkafka/src/rdkafka_topic.c +220 -137
  131. package/deps/librdkafka/src/rdkafka_topic.h +14 -8
  132. package/deps/librdkafka/src/rdkafka_transport.c +59 -47
  133. package/deps/librdkafka/src/rdkafka_transport.h +5 -0
  134. package/deps/librdkafka/src/rdkafka_txnmgr.c +6 -1
  135. package/deps/librdkafka/src/rdmap.c +6 -1
  136. package/deps/librdkafka/src/rdrand.c +11 -1
  137. package/deps/librdkafka/src/rdtime.h +48 -17
  138. package/deps/librdkafka/src/rdunittest.c +42 -25
  139. package/deps/librdkafka/src/rdunittest.h +2 -0
  140. package/deps/librdkafka/src/rdwin32.h +1 -1
  141. package/deps/librdkafka/src/regexp.c +47 -42
  142. package/deps/librdkafka/src/tinycthread_extra.c +45 -21
  143. package/deps/librdkafka/src/tinycthread_extra.h +7 -3
  144. package/deps/librdkafka/src-cpp/rdkafkacpp.h +28 -2
  145. package/deps/librdkafka/tests/0001-multiobj.c +4 -0
  146. package/deps/librdkafka/tests/0004-conf.c +103 -36
  147. package/deps/librdkafka/tests/0009-mock_cluster.c +1 -0
  148. package/deps/librdkafka/tests/0011-produce_batch.c +2 -1
  149. package/deps/librdkafka/tests/0016-client_swname.c +18 -3
  150. package/deps/librdkafka/tests/0017-compression.c +6 -8
  151. package/deps/librdkafka/tests/0018-cgrp_term.c +8 -3
  152. package/deps/librdkafka/tests/0021-rkt_destroy.c +1 -0
  153. package/deps/librdkafka/tests/0022-consume_batch.c +4 -1
  154. package/deps/librdkafka/tests/0026-consume_pause.c +12 -14
  155. package/deps/librdkafka/tests/0028-long_topicnames.c +1 -1
  156. package/deps/librdkafka/tests/0029-assign_offset.c +6 -8
  157. package/deps/librdkafka/tests/0030-offset_commit.c +2 -2
  158. package/deps/librdkafka/tests/0033-regex_subscribe.c +33 -17
  159. package/deps/librdkafka/tests/0034-offset_reset.c +25 -4
  160. package/deps/librdkafka/tests/0036-partial_fetch.c +1 -0
  161. package/deps/librdkafka/tests/0038-performance.c +1 -0
  162. package/deps/librdkafka/tests/0040-io_event.c +11 -5
  163. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +1 -0
  164. package/deps/librdkafka/tests/0044-partition_cnt.c +3 -2
  165. package/deps/librdkafka/tests/0045-subscribe_update.c +284 -20
  166. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +1 -0
  167. package/deps/librdkafka/tests/0048-partitioner.c +1 -1
  168. package/deps/librdkafka/tests/0050-subscribe_adds.c +1 -0
  169. package/deps/librdkafka/tests/0051-assign_adds.c +1 -0
  170. package/deps/librdkafka/tests/0052-msg_timestamps.c +22 -4
  171. package/deps/librdkafka/tests/0053-stats_cb.cpp +12 -20
  172. package/deps/librdkafka/tests/0055-producer_latency.c +176 -3
  173. package/deps/librdkafka/tests/0056-balanced_group_mt.c +6 -2
  174. package/deps/librdkafka/tests/0058-log.cpp +3 -3
  175. package/deps/librdkafka/tests/0059-bsearch.cpp +8 -4
  176. package/deps/librdkafka/tests/0061-consumer_lag.cpp +25 -5
  177. package/deps/librdkafka/tests/0067-empty_topic.cpp +3 -0
  178. package/deps/librdkafka/tests/0068-produce_timeout.c +21 -23
  179. package/deps/librdkafka/tests/0069-consumer_add_parts.c +3 -7
  180. package/deps/librdkafka/tests/0075-retry.c +38 -1
  181. package/deps/librdkafka/tests/0076-produce_retry.c +2 -0
  182. package/deps/librdkafka/tests/0077-compaction.c +8 -2
  183. package/deps/librdkafka/tests/0080-admin_ut.c +34 -4
  184. package/deps/librdkafka/tests/0081-admin.c +455 -155
  185. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +4 -0
  186. package/deps/librdkafka/tests/0083-cb_event.c +8 -3
  187. package/deps/librdkafka/tests/0084-destroy_flags.c +14 -18
  188. package/deps/librdkafka/tests/0085-headers.cpp +4 -0
  189. package/deps/librdkafka/tests/0086-purge.c +40 -7
  190. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +1 -1
  191. package/deps/librdkafka/tests/0089-max_poll_interval.c +12 -7
  192. package/deps/librdkafka/tests/0090-idempotence.c +1 -2
  193. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +5 -7
  194. package/deps/librdkafka/tests/0092-mixed_msgver.c +6 -0
  195. package/deps/librdkafka/tests/0093-holb.c +8 -5
  196. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +1 -0
  197. package/deps/librdkafka/tests/0097-ssl_verify.cpp +262 -70
  198. package/deps/librdkafka/tests/0098-consumer-txn.cpp +16 -16
  199. package/deps/librdkafka/tests/0099-commit_metadata.c +1 -1
  200. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +1 -1
  201. package/deps/librdkafka/tests/0102-static_group_rebalance.c +317 -16
  202. package/deps/librdkafka/tests/0103-transactions.c +7 -7
  203. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +1 -0
  204. package/deps/librdkafka/tests/0105-transactions_mock.c +18 -11
  205. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +35 -14
  206. package/deps/librdkafka/tests/0107-topic_recreate.c +2 -2
  207. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +86 -26
  208. package/deps/librdkafka/tests/0110-batch_size.cpp +1 -2
  209. package/deps/librdkafka/tests/0112-assign_unknown_part.c +3 -14
  210. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +248 -104
  211. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +3 -3
  212. package/deps/librdkafka/tests/0115-producer_auth.cpp +4 -1
  213. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +7 -5
  214. package/deps/librdkafka/tests/0117-mock_errors.c +15 -5
  215. package/deps/librdkafka/tests/0118-commit_rebalance.c +41 -8
  216. package/deps/librdkafka/tests/0119-consumer_auth.cpp +20 -1
  217. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +8 -3
  218. package/deps/librdkafka/tests/0125-immediate_flush.c +1 -1
  219. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +323 -8
  220. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +1 -0
  221. package/deps/librdkafka/tests/0132-strategy_ordering.c +12 -4
  222. package/deps/librdkafka/tests/0133-ssl_keys.c +28 -6
  223. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +24 -14
  224. package/deps/librdkafka/tests/0139-offset_validation_mock.c +510 -2
  225. package/deps/librdkafka/tests/0140-commit_metadata.cpp +1 -1
  226. package/deps/librdkafka/tests/0142-reauthentication.c +37 -17
  227. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +39 -40
  228. package/deps/librdkafka/tests/0146-metadata_mock.c +76 -15
  229. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +952 -0
  230. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +563 -0
  231. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  232. package/deps/librdkafka/tests/0150-telemetry_mock.c +9 -6
  233. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  234. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  235. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  236. package/deps/librdkafka/tests/CMakeLists.txt +6 -0
  237. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +34 -9
  238. package/deps/librdkafka/tests/autotest.sh +0 -0
  239. package/deps/librdkafka/tests/broker_version_tests.py +0 -0
  240. package/deps/librdkafka/tests/buildbox.sh +0 -0
  241. package/deps/librdkafka/tests/cleanup-checker-tests.sh +0 -0
  242. package/deps/librdkafka/tests/cluster_testing.py +0 -0
  243. package/deps/librdkafka/tests/delete-test-topics.sh +0 -0
  244. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  245. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  246. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  247. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  248. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +42 -101
  249. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  250. package/deps/librdkafka/tests/fixtures/ssl/client2.key +41 -29
  251. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +112 -37
  252. package/deps/librdkafka/tests/gen-ssl-certs.sh +0 -0
  253. package/deps/librdkafka/tests/interactive_broker_version.py +0 -0
  254. package/deps/librdkafka/tests/java/Makefile +2 -1
  255. package/deps/librdkafka/tests/java/run-class.sh +0 -0
  256. package/deps/librdkafka/tests/lz4_manual_test.sh +0 -0
  257. package/deps/librdkafka/tests/multi-broker-version-test.sh +0 -0
  258. package/deps/librdkafka/tests/parse-refcnt.sh +0 -0
  259. package/deps/librdkafka/tests/performance_plot.py +0 -0
  260. package/deps/librdkafka/tests/requirements.txt +1 -1
  261. package/deps/librdkafka/tests/run-all-tests.sh +79 -0
  262. package/deps/librdkafka/tests/run-consumer-tests.sh +0 -0
  263. package/deps/librdkafka/tests/run-producer-tests.sh +0 -0
  264. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  265. package/deps/librdkafka/tests/run-test.sh +0 -0
  266. package/deps/librdkafka/tests/sasl_test.py +0 -0
  267. package/deps/librdkafka/tests/test.c +478 -18
  268. package/deps/librdkafka/tests/test.h +62 -13
  269. package/deps/librdkafka/tests/testcpp.cpp +6 -1
  270. package/deps/librdkafka/tests/testcpp.h +30 -2
  271. package/deps/librdkafka/tests/testshared.h +16 -2
  272. package/deps/librdkafka/tests/tools/stats/graph.py +0 -0
  273. package/deps/librdkafka/tests/tools/stats/to_csv.py +1 -1
  274. package/deps/librdkafka/tests/trivup/trivup-0.14.0.tar.gz +0 -0
  275. package/deps/librdkafka/tests/until-fail.sh +0 -0
  276. package/deps/librdkafka/tests/xxxx-metadata.cpp +1 -1
  277. package/deps/librdkafka/vcpkg.json +1 -1
  278. package/deps/librdkafka/win32/setup-msys2.ps1 +24 -8
  279. package/deps/librdkafka/win32/setup-vcpkg.ps1 +28 -6
  280. package/deps/librdkafka/win32/tests/tests.vcxproj +6 -0
  281. package/deps/librdkafka/win32/wingetopt.h +5 -4
  282. package/errors.d.ts +27 -1
  283. package/lib/error.js +29 -3
  284. package/make_docs.sh +0 -0
  285. package/package.json +11 -11
  286. package/run_docker.sh +0 -0
  287. package/src/callbacks.cc +6 -9
  288. package/src/callbacks.h +1 -5
  289. package/test/kafka-consumer-worker.js +10 -7
  290. package/test/kafka-consumer.spec.js +32 -21
  291. package/ci/update-version.js +0 -123
  292. package/deps/librdkafka/.semaphore/project.yml +0 -43
  293. package/deps/librdkafka/.semaphore/project_public.yml +0 -20
  294. package/deps/librdkafka/win32/install-openssl.ps1 +0 -33
@@ -82,9 +82,9 @@
82
82
  static const int rd_kafka_max_block_ms = 1000;
83
83
 
84
84
  const char *rd_kafka_broker_state_names[] = {
85
- "INIT", "DOWN", "TRY_CONNECT", "CONNECT", "SSL_HANDSHAKE",
86
- "AUTH_LEGACY", "UP", "UPDATE", "APIVERSION_QUERY", "AUTH_HANDSHAKE",
87
- "AUTH_REQ", "REAUTH"};
85
+ "INIT", "DOWN", "TRY_CONNECT", "CONNECT",
86
+ "SSL_HANDSHAKE", "AUTH_LEGACY", "UP", "APIVERSION_QUERY",
87
+ "AUTH_HANDSHAKE", "AUTH_REQ", "REAUTH"};
88
88
 
89
89
  const char *rd_kafka_secproto_names[] = {
90
90
  [RD_KAFKA_PROTO_PLAINTEXT] = "plaintext",
@@ -111,7 +111,6 @@ rd_kafka_broker_needs_persistent_connection(rd_kafka_broker_t *rkb) {
111
111
  rd_atomic32_get(&rkb->rkb_persistconn.coord);
112
112
  }
113
113
 
114
-
115
114
  /**
116
115
  * @returns > 0 if a connection to this broker is needed, else 0.
117
116
  * @locality broker thread
@@ -119,7 +118,7 @@ rd_kafka_broker_needs_persistent_connection(rd_kafka_broker_t *rkb) {
119
118
  */
120
119
  static RD_INLINE int rd_kafka_broker_needs_connection(rd_kafka_broker_t *rkb) {
121
120
  return rkb->rkb_state == RD_KAFKA_BROKER_STATE_INIT &&
122
- !rd_kafka_terminating(rkb->rkb_rk) &&
121
+ !rd_kafka_broker_or_instance_terminating(rkb) &&
123
122
  !rd_kafka_fatal_error_code(rkb->rkb_rk) &&
124
123
  (!rkb->rkb_rk->rk_conf.sparse_connections ||
125
124
  rd_kafka_broker_needs_persistent_connection(rkb));
@@ -311,6 +310,32 @@ int16_t rd_kafka_broker_ApiVersion_supported(rd_kafka_broker_t *rkb,
311
310
  rkb, ApiKey, minver, maxver, featuresp, rd_true /* do_lock */);
312
311
  }
313
312
 
313
+ /**
314
+ * @brief Check that at least a ApiVersion greater or equal to
315
+ * \p minver exists for \p ApiKey.
316
+ *
317
+ * @returns `rd_true` if the broker supports \p ApiKey with
318
+ * a version greater than or equal to \p minver, else `rd_false`.
319
+ * @locks none
320
+ * @locks_acquired rd_kafka_broker_lock()
321
+ * @locality any
322
+ */
323
+ rd_bool_t rd_kafka_broker_ApiVersion_at_least(rd_kafka_broker_t *rkb,
324
+ int16_t ApiKey,
325
+ int16_t minver) {
326
+ return rd_kafka_broker_ApiVersion_supported0(
327
+ rkb, ApiKey, minver, RD_KAFKAP_RPC_VERSION_MAX, NULL,
328
+ rd_true /* do_lock */) != -1;
329
+ }
330
+
331
+ rd_bool_t rd_kafka_broker_ApiVersion_at_least_no_lock(rd_kafka_broker_t *rkb,
332
+ int16_t ApiKey,
333
+ int16_t minver) {
334
+ return rd_kafka_broker_ApiVersion_supported0(
335
+ rkb, ApiKey, minver, RD_KAFKAP_RPC_VERSION_MAX, NULL,
336
+ rd_false /* don't lock rkb */) != -1;
337
+ }
338
+
314
339
  /**
315
340
  * @brief Set broker state.
316
341
  *
@@ -321,7 +346,9 @@ int16_t rd_kafka_broker_ApiVersion_supported(rd_kafka_broker_t *rkb,
321
346
  * @locality broker thread
322
347
  */
323
348
  void rd_kafka_broker_set_state(rd_kafka_broker_t *rkb, int state) {
324
- rd_bool_t trigger_monitors = rd_false;
349
+ rd_bool_t trigger_monitors = rd_false,
350
+ reset_any_broker_down_reported = rd_false,
351
+ skip_broker_down = rkb->rkb_c.skip_broker_down;
325
352
 
326
353
  if ((int)rkb->rkb_state == state)
327
354
  return;
@@ -331,57 +358,70 @@ void rd_kafka_broker_set_state(rd_kafka_broker_t *rkb, int state) {
331
358
  rd_kafka_broker_state_names[rkb->rkb_state],
332
359
  rd_kafka_broker_state_names[state]);
333
360
 
334
- if (rkb->rkb_source == RD_KAFKA_INTERNAL) {
361
+ if (rd_kafka_broker_state_is_down(state) && skip_broker_down)
362
+ /* Reset the flag so if it disconnects again it won't be
363
+ * treated as a planned disconnection. */
364
+ rkb->rkb_c.skip_broker_down = rd_false;
365
+
366
+ if (rkb->rkb_source == RD_KAFKA_INTERNAL ||
367
+ RD_KAFKA_BROKER_IS_LOGICAL(rkb)) {
335
368
  /* no-op */
336
- } else if (state == RD_KAFKA_BROKER_STATE_DOWN &&
337
- !rkb->rkb_down_reported) {
369
+ } else if (rd_kafka_broker_state_is_down(state) && !skip_broker_down &&
370
+ /* Only 0 -> 1 */
371
+ rd_atomic32_set(&rkb->rkb_down_reported, 1) == 0) {
372
+
338
373
  /* Propagate ALL_BROKERS_DOWN event if all brokers are
339
- * now down, unless we're terminating.
340
- * Only trigger for brokers that has an address set,
341
- * e.g., not logical brokers that lost their address. */
374
+ * now down, unless we're terminating. */
342
375
  if (rd_atomic32_add(&rkb->rkb_rk->rk_broker_down_cnt, 1) ==
343
376
  rd_atomic32_get(&rkb->rkb_rk->rk_broker_cnt) -
344
377
  rd_atomic32_get(
345
- &rkb->rkb_rk->rk_broker_addrless_cnt) &&
346
- !rd_kafka_broker_is_addrless(rkb) &&
347
- !rd_kafka_terminating(rkb->rkb_rk))
378
+ &rkb->rkb_rk->rk_logical_broker_cnt) &&
379
+ !rd_kafka_terminating(rkb->rkb_rk)) {
380
+ rd_kafka_rebootstrap(rkb->rkb_rk);
348
381
  rd_kafka_op_err(
349
382
  rkb->rkb_rk, RD_KAFKA_RESP_ERR__ALL_BROKERS_DOWN,
350
383
  "%i/%i brokers are down",
351
384
  rd_atomic32_get(&rkb->rkb_rk->rk_broker_down_cnt),
352
385
  rd_atomic32_get(&rkb->rkb_rk->rk_broker_cnt) -
353
386
  rd_atomic32_get(
354
- &rkb->rkb_rk->rk_broker_addrless_cnt));
355
- rkb->rkb_down_reported = 1;
387
+ &rkb->rkb_rk->rk_logical_broker_cnt));
388
+ }
356
389
 
357
390
  } else if (rd_kafka_broker_state_is_up(state) &&
358
- rkb->rkb_down_reported) {
391
+ /* Only 1 -> 0 */
392
+ rd_atomic32_set(&rkb->rkb_down_reported, 0) == 1) {
359
393
  rd_atomic32_sub(&rkb->rkb_rk->rk_broker_down_cnt, 1);
360
- rkb->rkb_down_reported = 0;
361
394
  }
362
395
 
363
396
  if (rkb->rkb_source != RD_KAFKA_INTERNAL) {
364
397
  if (rd_kafka_broker_state_is_up(state) &&
365
398
  !rd_kafka_broker_state_is_up(rkb->rkb_state)) {
366
- /* Up -> Down */
367
- rd_atomic32_add(&rkb->rkb_rk->rk_broker_up_cnt, 1);
399
+ /* ~Up -> Up */
400
+ if (!RD_KAFKA_BROKER_IS_LOGICAL(rkb)) {
401
+ rd_atomic32_add(&rkb->rkb_rk->rk_broker_up_cnt,
402
+ 1);
403
+
404
+ /* If at least one broker connects we reset
405
+ * the down counter to try again with rest of
406
+ * brokers. Otherwise, a single broker
407
+ * connection can cause `ALL_BROKERS_DOWN` to
408
+ * get triggered even if the connection to rest
409
+ * of brokers was restored but they didn't
410
+ * attempt a re-connection because of sparse
411
+ * broker connections. */
412
+ reset_any_broker_down_reported = rd_true;
413
+ }
368
414
 
369
415
  trigger_monitors = rd_true;
370
416
 
371
- if (RD_KAFKA_BROKER_IS_LOGICAL(rkb))
372
- rd_atomic32_add(
373
- &rkb->rkb_rk->rk_logical_broker_up_cnt, 1);
374
-
375
417
  } else if (rd_kafka_broker_state_is_up(rkb->rkb_state) &&
376
418
  !rd_kafka_broker_state_is_up(state)) {
377
- /* ~Down(!Up) -> Up */
378
- rd_atomic32_sub(&rkb->rkb_rk->rk_broker_up_cnt, 1);
419
+ /* Up -> Down */
420
+ if (!RD_KAFKA_BROKER_IS_LOGICAL(rkb))
421
+ rd_atomic32_sub(&rkb->rkb_rk->rk_broker_up_cnt,
422
+ 1);
379
423
 
380
424
  trigger_monitors = rd_true;
381
-
382
- if (RD_KAFKA_BROKER_IS_LOGICAL(rkb))
383
- rd_atomic32_sub(
384
- &rkb->rkb_rk->rk_logical_broker_up_cnt, 1);
385
425
  }
386
426
 
387
427
  /* If the connection or connection attempt failed and there
@@ -397,6 +437,14 @@ void rd_kafka_broker_set_state(rd_kafka_broker_t *rkb, int state) {
397
437
  rkb->rkb_state = state;
398
438
  rkb->rkb_ts_state = rd_clock();
399
439
 
440
+ if (reset_any_broker_down_reported) {
441
+ rd_kafka_broker_unlock(rkb);
442
+ /* Releases rkb->rkb_lock to respect
443
+ * lock ordering and avoid deadlocks */
444
+ rd_kafka_reset_any_broker_down_reported(rkb->rkb_rk);
445
+ rd_kafka_broker_lock(rkb);
446
+ }
447
+
400
448
  if (trigger_monitors)
401
449
  rd_kafka_broker_trigger_monitors(rkb);
402
450
 
@@ -456,34 +504,31 @@ static void rd_kafka_broker_set_error(rd_kafka_broker_t *rkb,
456
504
 
457
505
  /* Provide more meaningful error messages in certain cases */
458
506
  if (err == RD_KAFKA_RESP_ERR__TRANSPORT &&
459
- !strcmp(errstr, "Disconnected")) {
507
+ rd_kafka_transport_error_disconnected(fmt)) {
460
508
  if (rkb->rkb_state == RD_KAFKA_BROKER_STATE_APIVERSION_QUERY) {
461
509
  /* A disconnect while requesting ApiVersion typically
462
510
  * means we're connecting to a SSL-listener as
463
511
  * PLAINTEXT, but may also be caused by connecting to
464
512
  * a broker that does not support ApiVersion (<0.10). */
465
-
466
513
  if (rkb->rkb_proto != RD_KAFKA_PROTO_SSL &&
467
- rkb->rkb_proto != RD_KAFKA_PROTO_SASL_SSL)
468
- rd_kafka_broker_set_error(
469
- rkb, level, err,
470
- "Disconnected while requesting "
514
+ rkb->rkb_proto != RD_KAFKA_PROTO_SASL_SSL) {
515
+ ofe = rd_snprintf(
516
+ errstr + of, sizeof(errstr) - of, "%s",
517
+ ": requesting "
471
518
  "ApiVersion: "
472
519
  "might be caused by incorrect "
473
520
  "security.protocol configuration "
474
521
  "(connecting to a SSL listener?) or "
475
522
  "broker version is < 0.10 "
476
- "(see api.version.request)",
477
- ap /*ignored*/);
478
- else
479
- rd_kafka_broker_set_error(
480
- rkb, level, err,
481
- "Disconnected while requesting "
523
+ "(see api.version.request)");
524
+ } else {
525
+ ofe = rd_snprintf(
526
+ errstr + of, sizeof(errstr) - of, "%s",
527
+ ": requesting "
482
528
  "ApiVersion: "
483
529
  "might be caused by broker version "
484
- "< 0.10 (see api.version.request)",
485
- ap /*ignored*/);
486
- return;
530
+ "< 0.10 (see api.version.request)");
531
+ }
487
532
 
488
533
  } else if (rkb->rkb_state == RD_KAFKA_BROKER_STATE_UP &&
489
534
  state_duration_ms < 2000 /*2s*/ &&
@@ -491,18 +536,20 @@ static void rd_kafka_broker_set_error(rd_kafka_broker_t *rkb,
491
536
  RD_KAFKA_PROTO_SASL_SSL &&
492
537
  rkb->rkb_rk->rk_conf.security_protocol !=
493
538
  RD_KAFKA_PROTO_SASL_PLAINTEXT) {
539
+
494
540
  /* If disconnected shortly after transitioning to UP
495
541
  * state it typically means the broker listener is
496
542
  * configured for SASL authentication but the client
497
543
  * is not. */
498
- rd_kafka_broker_set_error(
499
- rkb, level, err,
500
- "Disconnected: verify that security.protocol "
501
- "is correctly configured, broker might "
502
- "require SASL authentication",
503
- ap /*ignored*/);
504
- return;
544
+ ofe =
545
+ rd_snprintf(errstr + of, sizeof(errstr) - of, "%s",
546
+ ": verify that security.protocol "
547
+ "is correctly configured, broker might "
548
+ "require SASL authentication");
505
549
  }
550
+ if (ofe > sizeof(errstr) - of)
551
+ ofe = sizeof(errstr) - of;
552
+ of += ofe;
506
553
  }
507
554
 
508
555
  /* Check if error is identical to last error (prior to appending
@@ -554,13 +601,14 @@ static void rd_kafka_broker_set_error(rd_kafka_broker_t *rkb,
554
601
  identical ? ": identical to last error" : "",
555
602
  suppress ? ": error log suppressed" : "");
556
603
 
557
- if (level != LOG_DEBUG && (level <= LOG_CRIT || !suppress)) {
604
+ if (level <= LOG_CRIT || (level <= LOG_INFO && !suppress)) {
558
605
  rd_kafka_log(rkb->rkb_rk, level, "FAIL", "%s: %s",
559
606
  rkb->rkb_name, errstr);
560
607
 
561
- /* Send ERR op to application for processing. */
562
- rd_kafka_q_op_err(rkb->rkb_rk->rk_rep, err, "%s: %s",
563
- rkb->rkb_name, errstr);
608
+ if (level <= LOG_ERR)
609
+ /* Send ERR op to application for processing. */
610
+ rd_kafka_q_op_err(rkb->rkb_rk->rk_rep, err, "%s: %s",
611
+ rkb->rkb_name, errstr);
564
612
  }
565
613
  }
566
614
 
@@ -692,6 +740,13 @@ void rd_kafka_broker_fail(rd_kafka_broker_t *rkb,
692
740
 
693
741
  if (rktp->rktp_leader_id != rktp->rktp_broker_id) {
694
742
  rd_kafka_toppar_delegate_to_leader(rktp);
743
+ } else if (rd_kafka_broker_termination_in_progress(rkb)) {
744
+ /* Remove `rktp_broker` and `rktp_leader`
745
+ * references in `rktp`, even if this broker
746
+ * is still the leader, to allow to
747
+ * decommission it. */
748
+ rd_kafka_toppar_undelegate(rktp);
749
+ rd_kafka_toppar_forget_leader(rktp);
695
750
  }
696
751
  }
697
752
 
@@ -710,12 +765,18 @@ void rd_kafka_broker_fail(rd_kafka_broker_t *rkb,
710
765
 
711
766
  /* Query for topic leaders to quickly pick up on failover. */
712
767
  if (err != RD_KAFKA_RESP_ERR__DESTROY &&
768
+ err != RD_KAFKA_RESP_ERR__DESTROY_BROKER &&
713
769
  old_state >= RD_KAFKA_BROKER_STATE_UP)
714
770
  rd_kafka_metadata_refresh_known_topics(
715
771
  rkb->rkb_rk, NULL, rd_true /*force*/, "broker down");
716
772
  }
717
773
 
718
774
 
775
+ #define rd_kafka_broker_planned_fail(RKB, ERR, FMT, ...) \
776
+ do { \
777
+ (RKB)->rkb_c.skip_broker_down = rd_true; \
778
+ rd_kafka_broker_fail(RKB, LOG_DEBUG, ERR, FMT, __VA_ARGS__); \
779
+ } while (0)
719
780
 
720
781
  /**
721
782
  * @brief Handle broker connection close.
@@ -999,11 +1060,11 @@ static void rd_kafka_broker_timeout_scan(rd_kafka_broker_t *rkb, rd_ts_t now) {
999
1060
  1000.0f));
1000
1061
  else
1001
1062
  rttinfo[0] = 0;
1002
- rd_kafka_broker_fail(rkb, LOG_ERR,
1003
- RD_KAFKA_RESP_ERR__TIMED_OUT,
1004
- "%i request(s) timed out: "
1005
- "disconnect%s",
1006
- rkb->rkb_req_timeouts, rttinfo);
1063
+ rd_kafka_broker_planned_fail(
1064
+ rkb, RD_KAFKA_RESP_ERR__TIMED_OUT,
1065
+ "%i request(s) timed out: "
1066
+ "disconnect%s",
1067
+ rkb->rkb_req_timeouts, rttinfo);
1007
1068
  }
1008
1069
  }
1009
1070
  }
@@ -1042,8 +1103,9 @@ static int rd_kafka_broker_resolve(rd_kafka_broker_t *rkb,
1042
1103
  int save_idx = 0;
1043
1104
 
1044
1105
  if (!*nodename && rkb->rkb_source == RD_KAFKA_LOGICAL) {
1045
- rd_kafka_broker_fail(rkb, LOG_DEBUG, RD_KAFKA_RESP_ERR__RESOLVE,
1046
- "Logical broker has no address yet");
1106
+ rd_kafka_broker_planned_fail(
1107
+ rkb, RD_KAFKA_RESP_ERR__RESOLVE, "%s",
1108
+ "Logical broker has no address yet");
1047
1109
  return -1;
1048
1110
  }
1049
1111
 
@@ -1403,12 +1465,13 @@ rd_kafka_broker_t *rd_kafka_broker_random0(const char *func,
1403
1465
  int fcnt = 0;
1404
1466
 
1405
1467
  TAILQ_FOREACH(rkb, &rk->rk_brokers, rkb_link) {
1406
- if (RD_KAFKA_BROKER_IS_LOGICAL(rkb))
1468
+ if (rd_kafka_broker_or_instance_terminating(rkb) ||
1469
+ RD_KAFKA_BROKER_IS_LOGICAL(rkb))
1407
1470
  continue;
1408
1471
 
1409
1472
  rd_kafka_broker_lock(rkb);
1410
1473
  if ((is_up && rd_kafka_broker_state_is_up(rkb->rkb_state)) ||
1411
- (!is_up && (int)rkb->rkb_state == state)) {
1474
+ (!is_up && (state == -1 || (int)rkb->rkb_state == state))) {
1412
1475
  if (filter && filter(rkb, opaque)) {
1413
1476
  /* Filtered out */
1414
1477
  fcnt++;
@@ -1459,6 +1522,8 @@ rd_kafka_broker_weighted(rd_kafka_t *rk,
1459
1522
 
1460
1523
  TAILQ_FOREACH(rkb, &rk->rk_brokers, rkb_link) {
1461
1524
  int weight;
1525
+ if (rd_kafka_broker_or_instance_terminating(rkb))
1526
+ continue;
1462
1527
 
1463
1528
  rd_kafka_broker_lock(rkb);
1464
1529
  if (features && (rkb->rkb_features & features) != features)
@@ -1512,12 +1577,11 @@ rd_kafka_broker_weighted(rd_kafka_t *rk,
1512
1577
  static int rd_kafka_broker_weight_usable(rd_kafka_broker_t *rkb) {
1513
1578
  int weight = 0;
1514
1579
 
1515
- if (!rd_kafka_broker_state_is_up(rkb->rkb_state))
1580
+ if (!rd_kafka_broker_state_is_up(rkb->rkb_state) ||
1581
+ RD_KAFKA_BROKER_IS_LOGICAL(rkb))
1516
1582
  return 0;
1517
1583
 
1518
- weight +=
1519
- 2000 * (rkb->rkb_nodeid != -1 && !RD_KAFKA_BROKER_IS_LOGICAL(rkb));
1520
- weight += 10 * !RD_KAFKA_BROKER_IS_LOGICAL(rkb);
1584
+ weight += 2000;
1521
1585
 
1522
1586
  if (likely(!rd_atomic32_get(&rkb->rkb_blocking_request_cnt))) {
1523
1587
  rd_ts_t tx_last = rd_atomic64_get(&rkb->rkb_c.ts_send);
@@ -1526,6 +1590,9 @@ static int rd_kafka_broker_weight_usable(rd_kafka_broker_t *rkb) {
1526
1590
  1000000);
1527
1591
 
1528
1592
  weight += 1; /* is not blocking */
1593
+ if (rkb->rkb_source == RD_KAFKA_LEARNED)
1594
+ /* Prefer learned brokers */
1595
+ weight += 1000;
1529
1596
 
1530
1597
  /* Prefer least idle broker (based on last 10 minutes use) */
1531
1598
  if (idle < 0)
@@ -1740,6 +1807,9 @@ rd_list_t *rd_kafka_brokers_get_nodeids_async(rd_kafka_t *rk,
1740
1807
  }
1741
1808
  i = 0;
1742
1809
  TAILQ_FOREACH(rkb, &rk->rk_brokers, rkb_link) {
1810
+ if (rd_kafka_broker_or_instance_terminating(rkb))
1811
+ continue;
1812
+
1743
1813
  rd_kafka_broker_lock(rkb);
1744
1814
  if (rkb->rkb_nodeid != -1 &&
1745
1815
  !RD_KAFKA_BROKER_IS_LOGICAL(rkb)) {
@@ -2098,7 +2168,7 @@ int rd_kafka_recv(rd_kafka_broker_t *rkb) {
2098
2168
  err_parse:
2099
2169
  err = rkbuf->rkbuf_err;
2100
2170
  err:
2101
- if (!strcmp(errstr, "Disconnected"))
2171
+ if (rd_kafka_transport_error_disconnected(errstr))
2102
2172
  rd_kafka_broker_conn_closed(rkb, err, errstr);
2103
2173
  else
2104
2174
  rd_kafka_broker_fail(rkb, LOG_ERR, err, "Receive failed: %s",
@@ -2201,53 +2271,6 @@ rd_kafka_broker_reconnect_backoff(const rd_kafka_broker_t *rkb, rd_ts_t now) {
2201
2271
  return (int)(remains / 1000);
2202
2272
  }
2203
2273
 
2204
-
2205
- /**
2206
- * @brief Unittest for reconnect.backoff.ms
2207
- */
2208
- static int rd_ut_reconnect_backoff(void) {
2209
- rd_kafka_broker_t rkb = RD_ZERO_INIT;
2210
- rd_kafka_conf_t conf = {.reconnect_backoff_ms = 10,
2211
- .reconnect_backoff_max_ms = 90};
2212
- rd_ts_t now = 1000000;
2213
- int backoff;
2214
-
2215
- rkb.rkb_reconnect_backoff_ms = conf.reconnect_backoff_ms;
2216
-
2217
- /* broker's backoff is the initial reconnect.backoff.ms=10 */
2218
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2219
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2220
- RD_UT_ASSERT_RANGE(backoff, 7, 15, "%d");
2221
-
2222
- /* .. 20 */
2223
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2224
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2225
- RD_UT_ASSERT_RANGE(backoff, 15, 30, "%d");
2226
-
2227
- /* .. 40 */
2228
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2229
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2230
- RD_UT_ASSERT_RANGE(backoff, 30, 60, "%d");
2231
-
2232
- /* .. 80, the jitter is capped at reconnect.backoff.max.ms=90 */
2233
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2234
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2235
- RD_UT_ASSERT_RANGE(backoff, 60, conf.reconnect_backoff_max_ms, "%d");
2236
-
2237
- /* .. 90, capped by reconnect.backoff.max.ms */
2238
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2239
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2240
- RD_UT_ASSERT_RANGE(backoff, 67, conf.reconnect_backoff_max_ms, "%d");
2241
-
2242
- /* .. 90, should remain at capped value. */
2243
- rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
2244
- backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
2245
- RD_UT_ASSERT_RANGE(backoff, 67, conf.reconnect_backoff_max_ms, "%d");
2246
-
2247
- RD_UT_PASS();
2248
- }
2249
-
2250
-
2251
2274
  /**
2252
2275
  * @brief Initiate asynchronous connection attempt to the next address
2253
2276
  * in the broker's address list.
@@ -2337,6 +2360,7 @@ void rd_kafka_broker_connect_up(rd_kafka_broker_t *rkb) {
2337
2360
  if (rd_kafka_broker_ApiVersion_supported(
2338
2361
  rkb, RD_KAFKAP_GetTelemetrySubscriptions, 0, 0, &features) !=
2339
2362
  -1 &&
2363
+ rkb->rkb_source == RD_KAFKA_LEARNED &&
2340
2364
  rkb->rkb_rk->rk_conf.enable_metrics_push) {
2341
2365
  rd_kafka_t *rk = rkb->rkb_rk;
2342
2366
  rd_kafka_op_t *rko =
@@ -2370,7 +2394,7 @@ static void rd_kafka_broker_handle_SaslHandshake(rd_kafka_t *rk,
2370
2394
  char *mechs = "(n/a)";
2371
2395
  size_t msz, mof = 0;
2372
2396
 
2373
- if (err == RD_KAFKA_RESP_ERR__DESTROY)
2397
+ if (rd_kafka_broker_is_any_err_destroy(err))
2374
2398
  return;
2375
2399
 
2376
2400
  if (err)
@@ -2549,7 +2573,7 @@ static void rd_kafka_broker_handle_ApiVersion(rd_kafka_t *rk,
2549
2573
  size_t api_cnt = 0;
2550
2574
  int16_t retry_ApiVersion = -1;
2551
2575
 
2552
- if (err == RD_KAFKA_RESP_ERR__DESTROY)
2576
+ if (rd_kafka_broker_is_any_err_destroy(err))
2553
2577
  return;
2554
2578
 
2555
2579
  err = rd_kafka_handle_ApiVersion(rk, rkb, err, rkbuf, request, &apis,
@@ -2942,10 +2966,18 @@ void rd_kafka_broker_buf_retry(rd_kafka_broker_t *rkb, rd_kafka_buf_t *rkbuf) {
2942
2966
  rd_atomic64_add(&rkb->rkb_c.tx_retries, 1);
2943
2967
  /* In some cases, failed Produce requests do not increment the retry
2944
2968
  * count, see rd_kafka_handle_Produce_error. */
2945
- if (rkbuf->rkbuf_retries > 0)
2946
- backoff = (1 << (rkbuf->rkbuf_retries - 1)) *
2969
+ if (rkbuf->rkbuf_retries > 0) {
2970
+ int shift = rkbuf->rkbuf_retries - 1;
2971
+
2972
+ /* Cap shift at 34 to prevent overflow in final calculation.
2973
+ * Accounts for multiplication by retry_backoff_ms (max 300000)
2974
+ * and jitter (max 1200). */
2975
+ if (shift > 34)
2976
+ shift = 34;
2977
+
2978
+ backoff = ((int64_t)1 << shift) *
2947
2979
  (rkb->rkb_rk->rk_conf.retry_backoff_ms);
2948
- else
2980
+ } else
2949
2981
  backoff = rkb->rkb_rk->rk_conf.retry_backoff_ms;
2950
2982
 
2951
2983
  /* We are multiplying by 10 as (backoff_ms * percent * 1000)/100 ->
@@ -3101,53 +3133,6 @@ void rd_kafka_dr_implicit_ack(rd_kafka_broker_t *rkb,
3101
3133
  rd_kafka_dr_msgq(rktp->rktp_rkt, &acked, RD_KAFKA_RESP_ERR_NO_ERROR);
3102
3134
  }
3103
3135
 
3104
-
3105
-
3106
- /**
3107
- * @brief Map existing partitions to this broker using the
3108
- * toppar's leader_id. Only undelegated partitions
3109
- * matching this broker are mapped.
3110
- *
3111
- * @locks none
3112
- * @locality any
3113
- */
3114
- static void rd_kafka_broker_map_partitions(rd_kafka_broker_t *rkb) {
3115
- rd_kafka_t *rk = rkb->rkb_rk;
3116
- rd_kafka_topic_t *rkt;
3117
- int cnt = 0;
3118
-
3119
- if (rkb->rkb_nodeid == -1 || RD_KAFKA_BROKER_IS_LOGICAL(rkb))
3120
- return;
3121
-
3122
- rd_kafka_rdlock(rk);
3123
- TAILQ_FOREACH(rkt, &rk->rk_topics, rkt_link) {
3124
- int i;
3125
-
3126
- rd_kafka_topic_wrlock(rkt);
3127
- for (i = 0; i < rkt->rkt_partition_cnt; i++) {
3128
- rd_kafka_toppar_t *rktp = rkt->rkt_p[i];
3129
-
3130
- /* Only map undelegated partitions matching this
3131
- * broker*/
3132
- rd_kafka_toppar_lock(rktp);
3133
- if (rktp->rktp_leader_id == rkb->rkb_nodeid &&
3134
- !(rktp->rktp_broker && rktp->rktp_next_broker)) {
3135
- rd_kafka_toppar_broker_update(
3136
- rktp, rktp->rktp_leader_id, rkb,
3137
- "broker node information updated");
3138
- cnt++;
3139
- }
3140
- rd_kafka_toppar_unlock(rktp);
3141
- }
3142
- rd_kafka_topic_wrunlock(rkt);
3143
- }
3144
- rd_kafka_rdunlock(rk);
3145
-
3146
- rd_rkb_dbg(rkb, TOPIC | RD_KAFKA_DBG_BROKER, "LEADER",
3147
- "Mapped %d partition(s) to broker", cnt);
3148
- }
3149
-
3150
-
3151
3136
  /**
3152
3137
  * @brief Broker id comparator
3153
3138
  */
@@ -3188,6 +3173,10 @@ static void rd_kafka_broker_prepare_destroy(rd_kafka_broker_t *rkb) {
3188
3173
  rd_kafka_broker_monitor_del(&rkb->rkb_coord_monitor);
3189
3174
  }
3190
3175
 
3176
+ static rd_kafka_resp_err_t rd_kafka_broker_destroy_error(rd_kafka_t *rk) {
3177
+ return rd_kafka_terminating(rk) ? RD_KAFKA_RESP_ERR__DESTROY
3178
+ : RD_KAFKA_RESP_ERR__DESTROY_BROKER;
3179
+ }
3191
3180
 
3192
3181
  /**
3193
3182
  * @brief Serve a broker op (an op posted by another thread to be handled by
@@ -3207,7 +3196,7 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3207
3196
 
3208
3197
  switch (rko->rko_type) {
3209
3198
  case RD_KAFKA_OP_NODE_UPDATE: {
3210
- enum { _UPD_NAME = 0x1, _UPD_ID = 0x2 } updated = 0;
3199
+ rd_bool_t updated = rd_false;
3211
3200
  char brokername[RD_KAFKA_NODENAME_SIZE];
3212
3201
 
3213
3202
  /* Need kafka_wrlock for updating rk_broker_by_id */
@@ -3221,31 +3210,7 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3221
3210
  rd_strlcpy(rkb->rkb_nodename, rko->rko_u.node.nodename,
3222
3211
  sizeof(rkb->rkb_nodename));
3223
3212
  rkb->rkb_nodename_epoch++;
3224
- updated |= _UPD_NAME;
3225
- }
3226
-
3227
- if (rko->rko_u.node.nodeid != -1 &&
3228
- !RD_KAFKA_BROKER_IS_LOGICAL(rkb) &&
3229
- rko->rko_u.node.nodeid != rkb->rkb_nodeid) {
3230
- int32_t old_nodeid = rkb->rkb_nodeid;
3231
- rd_rkb_dbg(rkb, BROKER, "UPDATE",
3232
- "NodeId changed from %" PRId32
3233
- " to %" PRId32,
3234
- rkb->rkb_nodeid, rko->rko_u.node.nodeid);
3235
-
3236
- rkb->rkb_nodeid = rko->rko_u.node.nodeid;
3237
-
3238
- /* Update system thread name */
3239
- rd_kafka_set_thread_sysname("rdk:broker%" PRId32,
3240
- rkb->rkb_nodeid);
3241
-
3242
- /* Update broker_by_id sorted list */
3243
- if (old_nodeid == -1)
3244
- rd_list_add(&rkb->rkb_rk->rk_broker_by_id, rkb);
3245
- rd_list_sort(&rkb->rkb_rk->rk_broker_by_id,
3246
- rd_kafka_broker_cmp_by_id);
3247
-
3248
- updated |= _UPD_ID;
3213
+ updated = rd_true;
3249
3214
  }
3250
3215
 
3251
3216
  rd_kafka_mk_brokername(brokername, sizeof(brokername),
@@ -3264,22 +3229,10 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3264
3229
  rd_kafka_broker_unlock(rkb);
3265
3230
  rd_kafka_wrunlock(rkb->rkb_rk);
3266
3231
 
3267
- if (updated & _UPD_NAME)
3268
- rd_kafka_broker_fail(rkb, LOG_DEBUG,
3269
- RD_KAFKA_RESP_ERR__TRANSPORT,
3270
- "Broker hostname updated");
3271
- else if (updated & _UPD_ID) {
3272
- /* Map existing partitions to this broker. */
3273
- rd_kafka_broker_map_partitions(rkb);
3274
-
3275
- /* If broker is currently in state up we need
3276
- * to trigger a state change so it exits its
3277
- * state&type based .._serve() loop. */
3278
- rd_kafka_broker_lock(rkb);
3279
- if (rkb->rkb_state == RD_KAFKA_BROKER_STATE_UP)
3280
- rd_kafka_broker_set_state(
3281
- rkb, RD_KAFKA_BROKER_STATE_UPDATE);
3282
- rd_kafka_broker_unlock(rkb);
3232
+ if (updated) {
3233
+ rd_kafka_broker_planned_fail(
3234
+ rkb, RD_KAFKA_RESP_ERR__TRANSPORT, "%s",
3235
+ "Broker hostname updated");
3283
3236
  }
3284
3237
 
3285
3238
  rd_kafka_brokers_broadcast_state_change(rkb->rkb_rk);
@@ -3308,17 +3261,20 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3308
3261
  rd_kafka_toppar_lock(rktp);
3309
3262
 
3310
3263
  /* Abort join if instance is terminating */
3311
- if (rd_kafka_terminating(rkb->rkb_rk) ||
3264
+ if (rd_kafka_broker_or_instance_terminating(rkb) ||
3312
3265
  (rktp->rktp_flags & RD_KAFKA_TOPPAR_F_REMOVE)) {
3313
- rd_rkb_dbg(rkb, BROKER | RD_KAFKA_DBG_TOPIC, "TOPBRK",
3314
- "Topic %s [%" PRId32
3315
- "]: not joining broker: "
3316
- "%s",
3317
- rktp->rktp_rkt->rkt_topic->str,
3318
- rktp->rktp_partition,
3319
- rd_kafka_terminating(rkb->rkb_rk)
3320
- ? "instance is terminating"
3321
- : "partition removed");
3266
+ rd_rkb_dbg(
3267
+ rkb, BROKER | RD_KAFKA_DBG_TOPIC, "TOPBRK",
3268
+ "Topic %s [%" PRId32
3269
+ "]: not joining broker: "
3270
+ "%s",
3271
+ rktp->rktp_rkt->rkt_topic->str,
3272
+ rktp->rktp_partition,
3273
+ rd_kafka_terminating(rkb->rkb_rk)
3274
+ ? "instance is terminating"
3275
+ : rd_kafka_broker_termination_in_progress(rkb)
3276
+ ? "broker is terminating"
3277
+ : "partition removed");
3322
3278
 
3323
3279
  rd_kafka_broker_destroy(rktp->rktp_next_broker);
3324
3280
  rktp->rktp_next_broker = NULL;
@@ -3386,6 +3342,8 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3386
3342
  "finish before producing to "
3387
3343
  "new leader");
3388
3344
  }
3345
+ } else if (rkb->rkb_rk->rk_type == RD_KAFKA_CONSUMER) {
3346
+ rktp->rktp_ts_fetch_backoff = 0;
3389
3347
  }
3390
3348
 
3391
3349
  rd_kafka_broker_destroy(rktp->rktp_next_broker);
@@ -3525,10 +3483,13 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3525
3483
  * and trigger a state change.
3526
3484
  * This makes sure any eonce dependent on state changes
3527
3485
  * are triggered. */
3528
- rd_kafka_broker_fail(rkb, LOG_DEBUG, RD_KAFKA_RESP_ERR__DESTROY,
3529
- "Client is terminating");
3486
+ rd_kafka_broker_fail(rkb, LOG_DEBUG,
3487
+ rd_kafka_broker_destroy_error(rkb->rkb_rk),
3488
+ "Decommissioning this broker");
3530
3489
 
3531
3490
  rd_kafka_broker_prepare_destroy(rkb);
3491
+ /* Release main thread reference here */
3492
+ rd_kafka_broker_destroy(rkb);
3532
3493
  wakeup = rd_true;
3533
3494
  break;
3534
3495
 
@@ -3566,9 +3527,8 @@ rd_kafka_broker_op_serve(rd_kafka_broker_t *rkb, rd_kafka_op_t *rko) {
3566
3527
  rd_kafka_broker_unlock(rkb);
3567
3528
 
3568
3529
  if (do_disconnect)
3569
- rd_kafka_broker_fail(
3570
- rkb, LOG_DEBUG,
3571
- RD_KAFKA_RESP_ERR__TRANSPORT,
3530
+ rd_kafka_broker_planned_fail(
3531
+ rkb, RD_KAFKA_RESP_ERR__TRANSPORT, "%s",
3572
3532
  "Closing connection due to "
3573
3533
  "nodename change");
3574
3534
  }
@@ -3646,7 +3606,7 @@ rd_kafka_broker_ops_io_serve(rd_kafka_broker_t *rkb, rd_ts_t abs_timeout) {
3646
3606
  rd_ts_t now;
3647
3607
  rd_bool_t wakeup;
3648
3608
 
3649
- if (unlikely(rd_kafka_terminating(rkb->rkb_rk)))
3609
+ if (unlikely(rd_kafka_broker_or_instance_terminating(rkb)))
3650
3610
  abs_timeout = rd_clock() + 1000;
3651
3611
  else if (unlikely(rd_kafka_broker_needs_connection(rkb)))
3652
3612
  abs_timeout = RD_POLL_NOWAIT;
@@ -4395,6 +4355,8 @@ static RD_INLINE void rd_kafka_broker_idle_check(rd_kafka_broker_t *rkb) {
4395
4355
  rd_ts_t ts_recv = rd_atomic64_get(&rkb->rkb_c.ts_recv);
4396
4356
  rd_ts_t ts_last_activity = RD_MAX(ts_send, ts_recv);
4397
4357
  int idle_ms;
4358
+ const int max_jitter_ms = 2000;
4359
+ rd_dassert(rkb->rkb_rk->rk_conf.connections_max_idle_ms > 0);
4398
4360
 
4399
4361
  /* If nothing has been sent yet, use the connection time as
4400
4362
  * last activity. */
@@ -4403,13 +4365,22 @@ static RD_INLINE void rd_kafka_broker_idle_check(rd_kafka_broker_t *rkb) {
4403
4365
 
4404
4366
  idle_ms = (int)((rd_clock() - ts_last_activity) / 1000);
4405
4367
 
4406
- if (likely(idle_ms < rkb->rkb_rk->rk_conf.connections_max_idle_ms))
4368
+ if (unlikely(rkb->rkb_c.connections_max_idle_ms == -1)) {
4369
+ /* Add a different jitter for each broker. */
4370
+ rkb->rkb_c.connections_max_idle_ms =
4371
+ rkb->rkb_rk->rk_conf.connections_max_idle_ms;
4372
+ if (rkb->rkb_c.connections_max_idle_ms >= 2 * max_jitter_ms)
4373
+ rkb->rkb_c.connections_max_idle_ms -=
4374
+ rd_jitter(0, max_jitter_ms);
4375
+ }
4376
+
4377
+ if (likely(idle_ms < rkb->rkb_c.connections_max_idle_ms))
4407
4378
  return;
4408
4379
 
4409
- rd_kafka_broker_fail(rkb, LOG_DEBUG, RD_KAFKA_RESP_ERR__TRANSPORT,
4410
- "Connection max idle time exceeded "
4411
- "(%dms since last activity)",
4412
- idle_ms);
4380
+ rd_kafka_broker_planned_fail(rkb, RD_KAFKA_RESP_ERR__TRANSPORT,
4381
+ "Connection max idle time exceeded "
4382
+ "(%dms since last activity)",
4383
+ idle_ms);
4413
4384
  }
4414
4385
 
4415
4386
 
@@ -4485,7 +4456,7 @@ static RD_INLINE void rd_kafka_broker_idle_check(rd_kafka_broker_t *rkb) {
4485
4456
  static void rd_kafka_broker_serve(rd_kafka_broker_t *rkb, int timeout_ms) {
4486
4457
  rd_ts_t abs_timeout;
4487
4458
 
4488
- if (unlikely(rd_kafka_terminating(rkb->rkb_rk) ||
4459
+ if (unlikely(rd_kafka_broker_or_instance_terminating(rkb) ||
4489
4460
  timeout_ms == RD_POLL_NOWAIT))
4490
4461
  timeout_ms = 1;
4491
4462
  else if (timeout_ms == RD_POLL_INFINITE)
@@ -4537,6 +4508,7 @@ rd_kafka_broker_addresses_exhausted(const rd_kafka_broker_t *rkb) {
4537
4508
  static int rd_kafka_broker_thread_main(void *arg) {
4538
4509
  rd_kafka_broker_t *rkb = arg;
4539
4510
  rd_kafka_t *rk = rkb->rkb_rk;
4511
+ rd_kafka_op_t *terminate_op;
4540
4512
 
4541
4513
  rd_kafka_set_thread_name("%s", rkb->rkb_name);
4542
4514
  rd_kafka_set_thread_sysname("rdk:broker%" PRId32, rkb->rkb_nodeid);
@@ -4603,8 +4575,11 @@ static int rd_kafka_broker_thread_main(void *arg) {
4603
4575
  break;
4604
4576
  }
4605
4577
 
4606
- if (unlikely(rd_kafka_terminating(rkb->rkb_rk)))
4578
+ if (unlikely(
4579
+ rd_kafka_broker_or_instance_terminating(rkb))) {
4607
4580
  rd_kafka_broker_serve(rkb, 1000);
4581
+ break;
4582
+ }
4608
4583
 
4609
4584
  if (!rd_kafka_sasl_ready(rkb->rkb_rk)) {
4610
4585
  /* SASL provider not yet ready. */
@@ -4709,30 +4684,21 @@ static int rd_kafka_broker_thread_main(void *arg) {
4709
4684
  rd_kafka_broker_connect_auth(rkb);
4710
4685
  break;
4711
4686
 
4712
- case RD_KAFKA_BROKER_STATE_UPDATE:
4713
- /* FALLTHRU */
4714
4687
  case RD_KAFKA_BROKER_STATE_UP:
4715
4688
  rd_kafka_broker_serve(rkb, rd_kafka_max_block_ms);
4716
-
4717
- if (rkb->rkb_state == RD_KAFKA_BROKER_STATE_UPDATE) {
4718
- rd_kafka_broker_lock(rkb);
4719
- rd_kafka_broker_set_state(
4720
- rkb, RD_KAFKA_BROKER_STATE_UP);
4721
- rd_kafka_broker_unlock(rkb);
4722
- }
4723
4689
  break;
4724
4690
  }
4725
4691
 
4726
- if (rd_kafka_terminating(rkb->rkb_rk)) {
4692
+ if (rd_kafka_broker_or_instance_terminating(rkb)) {
4727
4693
  /* Handle is terminating: fail the send+retry queue
4728
4694
  * to speed up termination, otherwise we'll
4729
4695
  * need to wait for request timeouts. */
4730
4696
  r = rd_kafka_broker_bufq_timeout_scan(
4731
4697
  rkb, 0, &rkb->rkb_outbufs, NULL, -1,
4732
- RD_KAFKA_RESP_ERR__DESTROY, 0, NULL, 0);
4698
+ rd_kafka_broker_destroy_error(rk), 0, NULL, 0);
4733
4699
  r += rd_kafka_broker_bufq_timeout_scan(
4734
4700
  rkb, 0, &rkb->rkb_retrybufs, NULL, -1,
4735
- RD_KAFKA_RESP_ERR__DESTROY, 0, NULL, 0);
4701
+ rd_kafka_broker_destroy_error(rk), 0, NULL, 0);
4736
4702
  rd_rkb_dbg(
4737
4703
  rkb, BROKER, "TERMINATE",
4738
4704
  "Handle is terminating in state %s: "
@@ -4749,28 +4715,46 @@ static int rd_kafka_broker_thread_main(void *arg) {
4749
4715
  }
4750
4716
  }
4751
4717
 
4752
- if (rkb->rkb_source != RD_KAFKA_INTERNAL) {
4753
- rd_kafka_wrlock(rkb->rkb_rk);
4754
- TAILQ_REMOVE(&rkb->rkb_rk->rk_brokers, rkb, rkb_link);
4755
- if (rkb->rkb_nodeid != -1 && !RD_KAFKA_BROKER_IS_LOGICAL(rkb))
4756
- rd_list_remove(&rkb->rkb_rk->rk_broker_by_id, rkb);
4757
- (void)rd_atomic32_sub(&rkb->rkb_rk->rk_broker_cnt, 1);
4758
- rd_kafka_wrunlock(rkb->rkb_rk);
4759
- }
4760
-
4761
- rd_kafka_broker_fail(rkb, LOG_DEBUG, RD_KAFKA_RESP_ERR__DESTROY,
4762
- "Broker handle is terminating");
4763
-
4764
4718
  /* Disable and drain ops queue.
4765
4719
  * Simply purging the ops queue risks leaving dangling references
4766
4720
  * for ops such as PARTITION_JOIN/PARTITION_LEAVE where the broker
4767
4721
  * reference is not maintained in the rko (but in rktp_next_leader).
4768
- * #1596 */
4722
+ * #1596.
4723
+ * Do this before failing the broker to make sure no buffers
4724
+ * are enqueued after that. */
4769
4725
  rd_kafka_q_disable(rkb->rkb_ops);
4770
4726
  while (rd_kafka_broker_ops_serve(rkb, RD_POLL_NOWAIT))
4771
4727
  ;
4772
4728
 
4773
- rd_kafka_broker_destroy(rkb);
4729
+ rd_kafka_broker_fail(rkb, LOG_DEBUG, rd_kafka_broker_destroy_error(rk),
4730
+ "Broker handle is terminating");
4731
+
4732
+ rd_rkb_dbg(rkb, BROKER, "TERMINATE",
4733
+ "Handle terminates in state %s: "
4734
+ "%d refcnts (%p), %d toppar(s), "
4735
+ "%d active toppar(s), "
4736
+ "%d outbufs, %d waitresps, %d retrybufs",
4737
+ rd_kafka_broker_state_names[rkb->rkb_state],
4738
+ rd_refcnt_get(&rkb->rkb_refcnt), &rkb->rkb_refcnt,
4739
+ rkb->rkb_toppar_cnt, rkb->rkb_active_toppar_cnt,
4740
+ (int)rd_kafka_bufq_cnt(&rkb->rkb_outbufs),
4741
+ (int)rd_kafka_bufq_cnt(&rkb->rkb_waitresps),
4742
+ (int)rd_kafka_bufq_cnt(&rkb->rkb_retrybufs));
4743
+
4744
+ rd_dassert(rkb->rkb_state == RD_KAFKA_BROKER_STATE_DOWN);
4745
+ if (rkb->rkb_source != RD_KAFKA_INTERNAL) {
4746
+ rd_kafka_wrlock(rkb->rkb_rk);
4747
+ TAILQ_REMOVE(&rkb->rkb_rk->rk_brokers, rkb, rkb_link);
4748
+
4749
+ if (RD_KAFKA_BROKER_IS_LOGICAL(rkb)) {
4750
+ rd_atomic32_sub(&rkb->rkb_rk->rk_logical_broker_cnt, 1);
4751
+ } else if (rd_atomic32_set(&rkb->rkb_down_reported, 0) == 1) {
4752
+ /* Only 1 -> 0 */
4753
+ rd_atomic32_sub(&rkb->rkb_rk->rk_broker_down_cnt, 1);
4754
+ }
4755
+ rd_atomic32_sub(&rkb->rkb_rk->rk_broker_cnt, 1);
4756
+ rd_kafka_wrunlock(rkb->rkb_rk);
4757
+ }
4774
4758
 
4775
4759
  #if WITH_SSL
4776
4760
  /* Remove OpenSSL per-thread error state to avoid memory leaks */
@@ -4786,6 +4770,15 @@ static int rd_kafka_broker_thread_main(void *arg) {
4786
4770
 
4787
4771
  rd_atomic32_sub(&rd_kafka_thread_cnt_curr, 1);
4788
4772
 
4773
+ terminate_op = rd_kafka_op_new(RD_KAFKA_OP_TERMINATE);
4774
+ terminate_op->rko_u.terminated.rkb = rkb;
4775
+ terminate_op->rko_u.terminated.cb =
4776
+ rd_kafka_decommissioned_broker_thread_join;
4777
+ rd_kafka_q_enq(rk->rk_ops, terminate_op);
4778
+
4779
+ /* Release broker thread reference here and call destroy final. */
4780
+ rd_kafka_broker_destroy(rkb);
4781
+
4789
4782
  return 0;
4790
4783
  }
4791
4784
 
@@ -4919,13 +4912,14 @@ rd_kafka_broker_t *rd_kafka_broker_add(rd_kafka_t *rk,
4919
4912
  rd_snprintf(rkb->rkb_name, sizeof(rkb->rkb_name), "%s", name);
4920
4913
  }
4921
4914
 
4922
- rkb->rkb_source = source;
4923
- rkb->rkb_rk = rk;
4924
- rkb->rkb_ts_state = rd_clock();
4925
- rkb->rkb_nodeid = nodeid;
4926
- rkb->rkb_proto = proto;
4927
- rkb->rkb_port = port;
4928
- rkb->rkb_origname = rd_strdup(name);
4915
+ rkb->rkb_source = source;
4916
+ rkb->rkb_rk = rk;
4917
+ rkb->rkb_ts_state = rd_clock();
4918
+ rkb->rkb_nodeid = nodeid;
4919
+ rkb->rkb_proto = proto;
4920
+ rkb->rkb_port = port;
4921
+ rkb->rkb_origname = rd_strdup(name);
4922
+ rkb->rkb_c.connections_max_idle_ms = -1;
4929
4923
 
4930
4924
  mtx_init(&rkb->rkb_lock, mtx_plain);
4931
4925
  mtx_init(&rkb->rkb_logname_lock, mtx_plain);
@@ -4987,6 +4981,8 @@ rd_kafka_broker_t *rd_kafka_broker_add(rd_kafka_t *rk,
4987
4981
 
4988
4982
  rkb->rkb_reconnect_backoff_ms = rk->rk_conf.reconnect_backoff_ms;
4989
4983
  rd_atomic32_init(&rkb->rkb_persistconn.coord, 0);
4984
+ rd_atomic32_init(&rkb->termination_in_progress, 0);
4985
+ rd_atomic32_init(&rkb->rkb_down_reported, 0);
4990
4986
 
4991
4987
  rd_atomic64_init(&rkb->rkb_c.ts_send, 0);
4992
4988
  rd_atomic64_init(&rkb->rkb_c.ts_recv, 0);
@@ -5155,7 +5151,7 @@ rd_kafka_broker_t *rd_kafka_broker_add_logical(rd_kafka_t *rk,
5155
5151
  rd_assert(rkb && *"failed to create broker thread");
5156
5152
  rd_kafka_wrunlock(rk);
5157
5153
 
5158
- rd_atomic32_add(&rk->rk_broker_addrless_cnt, 1);
5154
+ rd_atomic32_add(&rk->rk_logical_broker_cnt, 1);
5159
5155
 
5160
5156
  rd_dassert(RD_KAFKA_BROKER_IS_LOGICAL(rkb));
5161
5157
  rd_kafka_broker_keep(rkb);
@@ -5214,14 +5210,6 @@ void rd_kafka_broker_set_nodename(rd_kafka_broker_t *rkb,
5214
5210
  rkb->rkb_nodename_epoch++;
5215
5211
  changed = rd_true;
5216
5212
  }
5217
-
5218
- if (rkb->rkb_nodeid != nodeid) {
5219
- rd_rkb_dbg(rkb, BROKER, "NODEID",
5220
- "Broker nodeid changed from %" PRId32 " to %" PRId32,
5221
- rkb->rkb_nodeid, nodeid);
5222
- rkb->rkb_nodeid = nodeid;
5223
- }
5224
-
5225
5213
  rd_kafka_broker_unlock(rkb);
5226
5214
 
5227
5215
  /* Update the log name to include (or exclude) the nodeid.
@@ -5234,11 +5222,6 @@ void rd_kafka_broker_set_nodename(rd_kafka_broker_t *rkb,
5234
5222
  if (!changed)
5235
5223
  return;
5236
5224
 
5237
- if (!rd_kafka_broker_is_addrless(rkb))
5238
- rd_atomic32_sub(&rkb->rkb_rk->rk_broker_addrless_cnt, 1);
5239
- else
5240
- rd_atomic32_add(&rkb->rkb_rk->rk_broker_addrless_cnt, 1);
5241
-
5242
5225
  /* Trigger a disconnect & reconnect */
5243
5226
  rd_kafka_broker_schedule_connection(rkb);
5244
5227
  }
@@ -5305,11 +5288,12 @@ static rd_kafka_broker_t *rd_kafka_broker_find(rd_kafka_t *rk,
5305
5288
  rd_kafka_mk_nodename(nodename, sizeof(nodename), name, port);
5306
5289
 
5307
5290
  TAILQ_FOREACH(rkb, &rk->rk_brokers, rkb_link) {
5308
- if (RD_KAFKA_BROKER_IS_LOGICAL(rkb))
5291
+ if (rd_kafka_broker_or_instance_terminating(rkb) ||
5292
+ RD_KAFKA_BROKER_IS_LOGICAL(rkb))
5309
5293
  continue;
5310
5294
 
5311
5295
  rd_kafka_broker_lock(rkb);
5312
- if (!rd_kafka_terminating(rk) && rkb->rkb_proto == proto &&
5296
+ if (rkb->rkb_proto == proto &&
5313
5297
  !strcmp(rkb->rkb_nodename, nodename)) {
5314
5298
  rd_kafka_broker_keep(rkb);
5315
5299
  rd_kafka_broker_unlock(rkb);
@@ -5552,6 +5536,9 @@ int rd_kafka_brokers_add0(rd_kafka_t *rk,
5552
5536
 
5553
5537
 
5554
5538
  int rd_kafka_brokers_add(rd_kafka_t *rk, const char *brokerlist) {
5539
+ rd_kafka_wrlock(rk);
5540
+ rd_list_add(&rk->additional_brokerlists, rd_strdup(brokerlist));
5541
+ rd_kafka_wrunlock(rk);
5555
5542
  return rd_kafka_brokers_add0(rk, brokerlist, rd_false);
5556
5543
  }
5557
5544
 
@@ -5590,12 +5577,6 @@ void rd_kafka_broker_update(rd_kafka_t *rk,
5590
5577
  * the hostname. */
5591
5578
  if (strcmp(rkb->rkb_nodename, nodename))
5592
5579
  needs_update = 1;
5593
- } else if ((rkb = rd_kafka_broker_find(rk, proto, mdb->host,
5594
- mdb->port))) {
5595
- /* Broker matched by hostname (but not by nodeid),
5596
- * update the nodeid. */
5597
- needs_update = 1;
5598
-
5599
5580
  } else if ((rkb = rd_kafka_broker_add(rk, RD_KAFKA_LEARNED, proto,
5600
5581
  mdb->host, mdb->port, mdb->id))) {
5601
5582
  rd_kafka_broker_keep(rkb);
@@ -5610,7 +5591,6 @@ void rd_kafka_broker_update(rd_kafka_t *rk,
5610
5591
  rko = rd_kafka_op_new(RD_KAFKA_OP_NODE_UPDATE);
5611
5592
  rd_strlcpy(rko->rko_u.node.nodename, nodename,
5612
5593
  sizeof(rko->rko_u.node.nodename));
5613
- rko->rko_u.node.nodeid = mdb->id;
5614
5594
  /* Perform a blocking op request so that all
5615
5595
  * broker-related state, such as the rk broker list,
5616
5596
  * is up to date by the time this call returns.
@@ -5631,24 +5611,12 @@ void rd_kafka_broker_update(rd_kafka_t *rk,
5631
5611
  * @returns the broker id, or RD_KAFKA_NODEID_UA if \p rkb is NULL.
5632
5612
  *
5633
5613
  * @locality any
5634
- * @locks_required none
5635
- * @locks_acquired rkb_lock
5636
5614
  */
5637
5615
  int32_t rd_kafka_broker_id(rd_kafka_broker_t *rkb) {
5638
- int32_t broker_id;
5639
-
5640
5616
  if (unlikely(!rkb))
5641
5617
  return RD_KAFKA_NODEID_UA;
5642
5618
 
5643
- /* Avoid locking if already on the broker thread */
5644
- if (thrd_is_current(rkb->rkb_thread))
5645
- return rkb->rkb_nodeid;
5646
-
5647
- rd_kafka_broker_lock(rkb);
5648
- broker_id = rkb->rkb_nodeid;
5649
- rd_kafka_broker_unlock(rkb);
5650
-
5651
- return broker_id;
5619
+ return rkb->rkb_nodeid;
5652
5620
  }
5653
5621
 
5654
5622
 
@@ -5733,6 +5701,17 @@ static int rd_kafka_broker_filter_never_connected(rd_kafka_broker_t *rkb,
5733
5701
  return rd_atomic32_get(&rkb->rkb_c.connects);
5734
5702
  }
5735
5703
 
5704
+ static void rd_kafka_connect_any_timer_cb(rd_kafka_timers_t *rkts, void *arg) {
5705
+ const char *reason = (const char *)arg;
5706
+ rd_kafka_t *rk = rkts->rkts_rk;
5707
+ if (rd_kafka_terminating(rk))
5708
+ return;
5709
+
5710
+ /* Acquire the read lock for `rd_kafka_connect_any` */
5711
+ rd_kafka_rdlock(rk);
5712
+ rd_kafka_connect_any(rk, reason);
5713
+ rd_kafka_rdunlock(rk);
5714
+ }
5736
5715
 
5737
5716
  /**
5738
5717
  * @brief Sparse connections:
@@ -5752,15 +5731,14 @@ void rd_kafka_connect_any(rd_kafka_t *rk, const char *reason) {
5752
5731
  * a specific purpose (group coordinator) and their connections
5753
5732
  * should not be reused for other purposes.
5754
5733
  * rd_kafka_broker_random() will not return LOGICAL brokers. */
5755
- if (rd_atomic32_get(&rk->rk_broker_up_cnt) -
5756
- rd_atomic32_get(&rk->rk_logical_broker_up_cnt) >
5757
- 0 ||
5734
+ if (rd_atomic32_get(&rk->rk_broker_up_cnt) > 0 ||
5758
5735
  rd_atomic32_get(&rk->rk_broker_cnt) -
5759
- rd_atomic32_get(&rk->rk_broker_addrless_cnt) ==
5736
+ rd_atomic32_get(&rk->rk_logical_broker_cnt) ==
5760
5737
  0)
5761
5738
  return;
5762
5739
 
5763
5740
  mtx_lock(&rk->rk_suppress.sparse_connect_lock);
5741
+
5764
5742
  suppr = rd_interval(&rk->rk_suppress.sparse_connect_random,
5765
5743
  rk->rk_conf.sparse_connect_intvl * 1000, 0);
5766
5744
  mtx_unlock(&rk->rk_suppress.sparse_connect_lock);
@@ -5770,6 +5748,11 @@ void rd_kafka_connect_any(rd_kafka_t *rk, const char *reason) {
5770
5748
  "Not selecting any broker for cluster connection: "
5771
5749
  "still suppressed for %" PRId64 "ms: %s",
5772
5750
  -suppr / 1000, reason);
5751
+ /* Retry after interval + 1ms has passed */
5752
+ rd_kafka_timer_start_oneshot(
5753
+ &rk->rk_timers, &rk->rk_suppress.sparse_connect_random_tmr,
5754
+ rd_false /* don't restart */, 1000LL - suppr,
5755
+ rd_kafka_connect_any_timer_cb, (void *)reason);
5773
5756
  return;
5774
5757
  }
5775
5758
 
@@ -5786,7 +5769,7 @@ void rd_kafka_connect_any(rd_kafka_t *rk, const char *reason) {
5786
5769
 
5787
5770
  if (!rkb) {
5788
5771
  /* No brokers matched:
5789
- * this happens if there are brokers in > INIT state,
5772
+ * this happens if all brokers are in > INIT state,
5790
5773
  * in which case they're already connecting. */
5791
5774
 
5792
5775
  rd_kafka_dbg(rk, BROKER | RD_KAFKA_DBG_GENERIC, "CONNECT",
@@ -5868,8 +5851,8 @@ static void rd_kafka_broker_handle_purge_queues(rd_kafka_broker_t *rkb,
5868
5851
  * the protocol stream, so we need to disconnect from the broker
5869
5852
  * to get a clean protocol socket. */
5870
5853
  if (partial_cnt)
5871
- rd_kafka_broker_fail(
5872
- rkb, LOG_DEBUG, RD_KAFKA_RESP_ERR__PURGE_QUEUE,
5854
+ rd_kafka_broker_planned_fail(
5855
+ rkb, RD_KAFKA_RESP_ERR__PURGE_QUEUE,
5873
5856
  "Purged %d partially sent request: "
5874
5857
  "forcing disconnect",
5875
5858
  partial_cnt);
@@ -5992,7 +5975,6 @@ void rd_kafka_broker_active_toppar_del(rd_kafka_broker_t *rkb,
5992
5975
  */
5993
5976
  void rd_kafka_broker_schedule_connection(rd_kafka_broker_t *rkb) {
5994
5977
  rd_kafka_op_t *rko;
5995
-
5996
5978
  rko = rd_kafka_op_new(RD_KAFKA_OP_CONNECT);
5997
5979
  rd_kafka_op_set_prio(rko, RD_KAFKA_PRIO_FLASH);
5998
5980
  rd_kafka_q_enq(rkb->rkb_ops, rko);
@@ -6170,6 +6152,174 @@ void rd_kafka_broker_start_reauth_cb(rd_kafka_timers_t *rkts, void *_rkb) {
6170
6152
  rd_kafka_q_enq(rkb->rkb_ops, rko);
6171
6153
  }
6172
6154
 
6155
+ int32_t *rd_kafka_brokers_learned_ids(rd_kafka_t *rk, size_t *cntp) {
6156
+ rd_kafka_broker_t *rkb;
6157
+ int32_t *ids, *p;
6158
+ int32_t i;
6159
+
6160
+ *cntp = 0;
6161
+ rd_kafka_rdlock(rk);
6162
+ ids = malloc(sizeof(*ids) * rd_list_cnt(&rk->rk_broker_by_id));
6163
+ p = ids;
6164
+ RD_LIST_FOREACH(rkb, &rk->rk_broker_by_id, i) {
6165
+ *p++ = rkb->rkb_nodeid;
6166
+ (*cntp)++;
6167
+ }
6168
+ rd_kafka_rdunlock(rk);
6169
+
6170
+ return ids;
6171
+ }
6172
+
6173
+ /**
6174
+ * @brief Decommission a broker.
6175
+ *
6176
+ * @param rk Client instance.
6177
+ * @param rkb Broker to decommission.
6178
+ * @param wait_thrds Add the broker's thread to this list if not NULL.
6179
+ *
6180
+ * @locks rd_kafka_wrlock() is dropped and reacquired.
6181
+ *
6182
+ * Broker threads hold a refcount and detect when it reaches 1 and then
6183
+ * decommissions itself. Callers can wait for this to happen by calling
6184
+ * thrd_join() on elements of \p wait_thrds. Callers are responsible for
6185
+ * managing the creation and destruction of \p wait_thrds which can be NULL.
6186
+ */
6187
+ void rd_kafka_broker_decommission(rd_kafka_t *rk,
6188
+ rd_kafka_broker_t *rkb,
6189
+ rd_list_t *wait_thrds) {
6190
+
6191
+ if (rd_atomic32_get(&rkb->termination_in_progress) > 0)
6192
+ return;
6193
+
6194
+ rd_atomic32_add(&rkb->termination_in_progress, 1);
6195
+
6196
+ /* Add broker's thread to wait_thrds list for later joining */
6197
+ if (wait_thrds) {
6198
+ thrd_t *thrd = rd_malloc(sizeof(*thrd));
6199
+ *thrd = rkb->rkb_thread;
6200
+
6201
+ rd_list_add(wait_thrds, thrd);
6202
+ }
6203
+
6204
+ rd_list_remove(&rk->rk_broker_by_id, rkb);
6205
+ rd_kafka_wrunlock(rk);
6206
+
6207
+ rd_kafka_dbg(rk, BROKER, "DESTROY", "Sending TERMINATE to %s",
6208
+ rd_kafka_broker_name(rkb));
6209
+
6210
+ #ifndef _WIN32
6211
+ /* Interrupt IO threads to speed up termination. */
6212
+ if (rk->rk_conf.term_sig)
6213
+ pthread_kill(rkb->rkb_thread, rk->rk_conf.term_sig);
6214
+ #endif
6215
+
6216
+ if (rk->rk_cgrp && rk->rk_cgrp->rkcg_curr_coord &&
6217
+ rk->rk_cgrp->rkcg_curr_coord == rkb)
6218
+ /* If we're decommissioning current coordinator handle,
6219
+ * mark it as dead and decrease its reference count. */
6220
+ rd_kafka_cgrp_coord_dead(rk->rk_cgrp,
6221
+ RD_KAFKA_RESP_ERR__DESTROY_BROKER,
6222
+ "Group coordinator decommissioned");
6223
+ /* Send op to trigger queue/io wake-up.
6224
+ * Broker thread will destroy this thread reference.
6225
+ * WARNING: This is last time we can read from rkb in this thread! */
6226
+ rd_kafka_q_enq(rkb->rkb_ops, rd_kafka_op_new(RD_KAFKA_OP_TERMINATE));
6227
+
6228
+ rd_kafka_wrlock(rk);
6229
+ }
6230
+
6231
+ /**
6232
+ * @brief Unittest for reconnect.backoff.ms
6233
+ */
6234
+ static int rd_ut_reconnect_backoff(void) {
6235
+ rd_kafka_broker_t rkb = RD_ZERO_INIT;
6236
+ rd_kafka_conf_t conf = {.reconnect_backoff_ms = 10,
6237
+ .reconnect_backoff_max_ms = 90};
6238
+ rd_ts_t now = 1000000;
6239
+ int backoff;
6240
+
6241
+ rkb.rkb_reconnect_backoff_ms = conf.reconnect_backoff_ms;
6242
+
6243
+ /* broker's backoff is the initial reconnect.backoff.ms=10 */
6244
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6245
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6246
+ RD_UT_ASSERT_RANGE(backoff, 7, 15, "%d");
6247
+
6248
+ /* .. 20 */
6249
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6250
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6251
+ RD_UT_ASSERT_RANGE(backoff, 15, 30, "%d");
6252
+
6253
+ /* .. 40 */
6254
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6255
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6256
+ RD_UT_ASSERT_RANGE(backoff, 30, 60, "%d");
6257
+
6258
+ /* .. 80, the jitter is capped at reconnect.backoff.max.ms=90 */
6259
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6260
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6261
+ RD_UT_ASSERT_RANGE(backoff, 60, conf.reconnect_backoff_max_ms, "%d");
6262
+
6263
+ /* .. 90, capped by reconnect.backoff.max.ms */
6264
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6265
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6266
+ RD_UT_ASSERT_RANGE(backoff, 67, conf.reconnect_backoff_max_ms, "%d");
6267
+
6268
+ /* .. 90, should remain at capped value. */
6269
+ rd_kafka_broker_update_reconnect_backoff(&rkb, &conf, now);
6270
+ backoff = rd_kafka_broker_reconnect_backoff(&rkb, now);
6271
+ RD_UT_ASSERT_RANGE(backoff, 67, conf.reconnect_backoff_max_ms, "%d");
6272
+
6273
+ RD_UT_PASS();
6274
+ }
6275
+
6276
+ /**
6277
+ * @brief Unittest for reconnect.backoff.ms
6278
+ */
6279
+ static int rd_ut_ApiVersion_at_least(void) {
6280
+ rd_kafka_broker_t rkb = RD_ZERO_INIT;
6281
+ mtx_init(&rkb.rkb_lock, mtx_plain);
6282
+
6283
+ struct rd_kafka_ApiVersion av = {
6284
+ .ApiKey = RD_KAFKAP_Metadata,
6285
+ .MinVer = 5,
6286
+ .MaxVer = 10,
6287
+ };
6288
+
6289
+ rkb.rkb_ApiVersions_cnt = 1;
6290
+ rkb.rkb_ApiVersions = &av;
6291
+
6292
+ RD_UT_ASSERT(
6293
+ rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 0),
6294
+ "Metadata API version should be at least 0");
6295
+ RD_UT_ASSERT(
6296
+ rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 3),
6297
+ "Metadata API version should be at least 3");
6298
+ RD_UT_ASSERT(
6299
+ rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 5),
6300
+ "Metadata API version should be at least 5");
6301
+ RD_UT_ASSERT(
6302
+ rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 7),
6303
+ "Metadata API version should be at least 7");
6304
+ RD_UT_ASSERT(
6305
+ rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 10),
6306
+ "Metadata API version should be at least 10");
6307
+ RD_UT_ASSERT(
6308
+ !rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 11),
6309
+ "Metadata API version shouldn't be at least 11");
6310
+
6311
+ rkb.rkb_ApiVersions_cnt = 0;
6312
+ RD_UT_ASSERT(
6313
+ !rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 0),
6314
+ "Metadata API version shouldn't be at least 0");
6315
+ RD_UT_ASSERT(
6316
+ !rd_kafka_broker_ApiVersion_at_least(&rkb, RD_KAFKAP_Metadata, 3),
6317
+ "Metadata API version shouldn't be at least 3");
6318
+
6319
+ mtx_destroy(&rkb.rkb_lock);
6320
+ RD_UT_PASS();
6321
+ }
6322
+
6173
6323
  /**
6174
6324
  * @name Unit tests
6175
6325
  * @{
@@ -6179,6 +6329,7 @@ int unittest_broker(void) {
6179
6329
  int fails = 0;
6180
6330
 
6181
6331
  fails += rd_ut_reconnect_backoff();
6332
+ fails += rd_ut_ApiVersion_at_least();
6182
6333
 
6183
6334
  return fails;
6184
6335
  }