@ohos-ports/confluentinc-kafka-javascript 1.10.0-beta.1

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 (628) hide show
  1. package/CHANGELOG.md +457 -0
  2. package/LICENSE.kafkajs +31 -0
  3. package/LICENSE.node-rdkafka +25 -0
  4. package/LICENSE.txt +20 -0
  5. package/README.md +133 -0
  6. package/binding.gyp +184 -0
  7. package/build/Release/confluent-kafka-javascript.node +0 -0
  8. package/build/deps/librdkafka++.so.1 +0 -0
  9. package/build/deps/librdkafka.Makefile +6 -0
  10. package/build/deps/librdkafka.so.1 +0 -0
  11. package/build/deps/librdkafka.target.mk +55 -0
  12. package/deps/librdkafka/.clang-format +136 -0
  13. package/deps/librdkafka/.clang-format-cpp +103 -0
  14. package/deps/librdkafka/.dir-locals.el +10 -0
  15. package/deps/librdkafka/.formatignore +35 -0
  16. package/deps/librdkafka/.gdbmacros +19 -0
  17. package/deps/librdkafka/CHANGELOG.md +2477 -0
  18. package/deps/librdkafka/CMakeLists.txt +291 -0
  19. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  20. package/deps/librdkafka/CONFIGURATION.md +212 -0
  21. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  22. package/deps/librdkafka/Doxyfile +2375 -0
  23. package/deps/librdkafka/INTRODUCTION.md +2752 -0
  24. package/deps/librdkafka/LICENSE +26 -0
  25. package/deps/librdkafka/LICENSE.cjson +22 -0
  26. package/deps/librdkafka/LICENSE.crc32c +28 -0
  27. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  28. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  29. package/deps/librdkafka/LICENSE.lz4 +26 -0
  30. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  31. package/deps/librdkafka/LICENSE.nanopb +22 -0
  32. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  33. package/deps/librdkafka/LICENSE.pycrc +23 -0
  34. package/deps/librdkafka/LICENSE.queue +31 -0
  35. package/deps/librdkafka/LICENSE.regexp +5 -0
  36. package/deps/librdkafka/LICENSE.snappy +36 -0
  37. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  38. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  39. package/deps/librdkafka/LICENSES.txt +625 -0
  40. package/deps/librdkafka/Makefile +125 -0
  41. package/deps/librdkafka/README.md +201 -0
  42. package/deps/librdkafka/README.win32 +26 -0
  43. package/deps/librdkafka/STATISTICS.md +624 -0
  44. package/deps/librdkafka/configure +214 -0
  45. package/deps/librdkafka/configure.self +341 -0
  46. package/deps/librdkafka/dev-conf.sh +123 -0
  47. package/deps/librdkafka/lds-gen.py +73 -0
  48. package/deps/librdkafka/mainpage.doxy +40 -0
  49. package/deps/librdkafka/mklove/Makefile.base +329 -0
  50. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  51. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  52. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  53. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  54. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  55. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  56. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  57. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  58. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  59. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  60. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  61. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  62. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  63. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  64. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  65. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  66. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  67. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  68. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  69. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  70. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  71. package/deps/librdkafka/service.yml +182 -0
  72. package/deps/librdkafka/src/CMakeLists.txt +379 -0
  73. package/deps/librdkafka/src/Makefile +105 -0
  74. package/deps/librdkafka/src/README.lz4.md +30 -0
  75. package/deps/librdkafka/src/cJSON.c +3191 -0
  76. package/deps/librdkafka/src/cJSON.h +306 -0
  77. package/deps/librdkafka/src/crc32c.c +430 -0
  78. package/deps/librdkafka/src/crc32c.h +38 -0
  79. package/deps/librdkafka/src/generate_proto.sh +66 -0
  80. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  81. package/deps/librdkafka/src/lz4.c +2727 -0
  82. package/deps/librdkafka/src/lz4.h +842 -0
  83. package/deps/librdkafka/src/lz4frame.c +2078 -0
  84. package/deps/librdkafka/src/lz4frame.h +692 -0
  85. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  86. package/deps/librdkafka/src/lz4hc.c +1631 -0
  87. package/deps/librdkafka/src/lz4hc.h +413 -0
  88. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  89. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  90. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  91. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  92. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  93. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  94. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  95. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  96. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  97. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  98. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  99. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  100. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  101. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  102. package/deps/librdkafka/src/queue.h +850 -0
  103. package/deps/librdkafka/src/rd.h +592 -0
  104. package/deps/librdkafka/src/rdaddr.c +255 -0
  105. package/deps/librdkafka/src/rdaddr.h +202 -0
  106. package/deps/librdkafka/src/rdatomic.h +262 -0
  107. package/deps/librdkafka/src/rdavg.h +260 -0
  108. package/deps/librdkafka/src/rdavl.c +210 -0
  109. package/deps/librdkafka/src/rdavl.h +250 -0
  110. package/deps/librdkafka/src/rdbase64.c +200 -0
  111. package/deps/librdkafka/src/rdbase64.h +43 -0
  112. package/deps/librdkafka/src/rdbuf.c +1884 -0
  113. package/deps/librdkafka/src/rdbuf.h +375 -0
  114. package/deps/librdkafka/src/rdcrc32.c +114 -0
  115. package/deps/librdkafka/src/rdcrc32.h +170 -0
  116. package/deps/librdkafka/src/rddl.c +179 -0
  117. package/deps/librdkafka/src/rddl.h +43 -0
  118. package/deps/librdkafka/src/rdendian.h +175 -0
  119. package/deps/librdkafka/src/rdfloat.h +67 -0
  120. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  121. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  122. package/deps/librdkafka/src/rdgz.c +120 -0
  123. package/deps/librdkafka/src/rdgz.h +46 -0
  124. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  125. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  126. package/deps/librdkafka/src/rdhttp.c +831 -0
  127. package/deps/librdkafka/src/rdhttp.h +101 -0
  128. package/deps/librdkafka/src/rdinterval.h +177 -0
  129. package/deps/librdkafka/src/rdkafka.c +7287 -0
  130. package/deps/librdkafka/src/rdkafka.h +11795 -0
  131. package/deps/librdkafka/src/rdkafka_admin.c +10165 -0
  132. package/deps/librdkafka/src/rdkafka_admin.h +658 -0
  133. package/deps/librdkafka/src/rdkafka_assignment.c +1282 -0
  134. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  135. package/deps/librdkafka/src/rdkafka_assignor.c +1800 -0
  136. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  137. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  138. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  139. package/deps/librdkafka/src/rdkafka_background.c +222 -0
  140. package/deps/librdkafka/src/rdkafka_broker.c +6736 -0
  141. package/deps/librdkafka/src/rdkafka_broker.h +851 -0
  142. package/deps/librdkafka/src/rdkafka_buf.c +543 -0
  143. package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
  144. package/deps/librdkafka/src/rdkafka_cert.c +576 -0
  145. package/deps/librdkafka/src/rdkafka_cert.h +62 -0
  146. package/deps/librdkafka/src/rdkafka_cgrp.c +8310 -0
  147. package/deps/librdkafka/src/rdkafka_cgrp.h +589 -0
  148. package/deps/librdkafka/src/rdkafka_conf.c +5177 -0
  149. package/deps/librdkafka/src/rdkafka_conf.h +746 -0
  150. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  151. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  152. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  153. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  154. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  155. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  156. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  157. package/deps/librdkafka/src/rdkafka_feature.c +898 -0
  158. package/deps/librdkafka/src/rdkafka_feature.h +104 -0
  159. package/deps/librdkafka/src/rdkafka_fetcher.c +3820 -0
  160. package/deps/librdkafka/src/rdkafka_fetcher.h +62 -0
  161. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  162. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  163. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  164. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  165. package/deps/librdkafka/src/rdkafka_int.h +1505 -0
  166. package/deps/librdkafka/src/rdkafka_interceptor.c +842 -0
  167. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  168. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  169. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  170. package/deps/librdkafka/src/rdkafka_metadata.c +2347 -0
  171. package/deps/librdkafka/src/rdkafka_metadata.h +350 -0
  172. package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
  173. package/deps/librdkafka/src/rdkafka_mock.c +4514 -0
  174. package/deps/librdkafka/src/rdkafka_mock.h +867 -0
  175. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1877 -0
  176. package/deps/librdkafka/src/rdkafka_mock_handlers.c +5255 -0
  177. package/deps/librdkafka/src/rdkafka_mock_int.h +1005 -0
  178. package/deps/librdkafka/src/rdkafka_mock_sharegrp.c +1207 -0
  179. package/deps/librdkafka/src/rdkafka_msg.c +2619 -0
  180. package/deps/librdkafka/src/rdkafka_msg.h +629 -0
  181. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  182. package/deps/librdkafka/src/rdkafka_msgset.h +105 -0
  183. package/deps/librdkafka/src/rdkafka_msgset_reader.c +2099 -0
  184. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
  185. package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
  186. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  187. package/deps/librdkafka/src/rdkafka_op.c +1219 -0
  188. package/deps/librdkafka/src/rdkafka_op.h +1065 -0
  189. package/deps/librdkafka/src/rdkafka_partition.c +5109 -0
  190. package/deps/librdkafka/src/rdkafka_partition.h +1215 -0
  191. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  192. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  193. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  194. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  195. package/deps/librdkafka/src/rdkafka_proto.h +739 -0
  196. package/deps/librdkafka/src/rdkafka_protocol.h +131 -0
  197. package/deps/librdkafka/src/rdkafka_queue.c +1351 -0
  198. package/deps/librdkafka/src/rdkafka_queue.h +1235 -0
  199. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  200. package/deps/librdkafka/src/rdkafka_request.c +7298 -0
  201. package/deps/librdkafka/src/rdkafka_request.h +761 -0
  202. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  203. package/deps/librdkafka/src/rdkafka_sasl.c +589 -0
  204. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  205. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  206. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  207. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
  208. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  209. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1827 -0
  210. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +52 -0
  211. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  212. package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
  213. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  214. package/deps/librdkafka/src/rdkafka_share_acknowledgement.c +1445 -0
  215. package/deps/librdkafka/src/rdkafka_share_acknowledgement.h +373 -0
  216. package/deps/librdkafka/src/rdkafka_ssl.c +2235 -0
  217. package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
  218. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
  219. package/deps/librdkafka/src/rdkafka_subscription.c +411 -0
  220. package/deps/librdkafka/src/rdkafka_telemetry.c +761 -0
  221. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  222. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1307 -0
  223. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  224. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +1309 -0
  225. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +459 -0
  226. package/deps/librdkafka/src/rdkafka_timer.c +407 -0
  227. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  228. package/deps/librdkafka/src/rdkafka_topic.c +2382 -0
  229. package/deps/librdkafka/src/rdkafka_topic.h +369 -0
  230. package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
  231. package/deps/librdkafka/src/rdkafka_transport.h +99 -0
  232. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  233. package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
  234. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  235. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  236. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  237. package/deps/librdkafka/src/rdlist.c +593 -0
  238. package/deps/librdkafka/src/rdlist.h +444 -0
  239. package/deps/librdkafka/src/rdlog.c +89 -0
  240. package/deps/librdkafka/src/rdlog.h +41 -0
  241. package/deps/librdkafka/src/rdmap.c +508 -0
  242. package/deps/librdkafka/src/rdmap.h +492 -0
  243. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  244. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  245. package/deps/librdkafka/src/rdports.c +61 -0
  246. package/deps/librdkafka/src/rdports.h +38 -0
  247. package/deps/librdkafka/src/rdposix.h +250 -0
  248. package/deps/librdkafka/src/rdrand.c +151 -0
  249. package/deps/librdkafka/src/rdrand.h +72 -0
  250. package/deps/librdkafka/src/rdregex.c +156 -0
  251. package/deps/librdkafka/src/rdregex.h +43 -0
  252. package/deps/librdkafka/src/rdsignal.h +57 -0
  253. package/deps/librdkafka/src/rdstring.c +645 -0
  254. package/deps/librdkafka/src/rdstring.h +98 -0
  255. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  256. package/deps/librdkafka/src/rdtime.h +356 -0
  257. package/deps/librdkafka/src/rdtypes.h +86 -0
  258. package/deps/librdkafka/src/rdunittest.c +564 -0
  259. package/deps/librdkafka/src/rdunittest.h +232 -0
  260. package/deps/librdkafka/src/rdunittest_acknowledge.c +1177 -0
  261. package/deps/librdkafka/src/rdunittest_fetcher.c +1211 -0
  262. package/deps/librdkafka/src/rdunittest_msgset_errors.c +1521 -0
  263. package/deps/librdkafka/src/rdvarint.c +134 -0
  264. package/deps/librdkafka/src/rdvarint.h +165 -0
  265. package/deps/librdkafka/src/rdwin32.h +382 -0
  266. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  267. package/deps/librdkafka/src/rdxxhash.h +328 -0
  268. package/deps/librdkafka/src/regexp.c +1352 -0
  269. package/deps/librdkafka/src/regexp.h +41 -0
  270. package/deps/librdkafka/src/snappy.c +1866 -0
  271. package/deps/librdkafka/src/snappy.h +62 -0
  272. package/deps/librdkafka/src/snappy_compat.h +138 -0
  273. package/deps/librdkafka/src/statistics_schema.json +444 -0
  274. package/deps/librdkafka/src/tinycthread.c +932 -0
  275. package/deps/librdkafka/src/tinycthread.h +503 -0
  276. package/deps/librdkafka/src/tinycthread_extra.c +210 -0
  277. package/deps/librdkafka/src/tinycthread_extra.h +218 -0
  278. package/deps/librdkafka/src/win32_config.h +58 -0
  279. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  280. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  281. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  282. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  283. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  284. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  285. package/deps/librdkafka/src-cpp/Makefile +55 -0
  286. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  287. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  288. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  289. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  290. package/deps/librdkafka/src-cpp/README.md +16 -0
  291. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  292. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  293. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  294. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
  295. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  296. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  297. package/deps/librdkafka/tests/0001-multiobj.c +102 -0
  298. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  299. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  300. package/deps/librdkafka/tests/0004-conf.c +934 -0
  301. package/deps/librdkafka/tests/0005-order.c +133 -0
  302. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  303. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  304. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  305. package/deps/librdkafka/tests/0009-mock_cluster.c +272 -0
  306. package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
  307. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  308. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  309. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  310. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  311. package/deps/librdkafka/tests/0016-client_swname.c +181 -0
  312. package/deps/librdkafka/tests/0017-compression.c +140 -0
  313. package/deps/librdkafka/tests/0018-cgrp_term.c +444 -0
  314. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  315. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  316. package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
  317. package/deps/librdkafka/tests/0022-consume_batch.c +331 -0
  318. package/deps/librdkafka/tests/0025-timers.c +147 -0
  319. package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
  320. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  321. package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
  322. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  323. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  324. package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
  325. package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
  326. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  327. package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
  328. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  329. package/deps/librdkafka/tests/0038-performance.c +121 -0
  330. package/deps/librdkafka/tests/0039-event.c +284 -0
  331. package/deps/librdkafka/tests/0040-io_event.c +257 -0
  332. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
  333. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  334. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  335. package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
  336. package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
  337. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  338. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
  339. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  340. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  341. package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
  342. package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
  343. package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
  344. package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
  345. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  346. package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
  347. package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
  348. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  349. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  350. package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
  351. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  352. package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
  353. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  354. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  355. package/deps/librdkafka/tests/0064-interceptors.c +529 -0
  356. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  357. package/deps/librdkafka/tests/0066-plugins.cpp +143 -0
  358. package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
  359. package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
  360. package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
  361. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  362. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  363. package/deps/librdkafka/tests/0073-headers.c +381 -0
  364. package/deps/librdkafka/tests/0074-producev.c +87 -0
  365. package/deps/librdkafka/tests/0075-retry.c +290 -0
  366. package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
  367. package/deps/librdkafka/tests/0077-compaction.c +366 -0
  368. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  369. package/deps/librdkafka/tests/0079-fork.c +93 -0
  370. package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
  371. package/deps/librdkafka/tests/0081-admin.c +5633 -0
  372. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
  373. package/deps/librdkafka/tests/0083-cb_event.c +233 -0
  374. package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
  375. package/deps/librdkafka/tests/0085-headers.cpp +392 -0
  376. package/deps/librdkafka/tests/0086-purge.c +368 -0
  377. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  378. package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
  379. package/deps/librdkafka/tests/0090-idempotence.c +171 -0
  380. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
  381. package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
  382. package/deps/librdkafka/tests/0093-holb.c +200 -0
  383. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
  384. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  385. package/deps/librdkafka/tests/0097-ssl_verify.cpp +674 -0
  386. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  387. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  388. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  389. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  390. package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
  391. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  392. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
  393. package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
  394. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
  395. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  396. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
  397. package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
  398. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  399. package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
  400. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
  401. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  402. package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
  403. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
  404. package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
  405. package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
  406. package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
  407. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
  408. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  409. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  410. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  411. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  412. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  413. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +1164 -0
  414. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  415. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +217 -0
  416. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
  417. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  418. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  419. package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
  420. package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
  421. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  422. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +279 -0
  423. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  424. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +752 -0
  425. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  426. package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
  427. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  428. package/deps/librdkafka/tests/0142-reauthentication.c +931 -0
  429. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
  430. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  431. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  432. package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
  433. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +1210 -0
  434. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +569 -0
  435. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  436. package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
  437. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  438. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  439. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  440. package/deps/librdkafka/tests/0155-share_group_heartbeat_mock.c +2695 -0
  441. package/deps/librdkafka/tests/0156-share_consumer_fetch_mock.c +1551 -0
  442. package/deps/librdkafka/tests/0157-share_consumer_ack_mock.c +1788 -0
  443. package/deps/librdkafka/tests/0158-share_consumer_transactions_mock.c +467 -0
  444. package/deps/librdkafka/tests/0170-share_consumer_subscription.c +2192 -0
  445. package/deps/librdkafka/tests/0171-share_consumer_consume.c +2150 -0
  446. package/deps/librdkafka/tests/0172-share_consumer_acknowledge.c +1919 -0
  447. package/deps/librdkafka/tests/0173-share_consumer_commit_async.c +2735 -0
  448. package/deps/librdkafka/tests/0174-share_consumer_concurrency.c +1434 -0
  449. package/deps/librdkafka/tests/0175-share_consumer_groups.c +574 -0
  450. package/deps/librdkafka/tests/0176-share_consumer_commit_sync.c +2986 -0
  451. package/deps/librdkafka/tests/0177-share_consumer_transactions.c +1815 -0
  452. package/deps/librdkafka/tests/0178-share_consumer_close.c +2102 -0
  453. package/deps/librdkafka/tests/0179-share_consumer_destroy.c +2482 -0
  454. package/deps/librdkafka/tests/0180-share_consumer_config.c +1677 -0
  455. package/deps/librdkafka/tests/0181-share_consumer_topic_delete.c +354 -0
  456. package/deps/librdkafka/tests/0182-share_consumer_error_handling_mock.c +3358 -0
  457. package/deps/librdkafka/tests/0183-share_consumer_leader_change_mock.c +1234 -0
  458. package/deps/librdkafka/tests/0184-share_consumer_topic_recreate.c +1356 -0
  459. package/deps/librdkafka/tests/0185-share_consumer_max_poll_interval.c +557 -0
  460. package/deps/librdkafka/tests/0186-share_consumer_fatal_error.c +360 -0
  461. package/deps/librdkafka/tests/0190-share_consumer_telemetry.c +387 -0
  462. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  463. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  464. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  465. package/deps/librdkafka/tests/CMakeLists.txt +193 -0
  466. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
  467. package/deps/librdkafka/tests/Makefile +182 -0
  468. package/deps/librdkafka/tests/README.md +514 -0
  469. package/deps/librdkafka/tests/autotest.sh +33 -0
  470. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  471. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  472. package/deps/librdkafka/tests/buildbox.sh +17 -0
  473. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  474. package/deps/librdkafka/tests/cluster_testing.py +203 -0
  475. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  476. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  477. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  478. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  479. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  480. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  481. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  482. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
  483. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  484. package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
  485. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
  486. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  487. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  488. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  489. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  490. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  491. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  492. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  493. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  494. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  495. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  496. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  497. package/deps/librdkafka/tests/java/Makefile +13 -0
  498. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  499. package/deps/librdkafka/tests/java/README.md +14 -0
  500. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  501. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  502. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  503. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  504. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  505. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  506. package/deps/librdkafka/tests/performance_plot.py +115 -0
  507. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  508. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  509. package/deps/librdkafka/tests/requirements.txt +2 -0
  510. package/deps/librdkafka/tests/run-all-tests.sh +81 -0
  511. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  512. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  513. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  514. package/deps/librdkafka/tests/run-test.sh +141 -0
  515. package/deps/librdkafka/tests/rusage.c +249 -0
  516. package/deps/librdkafka/tests/sasl_test.py +289 -0
  517. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  518. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  519. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  520. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  521. package/deps/librdkafka/tests/share_telemetry_verify/share-otel-collector-config.yaml +28 -0
  522. package/deps/librdkafka/tests/sockem.c +801 -0
  523. package/deps/librdkafka/tests/sockem.h +85 -0
  524. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  525. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  526. package/deps/librdkafka/tests/test.c +8376 -0
  527. package/deps/librdkafka/tests/test.conf.example +27 -0
  528. package/deps/librdkafka/tests/test.h +1150 -0
  529. package/deps/librdkafka/tests/testcpp.cpp +131 -0
  530. package/deps/librdkafka/tests/testcpp.h +388 -0
  531. package/deps/librdkafka/tests/testshared.h +416 -0
  532. package/deps/librdkafka/tests/tools/README.md +4 -0
  533. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  534. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  535. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  536. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  537. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  538. package/deps/librdkafka/tests/trivup/trivup-0.15.0.tar.gz +0 -0
  539. package/deps/librdkafka/tests/until-fail.sh +87 -0
  540. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  541. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  542. package/deps/librdkafka/vcpkg.json +23 -0
  543. package/deps/librdkafka/win32/README.md +5 -0
  544. package/deps/librdkafka/win32/build-package.bat +3 -0
  545. package/deps/librdkafka/win32/build.bat +19 -0
  546. package/deps/librdkafka/win32/common.vcxproj +84 -0
  547. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  548. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  549. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  550. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  551. package/deps/librdkafka/win32/librdkafka.vcxproj +282 -0
  552. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  553. package/deps/librdkafka/win32/msbuild.ps1 +58 -0
  554. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  555. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  556. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  557. package/deps/librdkafka/win32/push-package.bat +4 -0
  558. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  559. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  560. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  561. package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
  562. package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
  563. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  564. package/deps/librdkafka/win32/tests/tests.vcxproj +278 -0
  565. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  566. package/deps/librdkafka/win32/wingetopt.c +564 -0
  567. package/deps/librdkafka/win32/wingetopt.h +101 -0
  568. package/deps/librdkafka/win32/wintime.h +33 -0
  569. package/deps/librdkafka.gyp +83 -0
  570. package/deps/windows-install.py +80 -0
  571. package/index.d.ts +3 -0
  572. package/lib/admin.js +732 -0
  573. package/lib/client.js +679 -0
  574. package/lib/error.js +501 -0
  575. package/lib/index.js +8 -0
  576. package/lib/kafka-consumer-stream.js +399 -0
  577. package/lib/kafka-consumer.js +798 -0
  578. package/lib/kafkajs/_admin.js +1052 -0
  579. package/lib/kafkajs/_common.js +887 -0
  580. package/lib/kafkajs/_consumer.js +2156 -0
  581. package/lib/kafkajs/_consumer_cache.js +310 -0
  582. package/lib/kafkajs/_error.js +298 -0
  583. package/lib/kafkajs/_kafka.js +125 -0
  584. package/lib/kafkajs/_linked-list.js +220 -0
  585. package/lib/kafkajs/_producer.js +863 -0
  586. package/lib/kafkajs/index.js +5 -0
  587. package/lib/producer/high-level-producer.js +400 -0
  588. package/lib/producer-stream.js +337 -0
  589. package/lib/producer.js +405 -0
  590. package/lib/rdkafka.js +44 -0
  591. package/lib/tools/ref-counter.js +53 -0
  592. package/lib/topic-partition.js +91 -0
  593. package/lib/topic.js +43 -0
  594. package/lib/util.js +55 -0
  595. package/librdkafka.js +12 -0
  596. package/package.json +85 -0
  597. package/shim/source_location +54 -0
  598. package/src/admin.cc +1597 -0
  599. package/src/admin.h +112 -0
  600. package/src/binding.cc +76 -0
  601. package/src/binding.h +25 -0
  602. package/src/callbacks.cc +676 -0
  603. package/src/callbacks.h +302 -0
  604. package/src/common.cc +1628 -0
  605. package/src/common.h +192 -0
  606. package/src/config.cc +219 -0
  607. package/src/config.h +61 -0
  608. package/src/connection.cc +703 -0
  609. package/src/connection.h +117 -0
  610. package/src/errors.cc +119 -0
  611. package/src/errors.h +60 -0
  612. package/src/kafka-consumer.cc +1539 -0
  613. package/src/kafka-consumer.h +147 -0
  614. package/src/producer.cc +917 -0
  615. package/src/producer.h +124 -0
  616. package/src/topic.cc +173 -0
  617. package/src/topic.h +54 -0
  618. package/src/workers.cc +1714 -0
  619. package/src/workers.h +690 -0
  620. package/types/config.d.ts +1269 -0
  621. package/types/errors.d.ts +373 -0
  622. package/types/kafkajs.d.ts +568 -0
  623. package/types/rdkafka.d.ts +571 -0
  624. package/util/configure.js +32 -0
  625. package/util/generate-docs.sh +18 -0
  626. package/util/get-env.js +6 -0
  627. package/util/test-compile.js +11 -0
  628. package/util/test-producer-delivery.js +100 -0
