@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,1207 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2025, 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
+
29
+ /**
30
+ * Mocks
31
+ *
32
+ */
33
+
34
+
35
+ #include "rdkafka_int.h"
36
+ #include "rdbuf.h"
37
+ #include "rdkafka_mock_int.h"
38
+ #include <math.h>
39
+
40
+ /**
41
+ * @brief Share group target assignment (manual)
42
+ */
43
+ typedef struct rd_kafka_mock_sharegroup_target_assignments_s {
44
+ rd_list_t member_ids; /**< List of member ids (char *) */
45
+ rd_list_t assignment; /**< List of rd_kafka_topic_partition_list_t */
46
+ } rd_kafka_mock_sharegroup_target_assignment_t;
47
+
48
+ /* Forward declarations */
49
+ static void rd_kafka_mock_sharegroup_session_tmr_cb(rd_kafka_timers_t *rkts,
50
+ void *arg);
51
+
52
+ /**
53
+ * @brief Initializes sharegroups in mock cluster
54
+ */
55
+ void rd_kafka_mock_sharegrps_init(rd_kafka_mock_cluster_t *mcluster) {
56
+ TAILQ_INIT(&mcluster->sharegrps);
57
+ mcluster->defaults.sharegroup_session_timeout_ms = 45000;
58
+ mcluster->defaults.sharegroup_heartbeat_interval_ms = 5000;
59
+ mcluster->defaults.sharegroup_max_delivery_attempts = 5;
60
+ mcluster->defaults.sharegroup_record_lock_duration_ms = 30000;
61
+ mcluster->defaults.sharegroup_max_size = 200;
62
+ mcluster->defaults.sharegroup_isolation_level = 0;
63
+ mcluster->defaults.sharegroup_max_fetch_sessions = 2000;
64
+ mcluster->defaults.sharegroup_max_record_locks = 2000;
65
+ mcluster->defaults.sharegroup_auto_offset_reset = 0; /* latest */
66
+ }
67
+
68
+ /**
69
+ * @brief Find a share group by GroupId.
70
+ */
71
+ rd_kafka_mock_sharegroup_t *
72
+ rd_kafka_mock_sharegroup_find(rd_kafka_mock_cluster_t *mcluster,
73
+ const rd_kafkap_str_t *GroupId) {
74
+ rd_kafka_mock_sharegroup_t *mshgrp;
75
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link) {
76
+ if (!rd_kafkap_str_cmp_str(GroupId, mshgrp->id))
77
+ return mshgrp;
78
+ }
79
+ return NULL;
80
+ }
81
+
82
+ /**
83
+ * @brief Get or create a share group
84
+ */
85
+ rd_kafka_mock_sharegroup_t *
86
+ rd_kafka_mock_sharegroup_get(rd_kafka_mock_cluster_t *mcluster,
87
+ const rd_kafkap_str_t *GroupID) {
88
+ rd_kafka_mock_sharegroup_t *mshgrp;
89
+
90
+ /* Check if the share group already exists */
91
+ mshgrp = rd_kafka_mock_sharegroup_find(mcluster, GroupID);
92
+ if (mshgrp)
93
+ return mshgrp;
94
+
95
+ /* Create new share group */
96
+ mshgrp = rd_calloc(1, sizeof(*mshgrp));
97
+ mshgrp->cluster = mcluster;
98
+ mshgrp->id = RD_KAFKAP_STR_DUP(GroupID);
99
+ mshgrp->group_epoch = 1;
100
+ mshgrp->session_timeout_ms =
101
+ mcluster->defaults.sharegroup_session_timeout_ms;
102
+ mshgrp->heartbeat_interval_ms =
103
+ mcluster->defaults.sharegroup_heartbeat_interval_ms;
104
+
105
+ TAILQ_INIT(&mshgrp->members);
106
+ mshgrp->member_cnt = 0;
107
+
108
+ /* ShareFetch state */
109
+ TAILQ_INIT(&mshgrp->partitions);
110
+ TAILQ_INIT(&mshgrp->fetch_sessions);
111
+ mshgrp->partition_cnt = 0;
112
+ mshgrp->fetch_session_cnt = 0;
113
+
114
+ /* Per-record limits */
115
+ mshgrp->max_delivery_attempts =
116
+ mcluster->defaults.sharegroup_max_delivery_attempts;
117
+ mshgrp->record_lock_duration_ms =
118
+ mcluster->defaults.sharegroup_record_lock_duration_ms;
119
+ mshgrp->isolation_level = mcluster->defaults.sharegroup_isolation_level;
120
+ mshgrp->max_size = mcluster->defaults.sharegroup_max_size;
121
+ mshgrp->max_fetch_sessions =
122
+ mcluster->defaults.sharegroup_max_fetch_sessions;
123
+ mshgrp->max_record_locks =
124
+ mcluster->defaults.sharegroup_max_record_locks;
125
+ mshgrp->auto_offset_reset =
126
+ mcluster->defaults.sharegroup_auto_offset_reset;
127
+
128
+ rd_kafka_timer_start(&mcluster->timers, &mshgrp->session_tmr,
129
+ 1000 * 1000 /* 1s */,
130
+ rd_kafka_mock_sharegroup_session_tmr_cb, mshgrp);
131
+
132
+ /* Fetch session expiry timer */
133
+ rd_kafka_timer_start(&mcluster->timers, &mshgrp->fetch_session_tmr,
134
+ 1000 * 1000 /* 1s */,
135
+ rd_kafka_mock_sgrp_fetch_session_tmr_cb, mshgrp);
136
+
137
+ TAILQ_INSERT_TAIL(&mcluster->sharegrps, mshgrp, link);
138
+
139
+ return mshgrp;
140
+ }
141
+
142
+ /**
143
+ * @brief Destroy a share group
144
+ */
145
+ void rd_kafka_mock_sharegroup_destroy(rd_kafka_mock_sharegroup_t *mshgrp) {
146
+ rd_kafka_mock_sharegroup_member_t *member;
147
+ rd_kafka_mock_sgrp_partmeta_t *pmeta;
148
+ rd_kafka_mock_sgrp_fetch_session_t *session;
149
+
150
+ TAILQ_REMOVE(&mshgrp->cluster->sharegrps, mshgrp, link);
151
+ rd_kafka_timer_stop(&mshgrp->cluster->timers, &mshgrp->session_tmr,
152
+ RD_DO_LOCK);
153
+ rd_kafka_timer_stop(&mshgrp->cluster->timers,
154
+ &mshgrp->fetch_session_tmr, RD_DO_LOCK);
155
+
156
+ /* Destroy all members */
157
+ while ((member = TAILQ_FIRST(&mshgrp->members)))
158
+ rd_kafka_mock_sharegroup_member_destroy(mshgrp, member);
159
+
160
+ /* Destroy ShareFetch partition metadata */
161
+ while ((pmeta = TAILQ_FIRST(&mshgrp->partitions))) {
162
+ rd_kafka_mock_sgrp_record_state_t *state;
163
+ TAILQ_REMOVE(&mshgrp->partitions, pmeta, link);
164
+ while ((state = TAILQ_FIRST(&pmeta->inflight))) {
165
+ TAILQ_REMOVE(&pmeta->inflight, state, link);
166
+ rd_free(state->owner_member_id);
167
+ rd_free(state);
168
+ }
169
+ rd_free(pmeta);
170
+ }
171
+
172
+ /* Destroy ShareFetch sessions */
173
+ while ((session = TAILQ_FIRST(&mshgrp->fetch_sessions))) {
174
+ TAILQ_REMOVE(&mshgrp->fetch_sessions, session, link);
175
+ mshgrp->fetch_session_cnt--;
176
+ rd_kafka_mock_sgrp_fetch_session_destroy(session);
177
+ }
178
+
179
+ rd_free(mshgrp->id);
180
+ rd_free(mshgrp);
181
+ }
182
+
183
+ /**
184
+ * @brief Find a share group member by MemberId.
185
+ */
186
+ rd_kafka_mock_sharegroup_member_t *
187
+ rd_kafka_mock_sharegroup_member_find(rd_kafka_mock_sharegroup_t *mshgrp,
188
+ const rd_kafkap_str_t *MemberId) {
189
+ rd_kafka_mock_sharegroup_member_t *member;
190
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
191
+ if (!rd_kafkap_str_cmp_str(MemberId, member->id))
192
+ return member;
193
+ }
194
+ return NULL;
195
+ }
196
+
197
+ /**
198
+ * @brief Destroy a share group member.
199
+ */
200
+ void rd_kafka_mock_sharegroup_member_destroy(
201
+ rd_kafka_mock_sharegroup_t *mshgrp,
202
+ rd_kafka_mock_sharegroup_member_t *member) {
203
+ rd_assert(mshgrp->member_cnt > 0);
204
+ TAILQ_REMOVE(&mshgrp->members, member, link);
205
+ mshgrp->member_cnt--;
206
+ rd_free(member->id);
207
+
208
+ RD_IF_FREE(member->subscribed_topic_names, rd_list_destroy_free);
209
+ RD_IF_FREE(member->assignment, rd_kafka_topic_partition_list_destroy);
210
+ rd_free(member);
211
+ }
212
+
213
+ /**
214
+ * @brief Mark member as active.
215
+ */
216
+ void rd_kafka_mock_sharegroup_member_active(
217
+ rd_kafka_mock_sharegroup_t *mshgrp,
218
+ rd_kafka_mock_sharegroup_member_t *member) {
219
+ rd_kafka_dbg(mshgrp->cluster->rk, MOCK, "MOCK",
220
+ "Marking mock share group member %s as active",
221
+ member->id);
222
+ member->ts_last_activity = rd_clock();
223
+ }
224
+
225
+ /**
226
+ * @brief Fence a member.
227
+ */
228
+ void rd_kafka_mock_sharegroup_member_fenced(
229
+ rd_kafka_mock_sharegroup_t *mshgrp,
230
+ rd_kafka_mock_sharegroup_member_t *member) {
231
+ rd_kafka_dbg(mshgrp->cluster->rk, MOCK, "MOCK",
232
+ "Member %s is fenced from sharegroup %s", member->id,
233
+ mshgrp->id);
234
+
235
+ rd_kafka_mock_sharegroup_member_destroy(mshgrp, member);
236
+
237
+ /* Recalculate assignments so remaining members get the
238
+ * freed partitions. */
239
+ rd_kafka_mock_sharegroup_assignment_recalculate(mshgrp);
240
+ }
241
+
242
+ /**
243
+ * @brief Check all members for inactivity and remove them if timed out.
244
+ */
245
+ static void rd_kafka_mock_sharegroup_session_tmr_cb(rd_kafka_timers_t *rkts,
246
+ void *arg) {
247
+ rd_kafka_mock_sharegroup_t *mshgrp = arg;
248
+ rd_kafka_mock_sharegroup_member_t *member, *tmp;
249
+ rd_ts_t now = rd_clock();
250
+ rd_kafka_mock_cluster_t *mcluster = mshgrp->cluster;
251
+
252
+ mtx_lock(&mcluster->lock);
253
+ TAILQ_FOREACH_SAFE(member, &mshgrp->members, link, tmp) {
254
+ if (member->ts_last_activity +
255
+ (mshgrp->session_timeout_ms * 1000) >
256
+ now)
257
+ continue;
258
+
259
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
260
+ "Member %s session timed out for sharegroup %s",
261
+ member->id, mshgrp->id);
262
+
263
+ rd_kafka_mock_sharegroup_member_fenced(mshgrp, member);
264
+ }
265
+ mtx_unlock(&mcluster->lock);
266
+ }
267
+
268
+ /**
269
+ * @brief Get or create a share group member.
270
+ */
271
+ rd_kafka_mock_sharegroup_member_t *
272
+ rd_kafka_mock_sharegroup_member_get(rd_kafka_mock_sharegroup_t *mshgrp,
273
+ const rd_kafkap_str_t *MemberID,
274
+ int32_t MemberEpoch,
275
+ rd_kafka_mock_connection_t *mconn) {
276
+ rd_kafka_mock_sharegroup_member_t *member;
277
+
278
+ /* Check if the member already exists */
279
+ member = rd_kafka_mock_sharegroup_member_find(mshgrp, MemberID);
280
+ if (member) {
281
+ member->conn = mconn;
282
+ rd_kafka_mock_sharegroup_member_active(mshgrp, member);
283
+ return member;
284
+ }
285
+
286
+ /* Only create if epoch is 0 */
287
+ if (MemberEpoch != 0)
288
+ return NULL;
289
+
290
+ /* Create new member */
291
+ member = rd_calloc(1, sizeof(*member));
292
+ member->mshgrp = mshgrp;
293
+ member->id = RD_KAFKAP_STR_DUP(MemberID);
294
+ member->member_epoch = mshgrp->group_epoch;
295
+ member->previous_member_epoch =
296
+ -1; /* No previous epoch for new members */
297
+ member->conn = mconn;
298
+
299
+ TAILQ_INSERT_TAIL(&mshgrp->members, member, link);
300
+ mshgrp->member_cnt++;
301
+ rd_kafka_mock_sharegroup_member_active(mshgrp, member);
302
+
303
+ return member;
304
+ }
305
+
306
+ /**
307
+ * @brief Update share group member's subscribed topic names.
308
+ *
309
+ * @param member The member to update.
310
+ * @param SubscribedTopicNames Array of topic names.
311
+ * @param SubscribedTopicNamesCnt Count of topic names:
312
+ * -1 = unchanged (no modification)
313
+ * 0 = clear all subscriptions
314
+ * >0 = set to provided topics
315
+ *
316
+ * @returns rd_true if subscriptions changed, rd_false otherwise.
317
+ */
318
+ rd_bool_t rd_kafka_mock_sharegroup_member_subscribed_topic_names_set(
319
+ rd_kafka_mock_sharegroup_member_t *member,
320
+ const rd_kafkap_str_t *SubscribedTopicNames,
321
+ int32_t SubscribedTopicNamesCnt) {
322
+ int32_t i;
323
+
324
+ if (SubscribedTopicNamesCnt < 0) {
325
+ /* -1 means unchanged */
326
+ return rd_false;
327
+ }
328
+
329
+ if (SubscribedTopicNamesCnt == 0) {
330
+ /* 0 means clear all subscriptions */
331
+ if (!member->subscribed_topic_names ||
332
+ rd_list_cnt(member->subscribed_topic_names) == 0) {
333
+ /* Already empty, no change */
334
+ return rd_false;
335
+ }
336
+ rd_list_destroy(member->subscribed_topic_names);
337
+ member->subscribed_topic_names = NULL;
338
+ return rd_true;
339
+ }
340
+
341
+ /* SubscribedTopicNamesCnt > 0: Check if subscription changed */
342
+ if (member->subscribed_topic_names) {
343
+ if (rd_list_cnt(member->subscribed_topic_names) ==
344
+ SubscribedTopicNamesCnt) {
345
+ rd_bool_t same = rd_true;
346
+ char *topic;
347
+ int j;
348
+
349
+ RD_LIST_FOREACH(topic, member->subscribed_topic_names,
350
+ j) {
351
+ rd_bool_t found = rd_false;
352
+ for (i = 0; i < SubscribedTopicNamesCnt; i++) {
353
+ if (!rd_kafkap_str_cmp_str(
354
+ &SubscribedTopicNames[i],
355
+ topic)) {
356
+ found = rd_true;
357
+ break;
358
+ }
359
+ }
360
+ if (!found) {
361
+ same = rd_false;
362
+ break;
363
+ }
364
+ }
365
+ if (same)
366
+ return rd_false;
367
+ }
368
+ }
369
+
370
+ /* Subscription changed, update the list */
371
+ RD_IF_FREE(member->subscribed_topic_names, rd_list_destroy);
372
+ member->subscribed_topic_names =
373
+ rd_list_new(SubscribedTopicNamesCnt, rd_free);
374
+
375
+ for (i = 0; i < SubscribedTopicNamesCnt; i++) {
376
+ rd_list_add(member->subscribed_topic_names,
377
+ RD_KAFKAP_STR_DUP(&SubscribedTopicNames[i]));
378
+ }
379
+
380
+ return rd_true;
381
+ }
382
+
383
+ /**
384
+ * @brief Collect all subscribed topic names from all members.
385
+ */
386
+ static rd_list_t *rd_kafka_mock_sharegroup_collect_subscribed_topics(
387
+ rd_kafka_mock_sharegroup_t *mshgrp) {
388
+ rd_kafka_mock_sharegroup_member_t *member;
389
+ rd_list_t *all_topics;
390
+
391
+ all_topics = rd_list_new(32, rd_free);
392
+
393
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
394
+ const char *topic;
395
+ int i;
396
+
397
+ if (!member->subscribed_topic_names)
398
+ continue;
399
+
400
+ RD_LIST_FOREACH(topic, member->subscribed_topic_names, i) {
401
+ const char *existing;
402
+ int j;
403
+ rd_bool_t found = rd_false;
404
+
405
+ /* Check if topic already in all_topics */
406
+ RD_LIST_FOREACH(existing, all_topics, j) {
407
+ if (!strcmp(topic, existing)) {
408
+ found = rd_true;
409
+ break;
410
+ }
411
+ }
412
+
413
+ /* Add if not found */
414
+ if (!found) {
415
+ rd_list_add(all_topics, rd_strdup(topic));
416
+ }
417
+ }
418
+ }
419
+
420
+ return all_topics;
421
+ }
422
+
423
+ /**
424
+ * @brief Get list of member ID's subscribed to a topic.
425
+ */
426
+ rd_list_t *rd_kafka_mock_sharegroup_get_members_for_topic(
427
+ rd_kafka_mock_sharegroup_t *mshgrp,
428
+ char *topic_name) {
429
+ rd_kafka_mock_sharegroup_member_t *member;
430
+ rd_list_t *subscribed_members;
431
+ int member_idx = 0;
432
+
433
+ subscribed_members = rd_list_new(mshgrp->member_cnt, rd_free);
434
+
435
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
436
+ char *topic;
437
+ int i;
438
+
439
+ if (member->subscribed_topic_names) {
440
+ RD_LIST_FOREACH(topic, member->subscribed_topic_names,
441
+ i) {
442
+ if (!strcmp(topic, topic_name)) {
443
+ int *idx = rd_malloc(sizeof(*idx));
444
+ *idx = member_idx;
445
+ rd_list_add(subscribed_members, idx);
446
+ break;
447
+ }
448
+ }
449
+ }
450
+ member_idx++;
451
+ }
452
+
453
+ return subscribed_members;
454
+ }
455
+
456
+ /**
457
+ * @brief Assign partitions of a single topic to subscribed members.
458
+ */
459
+ void rd_kafka_mock_sharegroup_assign_topic_partitions(
460
+ rd_kafka_mock_sharegroup_t *mshgrp,
461
+ rd_kafka_mock_topic_t *mtopic,
462
+ rd_list_t *subscribed_member_indices) {
463
+ int member_count;
464
+ int partition_cnt;
465
+ int partition_idx;
466
+ double precise;
467
+ int i;
468
+
469
+ member_count = rd_list_cnt(subscribed_member_indices);
470
+ partition_cnt = mtopic->partition_cnt;
471
+
472
+ if (member_count == 0 || partition_cnt == 0)
473
+ return;
474
+
475
+ precise = (double)partition_cnt / (double)member_count;
476
+ partition_idx = 0;
477
+
478
+ for (i = 0; i < member_count; i++) {
479
+ int *member_idx_ptr =
480
+ (int *)rd_list_elem(subscribed_member_indices, i);
481
+ rd_kafka_mock_sharegroup_member_t *member;
482
+ int j, cnt = 0;
483
+ int num_partitions;
484
+
485
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
486
+ if (cnt == *member_idx_ptr)
487
+ break;
488
+ cnt++;
489
+ }
490
+
491
+ if (!member)
492
+ continue;
493
+
494
+ num_partitions = (int)ceil(precise * (double)(i + 1)) -
495
+ (int)ceil(precise * (double)i);
496
+
497
+ if (!member->assignment)
498
+ member->assignment =
499
+ rd_kafka_topic_partition_list_new(num_partitions);
500
+
501
+ for (j = 0; j < num_partitions && partition_idx < partition_cnt;
502
+ j++, partition_idx++) {
503
+ rd_kafka_topic_partition_t *rktpar;
504
+ rktpar = rd_kafka_topic_partition_list_add(
505
+ member->assignment, mtopic->name, partition_idx);
506
+ /* Set topic ID so the response can include it */
507
+ rd_kafka_topic_partition_set_topic_id(rktpar,
508
+ mtopic->id);
509
+ }
510
+ }
511
+ }
512
+
513
+ /**
514
+ * @brief Recalculate assignments for all members in the share group.
515
+ */
516
+ void rd_kafka_mock_sharegroup_assignment_recalculate(
517
+ rd_kafka_mock_sharegroup_t *mshgrp) {
518
+ rd_kafka_mock_sharegroup_member_t *member;
519
+ rd_list_t *all_topics;
520
+ char *topic_name;
521
+ int i;
522
+
523
+ if (mshgrp->member_cnt == 0)
524
+ return;
525
+
526
+ /* Skip automatic assignment if manual mode is enabled */
527
+ if (mshgrp->manual_assignment)
528
+ return;
529
+
530
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
531
+ if (member->assignment) {
532
+ rd_kafka_topic_partition_list_destroy(
533
+ member->assignment);
534
+ member->assignment = NULL;
535
+ }
536
+ }
537
+
538
+ all_topics = rd_kafka_mock_sharegroup_collect_subscribed_topics(mshgrp);
539
+
540
+ RD_LIST_FOREACH(topic_name, all_topics, i) {
541
+ rd_kafka_mock_topic_t *mtopic;
542
+ rd_list_t *subscribed_members;
543
+
544
+ mtopic = rd_kafka_mock_topic_find(mshgrp->cluster, topic_name);
545
+ if (!mtopic)
546
+ continue;
547
+
548
+ subscribed_members =
549
+ rd_kafka_mock_sharegroup_get_members_for_topic(mshgrp,
550
+ topic_name);
551
+
552
+ rd_kafka_mock_sharegroup_assign_topic_partitions(
553
+ mshgrp, mtopic, subscribed_members);
554
+
555
+ rd_list_destroy(subscribed_members);
556
+ }
557
+
558
+ mshgrp->group_epoch++;
559
+
560
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
561
+ /* Save the current epoch as previous before bumping.
562
+ * This allows the client to catch up if the response
563
+ * with the new epoch was lost. */
564
+ member->previous_member_epoch = member->member_epoch;
565
+ member->member_epoch = mshgrp->group_epoch;
566
+ }
567
+
568
+ rd_list_destroy(all_topics);
569
+ }
570
+
571
+ /**
572
+ * @brief Create a new target assignment (manual)
573
+ */
574
+ rd_kafka_mock_sharegroup_target_assignment_t *
575
+ rd_kafka_mock_sharegroup_target_assignment_new(void) {
576
+ rd_kafka_mock_sharegroup_target_assignment_t *target_assignment;
577
+ target_assignment = rd_calloc(1, sizeof(*target_assignment));
578
+ rd_list_init(&target_assignment->member_ids, 0, rd_free);
579
+ rd_list_init(&target_assignment->assignment, 0,
580
+ (void *)rd_kafka_topic_partition_list_destroy);
581
+
582
+ return target_assignment;
583
+ }
584
+
585
+ /**
586
+ * @brief Destroy target assignment
587
+ */
588
+ void rd_kafka_mock_sharegroup_target_assignment_destroy(
589
+ rd_kafka_mock_sharegroup_target_assignment_t *target_assignment) {
590
+ rd_list_destroy(&target_assignment->member_ids);
591
+ rd_list_destroy(&target_assignment->assignment);
592
+ rd_free(target_assignment);
593
+ }
594
+
595
+ /**
596
+ * @brief Set the target assignment for the sharegroup.
597
+ * This applies the manual assignment to the members.
598
+ *
599
+ * @locks mcluster->lock MUST be held.
600
+ */
601
+ static void rd_kafka_mock_sharegroup_target_assignment_set(
602
+ rd_kafka_mock_sharegroup_t *mshgrp,
603
+ rd_kafka_mock_sharegroup_target_assignment_t *target_assignment) {
604
+ rd_kafka_mock_sharegroup_member_t *member;
605
+ int i;
606
+
607
+ for (i = 0; i < rd_list_cnt(&target_assignment->member_ids); i++) {
608
+ const char *member_id =
609
+ rd_list_elem(&target_assignment->member_ids, i);
610
+ const rd_kafka_topic_partition_list_t *partitions =
611
+ rd_list_elem(&target_assignment->assignment, i);
612
+ rd_kafkap_str_t *member_id_str;
613
+
614
+ member_id_str = rd_kafkap_str_new(member_id, -1);
615
+ member =
616
+ rd_kafka_mock_sharegroup_member_find(mshgrp, member_id_str);
617
+ rd_kafkap_str_destroy(member_id_str);
618
+
619
+ if (!member) {
620
+ rd_kafka_dbg(mshgrp->cluster->rk, MOCK, "MOCK",
621
+ "Cannot set target assignment for "
622
+ "non-existing member %s in sharegroup %s",
623
+ member_id, mshgrp->id);
624
+ continue;
625
+ }
626
+
627
+ if (member->assignment) {
628
+ rd_kafka_topic_partition_list_destroy(
629
+ member->assignment);
630
+ }
631
+
632
+ member->assignment =
633
+ rd_kafka_topic_partition_list_copy(partitions);
634
+
635
+ /* Set topic IDs on each partition so the heartbeat response
636
+ * can include them (ShareGroupHeartbeat uses topic IDs) */
637
+ {
638
+ int j;
639
+ for (j = 0; j < member->assignment->cnt; j++) {
640
+ rd_kafka_topic_partition_t *rktpar =
641
+ &member->assignment->elems[j];
642
+ rd_kafkap_str_t topic_str = {
643
+ .str = rktpar->topic,
644
+ .len = strlen(rktpar->topic)};
645
+ rd_kafka_mock_topic_t *mtopic =
646
+ rd_kafka_mock_topic_find_by_kstr(
647
+ mshgrp->cluster, &topic_str);
648
+ if (mtopic) {
649
+ rd_kafka_topic_partition_set_topic_id(
650
+ rktpar, mtopic->id);
651
+ }
652
+ }
653
+ }
654
+
655
+ rd_kafka_dbg(
656
+ mshgrp->cluster->rk, MOCK, "MOCK",
657
+ "Target assignment set for member %s: %d partition(s)",
658
+ member_id, member->assignment->cnt);
659
+ }
660
+
661
+ /* Bump the epochs */
662
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
663
+ member->previous_member_epoch = member->member_epoch;
664
+ member->member_epoch = ++mshgrp->group_epoch;
665
+ }
666
+ }
667
+
668
+ /**
669
+ * @brief Manual target assignment interface for sharegroups.
670
+ */
671
+ void rd_kafka_mock_sharegroup_target_assignment(
672
+ rd_kafka_mock_cluster_t *mcluster,
673
+ const char *group_id,
674
+ const char **member_ids,
675
+ rd_kafka_topic_partition_list_t **assignment,
676
+ size_t member_cnt) {
677
+ rd_kafka_mock_sharegroup_t *mshgrp;
678
+ rd_kafka_mock_sharegroup_target_assignment_t *target_assignment;
679
+ size_t i;
680
+ rd_kafkap_str_t *group_id_str;
681
+
682
+ mtx_lock(&mcluster->lock);
683
+ group_id_str = rd_kafkap_str_new(group_id, -1);
684
+ mshgrp = rd_kafka_mock_sharegroup_find(mcluster, group_id_str);
685
+ rd_kafkap_str_destroy(group_id_str);
686
+
687
+ if (!mshgrp) {
688
+ rd_kafka_log(mcluster->rk, LOG_ERR, "MOCK",
689
+ "Sharegroup %s not found for target assignment",
690
+ group_id);
691
+ mtx_unlock(&mcluster->lock);
692
+ return;
693
+ }
694
+
695
+ mshgrp->manual_assignment = rd_true;
696
+ target_assignment = rd_kafka_mock_sharegroup_target_assignment_new();
697
+
698
+ for (i = 0; i < member_cnt; i++) {
699
+ rd_list_add(&target_assignment->member_ids,
700
+ rd_strdup(member_ids[i]));
701
+ rd_list_add(&target_assignment->assignment,
702
+ rd_kafka_topic_partition_list_copy(assignment[i]));
703
+ }
704
+ rd_kafka_mock_sharegroup_target_assignment_set(mshgrp,
705
+ target_assignment);
706
+ rd_kafka_mock_sharegroup_target_assignment_destroy(target_assignment);
707
+ mtx_unlock(&mcluster->lock);
708
+ }
709
+
710
+ /**
711
+ * @brief Set the sharegroup session timeout for the sharegroup.
712
+ */
713
+ void rd_kafka_mock_sharegroup_set_session_timeout(
714
+ rd_kafka_mock_cluster_t *mcluster,
715
+ int session_timeout_ms) {
716
+ mtx_lock(&mcluster->lock);
717
+ mcluster->defaults.sharegroup_session_timeout_ms = session_timeout_ms;
718
+ mtx_unlock(&mcluster->lock);
719
+ }
720
+
721
+ /**
722
+ * @brief Set the sharegroup heartbeat interval for the sharegroup.
723
+ */
724
+ void rd_kafka_mock_sharegroup_set_heartbeat_interval(
725
+ rd_kafka_mock_cluster_t *mcluster,
726
+ int heartbeat_interval_ms) {
727
+ mtx_lock(&mcluster->lock);
728
+ mcluster->defaults.sharegroup_heartbeat_interval_ms =
729
+ heartbeat_interval_ms;
730
+ mtx_unlock(&mcluster->lock);
731
+ }
732
+
733
+ /**
734
+ * @brief Set the maximum delivery attempts per record for the sharegroup.
735
+ */
736
+ void rd_kafka_mock_sharegroup_set_max_delivery_attempts(
737
+ rd_kafka_mock_cluster_t *mcluster,
738
+ int max_attempts) {
739
+ rd_kafka_mock_sharegroup_t *mshgrp;
740
+ mtx_lock(&mcluster->lock);
741
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
742
+ mshgrp->max_delivery_attempts = max_attempts;
743
+ mcluster->defaults.sharegroup_max_delivery_attempts = max_attempts;
744
+ mtx_unlock(&mcluster->lock);
745
+ }
746
+
747
+ /**
748
+ * @brief Set the per-record lock duration in milliseconds for the sharegroup.
749
+ */
750
+ void rd_kafka_mock_sharegroup_set_record_lock_duration(
751
+ rd_kafka_mock_cluster_t *mcluster,
752
+ int lock_duration_ms) {
753
+ rd_kafka_mock_sharegroup_t *mshgrp;
754
+ mtx_lock(&mcluster->lock);
755
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
756
+ mshgrp->record_lock_duration_ms = lock_duration_ms;
757
+ mcluster->defaults.sharegroup_record_lock_duration_ms =
758
+ lock_duration_ms;
759
+ mtx_unlock(&mcluster->lock);
760
+ }
761
+
762
+ /**
763
+ * @brief Set the share group isolation level for transactions.
764
+ */
765
+ void rd_kafka_mock_sharegroup_set_isolation_level(
766
+ rd_kafka_mock_cluster_t *mcluster,
767
+ int level) {
768
+ rd_kafka_mock_sharegroup_t *mshgrp;
769
+ mtx_lock(&mcluster->lock);
770
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
771
+ mshgrp->isolation_level = level;
772
+ mcluster->defaults.sharegroup_isolation_level = level;
773
+ mtx_unlock(&mcluster->lock);
774
+ }
775
+
776
+ /**
777
+ * @brief Set the maximum number of members allowed in a share group.
778
+ */
779
+ void rd_kafka_mock_sharegroup_set_max_size(rd_kafka_mock_cluster_t *mcluster,
780
+ int max_size) {
781
+ rd_kafka_mock_sharegroup_t *mshgrp;
782
+ mtx_lock(&mcluster->lock);
783
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
784
+ mshgrp->max_size = max_size;
785
+ mcluster->defaults.sharegroup_max_size = max_size;
786
+ mtx_unlock(&mcluster->lock);
787
+ }
788
+
789
+ /**
790
+ * @brief Set the maximum number of fetch sessions allowed per broker.
791
+ */
792
+ void rd_kafka_mock_sharegroup_set_max_fetch_sessions(
793
+ rd_kafka_mock_cluster_t *mcluster,
794
+ int max_fetch_sessions) {
795
+ rd_kafka_mock_sharegroup_t *mshgrp;
796
+ mtx_lock(&mcluster->lock);
797
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
798
+ mshgrp->max_fetch_sessions = max_fetch_sessions;
799
+ mcluster->defaults.sharegroup_max_fetch_sessions = max_fetch_sessions;
800
+ mtx_unlock(&mcluster->lock);
801
+ }
802
+
803
+ /**
804
+ * @brief Set the maximum number of in-flight record locks per
805
+ * share-partition.
806
+ */
807
+ void rd_kafka_mock_sharegroup_set_max_record_locks(
808
+ rd_kafka_mock_cluster_t *mcluster,
809
+ int max_record_locks) {
810
+ rd_kafka_mock_sharegroup_t *mshgrp;
811
+ mtx_lock(&mcluster->lock);
812
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
813
+ mshgrp->max_record_locks = max_record_locks;
814
+ mcluster->defaults.sharegroup_max_record_locks = max_record_locks;
815
+ mtx_unlock(&mcluster->lock);
816
+ }
817
+
818
+ /**
819
+ * @brief Set the auto offset reset policy for share groups.
820
+ */
821
+ void rd_kafka_mock_sharegroup_set_auto_offset_reset(
822
+ rd_kafka_mock_cluster_t *mcluster,
823
+ int auto_offset_reset) {
824
+ rd_kafka_mock_sharegroup_t *mshgrp;
825
+ mtx_lock(&mcluster->lock);
826
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link)
827
+ mshgrp->auto_offset_reset = auto_offset_reset;
828
+ mcluster->defaults.sharegroup_auto_offset_reset = auto_offset_reset;
829
+ mtx_unlock(&mcluster->lock);
830
+ }
831
+
832
+ /**
833
+ * @brief Destroy share fetch session.
834
+ */
835
+ void rd_kafka_mock_sgrp_fetch_session_destroy(
836
+ rd_kafka_mock_sgrp_fetch_session_t *session) {
837
+ rd_free(session->member_id);
838
+ RD_IF_FREE(session->partitions, rd_kafka_topic_partition_list_destroy);
839
+ rd_free(session);
840
+ }
841
+
842
+
843
+ /**
844
+ * @brief Common share-session validation for ShareFetch / ShareAcknowledge.
845
+ *
846
+ * Performs:
847
+ * 1. Session lookup by (MemberId, NodeId).
848
+ * 2. SessionEpoch == 0 : destroy old session if any (caller creates new).
849
+ * 3. SessionEpoch == -1 : keep session alive (FinalContext behaviour).
850
+ * 4. SessionEpoch > 0 : validate that session exists and epoch matches.
851
+ *
852
+ * On return, \p *sessionp is set to the looked-up session (or NULL if
853
+ * no session was found or it was closed).
854
+ *
855
+ * @note Does NOT handle SessionEpoch == 0 (open new session), which is
856
+ * ShareFetch-specific. The caller is also responsible for
857
+ * incrementing session_epoch and updating ts_last_activity on
858
+ * success.
859
+ *
860
+ * @param sgrp Share group.
861
+ * @param MemberId Member identifier from the request.
862
+ * @param NodeId Node ID of the broker handling the request.
863
+ * @param SessionEpoch Session epoch from the request.
864
+ * @param sessionp [out] Session pointer.
865
+ * @param api_name API name for debug messages ("ShareFetch" etc.).
866
+ *
867
+ * @returns Error code, or RD_KAFKA_RESP_ERR_NO_ERROR on success.
868
+ *
869
+ * @locks mcluster->lock MUST be held.
870
+ */
871
+ rd_kafka_resp_err_t rd_kafka_mock_sgrp_session_validate(
872
+ rd_kafka_mock_sharegroup_t *sgrp,
873
+ const rd_kafkap_str_t *MemberId,
874
+ int32_t NodeId,
875
+ int32_t SessionEpoch,
876
+ rd_kafka_mock_sgrp_fetch_session_t **sessionp,
877
+ const char *api_name) {
878
+ rd_kafka_mock_sgrp_fetch_session_t *session = NULL;
879
+
880
+ *sessionp = NULL;
881
+
882
+ /* The real Kafka broker's partition leader does NOT
883
+ * validate group membership on ShareFetch — share sessions are
884
+ * managed independently of the group coordinator. */
885
+
886
+ /* 1. Look up existing session by (MemberId, NodeId).
887
+ * In real Kafka, ShareSessionCache is per-broker, so each
888
+ * broker maintains its own independent session for the same
889
+ * member. We emulate this by keying on both fields. */
890
+ TAILQ_FOREACH(session, &sgrp->fetch_sessions, link) {
891
+ if (!rd_kafkap_str_cmp_str(MemberId, session->member_id) &&
892
+ session->node_id == NodeId)
893
+ break;
894
+ }
895
+
896
+ /* 2. SessionEpoch == 0: open a new session.
897
+ * If an old session exists for this member (e.g. after a
898
+ * LEAVE→rejoin cycle), destroy it so the caller creates a
899
+ * fresh one. */
900
+ if (SessionEpoch == 0) {
901
+ if (session) {
902
+ rd_kafka_mock_sgrp_release_session_locks(sgrp, session);
903
+ TAILQ_REMOVE(&sgrp->fetch_sessions, session, link);
904
+ sgrp->fetch_session_cnt--;
905
+ rd_kafka_mock_sgrp_fetch_session_destroy(session);
906
+ session = NULL;
907
+ }
908
+ } else if (SessionEpoch == -1) {
909
+ /* 3. SessionEpoch == -1 (FINAL_EPOCH): return the existing
910
+ * session so the caller can process final acks and
911
+ * then close it. If no session exists, fail with
912
+ * SHARE_SESSION_NOT_FOUND per the protocol. */
913
+ if (!session) {
914
+ *sessionp = NULL;
915
+ return RD_KAFKA_RESP_ERR_SHARE_SESSION_NOT_FOUND;
916
+ }
917
+ } else if (SessionEpoch > 0) {
918
+ /* 4. SessionEpoch > 0: validate epoch. */
919
+ if (!session) {
920
+ /* Session not in cache →
921
+ * SHARE_SESSION_NOT_FOUND (distinct from epoch
922
+ * mismatch which uses
923
+ * INVALID_SHARE_SESSION_EPOCH). */
924
+ *sessionp = NULL;
925
+ return RD_KAFKA_RESP_ERR_SHARE_SESSION_NOT_FOUND;
926
+ } else if (SessionEpoch != session->session_epoch) {
927
+ /* Epoch mismatch → destroy the stale
928
+ * session and return INVALID_SHARE_SESSION_EPOCH.
929
+ * The client handles this by resetting its
930
+ * per-broker epoch to 0 (opening a fresh session
931
+ * on the next fetch). */
932
+ rd_kafka_mock_sgrp_release_session_locks(sgrp, session);
933
+ TAILQ_REMOVE(&sgrp->fetch_sessions, session, link);
934
+ sgrp->fetch_session_cnt--;
935
+ rd_kafka_mock_sgrp_fetch_session_destroy(session);
936
+ *sessionp = NULL;
937
+ return RD_KAFKA_RESP_ERR_INVALID_SHARE_SESSION_EPOCH;
938
+ }
939
+ }
940
+
941
+ *sessionp = session;
942
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
943
+ }
944
+
945
+
946
+ /**
947
+ * @brief Release a single ACQUIRED record state back to AVAILABLE or ARCHIVED.
948
+ *
949
+ * If \p mshgrp has a max_delivery_attempts limit and the record's
950
+ * delivery_count has reached it, the record is archived instead of
951
+ * made available again. Clears owner_member_id and lock_expiry_ts.
952
+ *
953
+ * @locks mcluster->lock MUST be held.
954
+ */
955
+ void rd_kafka_mock_sgrp_record_release(
956
+ rd_kafka_mock_sharegroup_t *mshgrp,
957
+ rd_kafka_mock_sgrp_partmeta_t *pmeta,
958
+ rd_kafka_mock_sgrp_record_state_t *state) {
959
+ if (state->state == RD_KAFKA_MOCK_SGRP_RECORD_ACQUIRED)
960
+ pmeta->acquired_cnt--;
961
+ if (mshgrp->max_delivery_attempts > 0 &&
962
+ state->delivery_count >= mshgrp->max_delivery_attempts) {
963
+ state->state = RD_KAFKA_MOCK_SGRP_RECORD_ARCHIVED;
964
+ } else {
965
+ state->state = RD_KAFKA_MOCK_SGRP_RECORD_AVAILABLE;
966
+ }
967
+ rd_free(state->owner_member_id);
968
+ state->owner_member_id = NULL;
969
+ state->lock_expiry_ts = 0;
970
+ }
971
+
972
+ /**
973
+ * @brief Release all ACQUIRED records owned by \p session's member on
974
+ * the partitions belonging to \p session.
975
+ *
976
+ * Share sessions are per-broker: closing one broker's session must
977
+ * only release the records acquired through that session (the
978
+ * partitions that broker leads), never the member's locks held
979
+ * through other brokers' intact sessions.
980
+ *
981
+ * This is called when a session is closed (epoch=-1), replaced
982
+ * (epoch=0), invalidated (epoch mismatch), times out, or its
983
+ * connection is closed.
984
+ *
985
+ * @locks mcluster->lock MUST be held.
986
+ */
987
+ void rd_kafka_mock_sgrp_release_session_locks(
988
+ rd_kafka_mock_sharegroup_t *mshgrp,
989
+ const rd_kafka_mock_sgrp_fetch_session_t *session) {
990
+ rd_kafka_mock_sgrp_partmeta_t *pmeta;
991
+
992
+ if (!session->partitions)
993
+ return;
994
+
995
+ TAILQ_FOREACH(pmeta, &mshgrp->partitions, link) {
996
+ rd_kafka_mock_sgrp_record_state_t *state, *tmp;
997
+ rd_kafka_mock_topic_t *mtopic;
998
+ rd_kafka_mock_partition_t *mpart;
999
+
1000
+ if (rd_kafka_topic_partition_list_find_idx_by_id(
1001
+ session->partitions, pmeta->topic_id,
1002
+ pmeta->partition) < 0)
1003
+ continue;
1004
+
1005
+ /* A session can only release locks for partitions its
1006
+ * broker currently leads: a session's partition list
1007
+ * can be stale after a leader change, while the locks
1008
+ * now belong to the new leader's session. */
1009
+ mtopic = rd_kafka_mock_topic_find_by_id(mshgrp->cluster,
1010
+ pmeta->topic_id);
1011
+ mpart = mtopic ? rd_kafka_mock_partition_find(mtopic,
1012
+ pmeta->partition)
1013
+ : NULL;
1014
+ if (!mpart || !mpart->leader ||
1015
+ mpart->leader->id != session->node_id)
1016
+ continue;
1017
+
1018
+ TAILQ_FOREACH_SAFE(state, &pmeta->inflight, link, tmp) {
1019
+ if (state->state != RD_KAFKA_MOCK_SGRP_RECORD_ACQUIRED)
1020
+ continue;
1021
+ if (!state->owner_member_id)
1022
+ continue;
1023
+ if (strcmp(state->owner_member_id,
1024
+ session->member_id) != 0)
1025
+ continue;
1026
+
1027
+ rd_kafka_mock_sgrp_record_release(mshgrp, pmeta, state);
1028
+ }
1029
+ }
1030
+ }
1031
+
1032
+ /**
1033
+ * @brief Proactively release any expired acquisition locks.
1034
+ *
1035
+ * Iterates all partition metadata in the share group and flips
1036
+ * ACQUIRED records whose lock_expiry_ts has passed back to AVAILABLE.
1037
+ *
1038
+ * @locks mcluster->lock MUST be held.
1039
+ */
1040
+ static void rd_kafka_mock_sgrp_expire_locks(rd_kafka_mock_sharegroup_t *mshgrp,
1041
+ rd_ts_t now) {
1042
+ rd_kafka_mock_sgrp_partmeta_t *pmeta;
1043
+
1044
+ TAILQ_FOREACH(pmeta, &mshgrp->partitions, link) {
1045
+ rd_kafka_mock_sgrp_record_state_t *state, *tmp;
1046
+ TAILQ_FOREACH_SAFE(state, &pmeta->inflight, link, tmp) {
1047
+ if (state->state != RD_KAFKA_MOCK_SGRP_RECORD_ACQUIRED)
1048
+ continue;
1049
+ if (!state->lock_expiry_ts ||
1050
+ state->lock_expiry_ts > now)
1051
+ continue;
1052
+
1053
+ /* Lock has expired. If delivery
1054
+ * count has reached the limit, archive the
1055
+ * record instead of making it available. */
1056
+ rd_kafka_mock_sgrp_record_release(mshgrp, pmeta, state);
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ /**
1062
+ * @brief Periodic timer: expire stale share-fetch sessions and
1063
+ * proactively reclaim expired acquisition locks.
1064
+ *
1065
+ * @locks mcluster->lock is acquired and released.
1066
+ */
1067
+ void rd_kafka_mock_sgrp_fetch_session_tmr_cb(rd_kafka_timers_t *rkts,
1068
+ void *arg) {
1069
+ rd_kafka_mock_sharegroup_t *mshgrp = arg;
1070
+ rd_kafka_mock_sgrp_fetch_session_t *session, *tmp;
1071
+ rd_ts_t now = rd_clock();
1072
+ rd_kafka_mock_cluster_t *mcluster = mshgrp->cluster;
1073
+
1074
+ (void)rkts;
1075
+
1076
+ mtx_lock(&mcluster->lock);
1077
+
1078
+ /* 1. Expire stale sessions and release their member locks. */
1079
+ TAILQ_FOREACH_SAFE(session, &mshgrp->fetch_sessions, link, tmp) {
1080
+ if (session->ts_last_activity +
1081
+ (mshgrp->session_timeout_ms * 1000) >
1082
+ now)
1083
+ continue;
1084
+
1085
+ /* Release all locks held by this member before
1086
+ * destroying the session. */
1087
+ rd_kafka_mock_sgrp_release_session_locks(mshgrp, session);
1088
+
1089
+ TAILQ_REMOVE(&mshgrp->fetch_sessions, session, link);
1090
+ mshgrp->fetch_session_cnt--;
1091
+ rd_kafka_mock_sgrp_fetch_session_destroy(session);
1092
+ }
1093
+
1094
+ /* 2. Proactively reclaim any expired acquisition locks.
1095
+ * This catches records whose owning consumer crashed
1096
+ * without closing its session cleanly. */
1097
+ rd_kafka_mock_sgrp_expire_locks(mshgrp, now);
1098
+
1099
+ mtx_unlock(&mcluster->lock);
1100
+ }
1101
+
1102
+ /**
1103
+ * @brief A client connection closed, check if any sharegroup has any
1104
+ * state for this connection that needs to be cleared.
1105
+ *
1106
+ * @param mcluster Cluster to search in.
1107
+ * @param mconn Connection that was closed.
1108
+ *
1109
+ * @locks mcluster->lock MUST be held.
1110
+ */
1111
+ void rd_kafka_mock_sharegrps_connection_closed(
1112
+ rd_kafka_mock_cluster_t *mcluster,
1113
+ rd_kafka_mock_connection_t *mconn) {
1114
+ rd_kafka_mock_sharegroup_t *mshgrp;
1115
+
1116
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link) {
1117
+ rd_kafka_mock_sharegroup_member_t *member;
1118
+ /* Clear heartbeat connection for any member on this conn. */
1119
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
1120
+ if (member->conn == mconn)
1121
+ member->conn = NULL;
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ /**
1127
+ * @brief Close all share fetch sessions on \p node_id.
1128
+ *
1129
+ * Called from rd_kafka_mock_connection_close() where mconn->broker is
1130
+ * guaranteed to be valid. Must NOT be called with a fake connection pointer.
1131
+ *
1132
+ * @locks mcluster->lock MUST be held.
1133
+ */
1134
+ void rd_kafka_mock_sharegrps_node_connection_closed(
1135
+ rd_kafka_mock_cluster_t *mcluster,
1136
+ int32_t node_id) {
1137
+ rd_kafka_mock_sharegroup_t *mshgrp;
1138
+
1139
+ TAILQ_FOREACH(mshgrp, &mcluster->sharegrps, link) {
1140
+ rd_kafka_mock_sgrp_fetch_session_t *session, *tmp;
1141
+ /* When a connection is disconnected, any share session
1142
+ * on that broker is automatically closed. */
1143
+ TAILQ_FOREACH_SAFE(session, &mshgrp->fetch_sessions, link,
1144
+ tmp) {
1145
+ if (session->node_id != node_id)
1146
+ continue;
1147
+ rd_kafka_mock_sgrp_release_session_locks(mshgrp,
1148
+ session);
1149
+ TAILQ_REMOVE(&mshgrp->fetch_sessions, session, link);
1150
+ mshgrp->fetch_session_cnt--;
1151
+ rd_kafka_mock_sgrp_fetch_session_destroy(session);
1152
+ }
1153
+ }
1154
+ }
1155
+
1156
+ /**
1157
+ * @brief Retrieve the member IDs from a sharegroup.
1158
+ *
1159
+ * @param mcluster Mock cluster instance.
1160
+ * @param group_id The sharegroup ID.
1161
+ * @param member_ids_out Output array of member IDs (caller must free each
1162
+ * string and the array itself).
1163
+ * @param member_cnt_out Output count of members.
1164
+ *
1165
+ * @returns RD_KAFKA_RESP_ERR_NO_ERROR on success,
1166
+ * RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND if sharegroup not found.
1167
+ */
1168
+ rd_kafka_resp_err_t
1169
+ rd_kafka_mock_sharegroup_get_member_ids(rd_kafka_mock_cluster_t *mcluster,
1170
+ const char *group_id,
1171
+ char ***member_ids_out,
1172
+ size_t *member_cnt_out) {
1173
+ rd_kafka_mock_sharegroup_t *mshgrp;
1174
+ rd_kafka_mock_sharegroup_member_t *member;
1175
+ rd_kafkap_str_t *group_id_str;
1176
+ char **member_ids;
1177
+ size_t i;
1178
+
1179
+ mtx_lock(&mcluster->lock);
1180
+ group_id_str = rd_kafkap_str_new(group_id, -1);
1181
+ mshgrp = rd_kafka_mock_sharegroup_find(mcluster, group_id_str);
1182
+ rd_kafkap_str_destroy(group_id_str);
1183
+
1184
+ if (!mshgrp) {
1185
+ mtx_unlock(&mcluster->lock);
1186
+ *member_ids_out = NULL;
1187
+ *member_cnt_out = 0;
1188
+ return RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND;
1189
+ }
1190
+
1191
+ *member_cnt_out = mshgrp->member_cnt;
1192
+ if (mshgrp->member_cnt == 0) {
1193
+ mtx_unlock(&mcluster->lock);
1194
+ *member_ids_out = NULL;
1195
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1196
+ }
1197
+
1198
+ member_ids = rd_malloc(sizeof(*member_ids) * mshgrp->member_cnt);
1199
+ i = 0;
1200
+ TAILQ_FOREACH(member, &mshgrp->members, link) {
1201
+ member_ids[i++] = rd_strdup(member->id);
1202
+ }
1203
+
1204
+ mtx_unlock(&mcluster->lock);
1205
+ *member_ids_out = member_ids;
1206
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1207
+ }