@@ -0,0 +1,1445 @@
1
+ /*
2
+ * librdkafka - The Apache Kafka C/C++ library
3
+ *
4
+ * Copyright (c) 2026, Confluent Inc.
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ * this list of conditions and the following disclaimer in the documentation
14
+ * and/or other materials provided with the distribution.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+ #include "rdkafka_int.h"
29
+ #include "rdkafka_metadata.h"
30
+ #include "rdkafka_share_acknowledgement.h"
31
+
32
+ rd_kafka_share_ack_batch_entry_t *
33
+ rd_kafka_share_ack_batch_entry_new(int64_t start_offset,
34
+ int64_t end_offset,
35
+ int32_t types_cnt,
36
+ int16_t delivery_count) {
37
+ rd_kafka_share_ack_batch_entry_t *entry;
38
+
39
+ entry = rd_calloc(1, sizeof(*entry));
40
+ entry->start_offset = start_offset;
41
+ entry->end_offset = end_offset;
42
+ entry->size = end_offset - start_offset + 1;
43
+ entry->types_cnt = types_cnt;
44
+ entry->delivery_count = delivery_count;
45
+ entry->types =
46
+ rd_calloc((size_t)types_cnt,
47
+ sizeof(rd_kafka_share_internal_acknowledgement_type));
48
+ return entry;
49
+ }
50
+
51
+ void rd_kafka_share_ack_batch_entry_destroy(
52
+ rd_kafka_share_ack_batch_entry_t *entry) {
53
+ if (!entry)
54
+ return;
55
+ rd_free(entry->types);
56
+ rd_free(entry);
57
+ }
58
+
59
+ static void rd_kafka_share_ack_batch_entry_destroy_free(void *ptr) {
60
+ rd_kafka_share_ack_batch_entry_destroy(
61
+ (rd_kafka_share_ack_batch_entry_t *)ptr);
62
+ }
63
+
64
+ rd_bool_t
65
+ rd_kafka_share_acknowledgement_mode_is_implicit(rd_kafka_share_t *rkshare) {
66
+ return rkshare->rkshare_rk->rk_conf.share.share_acknowledgement_mode &&
67
+ !strcmp(rkshare->rkshare_rk->rk_conf.share
68
+ .share_acknowledgement_mode,
69
+ "implicit");
70
+ }
71
+
72
+ rd_bool_t
73
+ rd_kafka_share_acknowledgement_mode_is_explicit(rd_kafka_share_t *rkshare) {
74
+ return rkshare->rkshare_rk->rk_conf.share.share_acknowledgement_mode &&
75
+ !strcmp(rkshare->rkshare_rk->rk_conf.share
76
+ .share_acknowledgement_mode,
77
+ "explicit");
78
+ }
79
+
80
+ void rd_kafka_share_acknowledge_all_if_implicit(rd_kafka_share_t *rkshare) {
81
+ if (rd_kafka_share_acknowledgement_mode_is_implicit(rkshare))
82
+ rd_kafka_share_ack_all(rkshare);
83
+ }
84
+
85
+ rd_kafka_error_t *
86
+ rd_kafka_share_ensure_all_acknowledged_if_explicit(rd_kafka_share_t *rkshare) {
87
+ if (rd_kafka_share_acknowledgement_mode_is_explicit(rkshare) &&
88
+ rkshare->rkshare_unacked_cnt > 0)
89
+ return rd_kafka_error_new(
90
+ RD_KAFKA_RESP_ERR__STATE,
91
+ "%" PRId64
92
+ " records from previous poll have not "
93
+ "been acknowledged",
94
+ rkshare->rkshare_unacked_cnt);
95
+ return NULL;
96
+ }
97
+
98
+ rd_kafka_share_ack_batch_entry_t *rd_kafka_share_ack_batch_entry_copy(
99
+ const rd_kafka_share_ack_batch_entry_t *src) {
100
+ rd_kafka_share_ack_batch_entry_t *dst;
101
+
102
+ dst = rd_kafka_share_ack_batch_entry_new(
103
+ src->start_offset, src->end_offset, src->types_cnt,
104
+ src->delivery_count);
105
+ memcpy(dst->types, src->types,
106
+ (size_t)src->types_cnt *
107
+ sizeof(rd_kafka_share_internal_acknowledgement_type));
108
+ return dst;
109
+ }
110
+
111
+ static void *rd_kafka_share_ack_batch_entry_copy_void(const void *elem,
112
+ void *opaque) {
113
+ return rd_kafka_share_ack_batch_entry_copy(
114
+ (const rd_kafka_share_ack_batch_entry_t *)elem);
115
+ }
116
+
117
+ rd_kafka_share_ack_batches_t *rd_kafka_share_ack_batches_new_empty(void) {
118
+ return rd_kafka_share_ack_batches_new(NULL, 0, 0);
119
+ }
120
+
121
+ rd_kafka_share_ack_batches_t *
122
+ rd_kafka_share_ack_batches_new(rd_kafka_topic_partition_t *rktpar,
123
+ int32_t response_leader_id,
124
+ int64_t response_acquired_offsets_count) {
125
+ rd_kafka_share_ack_batches_t *batches;
126
+
127
+ batches = rd_calloc(1, sizeof(*batches));
128
+ batches->rktpar = rktpar;
129
+ batches->response_leader_id = response_leader_id;
130
+ batches->response_acquired_offsets_count =
131
+ response_acquired_offsets_count;
132
+ rd_list_init(&batches->entries, 0,
133
+ rd_kafka_share_ack_batch_entry_destroy_free);
134
+ return batches;
135
+ }
136
+
137
+ void rd_kafka_share_ack_batches_destroy(rd_kafka_share_ack_batches_t *batches) {
138
+ rd_list_destroy(&batches->entries);
139
+ if (batches->rktpar)
140
+ rd_kafka_topic_partition_destroy(batches->rktpar);
141
+ rd_free(batches);
142
+ }
143
+
144
+ void rd_kafka_share_ack_batches_destroy_free(void *ptr) {
145
+ rd_kafka_share_ack_batches_destroy((rd_kafka_share_ack_batches_t *)ptr);
146
+ }
147
+
148
+ rd_kafka_share_ack_batches_t *
149
+ rd_kafka_share_ack_batches_copy(const rd_kafka_share_ack_batches_t *src) {
150
+ rd_kafka_share_ack_batches_t *dst;
151
+
152
+ dst = rd_kafka_share_ack_batches_new(
153
+ src->rktpar ? rd_kafka_topic_partition_copy(src->rktpar) : NULL,
154
+ src->response_leader_id, src->response_acquired_offsets_count);
155
+
156
+ /* Deep copy all entries and preserve flags (e.g., RD_LIST_F_SORTED) */
157
+ rd_list_copy_to(&dst->entries, &src->entries,
158
+ rd_kafka_share_ack_batch_entry_copy_void, NULL);
159
+ dst->entries.rl_flags = src->entries.rl_flags;
160
+ return dst;
161
+ }
162
+
163
+ void *rd_kafka_share_ack_batches_copy_void(const void *elem, void *opaque) {
164
+ return rd_kafka_share_ack_batches_copy(
165
+ (const rd_kafka_share_ack_batches_t *)elem);
166
+ }
167
+
168
+ /**
169
+ * @brief Transfer inflight acks from response RKO into rkshare's inflight map.
170
+ *
171
+ * Takes each batch from the response's inflight_acks list and stores it in
172
+ * the map (key = topic-partition). Ownership is transferred; the response
173
+ * RKO must not free these when destroyed.
174
+ * In the future, the map will be cleared per partition after acks are sent.
175
+ *
176
+ * @param rkshare Share consumer handle
177
+ * @param response_rko The share fetch response RKO containing inflight_acks
178
+ */
179
+ void rd_kafka_share_build_inflight_acks_map(rd_kafka_share_t *rkshare,
180
+ rd_kafka_op_t *response_rko) {
181
+ rd_list_t *list =
182
+ response_rko->rko_u.share_fetch_response.inflight_acks;
183
+
184
+ while (rd_list_cnt(list) > 0) {
185
+ rd_kafka_share_ack_batches_t *batches = rd_list_pop(list);
186
+ rd_kafka_topic_partition_t *key;
187
+ rd_kafka_share_ack_batch_entry_t *entry;
188
+ int i, k;
189
+
190
+ rd_dassert(batches->rktpar != NULL);
191
+
192
+ key = rd_kafka_topic_partition_new_with_id_and_name(
193
+ rd_kafka_topic_partition_get_topic_id(batches->rktpar),
194
+ batches->rktpar->topic, batches->rktpar->partition);
195
+
196
+ /* Each topic-partition is always a new entry (no overwrites).
197
+ */
198
+ RD_MAP_SET(&rkshare->rkshare_inflight_acks, key, batches);
199
+
200
+ /* Count ACQUIRED types for unacked tracking */
201
+ RD_LIST_FOREACH(entry, &batches->entries, i) {
202
+ for (k = 0; k < entry->types_cnt; k++) {
203
+ if (entry->types[k] ==
204
+ RD_KAFKA_SHARE_INTERNAL_ACK_ACQUIRED)
205
+ rkshare->rkshare_unacked_cnt++;
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ /**
212
+ * @brief Create a new collated batch entry with a single acknowledgement type.
213
+ *
214
+ * Creates an entry where size=1 and types[0] holds the single ack type
215
+ * for the entire offset range [start_offset, end_offset].
216
+ *
217
+ * @param start_offset First offset in the range
218
+ * @param end_offset Last offset in the range (inclusive)
219
+ * @param type The acknowledgement type for the entire range
220
+ *
221
+ * @returns Newly allocated collated entry (caller must free)
222
+ */
223
+ static rd_kafka_share_ack_batch_entry_t *
224
+ rd_kafka_share_ack_batch_entry_collated_new(
225
+ int64_t start_offset,
226
+ int64_t end_offset,
227
+ rd_kafka_share_internal_acknowledgement_type type,
228
+ int16_t delivery_count) {
229
+ rd_kafka_share_ack_batch_entry_t *entry =
230
+ rd_kafka_share_ack_batch_entry_new(start_offset, end_offset, 1,
231
+ delivery_count);
232
+ entry->types[0] = type;
233
+ return entry;
234
+ }
235
+
236
+ /**
237
+ * @brief Implicit acknowledgement: convert all ACQUIRED types to ACCEPT.
238
+ *
239
+ * In implicit ack mode, all records delivered to the application are
240
+ * automatically acknowledged as ACCEPT on the next poll(). This function
241
+ * walks through all entries in the inflight map and changes ACQUIRED
242
+ * types to ACCEPT so that rd_kafka_share_build_ack_details() will
243
+ * extract them for sending to the broker.
244
+ *
245
+ * @param rkshare Share consumer handle
246
+ */
247
+ void rd_kafka_share_ack_all(rd_kafka_share_t *rkshare) {
248
+ const rd_kafka_topic_partition_t *tp_key;
249
+ rd_kafka_share_ack_batches_t *inflight_batches;
250
+
251
+ RD_MAP_FOREACH(tp_key, inflight_batches,
252
+ &rkshare->rkshare_inflight_acks) {
253
+ rd_kafka_share_ack_batch_entry_t *entry;
254
+ int i;
255
+ rd_kafka_dbg(rkshare->rkshare_rk, CGRP, "SHAREACK",
256
+ "Implicit ack: converting ACQUIRED to ACCEPT "
257
+ "for %s [%" PRId32 "]",
258
+ tp_key->topic, tp_key->partition);
259
+ RD_LIST_FOREACH(entry, &inflight_batches->entries, i) {
260
+ int k;
261
+ for (k = 0; k < entry->types_cnt; k++) {
262
+ if (entry->types[k] ==
263
+ RD_KAFKA_SHARE_INTERNAL_ACK_ACQUIRED)
264
+ entry->types[k] =
265
+ RD_KAFKA_SHARE_INTERNAL_ACK_ACCEPT;
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * @brief Free an ack details batch, its entries, and its owned rktpar.
273
+ *
274
+ * Used as rd_list_t free callback for ack_details output lists where
275
+ * each batch owns a copy of its rktpar.
276
+ */
277
+ static void rd_kafka_share_ack_details_batch_destroy(void *ptr) {
278
+ rd_kafka_share_ack_batches_t *batch = ptr;
279
+ rd_kafka_share_ack_batches_destroy(batch);
280
+ }
281
+
282
+ /**
283
+ * @brief Find an existing ack batch for the same topic-partition in a list.
284
+ *
285
+ * @param ack_list List of rd_kafka_share_ack_batches_t*
286
+ * @param rktpar Topic-partition to match (by topic id and partition)
287
+ *
288
+ * @returns Matching batch, or NULL if not found.
289
+ * @locality main thread
290
+ */
291
+ rd_kafka_share_ack_batches_t *
292
+ rd_kafka_share_find_ack_batch(rd_list_t *ack_list,
293
+ const rd_kafka_topic_partition_t *rktpar) {
294
+ rd_kafka_share_ack_batches_t *existing;
295
+ int i;
296
+
297
+ RD_LIST_FOREACH(existing, ack_list, i) {
298
+ if (rd_kafka_topic_partition_by_id_cmp(existing->rktpar,
299
+ rktpar) == 0)
300
+ return existing;
301
+ }
302
+ return NULL;
303
+ }
304
+
305
+ /**
306
+ * @brief Find an existing ack batch by topic id and partition.
307
+ *
308
+ * Same as rd_kafka_share_find_ack_batch but takes topic_id and
309
+ * partition directly to avoid allocating a temporary
310
+ * rd_kafka_topic_partition_t for the lookup.
311
+ *
312
+ * TODO KIP-932: Merge this with rd_kafka_share_find_ack_batch and use
313
+ * rd_list_find with binary search once ack_list is kept sorted.
314
+ *
315
+ * @param ack_list List of rd_kafka_share_ack_batches_t*.
316
+ * @param topic_id Topic UUID to match.
317
+ * @param partition Partition id to match.
318
+ *
319
+ * @returns Matching batch, or NULL if not found.
320
+ */
321
+ rd_kafka_share_ack_batches_t *
322
+ rd_kafka_share_find_ack_batch_by_id(rd_list_t *ack_list,
323
+ rd_kafka_Uuid_t topic_id,
324
+ int32_t partition) {
325
+ rd_kafka_share_ack_batches_t *existing;
326
+ int i;
327
+
328
+ RD_LIST_FOREACH(existing, ack_list, i) {
329
+ if (existing->rktpar->partition == partition &&
330
+ !rd_kafka_Uuid_cmp(
331
+ rd_kafka_topic_partition_get_topic_id(existing->rktpar),
332
+ topic_id))
333
+ return existing;
334
+ }
335
+ return NULL;
336
+ }
337
+
338
+ /**
339
+ * @brief Reply to a SHARE_FETCH op with an error, propagating the
340
+ * error to each batch in ack_details.
341
+ *
342
+ * On top-level error (err != 0):
343
+ * - If err is BAD_MSG / __UNDERFLOW (wire-level parse failure):
344
+ * override every batch with INVALID_RECORD_STATE so the consumer
345
+ * treats these as "outcome unknown" and re-acquires; any
346
+ * per-partition err the parser may have written before failing
347
+ * could be a misaligned read and is no longer trustworthy.
348
+ * - Otherwise: propagate err to each batch still at _IN_PROGRESS,
349
+ * preserving any deliberately pre-set err and any per-partition
350
+ * err already written by the parser.
351
+ *
352
+ * On success (err == 0), the per-partition errors have already been
353
+ * set by the response parser and we leave ack_details untouched.
354
+ */
355
+ void rd_kafka_share_fetch_op_reply_and_update_ack_details_with_err(
356
+ rd_kafka_op_t *rko,
357
+ rd_kafka_resp_err_t err) {
358
+ if (err && rko->rko_u.share_fetch.ack_details) {
359
+ rd_kafka_share_ack_batches_t *batch;
360
+ int i;
361
+
362
+ if (likely(err != RD_KAFKA_RESP_ERR__BAD_MSG &&
363
+ err != RD_KAFKA_RESP_ERR__UNDERFLOW)) {
364
+
365
+ /* Propagate top-level err to each batch in
366
+ * ack_details, but only override the _IN_PROGRESS
367
+ * sentinel. This preserves:
368
+ * - Deliberately pre-set err (e.g.
369
+ * INVALID_SHARE_SESSION_EPOCH from the
370
+ * epoch-0 strip path).
371
+ * - Per-partition err already written by the
372
+ * parser. */
373
+ RD_LIST_FOREACH(batch,
374
+ rko->rko_u.share_fetch.ack_details, i) {
375
+ if (batch->rktpar->err ==
376
+ RD_KAFKA_RESP_ERR__IN_PROGRESS)
377
+ batch->rktpar->err = err;
378
+ }
379
+ } else {
380
+ /* Wire-level parse failure: response framing is
381
+ * untrusted, so any per-partition err the parser
382
+ * may have written before failing could be a
383
+ * misaligned read. */
384
+ RD_LIST_FOREACH(batch,
385
+ rko->rko_u.share_fetch.ack_details, i) {
386
+ batch->rktpar->err = err;
387
+ }
388
+ }
389
+ }
390
+ rd_kafka_op_reply(rko, err);
391
+ }
392
+
393
+ /**
394
+ * @brief Whether the leader cached for the partition has diverged
395
+ * from the leader at which \p batch's records were acquired.
396
+ */
397
+ static rd_bool_t
398
+ rd_kafka_share_ack_batch_leader_stale(rd_kafka_share_ack_batches_t *batch,
399
+ int32_t current_leader_id) {
400
+ return current_leader_id != batch->response_leader_id;
401
+ }
402
+
403
+ /**
404
+ * @brief Resolve the leader broker for an ack batch, or fail the
405
+ * batch locally with the appropriate error code.
406
+ *
407
+ * Snapshots (rktp_leader, rktp_leader_id) under rktp_lock to
408
+ * avoid racing with concurrent leader-state clearing on the
409
+ * broker thread. On success, returns a kept broker handle;
410
+ * the caller MUST rd_kafka_broker_destroy() it after use.
411
+ * On failure returns NULL with \p *errp set.
412
+ *
413
+ * @locality main thread
414
+ */
415
+ static rd_kafka_broker_t *rd_kafka_share_ack_batch_resolve_leader_or_fail_acks(
416
+ rd_kafka_t *rk,
417
+ rd_kafka_share_ack_batches_t *batch,
418
+ rd_kafka_resp_err_t *errp) {
419
+ rd_kafka_toppar_t *rktp;
420
+ rd_kafka_broker_t *leader_rkb;
421
+ int32_t leader_id;
422
+
423
+ rktp = rd_kafka_topic_partition_toppar(rk, batch->rktpar);
424
+
425
+ /* Defensive: in production the rktp is always attached to the
426
+ * batch by the ShareFetch reply parser via toppar_keep, so
427
+ * this branch should never fire. Trigger a cluster-wide
428
+ * metadata refresh to recover if it ever does. */
429
+ if (unlikely(!rktp)) {
430
+ rd_kafka_dbg(rk, CGRP, "SHARE",
431
+ "Ack batch for partition %" PRId32
432
+ " dropped: toppar not found "
433
+ "(should be unreachable)",
434
+ batch->rktpar->partition);
435
+ rd_kafka_metadata_refresh_known_topics(
436
+ rk, NULL, rd_false /*don't force*/,
437
+ "shareack toppar not found");
438
+ *errp = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
439
+ return NULL;
440
+ }
441
+
442
+ /* Snapshot (rktp_leader, rktp_leader_id) under rktp_lock to
443
+ * avoid racing with concurrent leader-state clearing on the
444
+ * broker thread. */
445
+ rd_kafka_toppar_lock(rktp);
446
+ leader_rkb = rktp->rktp_leader;
447
+ leader_id = rktp->rktp_leader_id;
448
+ if (leader_rkb)
449
+ rd_kafka_broker_keep(leader_rkb);
450
+ rd_kafka_toppar_unlock(rktp);
451
+
452
+ /* Cached leader differs from the leader at which records
453
+ * were acquired. The session for these records lives on the
454
+ * original broker which no longer leads this partition. No
455
+ * metadata refresh - the cached current leader is already
456
+ * the new one (that's how this check fired). */
457
+ if (unlikely(rd_kafka_share_ack_batch_leader_stale(batch, leader_id))) {
458
+ rd_kafka_dbg(rk, CGRP, "SHARE",
459
+ "Ack batch for %s [%" PRId32
460
+ "] dropped locally: leader changed "
461
+ "since records were acquired "
462
+ "(was %" PRId32 ", now %" PRId32 ")",
463
+ batch->rktpar->topic, batch->rktpar->partition,
464
+ batch->response_leader_id, leader_id);
465
+ if (leader_rkb)
466
+ rd_kafka_broker_destroy(leader_rkb);
467
+ *errp = RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER;
468
+ return NULL;
469
+ }
470
+
471
+ /* Defensive: no cached leader. Unreachable in practice
472
+ * because leader-stale fires first when the cached leader id
473
+ * is -1, but kept to make the intent explicit and survive
474
+ * future invariant changes. Trigger a metadata refresh and
475
+ * surface NOT_LEADER_OR_FOLLOWER. */
476
+ if (unlikely(!leader_rkb)) {
477
+ rd_kafka_dbg(rk, CGRP, "SHARE",
478
+ "Ack batch for %s [%" PRId32
479
+ "] dropped: no cached leader, "
480
+ "triggering metadata refresh",
481
+ batch->rktpar->topic, batch->rktpar->partition);
482
+ rd_kafka_toppar_leader_unavailable(
483
+ rktp, "shareack", RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER);
484
+ *errp = RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER;
485
+ return NULL;
486
+ }
487
+
488
+ /* Cached leader broker is being decommissioned or the
489
+ * instance is terminating. Surface NOT_LEADER_OR_FOLLOWER and
490
+ * trigger a metadata refresh so the next request finds the
491
+ * new leader. */
492
+ if (unlikely(rd_kafka_broker_or_instance_terminating(leader_rkb))) {
493
+ rd_kafka_dbg(
494
+ rk, CGRP, "SHARE",
495
+ "Ack batch for %s [%" PRId32 "] dropped: broker %" PRId32
496
+ " is terminating, "
497
+ "triggering metadata refresh",
498
+ batch->rktpar->topic, batch->rktpar->partition, leader_id);
499
+ rd_kafka_toppar_leader_unavailable(
500
+ rktp, "shareack", RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER);
501
+ rd_kafka_broker_destroy(leader_rkb);
502
+ *errp = RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER;
503
+ return NULL;
504
+ }
505
+
506
+ *errp = RD_KAFKA_RESP_ERR_NO_ERROR;
507
+ return leader_rkb;
508
+ }
509
+
510
+
511
+ /**
512
+ * @brief Segregate sync ack batches by partition leader into
513
+ * each broker's pending_commit_sync list.
514
+ *
515
+ * Phase 1 of sync dispatch: puts ALL acks into rkb_pending_commit_sync
516
+ * regardless of whether the broker is free or busy. Updates the
517
+ * commit_sync results for partitions with no available leader.
518
+ *
519
+ * @param rk Client instance.
520
+ * @param rkcg Consumer group handle.
521
+ * @param ack_batches List of ack batches from the SYNC_FANOUT op.
522
+ * Elements are moved to broker lists; container destroyed.
523
+ * @param abs_timeout Absolute timeout for the commit_sync request.
524
+ *
525
+ * @locality main thread
526
+ */
527
+ void rd_kafka_share_segregate_sync_acks_by_leader(rd_kafka_t *rk,
528
+ rd_kafka_cgrp_t *rkcg,
529
+ rd_list_t *ack_batches,
530
+ rd_ts_t abs_timeout) {
531
+ rd_kafka_share_ack_batches_t *batch;
532
+ int batch_cnt = rd_list_cnt(ack_batches);
533
+
534
+ while ((batch = rd_list_pop(ack_batches))) {
535
+ rd_kafka_broker_t *leader_rkb;
536
+ rd_kafka_share_ack_batches_t *existing;
537
+ rd_kafka_topic_partition_t *result_rktpar;
538
+ rd_kafka_resp_err_t fail_err;
539
+
540
+ leader_rkb =
541
+ rd_kafka_share_ack_batch_resolve_leader_or_fail_acks(
542
+ rk, batch, &fail_err);
543
+ if (!leader_rkb) {
544
+ result_rktpar = rd_kafka_topic_partition_list_find(
545
+ rkcg->rkcg_commit_sync_request.results,
546
+ batch->rktpar->topic, batch->rktpar->partition);
547
+ if (result_rktpar)
548
+ result_rktpar->err = fail_err;
549
+ else
550
+ rd_kafka_dbg(rk, CGRP, "SHARE",
551
+ "Sync ack batch for %s [%" PRId32
552
+ "]: partition not found in "
553
+ "commit_sync results",
554
+ batch->rktpar->topic,
555
+ batch->rktpar->partition);
556
+
557
+ rd_kafka_share_enqueue_ack_commit_cb_op(rk, batch,
558
+ fail_err);
559
+ rd_kafka_share_ack_batches_destroy(batch);
560
+ continue;
561
+ }
562
+
563
+ /* Put all acks into pending_commit_sync */
564
+ if (!leader_rkb->rkb_pending_commit_sync.sync_ack_details)
565
+ leader_rkb->rkb_pending_commit_sync.sync_ack_details =
566
+ rd_list_new(
567
+ batch_cnt,
568
+ rd_kafka_share_ack_batches_destroy_free);
569
+
570
+ existing = rd_kafka_share_find_ack_batch(
571
+ leader_rkb->rkb_pending_commit_sync.sync_ack_details,
572
+ batch->rktpar);
573
+ if (existing) {
574
+ rd_kafka_share_ack_batch_entry_t *entry;
575
+ int j;
576
+ RD_LIST_FOREACH(entry, &batch->entries, j) {
577
+ rd_list_add(
578
+ &existing->entries,
579
+ rd_kafka_share_ack_batch_entry_copy(entry));
580
+ }
581
+ rd_list_sort(&existing->entries,
582
+ rd_kafka_share_ack_entries_sort_cmp_ptr);
583
+ rd_kafka_share_ack_batches_destroy(batch);
584
+ } else {
585
+ rd_list_add(leader_rkb->rkb_pending_commit_sync
586
+ .sync_ack_details,
587
+ batch);
588
+ }
589
+
590
+ leader_rkb->rkb_pending_commit_sync.abs_timeout = abs_timeout;
591
+ leader_rkb->rkb_pending_commit_sync.commit_sync_request_id =
592
+ rkcg->rkcg_commit_sync_request.id;
593
+
594
+ rd_kafka_broker_destroy(leader_rkb);
595
+ }
596
+
597
+ rd_list_destroy(ack_batches);
598
+ }
599
+
600
+
601
+ /**
602
+ * @brief Segregate ack batches from a FANOUT op by partition leader.
603
+ *
604
+ * For each ack batch, looks up the current leader broker via the
605
+ * toppar reference in batch->rktpar, and merges the batch into that
606
+ * broker's rkb_share_async_ack_details list. If the broker already
607
+ * has cached acks for the same topic-partition, the entries are
608
+ * appended to the existing batch.
609
+ *
610
+ * @param rk Client instance
611
+ * @param ack_batches List of rd_kafka_share_ack_batches_t* from FANOUT op.
612
+ * Elements whose leader is found are moved to broker
613
+ * ack_details; remaining elements are not freed.
614
+ *
615
+ * @locality main thread
616
+ */
617
+ void rd_kafka_share_segregate_acks_by_leader(rd_kafka_t *rk,
618
+ rd_list_t *ack_batches) {
619
+ rd_kafka_share_ack_batches_t *batch;
620
+ int batch_cnt = rd_list_cnt(ack_batches);
621
+
622
+ while ((batch = rd_list_pop(ack_batches))) {
623
+ rd_kafka_broker_t *leader_rkb;
624
+ rd_kafka_share_ack_batches_t *existing;
625
+ rd_kafka_resp_err_t fail_err;
626
+
627
+ leader_rkb =
628
+ rd_kafka_share_ack_batch_resolve_leader_or_fail_acks(
629
+ rk, batch, &fail_err);
630
+ if (!leader_rkb) {
631
+ rd_kafka_share_enqueue_ack_commit_cb_op(rk, batch,
632
+ fail_err);
633
+ rd_kafka_share_ack_batches_destroy(batch);
634
+ continue;
635
+ }
636
+
637
+ /* Allocate list on first use with incoming batch count
638
+ * as initial capacity hint */
639
+ if (!leader_rkb->rkb_share_async_ack_details)
640
+ leader_rkb->rkb_share_async_ack_details = rd_list_new(
641
+ batch_cnt, rd_kafka_share_ack_batches_destroy_free);
642
+
643
+ /* Check if there's already a batch for this topic-partition.
644
+ * If so, merge entries; otherwise add as new. */
645
+ existing = rd_kafka_share_find_ack_batch(
646
+ leader_rkb->rkb_share_async_ack_details, batch->rktpar);
647
+
648
+ if (existing) {
649
+ /* Merge: deep-copy entries from new batch into
650
+ * existing, preserving order. The source batch
651
+ * is then fully destroyed (freeing its entries). */
652
+ rd_kafka_share_ack_batch_entry_t *entry;
653
+ int j;
654
+ RD_LIST_FOREACH(entry, &batch->entries, j) {
655
+ rd_list_add(
656
+ &existing->entries,
657
+ rd_kafka_share_ack_batch_entry_copy(entry));
658
+ }
659
+ rd_kafka_share_ack_batches_destroy(batch);
660
+ } else {
661
+ rd_list_add(leader_rkb->rkb_share_async_ack_details,
662
+ batch);
663
+ }
664
+
665
+ rd_kafka_broker_destroy(leader_rkb);
666
+ }
667
+ }
668
+
669
+ /**
670
+ * @brief Extract acknowledged (non-ACQUIRED) records from inflight map.
671
+ *
672
+ * Iterates through the inflight acknowledgement map and separates each
673
+ * entry's per-offset types into:
674
+ * - Non-ACQUIRED offsets: collated into ack_details for sending to broker
675
+ * (consecutive same-type offsets merged into single entry with 1 type)
676
+ * - ACQUIRED offsets: kept in the map as new entries (per-offset types)
677
+ *
678
+ * Map entries with no remaining ACQUIRED offsets are removed.
679
+ * If the map becomes empty after processing, it is cleared.
680
+ *
681
+ * @param rkshare Share consumer handle
682
+ * @returns Allocated list of rd_kafka_share_ack_batches_t*, or NULL if
683
+ * there are no ack details to send. Caller must destroy.
684
+ * TODO KIP-932: Change name.
685
+ */
686
+ rd_list_t *rd_kafka_share_build_ack_details(rd_kafka_share_t *rkshare) {
687
+ const rd_kafka_topic_partition_t *tp_key;
688
+ rd_kafka_share_ack_batches_t *inflight_batches;
689
+ rd_list_t keys_to_delete;
690
+ rd_list_t *ack_details = NULL;
691
+ int i;
692
+ rd_kafka_topic_partition_t *del_key;
693
+
694
+ rd_list_init(&keys_to_delete, 0, NULL);
695
+
696
+ rkshare->rkshare_unacked_cnt = 0;
697
+
698
+ RD_MAP_FOREACH(tp_key, inflight_batches,
699
+ &rkshare->rkshare_inflight_acks) {
700
+ rd_kafka_share_ack_batches_t *ack_batch = NULL;
701
+ rd_kafka_share_ack_batch_entry_t *entry;
702
+ rd_list_t new_entries;
703
+ int ei;
704
+
705
+ rd_kafka_dbg(rkshare->rkshare_rk, CGRP, "SHAREACK",
706
+ "Building ack details for %s [%" PRId32 "]",
707
+ tp_key->topic, tp_key->partition);
708
+
709
+ rd_list_init(&new_entries, 0,
710
+ rd_kafka_share_ack_batch_entry_destroy_free);
711
+
712
+ RD_LIST_FOREACH(entry, &inflight_batches->entries, ei) {
713
+ int64_t j = 0;
714
+
715
+ while (j < entry->types_cnt) {
716
+ rd_kafka_share_internal_acknowledgement_type
717
+ run_type = entry->types[j];
718
+ int64_t run_start = entry->start_offset + j;
719
+ int64_t k = j + 1;
720
+
721
+ /* Find end of consecutive same-type run */
722
+ while (k < entry->types_cnt &&
723
+ entry->types[k] == run_type)
724
+ k++;
725
+
726
+ int64_t run_end = entry->start_offset + k - 1;
727
+
728
+ if (run_type ==
729
+ RD_KAFKA_SHARE_INTERNAL_ACK_ACQUIRED) {
730
+ /* ACQUIRED: keep in map */
731
+ int32_t cnt = (int32_t)(k - j);
732
+ rd_kafka_share_ack_batch_entry_t
733
+ *new_entry =
734
+ rd_kafka_share_ack_batch_entry_new(
735
+ run_start, run_end, cnt,
736
+ entry->delivery_count);
737
+ int32_t m;
738
+ for (m = 0; m < cnt; m++)
739
+ new_entry->types[m] =
740
+ RD_KAFKA_SHARE_INTERNAL_ACK_ACQUIRED;
741
+ rd_list_add(&new_entries, new_entry);
742
+ rkshare->rkshare_unacked_cnt += cnt;
743
+ } else {
744
+ /* Non-ACQUIRED: add to ack_details
745
+ */
746
+ if (!ack_batch) {
747
+ ack_batch =
748
+ rd_kafka_share_ack_batches_new(
749
+ rd_kafka_topic_partition_copy(
750
+ inflight_batches
751
+ ->rktpar),
752
+ inflight_batches
753
+ ->response_leader_id,
754
+ 0);
755
+ /* Sentinel: no reply path
756
+ * has touched this batch
757
+ * yet. Distinct from
758
+ * INVALID_RECORD_STATE
759
+ * (set in buf callback)
760
+ * which means "reply
761
+ * received but partition
762
+ * missing from response".
763
+ * Defensive check in main
764
+ * reply handler converts
765
+ * any remaining
766
+ * _IN_PROGRESS to the
767
+ * top-level rko_err so
768
+ * silent-destroy paths
769
+ * (q_enq disabled queue,
770
+ * helper bypassed) don't
771
+ * leak the sentinel to
772
+ * the app. */
773
+ ack_batch->rktpar->err =
774
+ RD_KAFKA_RESP_ERR__IN_PROGRESS;
775
+ }
776
+ rd_kafka_dbg(
777
+ rkshare->rkshare_rk, CGRP,
778
+ "SHAREACK",
779
+ " Adding ack detail for offsets "
780
+ "[%" PRId64 " - %" PRId64
781
+ "] with type %d",
782
+ run_start, run_end, run_type);
783
+ /* Collated: 1 type for entire
784
+ * range */
785
+ rd_list_add(
786
+ &ack_batch->entries,
787
+ rd_kafka_share_ack_batch_entry_collated_new(
788
+ run_start, run_end, run_type,
789
+ entry->delivery_count));
790
+ }
791
+
792
+ j = k;
793
+ }
794
+ }
795
+
796
+ /**
797
+ * TODO KIP-932: Check if it can be optimized as these are
798
+ * internal thread operations and they should
799
+ * be as fast as possible as this will be called
800
+ * again and again.
801
+ */
802
+ if (rd_list_is_sorted(&new_entries,
803
+ rd_kafka_share_ack_entries_sort_cmp_ptr))
804
+ new_entries.rl_flags |= RD_LIST_F_SORTED;
805
+
806
+ /* Replace inflight entries with ACQUIRED-only entries */
807
+ rd_list_destroy(&inflight_batches->entries);
808
+ inflight_batches->entries = new_entries;
809
+
810
+ /* If no ACQUIRED offsets remain, mark for removal */
811
+ if (rd_list_cnt(&inflight_batches->entries) == 0) {
812
+ rd_kafka_topic_partition_t *del_key =
813
+ rd_kafka_topic_partition_new_with_id_and_name(
814
+ rd_kafka_topic_partition_get_topic_id(
815
+ inflight_batches->rktpar),
816
+ inflight_batches->rktpar->topic,
817
+ inflight_batches->rktpar->partition);
818
+ rd_list_add(&keys_to_delete, del_key);
819
+ }
820
+
821
+ if (ack_batch) {
822
+ if (!ack_details)
823
+ ack_details = rd_list_new(
824
+ 0,
825
+ rd_kafka_share_ack_details_batch_destroy);
826
+ rd_list_add(ack_details, ack_batch);
827
+ }
828
+ }
829
+
830
+ /* Remove map entries with no remaining ACQUIRED offsets */
831
+ RD_LIST_FOREACH(del_key, &keys_to_delete, i) {
832
+ RD_MAP_DELETE(&rkshare->rkshare_inflight_acks, del_key);
833
+ rd_kafka_topic_partition_destroy(del_key);
834
+ }
835
+ rd_list_destroy(&keys_to_delete);
836
+
837
+ /* Clear map if empty */
838
+ if (RD_MAP_CNT(&rkshare->rkshare_inflight_acks) == 0)
839
+ RD_MAP_CLEAR(&rkshare->rkshare_inflight_acks);
840
+
841
+ return ack_details;
842
+ }
843
+
844
+ /**
845
+ * @brief Update acknowledgement type for a specific offset within an entry.
846
+ *
847
+ * Handles the transition from ACQUIRED state by decrementing the unacked count.
848
+ *
849
+ * @param rkshare Share consumer handle.
850
+ * @param entry The batch entry containing the offset.
851
+ * @param idx Index within the entry's types array.
852
+ * @param type New acknowledgement type.
853
+ */
854
+ static void rd_kafka_share_update_acknowledgement_type(
855
+ rd_kafka_share_t *rkshare,
856
+ rd_kafka_share_ack_batch_entry_t *entry,
857
+ int64_t idx,
858
+ rd_kafka_share_AcknowledgeType_t type) {
859
+ /* Decrement unacked count when transitioning from ACQUIRED */
860
+ if (entry->types[idx] == RD_KAFKA_SHARE_INTERNAL_ACK_ACQUIRED)
861
+ rkshare->rkshare_unacked_cnt--;
862
+
863
+ /* Update the type */
864
+ entry->types[idx] = (rd_kafka_share_internal_acknowledgement_type)type;
865
+ }
866
+
867
+ /**
868
+ * @brief Comparator for sorting/checking entries by start_offset.
869
+ *
870
+ * Used with rd_list_sort() and rd_list_is_sorted().
871
+ */
872
+ int rd_kafka_share_ack_entries_sort_cmp_ptr(const void *_a, const void *_b) {
873
+ const rd_kafka_share_ack_batch_entry_t *a =
874
+ (const rd_kafka_share_ack_batch_entry_t *)_a;
875
+ const rd_kafka_share_ack_batch_entry_t *b =
876
+ (const rd_kafka_share_ack_batch_entry_t *)_b;
877
+
878
+ if (a->start_offset < b->start_offset)
879
+ return -1;
880
+ if (a->start_offset > b->start_offset)
881
+ return 1;
882
+ return 0;
883
+ }
884
+
885
+ /**
886
+ * @brief Comparator for finding an entry containing a given offset.
887
+ *
888
+ * Used with rd_list_find() for binary search when RD_LIST_F_SORTED is set.
889
+ *
890
+ * @param _offset Pointer to the offset being searched (int64_t *)
891
+ * @param _entry Pointer to the batch entry (rd_kafka_share_ack_batch_entry_t *)
892
+ *
893
+ * @returns negative if offset < entry->start_offset
894
+ * @returns positive if offset > entry->end_offset
895
+ * @returns 0 if offset is within [start_offset, end_offset]
896
+ */
897
+ static int rd_kafka_share_ack_entries_offset_find_cmp_ptr(const void *_offset,
898
+ const void *_entry) {
899
+ const int64_t *offset = (const int64_t *)_offset;
900
+ const rd_kafka_share_ack_batch_entry_t *entry =
901
+ (const rd_kafka_share_ack_batch_entry_t *)_entry;
902
+
903
+ if (*offset < entry->start_offset)
904
+ return -1;
905
+ if (*offset > entry->end_offset)
906
+ return 1;
907
+ return 0;
908
+ }
909
+
910
+ /**
911
+ * @brief Look up a batch entry containing the given offset.
912
+ *
913
+ * Finds the partition in the inflight_acks map and locates the entry
914
+ * containing the specified offset using binary search.
915
+ *
916
+ * @param rkshare Share consumer handle.
917
+ * @param topic Topic name.
918
+ * @param partition Partition id.
919
+ * @param offset Offset to find.
920
+ * @param entry_out Output parameter for the found entry.
921
+ * @param idx_out Output parameter for the index within the entry.
922
+ *
923
+ * @returns RD_KAFKA_RESP_ERR_NO_ERROR on success,
924
+ * RD_KAFKA_RESP_ERR__STATE if partition or offset not found.
925
+ */
926
+ static rd_kafka_resp_err_t
927
+ rd_kafka_share_find_ack_entry(rd_kafka_share_t *rkshare,
928
+ const char *topic,
929
+ int32_t partition,
930
+ int64_t offset,
931
+ rd_kafka_share_ack_batch_entry_t **entry_out,
932
+ int64_t *idx_out) {
933
+ rd_kafka_topic_partition_t *lookup_key;
934
+ rd_kafka_share_ack_batches_t *batches;
935
+ rd_kafka_share_ack_batch_entry_t *entry;
936
+
937
+ /* Find partition in inflight_acks map */
938
+ lookup_key = rd_kafka_topic_partition_new(topic, partition);
939
+ batches = RD_MAP_GET(&rkshare->rkshare_inflight_acks, lookup_key);
940
+ rd_kafka_topic_partition_destroy(lookup_key);
941
+ if (!batches)
942
+ return RD_KAFKA_RESP_ERR__STATE;
943
+
944
+ /* Find entry containing offset using binary search.
945
+ * Entries are sorted by start_offset and don't overlap. */
946
+ entry = rd_list_find(&batches->entries, &offset,
947
+ rd_kafka_share_ack_entries_offset_find_cmp_ptr);
948
+ if (!entry)
949
+ return RD_KAFKA_RESP_ERR__STATE;
950
+
951
+ *entry_out = entry;
952
+ *idx_out = offset - entry->start_offset;
953
+
954
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
955
+ }
956
+
957
+ /**
958
+ * @brief Internal acknowledge-offset helper.
959
+ *
960
+ * Performs argument validation, inflight-map lookup, and type update.
961
+ * Does NOT take the share consumer access gate — callers must call
962
+ * rd_kafka_share_acquire() / rd_kafka_share_release() around this.
963
+ */
964
+ static rd_kafka_resp_err_t
965
+ rd_kafka_share_acknowledge_offset0(rd_kafka_share_t *rkshare,
966
+ const char *topic,
967
+ int32_t partition,
968
+ int64_t offset,
969
+ rd_kafka_share_AcknowledgeType_t type) {
970
+ rd_kafka_share_ack_batch_entry_t *entry;
971
+ int64_t idx;
972
+ rd_kafka_resp_err_t err;
973
+
974
+ if (unlikely((err = rd_kafka_share_consumer_closed_err(rkshare))))
975
+ return err;
976
+
977
+ if (!topic || partition < 0 || offset < 0)
978
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
979
+
980
+ /* Explicit acknowledge APIs require explicit acknowledgement mode */
981
+ if (rd_kafka_share_acknowledgement_mode_is_implicit(rkshare))
982
+ return RD_KAFKA_RESP_ERR__STATE;
983
+
984
+ /* Validate type - ACCEPT, RELEASE, REJECT allowed */
985
+ if (type < RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT ||
986
+ type > RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_REJECT)
987
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
988
+
989
+ /* Find partition and entry containing the offset */
990
+ err = rd_kafka_share_find_ack_entry(rkshare, topic, partition, offset,
991
+ &entry, &idx);
992
+ if (err)
993
+ return err;
994
+
995
+ /* GAP records cannot be acknowledged */
996
+ if (entry->types[idx] == RD_KAFKA_SHARE_INTERNAL_ACK_GAP)
997
+ return RD_KAFKA_RESP_ERR__STATE;
998
+
999
+ rd_kafka_share_update_acknowledgement_type(rkshare, entry, idx, type);
1000
+
1001
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1002
+ }
1003
+
1004
+ rd_kafka_resp_err_t
1005
+ rd_kafka_share_acknowledge(rd_kafka_share_t *rkshare,
1006
+ const rd_kafka_message_t *rkmessage) {
1007
+ return rd_kafka_share_acknowledge_type(
1008
+ rkshare, rkmessage, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
1009
+ }
1010
+
1011
+ rd_kafka_resp_err_t
1012
+ rd_kafka_share_acknowledge_type(rd_kafka_share_t *rkshare,
1013
+ const rd_kafka_message_t *rkmessage,
1014
+ rd_kafka_share_AcknowledgeType_t type) {
1015
+ rd_kafka_resp_err_t err;
1016
+ rd_kafka_error_t *error = NULL;
1017
+
1018
+ if (unlikely((error = rd_kafka_share_acquire(rkshare)) != NULL)) {
1019
+ err = rd_kafka_error_code(error);
1020
+ rd_kafka_error_destroy(error);
1021
+ return err;
1022
+ }
1023
+
1024
+ if (!rkmessage) {
1025
+ err = RD_KAFKA_RESP_ERR__INVALID_ARG;
1026
+ goto done;
1027
+ }
1028
+
1029
+ if (!rkmessage->rkt) {
1030
+ err = RD_KAFKA_RESP_ERR__STATE;
1031
+ goto done;
1032
+ }
1033
+
1034
+ err = rd_kafka_share_acknowledge_offset0(
1035
+ rkshare, rd_kafka_topic_name(rkmessage->rkt), rkmessage->partition,
1036
+ rkmessage->offset, type);
1037
+
1038
+ done:
1039
+ rd_kafka_share_release(rkshare);
1040
+ return err;
1041
+ }
1042
+
1043
+ rd_kafka_resp_err_t
1044
+ rd_kafka_share_acknowledge_offset(rd_kafka_share_t *rkshare,
1045
+ const char *topic,
1046
+ int32_t partition,
1047
+ int64_t offset,
1048
+ rd_kafka_share_AcknowledgeType_t type) {
1049
+ rd_kafka_resp_err_t err;
1050
+ rd_kafka_error_t *error = NULL;
1051
+
1052
+ if (unlikely((error = rd_kafka_share_acquire(rkshare)) != NULL)) {
1053
+ err = rd_kafka_error_code(error);
1054
+ rd_kafka_error_destroy(error);
1055
+ return err;
1056
+ }
1057
+
1058
+ err = rd_kafka_share_acknowledge_offset0(rkshare, topic, partition,
1059
+ offset, type);
1060
+
1061
+ rd_kafka_share_release(rkshare);
1062
+ return err;
1063
+ }
1064
+
1065
+
1066
+ /**
1067
+ * @brief Initialize a partition offsets element with topicid,topic, partition,
1068
+ * and offsets.
1069
+ *
1070
+ * @param topic_id Topic UUID.
1071
+ * @param topic Topic name (will be duplicated).
1072
+ * @param partition Partition id.
1073
+ * @param offsets_cnt Number of offsets to allocate space for.
1074
+ */
1075
+ static rd_kafka_share_partition_offsets_t *
1076
+ rd_kafka_share_partition_offsets_new(rd_kafka_topic_partition_t *tp,
1077
+ size_t offsets_cnt) {
1078
+ rd_kafka_share_partition_offsets_t *elem;
1079
+ size_t size;
1080
+
1081
+ /* Allocate struct + flexible array in one allocation */
1082
+ size = sizeof(*elem) + (offsets_cnt * sizeof(int64_t));
1083
+ elem = rd_calloc(1, size);
1084
+
1085
+ elem->partition = rd_kafka_topic_partition_new_with_id_and_name(
1086
+ rd_kafka_topic_partition_get_topic_id(tp), tp->topic,
1087
+ tp->partition);
1088
+ elem->cnt = offsets_cnt;
1089
+
1090
+ return elem;
1091
+ }
1092
+
1093
+ /**
1094
+ * @brief Destroy a partition offsets element.
1095
+ *
1096
+ * @param elem Element to destroy.
1097
+ */
1098
+ static void rd_kafka_share_partition_offsets_destroy(
1099
+ rd_kafka_share_partition_offsets_t *elem) {
1100
+ if (!elem)
1101
+ return;
1102
+ rd_kafka_topic_partition_destroy(elem->partition);
1103
+ rd_free(elem);
1104
+ }
1105
+
1106
+ /**
1107
+ * @brief Allocate and initialize a partition offsets list with given capacity.
1108
+ *
1109
+ * @param capacity Number of elements to allocate space for.
1110
+ * @returns Newly allocated list, or NULL if capacity is 0.
1111
+ * Caller must destroy with
1112
+ * rd_kafka_share_partition_offsets_list_destroy().
1113
+ */
1114
+ static rd_kafka_share_partition_offsets_list_t *
1115
+ rd_kafka_share_partition_offsets_list_new(size_t capacity) {
1116
+ rd_kafka_share_partition_offsets_list_t *list;
1117
+ size_t size;
1118
+
1119
+ /* Allocate list + flexible array in one allocation */
1120
+ size = sizeof(*list) +
1121
+ (capacity * sizeof(rd_kafka_share_partition_offsets_t *));
1122
+ list = rd_calloc(1, size);
1123
+
1124
+ return list;
1125
+ }
1126
+
1127
+ rd_kafka_share_partition_offsets_list_t *
1128
+ rd_kafka_share_build_partition_offsets_list(
1129
+ rd_kafka_share_ack_batches_t *batches) {
1130
+ rd_kafka_share_partition_offsets_list_t *list;
1131
+ rd_kafka_share_partition_offsets_t *elem;
1132
+ rd_kafka_share_ack_batch_entry_t *entry;
1133
+ int total_offsets = 0;
1134
+ int offset_idx = 0;
1135
+ int j;
1136
+
1137
+ /* Count total offsets */
1138
+ RD_LIST_FOREACH(entry, &batches->entries, j) {
1139
+ total_offsets +=
1140
+ (int)(entry->end_offset - entry->start_offset + 1);
1141
+ }
1142
+
1143
+ list = rd_kafka_share_partition_offsets_list_new(1);
1144
+
1145
+ /* Allocate elements */
1146
+ elem = rd_kafka_share_partition_offsets_new(batches->rktpar,
1147
+ total_offsets);
1148
+
1149
+ list->cnt = 1;
1150
+ list->elems[0] = elem;
1151
+
1152
+ /* Fill offsets array */
1153
+ RD_LIST_FOREACH(entry, &batches->entries, j) {
1154
+ int64_t off;
1155
+ for (off = entry->start_offset; off <= entry->end_offset;
1156
+ off++) {
1157
+ elem->offsets[offset_idx++] = off;
1158
+ }
1159
+ }
1160
+
1161
+ return list;
1162
+ }
1163
+
1164
+
1165
+ void rd_kafka_share_enqueue_ack_commit_cb_op(
1166
+ rd_kafka_t *rk,
1167
+ rd_kafka_share_ack_batches_t *batches,
1168
+ rd_kafka_resp_err_t err) {
1169
+ rd_kafka_op_t *cb_rko;
1170
+ rd_kafka_share_partition_offsets_list_t *partitions;
1171
+
1172
+ /* Check if a runtime callback is registered.
1173
+ * Locality: main thread - reads flag owned by main thread.
1174
+ * No race because the flag is only modified by the main thread
1175
+ * via RD_KAFKA_OP_SHARE_ACK_COMMIT_CB_REGISTER op handler. */
1176
+ if (!rk->rk_rkshare ||
1177
+ !rk->rk_share_consumer.acknowledgement_commit_cb_registered)
1178
+ return;
1179
+
1180
+ partitions = rd_kafka_share_build_partition_offsets_list(batches);
1181
+
1182
+ cb_rko = rd_kafka_op_new(RD_KAFKA_OP_SHARE_ACK_COMMIT_CB_EXECUTE);
1183
+ cb_rko->rko_err = err;
1184
+ cb_rko->rko_u.share_ack_commit_cb_execute.partitions = partitions;
1185
+
1186
+ rd_kafka_q_enq(rk->rk_rep, cb_rko);
1187
+ }
1188
+
1189
+
1190
+ size_t rd_kafka_share_partition_offsets_list_count(
1191
+ const rd_kafka_share_partition_offsets_list_t *list) {
1192
+ return list->cnt;
1193
+ }
1194
+
1195
+
1196
+ const rd_kafka_share_partition_offsets_t *
1197
+ rd_kafka_share_partition_offsets_list_get(
1198
+ const rd_kafka_share_partition_offsets_list_t *list,
1199
+ size_t index) {
1200
+ return list->elems[index];
1201
+ }
1202
+
1203
+
1204
+ void rd_kafka_share_partition_offsets_list_destroy(
1205
+ rd_kafka_share_partition_offsets_list_t *list) {
1206
+ size_t i;
1207
+
1208
+ if (!list)
1209
+ return;
1210
+
1211
+ /* Free each element */
1212
+ for (i = 0; i < list->cnt; i++) {
1213
+ rd_kafka_share_partition_offsets_destroy(list->elems[i]);
1214
+ }
1215
+ /* Free the list (elems array is inline via FAM) */
1216
+ rd_free(list);
1217
+ }
1218
+
1219
+
1220
+ const rd_kafka_topic_partition_t *rd_kafka_share_partition_offsets_partition(
1221
+ const rd_kafka_share_partition_offsets_t *partition_offsets) {
1222
+ return partition_offsets->partition;
1223
+ }
1224
+
1225
+
1226
+ const int64_t *rd_kafka_share_partition_offsets_offsets(
1227
+ const rd_kafka_share_partition_offsets_t *partition_offsets) {
1228
+ return partition_offsets->offsets;
1229
+ }
1230
+
1231
+
1232
+ size_t rd_kafka_share_partition_offsets_offsets_cnt(
1233
+ const rd_kafka_share_partition_offsets_t *partition_offsets) {
1234
+ return partition_offsets->cnt;
1235
+ }
1236
+
1237
+
1238
+ /**
1239
+ * @brief Translate librdkafka-internal err sentinels into the broker-equivalent
1240
+ * codes the application is expected to handle.
1241
+ */
1242
+ static rd_kafka_resp_err_t
1243
+ rd_kafka_share_translate_app_err(rd_kafka_resp_err_t err) {
1244
+ switch (err) {
1245
+ case RD_KAFKA_RESP_ERR__TIMED_OUT:
1246
+ case RD_KAFKA_RESP_ERR__TIMED_OUT_QUEUE:
1247
+ return RD_KAFKA_RESP_ERR_REQUEST_TIMED_OUT;
1248
+ case RD_KAFKA_RESP_ERR__DESTROY:
1249
+ case RD_KAFKA_RESP_ERR__DESTROY_BROKER:
1250
+ return RD_KAFKA_RESP_ERR__TRANSPORT;
1251
+ case RD_KAFKA_RESP_ERR__BAD_MSG:
1252
+ return RD_KAFKA_RESP_ERR_INVALID_MSG;
1253
+ case RD_KAFKA_RESP_ERR__AUTHENTICATION:
1254
+ return RD_KAFKA_RESP_ERR_SASL_AUTHENTICATION_FAILED;
1255
+ default:
1256
+ return err;
1257
+ }
1258
+ }
1259
+
1260
+ void rd_kafka_share_dispatch_ack_callbacks(rd_kafka_t *rk,
1261
+ rd_list_t *ack_details) {
1262
+ rd_kafka_share_ack_batches_t *ack_batch;
1263
+ int k;
1264
+
1265
+ /* Locality: main thread - checks runtime-set registration flag. */
1266
+ /**
1267
+ * TODO KIP-932: Check if we want to send individual ops or 1 op.
1268
+ */
1269
+ if (!rk->rk_share_consumer.acknowledgement_commit_cb_registered ||
1270
+ !ack_details || rd_list_cnt(ack_details) == 0)
1271
+ return;
1272
+
1273
+ /* Use per-partition error from each batch, translating internal
1274
+ * sentinels to their broker-equivalent codes before the app sees
1275
+ * them. */
1276
+ RD_LIST_FOREACH(ack_batch, ack_details, k) {
1277
+ ack_batch->rktpar->err =
1278
+ rd_kafka_share_translate_app_err(ack_batch->rktpar->err);
1279
+ rd_kafka_share_enqueue_ack_commit_cb_op(rk, ack_batch,
1280
+ ack_batch->rktpar->err);
1281
+ }
1282
+ }
1283
+
1284
+ /**
1285
+ * @brief Send commit_sync response to the app thread and clear state.
1286
+ *
1287
+ * Creates a SHARE_COMMIT_SYNC_FANOUT reply op with the per-partition
1288
+ * results and enqueues it on the app thread's temp queue. Clears the
1289
+ * commit_sync request state.
1290
+ *
1291
+ * @param rkcg Consumer group handle.
1292
+ *
1293
+ * @locality main thread
1294
+ */
1295
+ void rd_kafka_share_commit_sync_send_response(rd_kafka_cgrp_t *rkcg) {
1296
+ rd_kafka_op_t *rko_reply;
1297
+ rd_kafka_topic_partition_list_t *results =
1298
+ rkcg->rkcg_commit_sync_request.results;
1299
+ int i;
1300
+
1301
+ /* Translate internal sentinels to broker-equivalent codes before
1302
+ * the app sees them. This is the unique fan-in for every
1303
+ * commit_sync result: every writer (apply_result, segregate-fail,
1304
+ * api-timer-cb, broker decommission) lands its err in this list
1305
+ * before we ship it back to the caller. */
1306
+ for (i = 0; i < results->cnt; i++)
1307
+ results->elems[i].err =
1308
+ rd_kafka_share_translate_app_err(results->elems[i].err);
1309
+
1310
+ rko_reply = rd_kafka_op_new(RD_KAFKA_OP_SHARE_COMMIT_SYNC_FANOUT_REPLY);
1311
+ rko_reply->rko_u.share_commit_sync_fanout_reply.results = results;
1312
+
1313
+ rd_kafka_q_enq(rkcg->rkcg_commit_sync_request.replyq, rko_reply);
1314
+ rd_kafka_q_destroy(rkcg->rkcg_commit_sync_request.replyq);
1315
+
1316
+ rkcg->rkcg_commit_sync_request.id = 0;
1317
+ rkcg->rkcg_commit_sync_request.results = NULL;
1318
+ rkcg->rkcg_commit_sync_request.replyq = NULL;
1319
+ rkcg->rkcg_commit_sync_request.abs_timeout = 0;
1320
+ rkcg->rkcg_commit_sync_request.brokers_awaiting_result_cnt = 0;
1321
+ }
1322
+
1323
+ /**
1324
+ * @brief Check if all broker results are in and send response if done.
1325
+ *
1326
+ * Called after each broker reply arrives. If brokers_awaiting_result_cnt
1327
+ * reaches zero, stops the timeout timer and sends the response op
1328
+ * to the app thread's temp queue.
1329
+ *
1330
+ * @param rk Client instance.
1331
+ * @param rkcg Consumer group handle.
1332
+ *
1333
+ * @locality main thread
1334
+ */
1335
+ void rd_kafka_share_commit_sync_maybe_complete(rd_kafka_t *rk,
1336
+ rd_kafka_cgrp_t *rkcg) {
1337
+ if (rkcg->rkcg_commit_sync_request.brokers_awaiting_result_cnt > 0)
1338
+ return;
1339
+
1340
+ rd_kafka_dbg(rk, CGRP, "SHARE",
1341
+ "Commit sync request %" PRId64
1342
+ " complete; all broker replies received, "
1343
+ "sending response",
1344
+ rkcg->rkcg_commit_sync_request.id);
1345
+
1346
+ rd_kafka_timer_stop(&rk->rk_timers, &rkcg->rkcg_commit_sync_request.tmr,
1347
+ 1);
1348
+
1349
+ rd_kafka_share_commit_sync_send_response(rkcg);
1350
+ }
1351
+
1352
+ /**
1353
+ * @brief Apply a broker's commit_sync result: copy each batch's
1354
+ * per-partition err onto the corresponding entry in
1355
+ * rkcg_commit_sync_request.results, decrement the count of
1356
+ * brokers still awaiting reply, and complete the commit_sync
1357
+ * if this was the last broker outstanding.
1358
+ *
1359
+ * The caller is responsible for setting batch->rktpar->err on each
1360
+ * batch before invoking this (either from the broker reply path or
1361
+ * from a synthetic failure path like broker decommission).
1362
+ *
1363
+ * @locality main thread.
1364
+ */
1365
+ void rd_kafka_share_commit_sync_apply_result(rd_kafka_t *rk,
1366
+ rd_kafka_cgrp_t *rkcg,
1367
+ rd_list_t *ack_batches) {
1368
+ if (ack_batches) {
1369
+ rd_kafka_share_ack_batches_t *batch;
1370
+ int k;
1371
+
1372
+ RD_LIST_FOREACH(batch, ack_batches, k) {
1373
+ rd_kafka_topic_partition_t *dst =
1374
+ rd_kafka_topic_partition_list_find(
1375
+ rkcg->rkcg_commit_sync_request.results,
1376
+ batch->rktpar->topic, batch->rktpar->partition);
1377
+ if (dst)
1378
+ dst->err = batch->rktpar->err;
1379
+ }
1380
+ }
1381
+
1382
+ rkcg->rkcg_commit_sync_request.brokers_awaiting_result_cnt--;
1383
+ rd_kafka_share_commit_sync_maybe_complete(rk, rkcg);
1384
+ }
1385
+
1386
+
1387
+ void rd_kafka_share_acks_clear_during_broker_decommission(
1388
+ rd_kafka_t *rk,
1389
+ rd_kafka_broker_t *rkb) {
1390
+ rd_kafka_share_ack_batches_t *batch;
1391
+ int k;
1392
+
1393
+ /* Async acks: stamp SHARE_SESSION_NOT_FOUND on each batch and
1394
+ * fire the share-ack callback so the application sees the
1395
+ * failure. */
1396
+ if (rkb->rkb_share_async_ack_details) {
1397
+ rd_rkb_dbg(rkb, BROKER, "TERM",
1398
+ "Clearing %d pending async ack batch(es); "
1399
+ "dispatching ack callbacks with "
1400
+ "SHARE_SESSION_NOT_FOUND",
1401
+ rd_list_cnt(rkb->rkb_share_async_ack_details));
1402
+
1403
+ RD_LIST_FOREACH(batch, rkb->rkb_share_async_ack_details, k) {
1404
+ batch->rktpar->err =
1405
+ RD_KAFKA_RESP_ERR_SHARE_SESSION_NOT_FOUND;
1406
+ }
1407
+
1408
+ rd_kafka_share_dispatch_ack_callbacks(
1409
+ rk, rkb->rkb_share_async_ack_details);
1410
+
1411
+ rd_list_destroy(rkb->rkb_share_async_ack_details);
1412
+ rkb->rkb_share_async_ack_details = NULL;
1413
+ }
1414
+
1415
+ /* Sync acks: stamp SHARE_SESSION_NOT_FOUND on each batch and
1416
+ * apply the result to the in-flight commit_sync request (copies
1417
+ * err into the cgrp's result list, decrements awaiting count,
1418
+ * completes the sync if this was the last broker outstanding). */
1419
+ if (rkb->rkb_pending_commit_sync.sync_ack_details) {
1420
+ rd_kafka_cgrp_t *rkcg = rd_kafka_cgrp_get(rk);
1421
+
1422
+ rd_rkb_dbg(
1423
+ rkb, BROKER, "TERM",
1424
+ "Clearing %d pending commit sync ack batch(es); "
1425
+ "dispatching ack callbacks and "
1426
+ "stamping SHARE_SESSION_NOT_FOUND on commit_sync result "
1427
+ "for this broker's partitions",
1428
+ rd_list_cnt(rkb->rkb_pending_commit_sync.sync_ack_details));
1429
+
1430
+ RD_LIST_FOREACH(
1431
+ batch, rkb->rkb_pending_commit_sync.sync_ack_details, k) {
1432
+ batch->rktpar->err =
1433
+ RD_KAFKA_RESP_ERR_SHARE_SESSION_NOT_FOUND;
1434
+ }
1435
+
1436
+ rd_kafka_share_commit_sync_apply_result(
1437
+ rk, rkcg, rkb->rkb_pending_commit_sync.sync_ack_details);
1438
+
1439
+ rd_kafka_share_dispatch_ack_callbacks(
1440
+ rk, rkb->rkb_pending_commit_sync.sync_ack_details);
1441
+
1442
+ rd_list_destroy(rkb->rkb_pending_commit_sync.sync_ack_details);
1443
+ rkb->rkb_pending_commit_sync.sync_ack_details = NULL;
1444
+ }
1445
+ }