@platformatic/rdkafka 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (767) hide show
  1. package/.editorconfig +5 -0
  2. package/.jshintignore +1 -0
  3. package/.jshintrc +23 -0
  4. package/CONTRIBUTING.md +237 -0
  5. package/LICENSE.txt +21 -0
  6. package/Makefile +94 -0
  7. package/README.md +630 -0
  8. package/bench/consumer-raw-rdkafka.js +76 -0
  9. package/bench/consumer-subscribe.js +77 -0
  10. package/bench/kafka-consumer-stream.js +100 -0
  11. package/bench/producer-raw-rdkafka.js +125 -0
  12. package/bench/producer-rdkafka.js +117 -0
  13. package/bench/seed.sh +38 -0
  14. package/binding.gyp +155 -0
  15. package/ci/checks/librdkafka-correct-version.js +67 -0
  16. package/ci/checks/librdkafka-exists.js +13 -0
  17. package/ci/librdkafka-defs-generator.js +193 -0
  18. package/ci/prepublish.js +3 -0
  19. package/config.d.ts +1132 -0
  20. package/configure +15 -0
  21. package/cpplint.py +6325 -0
  22. package/deploy.enc +0 -0
  23. package/deps/librdkafka/.clang-format +136 -0
  24. package/deps/librdkafka/.clang-format-cpp +103 -0
  25. package/deps/librdkafka/.dir-locals.el +10 -0
  26. package/deps/librdkafka/.formatignore +33 -0
  27. package/deps/librdkafka/.gdbmacros +19 -0
  28. package/deps/librdkafka/.semaphore/project.yml +43 -0
  29. package/deps/librdkafka/.semaphore/project_public.yml +20 -0
  30. package/deps/librdkafka/.semaphore/semaphore.yml +355 -0
  31. package/deps/librdkafka/CHANGELOG.md +1738 -0
  32. package/deps/librdkafka/CMakeLists.txt +291 -0
  33. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  34. package/deps/librdkafka/CONFIGURATION.md +189 -0
  35. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  36. package/deps/librdkafka/Doxyfile +2375 -0
  37. package/deps/librdkafka/INTRODUCTION.md +2173 -0
  38. package/deps/librdkafka/LICENSE +26 -0
  39. package/deps/librdkafka/LICENSE.cjson +22 -0
  40. package/deps/librdkafka/LICENSE.crc32c +28 -0
  41. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  42. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  43. package/deps/librdkafka/LICENSE.lz4 +26 -0
  44. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  45. package/deps/librdkafka/LICENSE.nanopb +22 -0
  46. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  47. package/deps/librdkafka/LICENSE.pycrc +23 -0
  48. package/deps/librdkafka/LICENSE.queue +31 -0
  49. package/deps/librdkafka/LICENSE.regexp +5 -0
  50. package/deps/librdkafka/LICENSE.snappy +36 -0
  51. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  52. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  53. package/deps/librdkafka/LICENSES.txt +625 -0
  54. package/deps/librdkafka/Makefile +124 -0
  55. package/deps/librdkafka/README.md +199 -0
  56. package/deps/librdkafka/README.win32 +26 -0
  57. package/deps/librdkafka/STATISTICS.md +624 -0
  58. package/deps/librdkafka/configure +214 -0
  59. package/deps/librdkafka/configure.self +331 -0
  60. package/deps/librdkafka/debian/changelog +111 -0
  61. package/deps/librdkafka/debian/compat +1 -0
  62. package/deps/librdkafka/debian/control +71 -0
  63. package/deps/librdkafka/debian/copyright +99 -0
  64. package/deps/librdkafka/debian/gbp.conf +9 -0
  65. package/deps/librdkafka/debian/librdkafka++1.install +1 -0
  66. package/deps/librdkafka/debian/librdkafka-dev.examples +2 -0
  67. package/deps/librdkafka/debian/librdkafka-dev.install +9 -0
  68. package/deps/librdkafka/debian/librdkafka1.docs +5 -0
  69. package/deps/librdkafka/debian/librdkafka1.install +1 -0
  70. package/deps/librdkafka/debian/librdkafka1.symbols +135 -0
  71. package/deps/librdkafka/debian/rules +19 -0
  72. package/deps/librdkafka/debian/source/format +1 -0
  73. package/deps/librdkafka/debian/watch +2 -0
  74. package/deps/librdkafka/dev-conf.sh +123 -0
  75. package/deps/librdkafka/examples/CMakeLists.txt +79 -0
  76. package/deps/librdkafka/examples/Makefile +167 -0
  77. package/deps/librdkafka/examples/README.md +42 -0
  78. package/deps/librdkafka/examples/alter_consumer_group_offsets.c +338 -0
  79. package/deps/librdkafka/examples/consumer.c +261 -0
  80. package/deps/librdkafka/examples/delete_records.c +233 -0
  81. package/deps/librdkafka/examples/describe_cluster.c +322 -0
  82. package/deps/librdkafka/examples/describe_consumer_groups.c +436 -0
  83. package/deps/librdkafka/examples/describe_topics.c +427 -0
  84. package/deps/librdkafka/examples/elect_leaders.c +317 -0
  85. package/deps/librdkafka/examples/globals.json +11 -0
  86. package/deps/librdkafka/examples/idempotent_producer.c +344 -0
  87. package/deps/librdkafka/examples/incremental_alter_configs.c +348 -0
  88. package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +961 -0
  89. package/deps/librdkafka/examples/list_consumer_group_offsets.c +359 -0
  90. package/deps/librdkafka/examples/list_consumer_groups.c +365 -0
  91. package/deps/librdkafka/examples/list_offsets.c +327 -0
  92. package/deps/librdkafka/examples/misc.c +287 -0
  93. package/deps/librdkafka/examples/openssl_engine_example.cpp +249 -0
  94. package/deps/librdkafka/examples/producer.c +251 -0
  95. package/deps/librdkafka/examples/producer.cpp +228 -0
  96. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.c +617 -0
  97. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.cpp +467 -0
  98. package/deps/librdkafka/examples/rdkafka_consume_batch.cpp +264 -0
  99. package/deps/librdkafka/examples/rdkafka_example.c +853 -0
  100. package/deps/librdkafka/examples/rdkafka_example.cpp +679 -0
  101. package/deps/librdkafka/examples/rdkafka_performance.c +1781 -0
  102. package/deps/librdkafka/examples/transactions-older-broker.c +668 -0
  103. package/deps/librdkafka/examples/transactions.c +665 -0
  104. package/deps/librdkafka/examples/user_scram.c +492 -0
  105. package/deps/librdkafka/examples/win_ssl_cert_store.cpp +395 -0
  106. package/deps/librdkafka/lds-gen.py +73 -0
  107. package/deps/librdkafka/mainpage.doxy +40 -0
  108. package/deps/librdkafka/mklove/Makefile.base +329 -0
  109. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  110. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  111. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  112. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  113. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  114. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  115. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  116. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  117. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  118. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  119. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  120. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  121. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  122. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  123. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  124. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  125. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  126. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  127. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  128. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  129. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  130. package/deps/librdkafka/packaging/RELEASE.md +311 -0
  131. package/deps/librdkafka/packaging/alpine/build-alpine.sh +38 -0
  132. package/deps/librdkafka/packaging/archlinux/PKGBUILD +30 -0
  133. package/deps/librdkafka/packaging/cmake/Config.cmake.in +37 -0
  134. package/deps/librdkafka/packaging/cmake/Modules/FindLZ4.cmake +38 -0
  135. package/deps/librdkafka/packaging/cmake/Modules/FindZSTD.cmake +27 -0
  136. package/deps/librdkafka/packaging/cmake/Modules/LICENSE.FindZstd +178 -0
  137. package/deps/librdkafka/packaging/cmake/README.md +38 -0
  138. package/deps/librdkafka/packaging/cmake/config.h.in +52 -0
  139. package/deps/librdkafka/packaging/cmake/parseversion.cmake +60 -0
  140. package/deps/librdkafka/packaging/cmake/rdkafka.pc.in +12 -0
  141. package/deps/librdkafka/packaging/cmake/try_compile/atomic_32_test.c +8 -0
  142. package/deps/librdkafka/packaging/cmake/try_compile/atomic_64_test.c +8 -0
  143. package/deps/librdkafka/packaging/cmake/try_compile/c11threads_test.c +14 -0
  144. package/deps/librdkafka/packaging/cmake/try_compile/crc32c_hw_test.c +27 -0
  145. package/deps/librdkafka/packaging/cmake/try_compile/dlopen_test.c +11 -0
  146. package/deps/librdkafka/packaging/cmake/try_compile/libsasl2_test.c +7 -0
  147. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_darwin_test.c +6 -0
  148. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_freebsd_test.c +7 -0
  149. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_gnu_test.c +5 -0
  150. package/deps/librdkafka/packaging/cmake/try_compile/rand_r_test.c +7 -0
  151. package/deps/librdkafka/packaging/cmake/try_compile/rdkafka_setup.cmake +122 -0
  152. package/deps/librdkafka/packaging/cmake/try_compile/regex_test.c +10 -0
  153. package/deps/librdkafka/packaging/cmake/try_compile/strndup_test.c +5 -0
  154. package/deps/librdkafka/packaging/cmake/try_compile/sync_32_test.c +8 -0
  155. package/deps/librdkafka/packaging/cmake/try_compile/sync_64_test.c +8 -0
  156. package/deps/librdkafka/packaging/cp/README.md +13 -0
  157. package/deps/librdkafka/packaging/cp/check_features.c +64 -0
  158. package/deps/librdkafka/packaging/cp/verify-deb.sh +33 -0
  159. package/deps/librdkafka/packaging/cp/verify-packages.sh +48 -0
  160. package/deps/librdkafka/packaging/cp/verify-rpm.sh +39 -0
  161. package/deps/librdkafka/packaging/debian/changelog +66 -0
  162. package/deps/librdkafka/packaging/debian/compat +1 -0
  163. package/deps/librdkafka/packaging/debian/control +49 -0
  164. package/deps/librdkafka/packaging/debian/copyright +84 -0
  165. package/deps/librdkafka/packaging/debian/gbp.conf +9 -0
  166. package/deps/librdkafka/packaging/debian/librdkafka-dev.dirs +2 -0
  167. package/deps/librdkafka/packaging/debian/librdkafka-dev.examples +2 -0
  168. package/deps/librdkafka/packaging/debian/librdkafka-dev.install +6 -0
  169. package/deps/librdkafka/packaging/debian/librdkafka-dev.substvars +1 -0
  170. package/deps/librdkafka/packaging/debian/librdkafka.dsc +16 -0
  171. package/deps/librdkafka/packaging/debian/librdkafka1-dbg.substvars +1 -0
  172. package/deps/librdkafka/packaging/debian/librdkafka1.dirs +1 -0
  173. package/deps/librdkafka/packaging/debian/librdkafka1.install +2 -0
  174. package/deps/librdkafka/packaging/debian/librdkafka1.postinst.debhelper +5 -0
  175. package/deps/librdkafka/packaging/debian/librdkafka1.postrm.debhelper +5 -0
  176. package/deps/librdkafka/packaging/debian/librdkafka1.symbols +64 -0
  177. package/deps/librdkafka/packaging/debian/rules +19 -0
  178. package/deps/librdkafka/packaging/debian/source/format +1 -0
  179. package/deps/librdkafka/packaging/debian/watch +2 -0
  180. package/deps/librdkafka/packaging/get_version.py +21 -0
  181. package/deps/librdkafka/packaging/homebrew/README.md +15 -0
  182. package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +31 -0
  183. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw-static.sh +52 -0
  184. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw.sh +21 -0
  185. package/deps/librdkafka/packaging/mingw-w64/run-tests.sh +6 -0
  186. package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +38 -0
  187. package/deps/librdkafka/packaging/mingw-w64/travis-before-install.sh +20 -0
  188. package/deps/librdkafka/packaging/nuget/README.md +84 -0
  189. package/deps/librdkafka/packaging/nuget/artifact.py +177 -0
  190. package/deps/librdkafka/packaging/nuget/cleanup-s3.py +143 -0
  191. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr120.zip +0 -0
  192. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr140.zip +0 -0
  193. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr120.zip +0 -0
  194. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr140.zip +0 -0
  195. package/deps/librdkafka/packaging/nuget/nuget.sh +21 -0
  196. package/deps/librdkafka/packaging/nuget/nugetpackage.py +278 -0
  197. package/deps/librdkafka/packaging/nuget/packaging.py +448 -0
  198. package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +21 -0
  199. package/deps/librdkafka/packaging/nuget/release.py +167 -0
  200. package/deps/librdkafka/packaging/nuget/requirements.txt +3 -0
  201. package/deps/librdkafka/packaging/nuget/staticpackage.py +178 -0
  202. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.nuspec +21 -0
  203. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.props +18 -0
  204. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.targets +19 -0
  205. package/deps/librdkafka/packaging/nuget/zfile/__init__.py +0 -0
  206. package/deps/librdkafka/packaging/nuget/zfile/zfile.py +98 -0
  207. package/deps/librdkafka/packaging/rpm/Makefile +92 -0
  208. package/deps/librdkafka/packaging/rpm/README.md +23 -0
  209. package/deps/librdkafka/packaging/rpm/el7-x86_64.cfg +40 -0
  210. package/deps/librdkafka/packaging/rpm/librdkafka.spec +118 -0
  211. package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +96 -0
  212. package/deps/librdkafka/packaging/rpm/tests/Makefile +25 -0
  213. package/deps/librdkafka/packaging/rpm/tests/README.md +8 -0
  214. package/deps/librdkafka/packaging/rpm/tests/run-test.sh +42 -0
  215. package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +56 -0
  216. package/deps/librdkafka/packaging/rpm/tests/test.c +77 -0
  217. package/deps/librdkafka/packaging/rpm/tests/test.cpp +34 -0
  218. package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +10 -0
  219. package/deps/librdkafka/packaging/tools/build-deb-package.sh +64 -0
  220. package/deps/librdkafka/packaging/tools/build-debian.sh +65 -0
  221. package/deps/librdkafka/packaging/tools/build-manylinux.sh +68 -0
  222. package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +139 -0
  223. package/deps/librdkafka/packaging/tools/distro-build.sh +38 -0
  224. package/deps/librdkafka/packaging/tools/gh-release-checksums.py +39 -0
  225. package/deps/librdkafka/packaging/tools/rdutcoverage.sh +25 -0
  226. package/deps/librdkafka/packaging/tools/requirements.txt +2 -0
  227. package/deps/librdkafka/packaging/tools/style-format.sh +148 -0
  228. package/deps/librdkafka/service.yml +18 -0
  229. package/deps/librdkafka/src/CMakeLists.txt +374 -0
  230. package/deps/librdkafka/src/Makefile +103 -0
  231. package/deps/librdkafka/src/README.lz4.md +30 -0
  232. package/deps/librdkafka/src/cJSON.c +2834 -0
  233. package/deps/librdkafka/src/cJSON.h +398 -0
  234. package/deps/librdkafka/src/crc32c.c +430 -0
  235. package/deps/librdkafka/src/crc32c.h +38 -0
  236. package/deps/librdkafka/src/generate_proto.sh +66 -0
  237. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  238. package/deps/librdkafka/src/lz4.c +2727 -0
  239. package/deps/librdkafka/src/lz4.h +842 -0
  240. package/deps/librdkafka/src/lz4frame.c +2078 -0
  241. package/deps/librdkafka/src/lz4frame.h +692 -0
  242. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  243. package/deps/librdkafka/src/lz4hc.c +1631 -0
  244. package/deps/librdkafka/src/lz4hc.h +413 -0
  245. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  246. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  247. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  248. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  249. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  250. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  251. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  252. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  253. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  254. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  255. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  256. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  257. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  258. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  259. package/deps/librdkafka/src/queue.h +850 -0
  260. package/deps/librdkafka/src/rd.h +441 -0
  261. package/deps/librdkafka/src/rdaddr.c +255 -0
  262. package/deps/librdkafka/src/rdaddr.h +203 -0
  263. package/deps/librdkafka/src/rdatomic.h +226 -0
  264. package/deps/librdkafka/src/rdavg.h +259 -0
  265. package/deps/librdkafka/src/rdavl.c +210 -0
  266. package/deps/librdkafka/src/rdavl.h +250 -0
  267. package/deps/librdkafka/src/rdbase64.c +169 -0
  268. package/deps/librdkafka/src/rdbase64.h +41 -0
  269. package/deps/librdkafka/src/rdbuf.c +1884 -0
  270. package/deps/librdkafka/src/rdbuf.h +375 -0
  271. package/deps/librdkafka/src/rdcrc32.c +114 -0
  272. package/deps/librdkafka/src/rdcrc32.h +170 -0
  273. package/deps/librdkafka/src/rddl.c +179 -0
  274. package/deps/librdkafka/src/rddl.h +43 -0
  275. package/deps/librdkafka/src/rdendian.h +174 -0
  276. package/deps/librdkafka/src/rdfloat.h +67 -0
  277. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  278. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  279. package/deps/librdkafka/src/rdgz.c +120 -0
  280. package/deps/librdkafka/src/rdgz.h +46 -0
  281. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  282. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  283. package/deps/librdkafka/src/rdhttp.c +512 -0
  284. package/deps/librdkafka/src/rdhttp.h +83 -0
  285. package/deps/librdkafka/src/rdinterval.h +177 -0
  286. package/deps/librdkafka/src/rdkafka.c +5351 -0
  287. package/deps/librdkafka/src/rdkafka.h +10603 -0
  288. package/deps/librdkafka/src/rdkafka_admin.c +9417 -0
  289. package/deps/librdkafka/src/rdkafka_admin.h +619 -0
  290. package/deps/librdkafka/src/rdkafka_assignment.c +1010 -0
  291. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  292. package/deps/librdkafka/src/rdkafka_assignor.c +1786 -0
  293. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  294. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  295. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  296. package/deps/librdkafka/src/rdkafka_background.c +221 -0
  297. package/deps/librdkafka/src/rdkafka_broker.c +6186 -0
  298. package/deps/librdkafka/src/rdkafka_broker.h +686 -0
  299. package/deps/librdkafka/src/rdkafka_buf.c +540 -0
  300. package/deps/librdkafka/src/rdkafka_buf.h +1524 -0
  301. package/deps/librdkafka/src/rdkafka_cert.c +552 -0
  302. package/deps/librdkafka/src/rdkafka_cert.h +61 -0
  303. package/deps/librdkafka/src/rdkafka_cgrp.c +7262 -0
  304. package/deps/librdkafka/src/rdkafka_cgrp.h +443 -0
  305. package/deps/librdkafka/src/rdkafka_conf.c +4456 -0
  306. package/deps/librdkafka/src/rdkafka_conf.h +668 -0
  307. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  308. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  309. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  310. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  311. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  312. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  313. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  314. package/deps/librdkafka/src/rdkafka_feature.c +461 -0
  315. package/deps/librdkafka/src/rdkafka_feature.h +102 -0
  316. package/deps/librdkafka/src/rdkafka_fetcher.c +1402 -0
  317. package/deps/librdkafka/src/rdkafka_fetcher.h +44 -0
  318. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  319. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  320. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  321. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  322. package/deps/librdkafka/src/rdkafka_int.h +1222 -0
  323. package/deps/librdkafka/src/rdkafka_interceptor.c +819 -0
  324. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  325. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  326. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  327. package/deps/librdkafka/src/rdkafka_metadata.c +2124 -0
  328. package/deps/librdkafka/src/rdkafka_metadata.h +341 -0
  329. package/deps/librdkafka/src/rdkafka_metadata_cache.c +977 -0
  330. package/deps/librdkafka/src/rdkafka_mock.c +2885 -0
  331. package/deps/librdkafka/src/rdkafka_mock.h +491 -0
  332. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +710 -0
  333. package/deps/librdkafka/src/rdkafka_mock_handlers.c +2817 -0
  334. package/deps/librdkafka/src/rdkafka_mock_int.h +591 -0
  335. package/deps/librdkafka/src/rdkafka_msg.c +2573 -0
  336. package/deps/librdkafka/src/rdkafka_msg.h +614 -0
  337. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  338. package/deps/librdkafka/src/rdkafka_msgset.h +98 -0
  339. package/deps/librdkafka/src/rdkafka_msgset_reader.c +1806 -0
  340. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1470 -0
  341. package/deps/librdkafka/src/rdkafka_offset.c +1537 -0
  342. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  343. package/deps/librdkafka/src/rdkafka_op.c +997 -0
  344. package/deps/librdkafka/src/rdkafka_op.h +834 -0
  345. package/deps/librdkafka/src/rdkafka_partition.c +4801 -0
  346. package/deps/librdkafka/src/rdkafka_partition.h +1173 -0
  347. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  348. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  349. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  350. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  351. package/deps/librdkafka/src/rdkafka_proto.h +733 -0
  352. package/deps/librdkafka/src/rdkafka_protocol.h +127 -0
  353. package/deps/librdkafka/src/rdkafka_queue.c +1153 -0
  354. package/deps/librdkafka/src/rdkafka_queue.h +1201 -0
  355. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  356. package/deps/librdkafka/src/rdkafka_request.c +6817 -0
  357. package/deps/librdkafka/src/rdkafka_request.h +709 -0
  358. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  359. package/deps/librdkafka/src/rdkafka_sasl.c +528 -0
  360. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  361. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  362. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  363. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1829 -0
  364. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  365. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +589 -0
  366. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +37 -0
  367. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  368. package/deps/librdkafka/src/rdkafka_sasl_scram.c +857 -0
  369. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  370. package/deps/librdkafka/src/rdkafka_ssl.c +1904 -0
  371. package/deps/librdkafka/src/rdkafka_ssl.h +64 -0
  372. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4781 -0
  373. package/deps/librdkafka/src/rdkafka_subscription.c +278 -0
  374. package/deps/librdkafka/src/rdkafka_telemetry.c +703 -0
  375. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  376. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1053 -0
  377. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  378. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +993 -0
  379. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +301 -0
  380. package/deps/librdkafka/src/rdkafka_timer.c +402 -0
  381. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  382. package/deps/librdkafka/src/rdkafka_topic.c +2078 -0
  383. package/deps/librdkafka/src/rdkafka_topic.h +328 -0
  384. package/deps/librdkafka/src/rdkafka_transport.c +1297 -0
  385. package/deps/librdkafka/src/rdkafka_transport.h +94 -0
  386. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  387. package/deps/librdkafka/src/rdkafka_txnmgr.c +3251 -0
  388. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  389. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  390. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  391. package/deps/librdkafka/src/rdlist.c +576 -0
  392. package/deps/librdkafka/src/rdlist.h +434 -0
  393. package/deps/librdkafka/src/rdlog.c +89 -0
  394. package/deps/librdkafka/src/rdlog.h +41 -0
  395. package/deps/librdkafka/src/rdmap.c +503 -0
  396. package/deps/librdkafka/src/rdmap.h +492 -0
  397. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  398. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  399. package/deps/librdkafka/src/rdports.c +61 -0
  400. package/deps/librdkafka/src/rdports.h +38 -0
  401. package/deps/librdkafka/src/rdposix.h +250 -0
  402. package/deps/librdkafka/src/rdrand.c +70 -0
  403. package/deps/librdkafka/src/rdrand.h +43 -0
  404. package/deps/librdkafka/src/rdregex.c +156 -0
  405. package/deps/librdkafka/src/rdregex.h +43 -0
  406. package/deps/librdkafka/src/rdsignal.h +57 -0
  407. package/deps/librdkafka/src/rdstring.c +645 -0
  408. package/deps/librdkafka/src/rdstring.h +98 -0
  409. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  410. package/deps/librdkafka/src/rdtime.h +325 -0
  411. package/deps/librdkafka/src/rdtypes.h +86 -0
  412. package/deps/librdkafka/src/rdunittest.c +532 -0
  413. package/deps/librdkafka/src/rdunittest.h +230 -0
  414. package/deps/librdkafka/src/rdvarint.c +134 -0
  415. package/deps/librdkafka/src/rdvarint.h +165 -0
  416. package/deps/librdkafka/src/rdwin32.h +382 -0
  417. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  418. package/deps/librdkafka/src/rdxxhash.h +328 -0
  419. package/deps/librdkafka/src/regexp.c +1347 -0
  420. package/deps/librdkafka/src/regexp.h +41 -0
  421. package/deps/librdkafka/src/snappy.c +1866 -0
  422. package/deps/librdkafka/src/snappy.h +62 -0
  423. package/deps/librdkafka/src/snappy_compat.h +138 -0
  424. package/deps/librdkafka/src/statistics_schema.json +444 -0
  425. package/deps/librdkafka/src/tinycthread.c +932 -0
  426. package/deps/librdkafka/src/tinycthread.h +503 -0
  427. package/deps/librdkafka/src/tinycthread_extra.c +175 -0
  428. package/deps/librdkafka/src/tinycthread_extra.h +208 -0
  429. package/deps/librdkafka/src/win32_config.h +58 -0
  430. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  431. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  432. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  433. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  434. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  435. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  436. package/deps/librdkafka/src-cpp/Makefile +55 -0
  437. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  438. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  439. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  440. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  441. package/deps/librdkafka/src-cpp/README.md +16 -0
  442. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  443. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  444. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  445. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3771 -0
  446. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  447. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  448. package/deps/librdkafka/tests/0001-multiobj.c +98 -0
  449. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  450. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  451. package/deps/librdkafka/tests/0004-conf.c +867 -0
  452. package/deps/librdkafka/tests/0005-order.c +133 -0
  453. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  454. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  455. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  456. package/deps/librdkafka/tests/0009-mock_cluster.c +96 -0
  457. package/deps/librdkafka/tests/0011-produce_batch.c +752 -0
  458. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  459. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  460. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  461. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  462. package/deps/librdkafka/tests/0016-client_swname.c +166 -0
  463. package/deps/librdkafka/tests/0017-compression.c +142 -0
  464. package/deps/librdkafka/tests/0018-cgrp_term.c +333 -0
  465. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  466. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  467. package/deps/librdkafka/tests/0021-rkt_destroy.c +71 -0
  468. package/deps/librdkafka/tests/0022-consume_batch.c +276 -0
  469. package/deps/librdkafka/tests/0025-timers.c +147 -0
  470. package/deps/librdkafka/tests/0026-consume_pause.c +549 -0
  471. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  472. package/deps/librdkafka/tests/0029-assign_offset.c +204 -0
  473. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  474. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  475. package/deps/librdkafka/tests/0033-regex_subscribe.c +520 -0
  476. package/deps/librdkafka/tests/0034-offset_reset.c +377 -0
  477. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  478. package/deps/librdkafka/tests/0036-partial_fetch.c +86 -0
  479. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  480. package/deps/librdkafka/tests/0038-performance.c +120 -0
  481. package/deps/librdkafka/tests/0039-event.c +284 -0
  482. package/deps/librdkafka/tests/0040-io_event.c +251 -0
  483. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +96 -0
  484. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  485. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  486. package/deps/librdkafka/tests/0044-partition_cnt.c +93 -0
  487. package/deps/librdkafka/tests/0045-subscribe_update.c +746 -0
  488. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  489. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +97 -0
  490. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  491. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  492. package/deps/librdkafka/tests/0050-subscribe_adds.c +144 -0
  493. package/deps/librdkafka/tests/0051-assign_adds.c +125 -0
  494. package/deps/librdkafka/tests/0052-msg_timestamps.c +220 -0
  495. package/deps/librdkafka/tests/0053-stats_cb.cpp +535 -0
  496. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  497. package/deps/librdkafka/tests/0055-producer_latency.c +366 -0
  498. package/deps/librdkafka/tests/0056-balanced_group_mt.c +311 -0
  499. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  500. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  501. package/deps/librdkafka/tests/0059-bsearch.cpp +237 -0
  502. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  503. package/deps/librdkafka/tests/0061-consumer_lag.cpp +275 -0
  504. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  505. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  506. package/deps/librdkafka/tests/0064-interceptors.c +481 -0
  507. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  508. package/deps/librdkafka/tests/0066-plugins.cpp +129 -0
  509. package/deps/librdkafka/tests/0067-empty_topic.cpp +148 -0
  510. package/deps/librdkafka/tests/0068-produce_timeout.c +138 -0
  511. package/deps/librdkafka/tests/0069-consumer_add_parts.c +123 -0
  512. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  513. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  514. package/deps/librdkafka/tests/0073-headers.c +381 -0
  515. package/deps/librdkafka/tests/0074-producev.c +87 -0
  516. package/deps/librdkafka/tests/0075-retry.c +253 -0
  517. package/deps/librdkafka/tests/0076-produce_retry.c +450 -0
  518. package/deps/librdkafka/tests/0077-compaction.c +357 -0
  519. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  520. package/deps/librdkafka/tests/0079-fork.c +93 -0
  521. package/deps/librdkafka/tests/0080-admin_ut.c +3065 -0
  522. package/deps/librdkafka/tests/0081-admin.c +5333 -0
  523. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +133 -0
  524. package/deps/librdkafka/tests/0083-cb_event.c +228 -0
  525. package/deps/librdkafka/tests/0084-destroy_flags.c +212 -0
  526. package/deps/librdkafka/tests/0085-headers.cpp +388 -0
  527. package/deps/librdkafka/tests/0086-purge.c +335 -0
  528. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  529. package/deps/librdkafka/tests/0089-max_poll_interval.c +506 -0
  530. package/deps/librdkafka/tests/0090-idempotence.c +172 -0
  531. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +297 -0
  532. package/deps/librdkafka/tests/0092-mixed_msgver.c +97 -0
  533. package/deps/librdkafka/tests/0093-holb.c +197 -0
  534. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +230 -0
  535. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  536. package/deps/librdkafka/tests/0097-ssl_verify.cpp +466 -0
  537. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  538. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  539. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  540. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  541. package/deps/librdkafka/tests/0102-static_group_rebalance.c +535 -0
  542. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  543. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +624 -0
  544. package/deps/librdkafka/tests/0105-transactions_mock.c +3923 -0
  545. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +297 -0
  546. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  547. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +218 -0
  548. package/deps/librdkafka/tests/0110-batch_size.cpp +183 -0
  549. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  550. package/deps/librdkafka/tests/0112-assign_unknown_part.c +98 -0
  551. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3329 -0
  552. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  553. package/deps/librdkafka/tests/0115-producer_auth.cpp +179 -0
  554. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +214 -0
  555. package/deps/librdkafka/tests/0117-mock_errors.c +321 -0
  556. package/deps/librdkafka/tests/0118-commit_rebalance.c +121 -0
  557. package/deps/librdkafka/tests/0119-consumer_auth.cpp +148 -0
  558. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +180 -0
  559. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  560. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  561. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  562. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  563. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  564. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +213 -0
  565. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  566. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +125 -0
  567. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +78 -0
  568. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  569. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  570. package/deps/librdkafka/tests/0132-strategy_ordering.c +171 -0
  571. package/deps/librdkafka/tests/0133-ssl_keys.c +128 -0
  572. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  573. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +143 -0
  574. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  575. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +609 -0
  576. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  577. package/deps/librdkafka/tests/0139-offset_validation_mock.c +442 -0
  578. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  579. package/deps/librdkafka/tests/0142-reauthentication.c +495 -0
  580. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +553 -0
  581. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  582. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  583. package/deps/librdkafka/tests/0146-metadata_mock.c +444 -0
  584. package/deps/librdkafka/tests/0150-telemetry_mock.c +648 -0
  585. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  586. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  587. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  588. package/deps/librdkafka/tests/CMakeLists.txt +164 -0
  589. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +266 -0
  590. package/deps/librdkafka/tests/Makefile +182 -0
  591. package/deps/librdkafka/tests/README.md +509 -0
  592. package/deps/librdkafka/tests/autotest.sh +33 -0
  593. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  594. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  595. package/deps/librdkafka/tests/buildbox.sh +17 -0
  596. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  597. package/deps/librdkafka/tests/cluster_testing.py +191 -0
  598. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  599. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  600. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  601. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  602. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +109 -0
  603. package/deps/librdkafka/tests/fixtures/ssl/client2.key +34 -0
  604. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +93 -0
  605. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  606. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  607. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  608. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  609. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  610. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  611. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  612. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  613. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  614. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  615. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  616. package/deps/librdkafka/tests/java/Makefile +12 -0
  617. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  618. package/deps/librdkafka/tests/java/README.md +14 -0
  619. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  620. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  621. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  622. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  623. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  624. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  625. package/deps/librdkafka/tests/performance_plot.py +115 -0
  626. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  627. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  628. package/deps/librdkafka/tests/requirements.txt +2 -0
  629. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  630. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  631. package/deps/librdkafka/tests/run-test.sh +140 -0
  632. package/deps/librdkafka/tests/rusage.c +249 -0
  633. package/deps/librdkafka/tests/sasl_test.py +289 -0
  634. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  635. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  636. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  637. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  638. package/deps/librdkafka/tests/sockem.c +801 -0
  639. package/deps/librdkafka/tests/sockem.h +85 -0
  640. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  641. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  642. package/deps/librdkafka/tests/test.c +7318 -0
  643. package/deps/librdkafka/tests/test.conf.example +27 -0
  644. package/deps/librdkafka/tests/test.h +979 -0
  645. package/deps/librdkafka/tests/testcpp.cpp +126 -0
  646. package/deps/librdkafka/tests/testcpp.h +360 -0
  647. package/deps/librdkafka/tests/testshared.h +402 -0
  648. package/deps/librdkafka/tests/tools/README.md +4 -0
  649. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  650. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  651. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  652. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  653. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  654. package/deps/librdkafka/tests/until-fail.sh +87 -0
  655. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  656. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  657. package/deps/librdkafka/vcpkg.json +23 -0
  658. package/deps/librdkafka/win32/README.md +5 -0
  659. package/deps/librdkafka/win32/build-package.bat +3 -0
  660. package/deps/librdkafka/win32/build.bat +19 -0
  661. package/deps/librdkafka/win32/common.vcxproj +84 -0
  662. package/deps/librdkafka/win32/install-openssl.ps1 +33 -0
  663. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  664. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  665. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  666. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  667. package/deps/librdkafka/win32/librdkafka.vcxproj +276 -0
  668. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  669. package/deps/librdkafka/win32/msbuild.ps1 +15 -0
  670. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  671. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  672. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  673. package/deps/librdkafka/win32/push-package.bat +4 -0
  674. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  675. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  676. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  677. package/deps/librdkafka/win32/setup-msys2.ps1 +31 -0
  678. package/deps/librdkafka/win32/setup-vcpkg.ps1 +12 -0
  679. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  680. package/deps/librdkafka/win32/tests/tests.vcxproj +247 -0
  681. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  682. package/deps/librdkafka/win32/wingetopt.c +564 -0
  683. package/deps/librdkafka/win32/wingetopt.h +100 -0
  684. package/deps/librdkafka/win32/wintime.h +33 -0
  685. package/deps/librdkafka.gyp +62 -0
  686. package/deps/windows-install.py +73 -0
  687. package/docker-compose.yml +23 -0
  688. package/e2e/admin.spec.js +187 -0
  689. package/e2e/both.spec.js +726 -0
  690. package/e2e/consumer.spec.js +386 -0
  691. package/e2e/groups.spec.js +132 -0
  692. package/e2e/listener.js +51 -0
  693. package/e2e/producer-transaction.spec.js +333 -0
  694. package/e2e/producer.spec.js +283 -0
  695. package/errors.d.ts +347 -0
  696. package/examples/consumer-flow.md +76 -0
  697. package/examples/consumer.md +45 -0
  698. package/examples/docker-alpine.md +30 -0
  699. package/examples/high-level-producer.md +32 -0
  700. package/examples/metadata.md +27 -0
  701. package/examples/oauthbearer-default-flow.md +80 -0
  702. package/examples/producer-cluster.md +103 -0
  703. package/examples/producer.md +73 -0
  704. package/index.d.ts +357 -0
  705. package/lib/admin.js +233 -0
  706. package/lib/client.js +578 -0
  707. package/lib/error.js +472 -0
  708. package/lib/index.js +34 -0
  709. package/lib/kafka-consumer-stream.js +397 -0
  710. package/lib/kafka-consumer.js +698 -0
  711. package/lib/producer/high-level-producer.js +323 -0
  712. package/lib/producer-stream.js +307 -0
  713. package/lib/producer.js +375 -0
  714. package/lib/tools/ref-counter.js +52 -0
  715. package/lib/topic-partition.js +88 -0
  716. package/lib/topic.js +42 -0
  717. package/lib/util.js +29 -0
  718. package/librdkafka.js +12 -0
  719. package/make_docs.sh +59 -0
  720. package/package.json +53 -0
  721. package/renovate.json +30 -0
  722. package/run_docker.sh +42 -0
  723. package/src/admin.cc +624 -0
  724. package/src/admin.h +78 -0
  725. package/src/binding.cc +73 -0
  726. package/src/binding.h +25 -0
  727. package/src/callbacks.cc +614 -0
  728. package/src/callbacks.h +265 -0
  729. package/src/common.cc +582 -0
  730. package/src/common.h +134 -0
  731. package/src/config.cc +167 -0
  732. package/src/config.h +45 -0
  733. package/src/connection.cc +482 -0
  734. package/src/connection.h +108 -0
  735. package/src/errors.cc +96 -0
  736. package/src/errors.h +53 -0
  737. package/src/kafka-consumer.cc +1457 -0
  738. package/src/kafka-consumer.h +136 -0
  739. package/src/per-isolate-data.cc +57 -0
  740. package/src/per-isolate-data.h +39 -0
  741. package/src/producer.cc +873 -0
  742. package/src/producer.h +125 -0
  743. package/src/topic.cc +180 -0
  744. package/src/topic.h +56 -0
  745. package/src/workers.cc +1245 -0
  746. package/src/workers.h +511 -0
  747. package/test/binding.spec.js +66 -0
  748. package/test/consumer.spec.js +91 -0
  749. package/test/error.spec.js +8 -0
  750. package/test/index.spec.js +8 -0
  751. package/test/kafka-consumer-stream.spec.js +298 -0
  752. package/test/kafka-consumer-worker.js +51 -0
  753. package/test/kafka-consumer.spec.js +86 -0
  754. package/test/mocha.opts +1 -0
  755. package/test/mock.js +55 -0
  756. package/test/producer/high-level-producer.spec.js +496 -0
  757. package/test/producer-stream.spec.js +723 -0
  758. package/test/producer-worker.js +53 -0
  759. package/test/producer.spec.js +120 -0
  760. package/test/tools/ref-counter.spec.js +53 -0
  761. package/test/topic-partition.spec.js +104 -0
  762. package/test/util.spec.js +46 -0
  763. package/util/configure.js +30 -0
  764. package/util/get-env.js +6 -0
  765. package/util/test-compile.js +11 -0
  766. package/util/test-producer-delivery.js +100 -0
  767. package/win_install.ps1 +2 -0
@@ -0,0 +1,2885 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2019-2022, Magnus Edenhill
5
+ * 2023, Confluent Inc.
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright notice,
12
+ * this list of conditions and the following disclaimer.
13
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ /**
31
+ * Mocks
32
+ *
33
+ */
34
+
35
+ #include "rdkafka_int.h"
36
+ #include "rdbuf.h"
37
+ #include "rdrand.h"
38
+ #include "rdkafka_interceptor.h"
39
+ #include "rdkafka_mock_int.h"
40
+ #include "rdkafka_transport_int.h"
41
+ #include "rdkafka_mock.h"
42
+ #include <stdarg.h>
43
+
44
+ typedef struct rd_kafka_mock_request_s rd_kafka_mock_request_t;
45
+
46
+ static void rd_kafka_mock_cluster_destroy0(rd_kafka_mock_cluster_t *mcluster);
47
+ static rd_kafka_mock_request_t *
48
+ rd_kafka_mock_request_new(int32_t id, int16_t api_key, int64_t timestamp_us);
49
+ static void rd_kafka_mock_request_free(void *element);
50
+
51
+ static rd_kafka_mock_broker_t *
52
+ rd_kafka_mock_broker_find(const rd_kafka_mock_cluster_t *mcluster,
53
+ int32_t broker_id) {
54
+ const rd_kafka_mock_broker_t *mrkb;
55
+
56
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link)
57
+ if (mrkb->id == broker_id)
58
+ return (rd_kafka_mock_broker_t *)mrkb;
59
+
60
+ return NULL;
61
+ }
62
+
63
+
64
+
65
+ /**
66
+ * @brief Unlink and free message set.
67
+ */
68
+ static void rd_kafka_mock_msgset_destroy(rd_kafka_mock_partition_t *mpart,
69
+ rd_kafka_mock_msgset_t *mset) {
70
+ const rd_kafka_mock_msgset_t *next = TAILQ_NEXT(mset, link);
71
+
72
+ /* Removing last messageset */
73
+ if (!next)
74
+ mpart->start_offset = mpart->end_offset;
75
+ else if (mset == TAILQ_FIRST(&mpart->msgsets))
76
+ /* Removing first messageset */
77
+ mpart->start_offset = next->first_offset;
78
+
79
+ if (mpart->update_follower_start_offset)
80
+ mpart->follower_start_offset = mpart->start_offset;
81
+
82
+ rd_assert(mpart->cnt > 0);
83
+ mpart->cnt--;
84
+ mpart->size -= RD_KAFKAP_BYTES_LEN(&mset->bytes);
85
+ TAILQ_REMOVE(&mpart->msgsets, mset, link);
86
+ rd_free(mset);
87
+ }
88
+
89
+
90
+ /**
91
+ * @brief Create a new msgset object with a copy of \p bytes
92
+ * and appends it to the partition log.
93
+ */
94
+ static rd_kafka_mock_msgset_t *
95
+ rd_kafka_mock_msgset_new(rd_kafka_mock_partition_t *mpart,
96
+ const rd_kafkap_bytes_t *bytes,
97
+ size_t msgcnt) {
98
+ rd_kafka_mock_msgset_t *mset;
99
+ size_t totsize = sizeof(*mset) + RD_KAFKAP_BYTES_LEN(bytes);
100
+ int64_t BaseOffset;
101
+ int32_t PartitionLeaderEpoch;
102
+ int64_t orig_start_offset = mpart->start_offset;
103
+
104
+ rd_assert(!RD_KAFKAP_BYTES_IS_NULL(bytes));
105
+
106
+ mset = rd_malloc(totsize);
107
+ rd_assert(mset != NULL);
108
+
109
+ mset->first_offset = mpart->end_offset;
110
+ mset->last_offset = mset->first_offset + msgcnt - 1;
111
+ mpart->end_offset = mset->last_offset + 1;
112
+ if (mpart->update_follower_end_offset)
113
+ mpart->follower_end_offset = mpart->end_offset;
114
+ mpart->cnt++;
115
+
116
+ mset->bytes.len = bytes->len;
117
+ mset->leader_epoch = mpart->leader_epoch;
118
+
119
+
120
+ mset->bytes.data = (void *)(mset + 1);
121
+ memcpy((void *)mset->bytes.data, bytes->data, mset->bytes.len);
122
+ mpart->size += mset->bytes.len;
123
+
124
+ /* Update the base Offset in the MessageSet with the
125
+ * actual absolute log offset. */
126
+ BaseOffset = htobe64(mset->first_offset);
127
+ memcpy((void *)mset->bytes.data, &BaseOffset, sizeof(BaseOffset));
128
+ /* Update the base PartitionLeaderEpoch in the MessageSet with the
129
+ * actual partition leader epoch. */
130
+ PartitionLeaderEpoch = htobe32(mset->leader_epoch);
131
+ memcpy(((char *)mset->bytes.data) + 12, &PartitionLeaderEpoch,
132
+ sizeof(PartitionLeaderEpoch));
133
+
134
+ /* Remove old msgsets until within limits */
135
+ while (mpart->cnt > 1 &&
136
+ (mpart->cnt > mpart->max_cnt || mpart->size > mpart->max_size))
137
+ rd_kafka_mock_msgset_destroy(mpart,
138
+ TAILQ_FIRST(&mpart->msgsets));
139
+
140
+ TAILQ_INSERT_TAIL(&mpart->msgsets, mset, link);
141
+
142
+ rd_kafka_dbg(mpart->topic->cluster->rk, MOCK, "MOCK",
143
+ "Broker %" PRId32 ": Log append %s [%" PRId32
144
+ "] "
145
+ "%" PRIusz " messages, %" PRId32
146
+ " bytes at offset %" PRId64 " (log now %" PRId64
147
+ "..%" PRId64
148
+ ", "
149
+ "original start %" PRId64 ")",
150
+ mpart->leader->id, mpart->topic->name, mpart->id, msgcnt,
151
+ RD_KAFKAP_BYTES_LEN(&mset->bytes), mset->first_offset,
152
+ mpart->start_offset, mpart->end_offset, orig_start_offset);
153
+
154
+ return mset;
155
+ }
156
+
157
+ /**
158
+ * @brief Find message set containing \p offset
159
+ */
160
+ const rd_kafka_mock_msgset_t *
161
+ rd_kafka_mock_msgset_find(const rd_kafka_mock_partition_t *mpart,
162
+ int64_t offset,
163
+ rd_bool_t on_follower) {
164
+ const rd_kafka_mock_msgset_t *mset;
165
+
166
+ if (!on_follower &&
167
+ (offset < mpart->start_offset || offset > mpart->end_offset))
168
+ return NULL;
169
+
170
+ if (on_follower && (offset < mpart->follower_start_offset ||
171
+ offset > mpart->follower_end_offset))
172
+ return NULL;
173
+
174
+ /* FIXME: Maintain an index */
175
+
176
+ TAILQ_FOREACH(mset, &mpart->msgsets, link) {
177
+ if (mset->first_offset <= offset && offset <= mset->last_offset)
178
+ return mset;
179
+ }
180
+
181
+ return NULL;
182
+ }
183
+
184
+
185
+ /**
186
+ * @brief Looks up or creates a new pidstate for the given partition and PID.
187
+ *
188
+ * The pidstate is used to verify per-partition per-producer BaseSequences
189
+ * for the idempotent/txn producer.
190
+ */
191
+ static rd_kafka_mock_pid_t *
192
+ rd_kafka_mock_partition_pidstate_get(rd_kafka_mock_partition_t *mpart,
193
+ const rd_kafka_mock_pid_t *mpid) {
194
+ rd_kafka_mock_pid_t *pidstate;
195
+ size_t tidlen;
196
+
197
+ pidstate = rd_list_find(&mpart->pidstates, mpid, rd_kafka_mock_pid_cmp);
198
+ if (pidstate)
199
+ return pidstate;
200
+
201
+ tidlen = strlen(mpid->TransactionalId);
202
+ pidstate = rd_malloc(sizeof(*pidstate) + tidlen);
203
+ pidstate->pid = mpid->pid;
204
+ memcpy(pidstate->TransactionalId, mpid->TransactionalId, tidlen);
205
+ pidstate->TransactionalId[tidlen] = '\0';
206
+
207
+ pidstate->lo = pidstate->hi = pidstate->window = 0;
208
+ memset(pidstate->seq, 0, sizeof(pidstate->seq));
209
+
210
+ rd_list_add(&mpart->pidstates, pidstate);
211
+
212
+ return pidstate;
213
+ }
214
+
215
+
216
+ /**
217
+ * @brief Validate ProduceRequest records in \p rkbuf.
218
+ *
219
+ * @warning The \p rkbuf must not be read, just peek()ed.
220
+ *
221
+ * This is a very selective validation, currently only:
222
+ * - verify idempotency TransactionalId,PID,Epoch,Seq
223
+ */
224
+ static rd_kafka_resp_err_t
225
+ rd_kafka_mock_validate_records(rd_kafka_mock_partition_t *mpart,
226
+ rd_kafka_buf_t *rkbuf,
227
+ size_t RecordCount,
228
+ const rd_kafkap_str_t *TransactionalId,
229
+ rd_bool_t *is_dupd) {
230
+ const int log_decode_errors = LOG_ERR;
231
+ rd_kafka_mock_cluster_t *mcluster = mpart->topic->cluster;
232
+ rd_kafka_mock_pid_t *mpid;
233
+ rd_kafka_mock_pid_t *mpidstate = NULL;
234
+ rd_kafka_pid_t pid;
235
+ int32_t expected_BaseSequence = -1, BaseSequence = -1;
236
+ rd_kafka_resp_err_t err;
237
+
238
+ *is_dupd = rd_false;
239
+
240
+ if (!TransactionalId || RD_KAFKAP_STR_LEN(TransactionalId) < 1)
241
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
242
+
243
+ rd_kafka_buf_peek_i64(rkbuf, RD_KAFKAP_MSGSET_V2_OF_ProducerId,
244
+ &pid.id);
245
+ rd_kafka_buf_peek_i16(rkbuf, RD_KAFKAP_MSGSET_V2_OF_ProducerEpoch,
246
+ &pid.epoch);
247
+ rd_kafka_buf_peek_i32(rkbuf, RD_KAFKAP_MSGSET_V2_OF_BaseSequence,
248
+ &BaseSequence);
249
+
250
+ mtx_lock(&mcluster->lock);
251
+ err = rd_kafka_mock_pid_find(mcluster, TransactionalId, pid, &mpid);
252
+ mtx_unlock(&mcluster->lock);
253
+
254
+ if (likely(!err)) {
255
+
256
+ if (mpid->pid.epoch != pid.epoch)
257
+ err = RD_KAFKA_RESP_ERR_INVALID_PRODUCER_EPOCH;
258
+
259
+ /* Each partition tracks the 5 last Produce requests per PID.*/
260
+ mpidstate = rd_kafka_mock_partition_pidstate_get(mpart, mpid);
261
+
262
+ expected_BaseSequence = mpidstate->seq[mpidstate->hi];
263
+
264
+ /* A BaseSequence within the range of the last 5 requests is
265
+ * considered a legal duplicate and will be successfully acked
266
+ * but not written to the log. */
267
+ if (BaseSequence < mpidstate->seq[mpidstate->lo])
268
+ err = RD_KAFKA_RESP_ERR_DUPLICATE_SEQUENCE_NUMBER;
269
+ else if (BaseSequence > mpidstate->seq[mpidstate->hi])
270
+ err = RD_KAFKA_RESP_ERR_OUT_OF_ORDER_SEQUENCE_NUMBER;
271
+ else if (BaseSequence != expected_BaseSequence)
272
+ *is_dupd = rd_true;
273
+ }
274
+
275
+ if (unlikely(err)) {
276
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
277
+ "Broker %" PRId32 ": Log append %s [%" PRId32
278
+ "] failed: PID mismatch: TransactionalId=%.*s "
279
+ "expected %s BaseSeq %" PRId32
280
+ ", not %s BaseSeq %" PRId32 ": %s",
281
+ mpart->leader->id, mpart->topic->name, mpart->id,
282
+ RD_KAFKAP_STR_PR(TransactionalId),
283
+ mpid ? rd_kafka_pid2str(mpid->pid) : "n/a",
284
+ expected_BaseSequence, rd_kafka_pid2str(pid),
285
+ BaseSequence, rd_kafka_err2name(err));
286
+ return err;
287
+ }
288
+
289
+ /* Update BaseSequence window */
290
+ if (unlikely(mpidstate->window < 5))
291
+ mpidstate->window++;
292
+ else
293
+ mpidstate->lo = (mpidstate->lo + 1) % mpidstate->window;
294
+ mpidstate->hi = (mpidstate->hi + 1) % mpidstate->window;
295
+ mpidstate->seq[mpidstate->hi] = (int32_t)(BaseSequence + RecordCount);
296
+
297
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
298
+
299
+ err_parse:
300
+ return rkbuf->rkbuf_err;
301
+ }
302
+
303
+ /**
304
+ * @brief Append the MessageSets in \p bytes to the \p mpart partition log.
305
+ *
306
+ * @param BaseOffset will contain the first assigned offset of the message set.
307
+ */
308
+ rd_kafka_resp_err_t
309
+ rd_kafka_mock_partition_log_append(rd_kafka_mock_partition_t *mpart,
310
+ const rd_kafkap_bytes_t *records,
311
+ const rd_kafkap_str_t *TransactionalId,
312
+ int64_t *BaseOffset) {
313
+ const int log_decode_errors = LOG_ERR;
314
+ rd_kafka_buf_t *rkbuf;
315
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
316
+ int8_t MagicByte;
317
+ int32_t RecordCount;
318
+ int16_t Attributes;
319
+ rd_kafka_mock_msgset_t *mset;
320
+ rd_bool_t is_dup = rd_false;
321
+
322
+ /* Partially parse the MessageSet in \p bytes to get
323
+ * the message count. */
324
+ rkbuf = rd_kafka_buf_new_shadow(records->data,
325
+ RD_KAFKAP_BYTES_LEN(records), NULL);
326
+
327
+ rd_kafka_buf_peek_i8(rkbuf, RD_KAFKAP_MSGSET_V2_OF_MagicByte,
328
+ &MagicByte);
329
+ if (MagicByte != 2) {
330
+ /* We only support MsgVersion 2 for now */
331
+ err = RD_KAFKA_RESP_ERR_UNSUPPORTED_VERSION;
332
+ goto err;
333
+ }
334
+
335
+ rd_kafka_buf_peek_i32(rkbuf, RD_KAFKAP_MSGSET_V2_OF_RecordCount,
336
+ &RecordCount);
337
+ rd_kafka_buf_peek_i16(rkbuf, RD_KAFKAP_MSGSET_V2_OF_Attributes,
338
+ &Attributes);
339
+
340
+ if (RecordCount < 1 ||
341
+ (!(Attributes & RD_KAFKA_MSG_ATTR_COMPRESSION_MASK) &&
342
+ (size_t)RecordCount > RD_KAFKAP_BYTES_LEN(records) /
343
+ RD_KAFKAP_MESSAGE_V2_MIN_OVERHEAD)) {
344
+ err = RD_KAFKA_RESP_ERR_INVALID_MSG_SIZE;
345
+ goto err;
346
+ }
347
+
348
+ if ((err = rd_kafka_mock_validate_records(
349
+ mpart, rkbuf, (size_t)RecordCount, TransactionalId, &is_dup)))
350
+ goto err;
351
+
352
+ /* If this is a legit duplicate, don't write it to the log. */
353
+ if (is_dup)
354
+ goto err;
355
+
356
+ rd_kafka_buf_destroy(rkbuf);
357
+
358
+ mset = rd_kafka_mock_msgset_new(mpart, records, (size_t)RecordCount);
359
+
360
+ *BaseOffset = mset->first_offset;
361
+
362
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
363
+
364
+ err_parse:
365
+ err = rkbuf->rkbuf_err;
366
+ err:
367
+ rd_kafka_buf_destroy(rkbuf);
368
+ return err;
369
+ }
370
+
371
+
372
+ /**
373
+ * @brief Set the partition leader, or NULL for leader-less.
374
+ */
375
+ static void
376
+ rd_kafka_mock_partition_set_leader0(rd_kafka_mock_partition_t *mpart,
377
+ rd_kafka_mock_broker_t *mrkb) {
378
+ mpart->leader = mrkb;
379
+ mpart->leader_epoch++;
380
+ }
381
+
382
+
383
+ /**
384
+ * @brief Verifies that the client-provided leader_epoch matches that of the
385
+ * partition, else returns the appropriate error.
386
+ */
387
+ rd_kafka_resp_err_t rd_kafka_mock_partition_leader_epoch_check(
388
+ const rd_kafka_mock_partition_t *mpart,
389
+ int32_t leader_epoch) {
390
+ if (likely(leader_epoch == -1 || mpart->leader_epoch == leader_epoch))
391
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
392
+ else if (mpart->leader_epoch < leader_epoch)
393
+ return RD_KAFKA_RESP_ERR_UNKNOWN_LEADER_EPOCH;
394
+ else if (mpart->leader_epoch > leader_epoch)
395
+ return RD_KAFKA_RESP_ERR_FENCED_LEADER_EPOCH;
396
+
397
+ /* NOTREACHED, but avoids warning */
398
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
399
+ }
400
+
401
+ /**
402
+ * @brief Returns the end offset (last offset + 1)
403
+ * for the passed leader epoch in the mock partition.
404
+ *
405
+ * @param mpart The mock partition
406
+ * @param leader_epoch The leader epoch
407
+ *
408
+ * @return The end offset for the passed \p leader_epoch in \p mpart
409
+ */
410
+ int64_t rd_kafka_mock_partition_offset_for_leader_epoch(
411
+ const rd_kafka_mock_partition_t *mpart,
412
+ int32_t leader_epoch) {
413
+ const rd_kafka_mock_msgset_t *mset = NULL;
414
+
415
+ if (leader_epoch < 0)
416
+ return -1;
417
+
418
+ TAILQ_FOREACH_REVERSE(mset, &mpart->msgsets,
419
+ rd_kafka_mock_msgset_tailq_s, link) {
420
+ if (mset->leader_epoch == leader_epoch)
421
+ return mset->last_offset + 1;
422
+ }
423
+
424
+ return -1;
425
+ }
426
+
427
+
428
+ /**
429
+ * @brief Automatically assign replicas for partition
430
+ */
431
+ static void
432
+ rd_kafka_mock_partition_assign_replicas(rd_kafka_mock_partition_t *mpart,
433
+ int replication_factor) {
434
+ rd_kafka_mock_cluster_t *mcluster = mpart->topic->cluster;
435
+ int replica_cnt = RD_MIN(replication_factor, mcluster->broker_cnt);
436
+ rd_kafka_mock_broker_t *mrkb;
437
+ int i = 0;
438
+ int first_replica =
439
+ (mpart->id * replication_factor) % mcluster->broker_cnt;
440
+ int skipped = 0;
441
+
442
+ if (mpart->replicas)
443
+ rd_free(mpart->replicas);
444
+
445
+ mpart->replicas = rd_calloc(replica_cnt, sizeof(*mpart->replicas));
446
+ mpart->replica_cnt = replica_cnt;
447
+
448
+
449
+ /* Use a predictable, determininistic order on a per-topic basis.
450
+ *
451
+ * Two loops are needed for wraparound. */
452
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link) {
453
+ if (skipped < first_replica) {
454
+ skipped++;
455
+ continue;
456
+ }
457
+ if (i == mpart->replica_cnt)
458
+ break;
459
+ mpart->replicas[i++] = mrkb;
460
+ }
461
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link) {
462
+ if (i == mpart->replica_cnt)
463
+ break;
464
+ mpart->replicas[i++] = mrkb;
465
+ }
466
+
467
+ /* Select a random leader */
468
+ rd_kafka_mock_partition_set_leader0(
469
+ mpart, mpart->replicas[rd_jitter(0, replica_cnt - 1)]);
470
+ }
471
+
472
+ /**
473
+ * @brief Push a partition leader response to passed \p mpart .
474
+ */
475
+ static void
476
+ rd_kafka_mock_partition_push_leader_response0(rd_kafka_mock_partition_t *mpart,
477
+ int32_t leader_id,
478
+ int32_t leader_epoch) {
479
+ rd_kafka_mock_partition_leader_t *leader_response;
480
+
481
+ leader_response = rd_calloc(1, sizeof(*leader_response));
482
+ leader_response->leader_id = leader_id;
483
+ leader_response->leader_epoch = leader_epoch;
484
+ TAILQ_INSERT_TAIL(&mpart->leader_responses, leader_response, link);
485
+ }
486
+
487
+ /**
488
+ * @brief Return the first mocked partition leader response in \p mpart ,
489
+ * if available.
490
+ */
491
+ rd_kafka_mock_partition_leader_t *
492
+ rd_kafka_mock_partition_next_leader_response(rd_kafka_mock_partition_t *mpart) {
493
+ return TAILQ_FIRST(&mpart->leader_responses);
494
+ }
495
+
496
+ /**
497
+ * @brief Unlink and destroy a partition leader response
498
+ */
499
+ void rd_kafka_mock_partition_leader_destroy(
500
+ rd_kafka_mock_partition_t *mpart,
501
+ rd_kafka_mock_partition_leader_t *mpart_leader) {
502
+ TAILQ_REMOVE(&mpart->leader_responses, mpart_leader, link);
503
+ rd_free(mpart_leader);
504
+ }
505
+
506
+ /**
507
+ * @brief Unlink and destroy committed offset
508
+ */
509
+ static void
510
+ rd_kafka_mock_committed_offset_destroy(rd_kafka_mock_partition_t *mpart,
511
+ rd_kafka_mock_committed_offset_t *coff) {
512
+ rd_kafkap_str_destroy(coff->metadata);
513
+ TAILQ_REMOVE(&mpart->committed_offsets, coff, link);
514
+ rd_free(coff);
515
+ }
516
+
517
+
518
+ /**
519
+ * @brief Find previously committed offset for group.
520
+ */
521
+ rd_kafka_mock_committed_offset_t *
522
+ rd_kafka_mock_committed_offset_find(const rd_kafka_mock_partition_t *mpart,
523
+ const rd_kafkap_str_t *group) {
524
+ const rd_kafka_mock_committed_offset_t *coff;
525
+
526
+ TAILQ_FOREACH(coff, &mpart->committed_offsets, link) {
527
+ if (!rd_kafkap_str_cmp_str(group, coff->group))
528
+ return (rd_kafka_mock_committed_offset_t *)coff;
529
+ }
530
+
531
+ return NULL;
532
+ }
533
+
534
+
535
+ /**
536
+ * @brief Commit offset for group
537
+ */
538
+ rd_kafka_mock_committed_offset_t *
539
+ rd_kafka_mock_commit_offset(rd_kafka_mock_partition_t *mpart,
540
+ const rd_kafkap_str_t *group,
541
+ int64_t offset,
542
+ const rd_kafkap_str_t *metadata) {
543
+ rd_kafka_mock_committed_offset_t *coff;
544
+
545
+ if (!(coff = rd_kafka_mock_committed_offset_find(mpart, group))) {
546
+ size_t slen = (size_t)RD_KAFKAP_STR_LEN(group);
547
+
548
+ coff = rd_malloc(sizeof(*coff) + slen + 1);
549
+
550
+ coff->group = (char *)(coff + 1);
551
+ memcpy(coff->group, group->str, slen);
552
+ coff->group[slen] = '\0';
553
+
554
+ coff->metadata = NULL;
555
+
556
+ TAILQ_INSERT_HEAD(&mpart->committed_offsets, coff, link);
557
+ }
558
+
559
+ if (coff->metadata)
560
+ rd_kafkap_str_destroy(coff->metadata);
561
+
562
+ coff->metadata = rd_kafkap_str_copy(metadata);
563
+
564
+ coff->offset = offset;
565
+
566
+ rd_kafka_dbg(mpart->topic->cluster->rk, MOCK, "MOCK",
567
+ "Topic %s [%" PRId32 "] committing offset %" PRId64
568
+ " for group %.*s",
569
+ mpart->topic->name, mpart->id, offset,
570
+ RD_KAFKAP_STR_PR(group));
571
+
572
+ return coff;
573
+ }
574
+
575
+ /**
576
+ * @brief Destroy resources for partition, but the \p mpart itself is not freed.
577
+ */
578
+ static void rd_kafka_mock_partition_destroy(rd_kafka_mock_partition_t *mpart) {
579
+ rd_kafka_mock_msgset_t *mset, *tmp;
580
+ rd_kafka_mock_committed_offset_t *coff, *tmpcoff;
581
+ rd_kafka_mock_partition_leader_t *mpart_leader, *tmp_mpart_leader;
582
+
583
+ TAILQ_FOREACH_SAFE(mset, &mpart->msgsets, link, tmp)
584
+ rd_kafka_mock_msgset_destroy(mpart, mset);
585
+
586
+ TAILQ_FOREACH_SAFE(coff, &mpart->committed_offsets, link, tmpcoff)
587
+ rd_kafka_mock_committed_offset_destroy(mpart, coff);
588
+
589
+ TAILQ_FOREACH_SAFE(mpart_leader, &mpart->leader_responses, link,
590
+ tmp_mpart_leader)
591
+ rd_kafka_mock_partition_leader_destroy(mpart, mpart_leader);
592
+
593
+ rd_list_destroy(&mpart->pidstates);
594
+
595
+ rd_free(mpart->replicas);
596
+ }
597
+
598
+
599
+ static void rd_kafka_mock_partition_init(rd_kafka_mock_topic_t *mtopic,
600
+ rd_kafka_mock_partition_t *mpart,
601
+ int id,
602
+ int replication_factor) {
603
+ mpart->topic = mtopic;
604
+ mpart->id = id;
605
+
606
+ mpart->follower_id = -1;
607
+ mpart->leader_epoch = -1; /* Start at -1 since assign_replicas() will
608
+ * bump it right away to 0. */
609
+
610
+ TAILQ_INIT(&mpart->msgsets);
611
+
612
+ mpart->max_size = 1024 * 1024 * 5;
613
+ mpart->max_cnt = 100000;
614
+
615
+ mpart->update_follower_start_offset = rd_true;
616
+ mpart->update_follower_end_offset = rd_true;
617
+
618
+ TAILQ_INIT(&mpart->committed_offsets);
619
+ TAILQ_INIT(&mpart->leader_responses);
620
+
621
+ rd_list_init(&mpart->pidstates, 0, rd_free);
622
+
623
+ rd_kafka_mock_partition_assign_replicas(mpart, replication_factor);
624
+ }
625
+
626
+ rd_kafka_mock_partition_t *
627
+ rd_kafka_mock_partition_find(const rd_kafka_mock_topic_t *mtopic,
628
+ int32_t partition) {
629
+ if (!mtopic || partition < 0 || partition >= mtopic->partition_cnt)
630
+ return NULL;
631
+
632
+ return (rd_kafka_mock_partition_t *)&mtopic->partitions[partition];
633
+ }
634
+
635
+
636
+ static void rd_kafka_mock_topic_destroy(rd_kafka_mock_topic_t *mtopic) {
637
+ int i;
638
+
639
+ for (i = 0; i < mtopic->partition_cnt; i++)
640
+ rd_kafka_mock_partition_destroy(&mtopic->partitions[i]);
641
+
642
+ TAILQ_REMOVE(&mtopic->cluster->topics, mtopic, link);
643
+ mtopic->cluster->topic_cnt--;
644
+
645
+ rd_free(mtopic->partitions);
646
+ rd_free(mtopic->name);
647
+ rd_free(mtopic);
648
+ }
649
+
650
+
651
+ static rd_kafka_mock_topic_t *
652
+ rd_kafka_mock_topic_new(rd_kafka_mock_cluster_t *mcluster,
653
+ const char *topic,
654
+ int partition_cnt,
655
+ int replication_factor) {
656
+ rd_kafka_mock_topic_t *mtopic;
657
+ int i;
658
+
659
+ mtopic = rd_calloc(1, sizeof(*mtopic));
660
+ /* Assign random topic id */
661
+ mtopic->id = rd_kafka_Uuid_random();
662
+ mtopic->name = rd_strdup(topic);
663
+ mtopic->cluster = mcluster;
664
+
665
+ mtopic->partition_cnt = partition_cnt;
666
+ mtopic->partitions =
667
+ rd_calloc(partition_cnt, sizeof(*mtopic->partitions));
668
+
669
+ for (i = 0; i < partition_cnt; i++)
670
+ rd_kafka_mock_partition_init(mtopic, &mtopic->partitions[i], i,
671
+ replication_factor);
672
+
673
+ TAILQ_INSERT_TAIL(&mcluster->topics, mtopic, link);
674
+ mcluster->topic_cnt++;
675
+
676
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
677
+ "Created topic \"%s\" with %d partition(s) and "
678
+ "replication-factor %d",
679
+ mtopic->name, mtopic->partition_cnt, replication_factor);
680
+
681
+ return mtopic;
682
+ }
683
+
684
+
685
+ rd_kafka_mock_topic_t *
686
+ rd_kafka_mock_topic_find(const rd_kafka_mock_cluster_t *mcluster,
687
+ const char *name) {
688
+ const rd_kafka_mock_topic_t *mtopic;
689
+
690
+ TAILQ_FOREACH(mtopic, &mcluster->topics, link) {
691
+ if (!strcmp(mtopic->name, name))
692
+ return (rd_kafka_mock_topic_t *)mtopic;
693
+ }
694
+
695
+ return NULL;
696
+ }
697
+
698
+
699
+ rd_kafka_mock_topic_t *
700
+ rd_kafka_mock_topic_find_by_kstr(const rd_kafka_mock_cluster_t *mcluster,
701
+ const rd_kafkap_str_t *kname) {
702
+ const rd_kafka_mock_topic_t *mtopic;
703
+
704
+ TAILQ_FOREACH(mtopic, &mcluster->topics, link) {
705
+ if (!strncmp(mtopic->name, kname->str,
706
+ RD_KAFKAP_STR_LEN(kname)) &&
707
+ mtopic->name[RD_KAFKAP_STR_LEN(kname)] == '\0')
708
+ return (rd_kafka_mock_topic_t *)mtopic;
709
+ }
710
+
711
+ return NULL;
712
+ }
713
+
714
+ /**
715
+ * @brief Find a mock topic by id.
716
+ *
717
+ * @param mcluster Cluster to search in.
718
+ * @param id Topic id to find.
719
+ * @return Found topic or NULL.
720
+ *
721
+ * @locks mcluster->lock MUST be held.
722
+ */
723
+ rd_kafka_mock_topic_t *
724
+ rd_kafka_mock_topic_find_by_id(const rd_kafka_mock_cluster_t *mcluster,
725
+ rd_kafka_Uuid_t id) {
726
+ const rd_kafka_mock_topic_t *mtopic;
727
+
728
+ TAILQ_FOREACH(mtopic, &mcluster->topics, link) {
729
+ if (!rd_kafka_Uuid_cmp(mtopic->id, id))
730
+ return (rd_kafka_mock_topic_t *)mtopic;
731
+ }
732
+
733
+ return NULL;
734
+ }
735
+
736
+
737
+ /**
738
+ * @brief Create a topic using default settings.
739
+ * The topic must not already exist.
740
+ *
741
+ * @param errp will be set to an error code that is consistent with
742
+ * new topics on real clusters.
743
+ */
744
+ rd_kafka_mock_topic_t *
745
+ rd_kafka_mock_topic_auto_create(rd_kafka_mock_cluster_t *mcluster,
746
+ const char *topic,
747
+ int partition_cnt,
748
+ rd_kafka_resp_err_t *errp) {
749
+ rd_assert(!rd_kafka_mock_topic_find(mcluster, topic));
750
+ *errp = 0; // FIXME? RD_KAFKA_RESP_ERR_LEADER_NOT_AVAILABLE;
751
+ return rd_kafka_mock_topic_new(mcluster, topic,
752
+ partition_cnt == -1
753
+ ? mcluster->defaults.partition_cnt
754
+ : partition_cnt,
755
+ mcluster->defaults.replication_factor);
756
+ }
757
+
758
+
759
+ /**
760
+ * @brief Find or create topic.
761
+ *
762
+ * @param partition_cnt If not -1 and the topic does not exist, the automatic
763
+ * topic creation will create this number of topics.
764
+ * Otherwise use the default.
765
+ */
766
+ rd_kafka_mock_topic_t *
767
+ rd_kafka_mock_topic_get(rd_kafka_mock_cluster_t *mcluster,
768
+ const char *topic,
769
+ int partition_cnt) {
770
+ rd_kafka_mock_topic_t *mtopic;
771
+ rd_kafka_resp_err_t err;
772
+
773
+ if ((mtopic = rd_kafka_mock_topic_find(mcluster, topic)))
774
+ return mtopic;
775
+
776
+ return rd_kafka_mock_topic_auto_create(mcluster, topic, partition_cnt,
777
+ &err);
778
+ }
779
+
780
+ /**
781
+ * @brief Find or create a partition.
782
+ *
783
+ * @returns NULL if topic already exists and partition is out of range.
784
+ */
785
+ static rd_kafka_mock_partition_t *
786
+ rd_kafka_mock_partition_get(rd_kafka_mock_cluster_t *mcluster,
787
+ const char *topic,
788
+ int32_t partition) {
789
+ rd_kafka_mock_topic_t *mtopic;
790
+ rd_kafka_resp_err_t err;
791
+
792
+ if (!(mtopic = rd_kafka_mock_topic_find(mcluster, topic)))
793
+ mtopic = rd_kafka_mock_topic_auto_create(mcluster, topic,
794
+ partition + 1, &err);
795
+
796
+ if (partition >= mtopic->partition_cnt)
797
+ return NULL;
798
+
799
+ return &mtopic->partitions[partition];
800
+ }
801
+
802
+
803
+ /**
804
+ * @brief Set IO events for fd
805
+ */
806
+ static void
807
+ rd_kafka_mock_cluster_io_set_events(rd_kafka_mock_cluster_t *mcluster,
808
+ rd_socket_t fd,
809
+ int events) {
810
+ int i;
811
+
812
+ for (i = 0; i < mcluster->fd_cnt; i++) {
813
+ if (mcluster->fds[i].fd == fd) {
814
+ mcluster->fds[i].events |= events;
815
+ return;
816
+ }
817
+ }
818
+
819
+ rd_assert(!*"mock_cluster_io_set_events: fd not found");
820
+ }
821
+
822
+ /**
823
+ * @brief Set or clear single IO events for fd
824
+ */
825
+ static void
826
+ rd_kafka_mock_cluster_io_set_event(rd_kafka_mock_cluster_t *mcluster,
827
+ rd_socket_t fd,
828
+ rd_bool_t set,
829
+ int event) {
830
+ int i;
831
+
832
+ for (i = 0; i < mcluster->fd_cnt; i++) {
833
+ if (mcluster->fds[i].fd == fd) {
834
+ if (set)
835
+ mcluster->fds[i].events |= event;
836
+ else
837
+ mcluster->fds[i].events &= ~event;
838
+ return;
839
+ }
840
+ }
841
+
842
+ rd_assert(!*"mock_cluster_io_set_event: fd not found");
843
+ }
844
+
845
+
846
+ /**
847
+ * @brief Clear IO events for fd
848
+ */
849
+ static void
850
+ rd_kafka_mock_cluster_io_clear_events(rd_kafka_mock_cluster_t *mcluster,
851
+ rd_socket_t fd,
852
+ int events) {
853
+ int i;
854
+
855
+ for (i = 0; i < mcluster->fd_cnt; i++) {
856
+ if (mcluster->fds[i].fd == fd) {
857
+ mcluster->fds[i].events &= ~events;
858
+ return;
859
+ }
860
+ }
861
+
862
+ rd_assert(!*"mock_cluster_io_set_events: fd not found");
863
+ }
864
+
865
+
866
+ static void rd_kafka_mock_cluster_io_del(rd_kafka_mock_cluster_t *mcluster,
867
+ rd_socket_t fd) {
868
+ int i;
869
+
870
+ for (i = 0; i < mcluster->fd_cnt; i++) {
871
+ if (mcluster->fds[i].fd == fd) {
872
+ if (i + 1 < mcluster->fd_cnt) {
873
+ memmove(&mcluster->fds[i],
874
+ &mcluster->fds[i + 1],
875
+ sizeof(*mcluster->fds) *
876
+ (mcluster->fd_cnt - i));
877
+ memmove(&mcluster->handlers[i],
878
+ &mcluster->handlers[i + 1],
879
+ sizeof(*mcluster->handlers) *
880
+ (mcluster->fd_cnt - i));
881
+ }
882
+
883
+ mcluster->fd_cnt--;
884
+ return;
885
+ }
886
+ }
887
+
888
+ rd_assert(!*"mock_cluster_io_del: fd not found");
889
+ }
890
+
891
+
892
+ /**
893
+ * @brief Add \p fd to IO poll with initial desired events (POLLIN, et.al).
894
+ */
895
+ static void rd_kafka_mock_cluster_io_add(rd_kafka_mock_cluster_t *mcluster,
896
+ rd_socket_t fd,
897
+ int events,
898
+ rd_kafka_mock_io_handler_t handler,
899
+ void *opaque) {
900
+
901
+ if (mcluster->fd_cnt + 1 >= mcluster->fd_size) {
902
+ mcluster->fd_size += 8;
903
+
904
+ mcluster->fds = rd_realloc(
905
+ mcluster->fds, sizeof(*mcluster->fds) * mcluster->fd_size);
906
+ mcluster->handlers =
907
+ rd_realloc(mcluster->handlers,
908
+ sizeof(*mcluster->handlers) * mcluster->fd_size);
909
+ }
910
+
911
+ memset(&mcluster->fds[mcluster->fd_cnt], 0,
912
+ sizeof(mcluster->fds[mcluster->fd_cnt]));
913
+ mcluster->fds[mcluster->fd_cnt].fd = fd;
914
+ mcluster->fds[mcluster->fd_cnt].events = events;
915
+ mcluster->fds[mcluster->fd_cnt].revents = 0;
916
+ mcluster->handlers[mcluster->fd_cnt].cb = handler;
917
+ mcluster->handlers[mcluster->fd_cnt].opaque = opaque;
918
+ mcluster->fd_cnt++;
919
+ }
920
+
921
+
922
+ static void rd_kafka_mock_connection_close(rd_kafka_mock_connection_t *mconn,
923
+ const char *reason) {
924
+ rd_kafka_buf_t *rkbuf;
925
+
926
+ rd_kafka_dbg(mconn->broker->cluster->rk, MOCK, "MOCK",
927
+ "Broker %" PRId32 ": Connection from %s closed: %s",
928
+ mconn->broker->id,
929
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT),
930
+ reason);
931
+
932
+ rd_kafka_mock_cgrps_connection_closed(mconn->broker->cluster, mconn);
933
+
934
+ rd_kafka_timer_stop(&mconn->broker->cluster->timers, &mconn->write_tmr,
935
+ rd_true);
936
+
937
+ while ((rkbuf = TAILQ_FIRST(&mconn->outbufs.rkbq_bufs))) {
938
+ rd_kafka_bufq_deq(&mconn->outbufs, rkbuf);
939
+ rd_kafka_buf_destroy(rkbuf);
940
+ }
941
+
942
+ if (mconn->rxbuf)
943
+ rd_kafka_buf_destroy(mconn->rxbuf);
944
+
945
+ rd_kafka_mock_cluster_io_del(mconn->broker->cluster,
946
+ mconn->transport->rktrans_s);
947
+ TAILQ_REMOVE(&mconn->broker->connections, mconn, link);
948
+ rd_kafka_transport_close(mconn->transport);
949
+ rd_free(mconn);
950
+ }
951
+
952
+ void rd_kafka_mock_connection_send_response0(rd_kafka_mock_connection_t *mconn,
953
+ rd_kafka_buf_t *resp,
954
+ rd_bool_t tags_written) {
955
+
956
+ if (!tags_written && (resp->rkbuf_flags & RD_KAFKA_OP_F_FLEXVER)) {
957
+ /* Empty struct tags */
958
+ rd_kafka_buf_write_i8(resp, 0);
959
+ }
960
+
961
+ /* rkbuf_ts_sent might be initialized with a RTT delay, else 0. */
962
+ resp->rkbuf_ts_sent += rd_clock();
963
+
964
+ resp->rkbuf_reshdr.Size =
965
+ (int32_t)(rd_buf_write_pos(&resp->rkbuf_buf) - 4);
966
+
967
+ rd_kafka_buf_update_i32(resp, 0, resp->rkbuf_reshdr.Size);
968
+
969
+ rd_kafka_dbg(mconn->broker->cluster->rk, MOCK, "MOCK",
970
+ "Broker %" PRId32 ": Sending %sResponseV%hd to %s",
971
+ mconn->broker->id,
972
+ rd_kafka_ApiKey2str(resp->rkbuf_reqhdr.ApiKey),
973
+ resp->rkbuf_reqhdr.ApiVersion,
974
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
975
+
976
+ /* Set up a buffer reader for sending the buffer. */
977
+ rd_slice_init_full(&resp->rkbuf_reader, &resp->rkbuf_buf);
978
+
979
+ rd_kafka_bufq_enq(&mconn->outbufs, resp);
980
+
981
+ rd_kafka_mock_cluster_io_set_events(
982
+ mconn->broker->cluster, mconn->transport->rktrans_s, POLLOUT);
983
+ }
984
+
985
+
986
+ /**
987
+ * @returns 1 if a complete request is available in which case \p slicep
988
+ * is set to a new slice containing the data,
989
+ * 0 if a complete request is not yet available,
990
+ * -1 on error.
991
+ */
992
+ static int
993
+ rd_kafka_mock_connection_read_request(rd_kafka_mock_connection_t *mconn,
994
+ rd_kafka_buf_t **rkbufp) {
995
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
996
+ rd_kafka_t *rk = mcluster->rk;
997
+ const rd_bool_t log_decode_errors = rd_true;
998
+ rd_kafka_buf_t *rkbuf;
999
+ char errstr[128];
1000
+ ssize_t r;
1001
+
1002
+ if (!(rkbuf = mconn->rxbuf)) {
1003
+ /* Initial read for a protocol request.
1004
+ * Allocate enough room for the protocol header
1005
+ * (where the total size is located). */
1006
+ rkbuf = mconn->rxbuf =
1007
+ rd_kafka_buf_new(2, RD_KAFKAP_REQHDR_SIZE);
1008
+
1009
+ /* Protocol parsing code needs the rkb for logging */
1010
+ rkbuf->rkbuf_rkb = mconn->broker->cluster->dummy_rkb;
1011
+ rd_kafka_broker_keep(rkbuf->rkbuf_rkb);
1012
+
1013
+ /* Make room for request header */
1014
+ rd_buf_write_ensure(&rkbuf->rkbuf_buf, RD_KAFKAP_REQHDR_SIZE,
1015
+ RD_KAFKAP_REQHDR_SIZE);
1016
+ }
1017
+
1018
+ /* Read as much data as possible from the socket into the
1019
+ * connection receive buffer. */
1020
+ r = rd_kafka_transport_recv(mconn->transport, &rkbuf->rkbuf_buf, errstr,
1021
+ sizeof(errstr));
1022
+ if (r == -1) {
1023
+ rd_kafka_dbg(
1024
+ rk, MOCK, "MOCK",
1025
+ "Broker %" PRId32
1026
+ ": Connection %s: "
1027
+ "receive failed: %s",
1028
+ mconn->broker->id,
1029
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT),
1030
+ errstr);
1031
+ return -1;
1032
+ } else if (r == 0) {
1033
+ return 0; /* Need more data */
1034
+ }
1035
+
1036
+ if (rd_buf_write_pos(&rkbuf->rkbuf_buf) == RD_KAFKAP_REQHDR_SIZE) {
1037
+ /* Received the full header, now check full request
1038
+ * size and allocate the buffer accordingly. */
1039
+
1040
+ /* Initialize reader */
1041
+ rd_slice_init(&rkbuf->rkbuf_reader, &rkbuf->rkbuf_buf, 0,
1042
+ RD_KAFKAP_REQHDR_SIZE);
1043
+
1044
+ rd_kafka_buf_read_i32(rkbuf, &rkbuf->rkbuf_reqhdr.Size);
1045
+ rd_kafka_buf_read_i16(rkbuf, &rkbuf->rkbuf_reqhdr.ApiKey);
1046
+ rd_kafka_buf_read_i16(rkbuf, &rkbuf->rkbuf_reqhdr.ApiVersion);
1047
+
1048
+ if (rkbuf->rkbuf_reqhdr.ApiKey < 0 ||
1049
+ rkbuf->rkbuf_reqhdr.ApiKey >= RD_KAFKAP__NUM) {
1050
+ rd_kafka_buf_parse_fail(
1051
+ rkbuf, "Invalid ApiKey %hd from %s",
1052
+ rkbuf->rkbuf_reqhdr.ApiKey,
1053
+ rd_sockaddr2str(&mconn->peer,
1054
+ RD_SOCKADDR2STR_F_PORT));
1055
+ RD_NOTREACHED();
1056
+ }
1057
+
1058
+ /* Check if request version has flexible fields (KIP-482) */
1059
+ if (mcluster->api_handlers[rkbuf->rkbuf_reqhdr.ApiKey]
1060
+ .FlexVersion != -1 &&
1061
+ rkbuf->rkbuf_reqhdr.ApiVersion >=
1062
+ mcluster->api_handlers[rkbuf->rkbuf_reqhdr.ApiKey]
1063
+ .FlexVersion)
1064
+ rkbuf->rkbuf_flags |= RD_KAFKA_OP_F_FLEXVER;
1065
+
1066
+
1067
+ rd_kafka_buf_read_i32(rkbuf, &rkbuf->rkbuf_reqhdr.CorrId);
1068
+
1069
+ rkbuf->rkbuf_totlen = rkbuf->rkbuf_reqhdr.Size + 4;
1070
+
1071
+ if (rkbuf->rkbuf_totlen < RD_KAFKAP_REQHDR_SIZE + 2 ||
1072
+ rkbuf->rkbuf_totlen >
1073
+ (size_t)rk->rk_conf.recv_max_msg_size) {
1074
+ rd_kafka_buf_parse_fail(
1075
+ rkbuf, "Invalid request size %" PRId32 " from %s",
1076
+ rkbuf->rkbuf_reqhdr.Size,
1077
+ rd_sockaddr2str(&mconn->peer,
1078
+ RD_SOCKADDR2STR_F_PORT));
1079
+ RD_NOTREACHED();
1080
+ }
1081
+
1082
+ /* Now adjust totlen to skip the header */
1083
+ rkbuf->rkbuf_totlen -= RD_KAFKAP_REQHDR_SIZE;
1084
+
1085
+ if (!rkbuf->rkbuf_totlen) {
1086
+ /* Empty request (valid) */
1087
+ *rkbufp = rkbuf;
1088
+ mconn->rxbuf = NULL;
1089
+ return 1;
1090
+ }
1091
+
1092
+ /* Allocate space for the request payload */
1093
+ rd_buf_write_ensure(&rkbuf->rkbuf_buf, rkbuf->rkbuf_totlen,
1094
+ rkbuf->rkbuf_totlen);
1095
+
1096
+ } else if (rd_buf_write_pos(&rkbuf->rkbuf_buf) -
1097
+ RD_KAFKAP_REQHDR_SIZE ==
1098
+ rkbuf->rkbuf_totlen) {
1099
+ /* The full request is now read into the buffer. */
1100
+
1101
+ /* Set up response reader slice starting past the
1102
+ * request header */
1103
+ rd_slice_init(&rkbuf->rkbuf_reader, &rkbuf->rkbuf_buf,
1104
+ RD_KAFKAP_REQHDR_SIZE,
1105
+ rd_buf_len(&rkbuf->rkbuf_buf) -
1106
+ RD_KAFKAP_REQHDR_SIZE);
1107
+
1108
+ /* For convenience, shave off the ClientId */
1109
+ rd_kafka_buf_skip_str_no_flexver(rkbuf);
1110
+
1111
+ /* And the flexible versions header tags, if any */
1112
+ rd_kafka_buf_skip_tags(rkbuf);
1113
+
1114
+ /* Return the buffer to the caller */
1115
+ *rkbufp = rkbuf;
1116
+ mconn->rxbuf = NULL;
1117
+ return 1;
1118
+ }
1119
+
1120
+ return 0;
1121
+
1122
+
1123
+ err_parse:
1124
+ return -1;
1125
+ }
1126
+
1127
+ rd_kafka_buf_t *rd_kafka_mock_buf_new_response(const rd_kafka_buf_t *request) {
1128
+ rd_kafka_buf_t *rkbuf = rd_kafka_buf_new(1, 100);
1129
+
1130
+ /* Copy request header so the ApiVersion remains known */
1131
+ rkbuf->rkbuf_reqhdr = request->rkbuf_reqhdr;
1132
+
1133
+ /* Size, updated later */
1134
+ rd_kafka_buf_write_i32(rkbuf, 0);
1135
+
1136
+ /* CorrId */
1137
+ rd_kafka_buf_write_i32(rkbuf, request->rkbuf_reqhdr.CorrId);
1138
+
1139
+ if (request->rkbuf_flags & RD_KAFKA_OP_F_FLEXVER) {
1140
+ rkbuf->rkbuf_flags |= RD_KAFKA_OP_F_FLEXVER;
1141
+ /* Write empty response header tags, unless this is the
1142
+ * ApiVersionResponse which needs to be backwards compatible. */
1143
+ if (request->rkbuf_reqhdr.ApiKey != RD_KAFKAP_ApiVersion)
1144
+ rd_kafka_buf_write_i8(rkbuf, 0);
1145
+ }
1146
+
1147
+ return rkbuf;
1148
+ }
1149
+
1150
+
1151
+
1152
+ /**
1153
+ * @brief Parse protocol request.
1154
+ *
1155
+ * @returns 0 on success, -1 on parse error.
1156
+ */
1157
+ static int
1158
+ rd_kafka_mock_connection_parse_request(rd_kafka_mock_connection_t *mconn,
1159
+ rd_kafka_buf_t *rkbuf) {
1160
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1161
+ rd_kafka_t *rk = mcluster->rk;
1162
+
1163
+ if (rkbuf->rkbuf_reqhdr.ApiKey < 0 ||
1164
+ rkbuf->rkbuf_reqhdr.ApiKey >= RD_KAFKAP__NUM ||
1165
+ !mcluster->api_handlers[rkbuf->rkbuf_reqhdr.ApiKey].cb) {
1166
+ rd_kafka_log(
1167
+ rk, LOG_ERR, "MOCK",
1168
+ "Broker %" PRId32
1169
+ ": unsupported %sRequestV%hd "
1170
+ "from %s",
1171
+ mconn->broker->id,
1172
+ rd_kafka_ApiKey2str(rkbuf->rkbuf_reqhdr.ApiKey),
1173
+ rkbuf->rkbuf_reqhdr.ApiVersion,
1174
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
1175
+ return -1;
1176
+ }
1177
+
1178
+ /* ApiVersionRequest handles future versions, for everything else
1179
+ * make sure the ApiVersion is supported. */
1180
+ if (rkbuf->rkbuf_reqhdr.ApiKey != RD_KAFKAP_ApiVersion &&
1181
+ !rd_kafka_mock_cluster_ApiVersion_check(
1182
+ mcluster, rkbuf->rkbuf_reqhdr.ApiKey,
1183
+ rkbuf->rkbuf_reqhdr.ApiVersion)) {
1184
+ rd_kafka_log(
1185
+ rk, LOG_ERR, "MOCK",
1186
+ "Broker %" PRId32
1187
+ ": unsupported %sRequest "
1188
+ "version %hd from %s",
1189
+ mconn->broker->id,
1190
+ rd_kafka_ApiKey2str(rkbuf->rkbuf_reqhdr.ApiKey),
1191
+ rkbuf->rkbuf_reqhdr.ApiVersion,
1192
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
1193
+ return -1;
1194
+ }
1195
+
1196
+ mtx_lock(&mcluster->lock);
1197
+ if (mcluster->track_requests) {
1198
+ rd_list_add(&mcluster->request_list,
1199
+ rd_kafka_mock_request_new(
1200
+ mconn->broker->id, rkbuf->rkbuf_reqhdr.ApiKey,
1201
+ rd_clock()));
1202
+ }
1203
+ mtx_unlock(&mcluster->lock);
1204
+
1205
+ rd_kafka_dbg(rk, MOCK, "MOCK",
1206
+ "Broker %" PRId32 ": Received %sRequestV%hd from %s",
1207
+ mconn->broker->id,
1208
+ rd_kafka_ApiKey2str(rkbuf->rkbuf_reqhdr.ApiKey),
1209
+ rkbuf->rkbuf_reqhdr.ApiVersion,
1210
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
1211
+
1212
+ return mcluster->api_handlers[rkbuf->rkbuf_reqhdr.ApiKey].cb(mconn,
1213
+ rkbuf);
1214
+ }
1215
+
1216
+
1217
+ /**
1218
+ * @brief Timer callback to set the POLLOUT flag for a connection after
1219
+ * the delay has expired.
1220
+ */
1221
+ static void rd_kafka_mock_connection_write_out_tmr_cb(rd_kafka_timers_t *rkts,
1222
+ void *arg) {
1223
+ rd_kafka_mock_connection_t *mconn = arg;
1224
+
1225
+ rd_kafka_mock_cluster_io_set_events(
1226
+ mconn->broker->cluster, mconn->transport->rktrans_s, POLLOUT);
1227
+ }
1228
+
1229
+
1230
+ /**
1231
+ * @brief Send as many bytes as possible from the output buffer.
1232
+ *
1233
+ * @returns 1 if all buffers were sent, 0 if more buffers need to be sent, or
1234
+ * -1 on error.
1235
+ */
1236
+ static ssize_t
1237
+ rd_kafka_mock_connection_write_out(rd_kafka_mock_connection_t *mconn) {
1238
+ rd_kafka_buf_t *rkbuf;
1239
+ rd_ts_t now = rd_clock();
1240
+ rd_ts_t rtt = mconn->broker->rtt;
1241
+
1242
+ while ((rkbuf = TAILQ_FIRST(&mconn->outbufs.rkbq_bufs))) {
1243
+ ssize_t r;
1244
+ char errstr[128];
1245
+ rd_ts_t ts_delay = 0;
1246
+
1247
+ /* Connection delay/rtt is set. */
1248
+ if (rkbuf->rkbuf_ts_sent + rtt > now)
1249
+ ts_delay = rkbuf->rkbuf_ts_sent + rtt;
1250
+
1251
+ /* Response is being delayed */
1252
+ if (rkbuf->rkbuf_ts_retry && rkbuf->rkbuf_ts_retry > now)
1253
+ ts_delay = rkbuf->rkbuf_ts_retry + rtt;
1254
+
1255
+ if (ts_delay) {
1256
+ /* Delay response */
1257
+ rd_kafka_timer_start_oneshot(
1258
+ &mconn->broker->cluster->timers, &mconn->write_tmr,
1259
+ rd_false, ts_delay - now,
1260
+ rd_kafka_mock_connection_write_out_tmr_cb, mconn);
1261
+ break;
1262
+ }
1263
+
1264
+ if ((r = rd_kafka_transport_send(mconn->transport,
1265
+ &rkbuf->rkbuf_reader, errstr,
1266
+ sizeof(errstr))) == -1)
1267
+ return -1;
1268
+
1269
+ if (rd_slice_remains(&rkbuf->rkbuf_reader) > 0)
1270
+ return 0; /* Partial send, continue next time */
1271
+
1272
+ /* Entire buffer sent, unlink and free */
1273
+ rd_kafka_bufq_deq(&mconn->outbufs, rkbuf);
1274
+
1275
+ rd_kafka_buf_destroy(rkbuf);
1276
+ }
1277
+
1278
+ rd_kafka_mock_cluster_io_clear_events(
1279
+ mconn->broker->cluster, mconn->transport->rktrans_s, POLLOUT);
1280
+
1281
+ return 1;
1282
+ }
1283
+
1284
+
1285
+ /**
1286
+ * @brief Call connection_write_out() for all the broker's connections.
1287
+ *
1288
+ * Use to check if any responses should be sent when RTT has changed.
1289
+ */
1290
+ static void
1291
+ rd_kafka_mock_broker_connections_write_out(rd_kafka_mock_broker_t *mrkb) {
1292
+ rd_kafka_mock_connection_t *mconn, *tmp;
1293
+
1294
+ /* Need a safe loop since connections may be removed on send error */
1295
+ TAILQ_FOREACH_SAFE(mconn, &mrkb->connections, link, tmp) {
1296
+ rd_kafka_mock_connection_write_out(mconn);
1297
+ }
1298
+ }
1299
+
1300
+
1301
+ /**
1302
+ * @brief Per-Connection IO handler
1303
+ */
1304
+ static void rd_kafka_mock_connection_io(rd_kafka_mock_cluster_t *mcluster,
1305
+ rd_socket_t fd,
1306
+ int events,
1307
+ void *opaque) {
1308
+ rd_kafka_mock_connection_t *mconn = opaque;
1309
+
1310
+ if (events & POLLIN) {
1311
+ rd_kafka_buf_t *rkbuf;
1312
+ int r;
1313
+
1314
+ while (1) {
1315
+ /* Read full request */
1316
+ r = rd_kafka_mock_connection_read_request(mconn,
1317
+ &rkbuf);
1318
+ if (r == 0)
1319
+ break; /* Need more data */
1320
+ else if (r == -1) {
1321
+ rd_kafka_mock_connection_close(mconn,
1322
+ "Read error");
1323
+ return;
1324
+ }
1325
+
1326
+ /* Parse and handle request */
1327
+ r = rd_kafka_mock_connection_parse_request(mconn,
1328
+ rkbuf);
1329
+ rd_kafka_buf_destroy(rkbuf);
1330
+ if (r == -1) {
1331
+ rd_kafka_mock_connection_close(mconn,
1332
+ "Parse error");
1333
+ return;
1334
+ }
1335
+ }
1336
+ }
1337
+
1338
+ if (events & (POLLERR | POLLHUP)) {
1339
+ rd_kafka_mock_connection_close(mconn, "Disconnected");
1340
+ return;
1341
+ }
1342
+
1343
+ if (events & POLLOUT) {
1344
+ if (rd_kafka_mock_connection_write_out(mconn) == -1) {
1345
+ rd_kafka_mock_connection_close(mconn, "Write error");
1346
+ return;
1347
+ }
1348
+ }
1349
+ }
1350
+
1351
+
1352
+ /**
1353
+ * @brief Set connection as blocking, POLLIN will not be served.
1354
+ */
1355
+ void rd_kafka_mock_connection_set_blocking(rd_kafka_mock_connection_t *mconn,
1356
+ rd_bool_t blocking) {
1357
+ rd_kafka_mock_cluster_io_set_event(mconn->broker->cluster,
1358
+ mconn->transport->rktrans_s,
1359
+ !blocking, POLLIN);
1360
+ }
1361
+
1362
+
1363
+ static rd_kafka_mock_connection_t *
1364
+ rd_kafka_mock_connection_new(rd_kafka_mock_broker_t *mrkb,
1365
+ rd_socket_t fd,
1366
+ const struct sockaddr_in *peer) {
1367
+ rd_kafka_mock_connection_t *mconn;
1368
+ rd_kafka_transport_t *rktrans;
1369
+ char errstr[128];
1370
+
1371
+ if (!mrkb->up) {
1372
+ rd_socket_close(fd);
1373
+ return NULL;
1374
+ }
1375
+
1376
+ rktrans = rd_kafka_transport_new(mrkb->cluster->dummy_rkb, fd, errstr,
1377
+ sizeof(errstr));
1378
+ if (!rktrans) {
1379
+ rd_kafka_log(mrkb->cluster->rk, LOG_ERR, "MOCK",
1380
+ "Failed to create transport for new "
1381
+ "mock connection: %s",
1382
+ errstr);
1383
+ rd_socket_close(fd);
1384
+ return NULL;
1385
+ }
1386
+
1387
+ rd_kafka_transport_post_connect_setup(rktrans);
1388
+
1389
+ mconn = rd_calloc(1, sizeof(*mconn));
1390
+ mconn->broker = mrkb;
1391
+ mconn->transport = rktrans;
1392
+ mconn->peer = *peer;
1393
+ rd_kafka_bufq_init(&mconn->outbufs);
1394
+
1395
+ TAILQ_INSERT_TAIL(&mrkb->connections, mconn, link);
1396
+
1397
+ rd_kafka_mock_cluster_io_add(mrkb->cluster, mconn->transport->rktrans_s,
1398
+ POLLIN, rd_kafka_mock_connection_io,
1399
+ mconn);
1400
+
1401
+ rd_kafka_dbg(mrkb->cluster->rk, MOCK, "MOCK",
1402
+ "Broker %" PRId32 ": New connection from %s", mrkb->id,
1403
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
1404
+
1405
+ return mconn;
1406
+ }
1407
+
1408
+
1409
+
1410
+ static void rd_kafka_mock_cluster_op_io(rd_kafka_mock_cluster_t *mcluster,
1411
+ rd_socket_t fd,
1412
+ int events,
1413
+ void *opaque) {
1414
+ /* Read wake-up fd data and throw away, just used for wake-ups*/
1415
+ char buf[1024];
1416
+ while (rd_socket_read(fd, buf, sizeof(buf)) > 0)
1417
+ ; /* Read all buffered signalling bytes */
1418
+ }
1419
+
1420
+
1421
+ static int rd_kafka_mock_cluster_io_poll(rd_kafka_mock_cluster_t *mcluster,
1422
+ int timeout_ms) {
1423
+ int r;
1424
+ int i;
1425
+
1426
+ r = rd_socket_poll(mcluster->fds, mcluster->fd_cnt, timeout_ms);
1427
+ if (r == RD_SOCKET_ERROR) {
1428
+ rd_kafka_log(mcluster->rk, LOG_CRIT, "MOCK",
1429
+ "Mock cluster failed to poll %d fds: %d: %s",
1430
+ mcluster->fd_cnt, r,
1431
+ rd_socket_strerror(rd_socket_errno));
1432
+ return -1;
1433
+ }
1434
+
1435
+ /* Serve ops, if any */
1436
+ rd_kafka_q_serve(mcluster->ops, RD_POLL_NOWAIT, 0,
1437
+ RD_KAFKA_Q_CB_CALLBACK, NULL, NULL);
1438
+
1439
+ /* Handle IO events, if any, and if not terminating */
1440
+ for (i = 0; mcluster->run && r > 0 && i < mcluster->fd_cnt; i++) {
1441
+ if (!mcluster->fds[i].revents)
1442
+ continue;
1443
+
1444
+ /* Call IO handler */
1445
+ mcluster->handlers[i].cb(mcluster, mcluster->fds[i].fd,
1446
+ mcluster->fds[i].revents,
1447
+ mcluster->handlers[i].opaque);
1448
+ r--;
1449
+ }
1450
+
1451
+ return 0;
1452
+ }
1453
+
1454
+
1455
+ static int rd_kafka_mock_cluster_thread_main(void *arg) {
1456
+ rd_kafka_mock_cluster_t *mcluster = arg;
1457
+
1458
+ rd_kafka_set_thread_name("mock");
1459
+ rd_kafka_set_thread_sysname("rdk:mock");
1460
+ rd_kafka_interceptors_on_thread_start(mcluster->rk,
1461
+ RD_KAFKA_THREAD_BACKGROUND);
1462
+ rd_atomic32_add(&rd_kafka_thread_cnt_curr, 1);
1463
+
1464
+ /* Op wakeup fd */
1465
+ rd_kafka_mock_cluster_io_add(mcluster, mcluster->wakeup_fds[0], POLLIN,
1466
+ rd_kafka_mock_cluster_op_io, NULL);
1467
+
1468
+ mcluster->run = rd_true;
1469
+
1470
+ while (mcluster->run) {
1471
+ int sleeptime = (int)((rd_kafka_timers_next(&mcluster->timers,
1472
+ 1000 * 1000 /*1s*/,
1473
+ 1 /*lock*/) +
1474
+ 999) /
1475
+ 1000);
1476
+
1477
+ if (rd_kafka_mock_cluster_io_poll(mcluster, sleeptime) == -1)
1478
+ break;
1479
+
1480
+ rd_kafka_timers_run(&mcluster->timers, RD_POLL_NOWAIT);
1481
+ }
1482
+
1483
+ rd_kafka_mock_cluster_io_del(mcluster, mcluster->wakeup_fds[0]);
1484
+
1485
+
1486
+ rd_kafka_interceptors_on_thread_exit(mcluster->rk,
1487
+ RD_KAFKA_THREAD_BACKGROUND);
1488
+ rd_atomic32_sub(&rd_kafka_thread_cnt_curr, 1);
1489
+
1490
+ rd_kafka_mock_cluster_destroy0(mcluster);
1491
+
1492
+ return 0;
1493
+ }
1494
+
1495
+
1496
+
1497
+ static void rd_kafka_mock_broker_listen_io(rd_kafka_mock_cluster_t *mcluster,
1498
+ rd_socket_t fd,
1499
+ int events,
1500
+ void *opaque) {
1501
+ rd_kafka_mock_broker_t *mrkb = opaque;
1502
+
1503
+ if (events & (POLLERR | POLLHUP))
1504
+ rd_assert(!*"Mock broker listen socket error");
1505
+
1506
+ if (events & POLLIN) {
1507
+ rd_socket_t new_s;
1508
+ struct sockaddr_in peer;
1509
+ socklen_t peer_size = sizeof(peer);
1510
+
1511
+ new_s = accept(mrkb->listen_s, (struct sockaddr *)&peer,
1512
+ &peer_size);
1513
+ if (new_s == RD_SOCKET_ERROR) {
1514
+ rd_kafka_log(mcluster->rk, LOG_ERR, "MOCK",
1515
+ "Failed to accept mock broker socket: %s",
1516
+ rd_socket_strerror(rd_socket_errno));
1517
+ return;
1518
+ }
1519
+
1520
+ rd_kafka_mock_connection_new(mrkb, new_s, &peer);
1521
+ }
1522
+ }
1523
+
1524
+
1525
+ /**
1526
+ * @brief Close all connections to broker.
1527
+ */
1528
+ static void rd_kafka_mock_broker_close_all(rd_kafka_mock_broker_t *mrkb,
1529
+ const char *reason) {
1530
+ rd_kafka_mock_connection_t *mconn;
1531
+
1532
+ while ((mconn = TAILQ_FIRST(&mrkb->connections)))
1533
+ rd_kafka_mock_connection_close(mconn, reason);
1534
+ }
1535
+
1536
+ /**
1537
+ * @brief Destroy error stack, must be unlinked.
1538
+ */
1539
+ static void
1540
+ rd_kafka_mock_error_stack_destroy(rd_kafka_mock_error_stack_t *errstack) {
1541
+ if (errstack->errs)
1542
+ rd_free(errstack->errs);
1543
+ rd_free(errstack);
1544
+ }
1545
+
1546
+
1547
+ static void rd_kafka_mock_broker_destroy(rd_kafka_mock_broker_t *mrkb) {
1548
+ rd_kafka_mock_error_stack_t *errstack;
1549
+
1550
+ rd_kafka_mock_broker_close_all(mrkb, "Destroying broker");
1551
+
1552
+ if (mrkb->listen_s != -1) {
1553
+ if (mrkb->up)
1554
+ rd_kafka_mock_cluster_io_del(mrkb->cluster,
1555
+ mrkb->listen_s);
1556
+ rd_socket_close(mrkb->listen_s);
1557
+ }
1558
+
1559
+ while ((errstack = TAILQ_FIRST(&mrkb->errstacks))) {
1560
+ TAILQ_REMOVE(&mrkb->errstacks, errstack, link);
1561
+ rd_kafka_mock_error_stack_destroy(errstack);
1562
+ }
1563
+
1564
+ if (mrkb->rack)
1565
+ rd_free(mrkb->rack);
1566
+
1567
+ TAILQ_REMOVE(&mrkb->cluster->brokers, mrkb, link);
1568
+ mrkb->cluster->broker_cnt--;
1569
+
1570
+ rd_free(mrkb);
1571
+ }
1572
+
1573
+
1574
+ /**
1575
+ * @brief Starts listening on the mock broker socket.
1576
+ *
1577
+ * @returns 0 on success or -1 on error (logged).
1578
+ */
1579
+ static int rd_kafka_mock_broker_start_listener(rd_kafka_mock_broker_t *mrkb) {
1580
+ rd_assert(mrkb->listen_s != -1);
1581
+
1582
+ if (listen(mrkb->listen_s, 5) == RD_SOCKET_ERROR) {
1583
+ rd_kafka_log(mrkb->cluster->rk, LOG_CRIT, "MOCK",
1584
+ "Failed to listen on mock broker socket: %s",
1585
+ rd_socket_strerror(rd_socket_errno));
1586
+ return -1;
1587
+ }
1588
+
1589
+ rd_kafka_mock_cluster_io_add(mrkb->cluster, mrkb->listen_s, POLLIN,
1590
+ rd_kafka_mock_broker_listen_io, mrkb);
1591
+
1592
+ return 0;
1593
+ }
1594
+
1595
+
1596
+ /**
1597
+ * @brief Creates a new listener socket for \p mrkb but does NOT starts
1598
+ * listening.
1599
+ *
1600
+ * @param sin is the address and port to bind. If the port is zero a random
1601
+ * port will be assigned (by the kernel) and the address and port
1602
+ * will be returned in this pointer.
1603
+ *
1604
+ * @returns listener socket on success or -1 on error (errors are logged).
1605
+ */
1606
+ static int rd_kafka_mock_broker_new_listener(rd_kafka_mock_cluster_t *mcluster,
1607
+ struct sockaddr_in *sinp) {
1608
+ struct sockaddr_in sin = *sinp;
1609
+ socklen_t sin_len = sizeof(sin);
1610
+ int listen_s;
1611
+ int on = 1;
1612
+
1613
+ if (!sin.sin_family)
1614
+ sin.sin_family = AF_INET;
1615
+
1616
+ /*
1617
+ * Create and bind socket to any loopback port
1618
+ */
1619
+ listen_s =
1620
+ rd_kafka_socket_cb_linux(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL);
1621
+ if (listen_s == RD_SOCKET_ERROR) {
1622
+ rd_kafka_log(mcluster->rk, LOG_CRIT, "MOCK",
1623
+ "Unable to create mock broker listen socket: %s",
1624
+ rd_socket_strerror(rd_socket_errno));
1625
+ return -1;
1626
+ }
1627
+
1628
+ if (setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
1629
+ sizeof(on)) == -1) {
1630
+ rd_kafka_log(mcluster->rk, LOG_CRIT, "MOCK",
1631
+ "Failed to set SO_REUSEADDR on mock broker "
1632
+ "listen socket: %s",
1633
+ rd_socket_strerror(rd_socket_errno));
1634
+ rd_socket_close(listen_s);
1635
+ return -1;
1636
+ }
1637
+
1638
+ if (bind(listen_s, (struct sockaddr *)&sin, sizeof(sin)) ==
1639
+ RD_SOCKET_ERROR) {
1640
+ rd_kafka_log(mcluster->rk, LOG_CRIT, "MOCK",
1641
+ "Failed to bind mock broker socket to %s: %s",
1642
+ rd_socket_strerror(rd_socket_errno),
1643
+ rd_sockaddr2str(&sin, RD_SOCKADDR2STR_F_PORT));
1644
+ rd_socket_close(listen_s);
1645
+ return -1;
1646
+ }
1647
+
1648
+ if (getsockname(listen_s, (struct sockaddr *)&sin, &sin_len) ==
1649
+ RD_SOCKET_ERROR) {
1650
+ rd_kafka_log(mcluster->rk, LOG_CRIT, "MOCK",
1651
+ "Failed to get mock broker socket name: %s",
1652
+ rd_socket_strerror(rd_socket_errno));
1653
+ rd_socket_close(listen_s);
1654
+ return -1;
1655
+ }
1656
+ rd_assert(sin.sin_family == AF_INET);
1657
+ /* If a filled in sinp was passed make sure nothing changed. */
1658
+ rd_assert(!sinp->sin_port || !memcmp(sinp, &sin, sizeof(sin)));
1659
+
1660
+ *sinp = sin;
1661
+
1662
+ return listen_s;
1663
+ }
1664
+
1665
+
1666
+ static rd_kafka_mock_broker_t *
1667
+ rd_kafka_mock_broker_new(rd_kafka_mock_cluster_t *mcluster, int32_t broker_id) {
1668
+ rd_kafka_mock_broker_t *mrkb;
1669
+ rd_socket_t listen_s;
1670
+ struct sockaddr_in sin = {
1671
+ .sin_family = AF_INET,
1672
+ .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}};
1673
+
1674
+ listen_s = rd_kafka_mock_broker_new_listener(mcluster, &sin);
1675
+ if (listen_s == -1)
1676
+ return NULL;
1677
+
1678
+ /*
1679
+ * Create mock broker object
1680
+ */
1681
+ mrkb = rd_calloc(1, sizeof(*mrkb));
1682
+
1683
+ mrkb->id = broker_id;
1684
+ mrkb->cluster = mcluster;
1685
+ mrkb->up = rd_true;
1686
+ mrkb->listen_s = listen_s;
1687
+ mrkb->sin = sin;
1688
+ mrkb->port = ntohs(sin.sin_port);
1689
+ rd_snprintf(mrkb->advertised_listener,
1690
+ sizeof(mrkb->advertised_listener), "%s",
1691
+ rd_sockaddr2str(&sin, 0));
1692
+
1693
+ TAILQ_INIT(&mrkb->connections);
1694
+ TAILQ_INIT(&mrkb->errstacks);
1695
+
1696
+ TAILQ_INSERT_TAIL(&mcluster->brokers, mrkb, link);
1697
+ mcluster->broker_cnt++;
1698
+
1699
+ if (rd_kafka_mock_broker_start_listener(mrkb) == -1) {
1700
+ rd_kafka_mock_broker_destroy(mrkb);
1701
+ return NULL;
1702
+ }
1703
+
1704
+ return mrkb;
1705
+ }
1706
+
1707
+
1708
+ /**
1709
+ * @returns the coordtype_t for a coord type string, or -1 on error.
1710
+ */
1711
+ static rd_kafka_coordtype_t rd_kafka_mock_coord_str2type(const char *str) {
1712
+ if (!strcmp(str, "transaction"))
1713
+ return RD_KAFKA_COORD_TXN;
1714
+ else if (!strcmp(str, "group"))
1715
+ return RD_KAFKA_COORD_GROUP;
1716
+ else
1717
+ return (rd_kafka_coordtype_t)-1;
1718
+ }
1719
+
1720
+
1721
+ /**
1722
+ * @brief Unlink and destroy coordinator.
1723
+ */
1724
+ static void rd_kafka_mock_coord_destroy(rd_kafka_mock_cluster_t *mcluster,
1725
+ rd_kafka_mock_coord_t *mcoord) {
1726
+ TAILQ_REMOVE(&mcluster->coords, mcoord, link);
1727
+ rd_free(mcoord->key);
1728
+ rd_free(mcoord);
1729
+ }
1730
+
1731
+ /**
1732
+ * @brief Find coordinator by type and key.
1733
+ */
1734
+ static rd_kafka_mock_coord_t *
1735
+ rd_kafka_mock_coord_find(rd_kafka_mock_cluster_t *mcluster,
1736
+ rd_kafka_coordtype_t type,
1737
+ const char *key) {
1738
+ rd_kafka_mock_coord_t *mcoord;
1739
+
1740
+ TAILQ_FOREACH(mcoord, &mcluster->coords, link) {
1741
+ if (mcoord->type == type && !strcmp(mcoord->key, key))
1742
+ return mcoord;
1743
+ }
1744
+
1745
+ return NULL;
1746
+ }
1747
+
1748
+
1749
+ /**
1750
+ * @returns the coordinator for KeyType,Key (e.g., GROUP,mygroup).
1751
+ */
1752
+ rd_kafka_mock_broker_t *
1753
+ rd_kafka_mock_cluster_get_coord(rd_kafka_mock_cluster_t *mcluster,
1754
+ rd_kafka_coordtype_t KeyType,
1755
+ const rd_kafkap_str_t *Key) {
1756
+ rd_kafka_mock_broker_t *mrkb;
1757
+ rd_kafka_mock_coord_t *mcoord;
1758
+ char *key;
1759
+ rd_crc32_t hash;
1760
+ int idx;
1761
+
1762
+ /* Try the explicit coord list first */
1763
+ RD_KAFKAP_STR_DUPA(&key, Key);
1764
+ if ((mcoord = rd_kafka_mock_coord_find(mcluster, KeyType, key)))
1765
+ return rd_kafka_mock_broker_find(mcluster, mcoord->broker_id);
1766
+
1767
+ /* Else hash the key to select an available broker. */
1768
+ hash = rd_crc32(Key->str, RD_KAFKAP_STR_LEN(Key));
1769
+ idx = (int)(hash % mcluster->broker_cnt);
1770
+
1771
+ /* Use the broker index in the list */
1772
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link)
1773
+ if (idx-- == 0)
1774
+ return mrkb;
1775
+
1776
+ RD_NOTREACHED();
1777
+ return NULL;
1778
+ }
1779
+
1780
+
1781
+ /**
1782
+ * @brief Explicitly set coordinator for \p key_type ("transaction", "group")
1783
+ * and \p key.
1784
+ */
1785
+ static rd_kafka_mock_coord_t *
1786
+ rd_kafka_mock_coord_set(rd_kafka_mock_cluster_t *mcluster,
1787
+ const char *key_type,
1788
+ const char *key,
1789
+ int32_t broker_id) {
1790
+ rd_kafka_mock_coord_t *mcoord;
1791
+ rd_kafka_coordtype_t type;
1792
+
1793
+ if ((int)(type = rd_kafka_mock_coord_str2type(key_type)) == -1)
1794
+ return NULL;
1795
+
1796
+ if ((mcoord = rd_kafka_mock_coord_find(mcluster, type, key)))
1797
+ rd_kafka_mock_coord_destroy(mcluster, mcoord);
1798
+
1799
+ mcoord = rd_calloc(1, sizeof(*mcoord));
1800
+ mcoord->type = type;
1801
+ mcoord->key = rd_strdup(key);
1802
+ mcoord->broker_id = broker_id;
1803
+
1804
+ TAILQ_INSERT_TAIL(&mcluster->coords, mcoord, link);
1805
+
1806
+ return mcoord;
1807
+ }
1808
+
1809
+
1810
+ /**
1811
+ * @brief Remove and return the next error, or RD_KAFKA_RESP_ERR_NO_ERROR
1812
+ * if no error.
1813
+ */
1814
+ static rd_kafka_mock_error_rtt_t
1815
+ rd_kafka_mock_error_stack_next(rd_kafka_mock_error_stack_t *errstack) {
1816
+ rd_kafka_mock_error_rtt_t err_rtt = {RD_KAFKA_RESP_ERR_NO_ERROR, 0};
1817
+
1818
+ if (likely(errstack->cnt == 0))
1819
+ return err_rtt;
1820
+
1821
+ err_rtt = errstack->errs[0];
1822
+ errstack->cnt--;
1823
+ if (errstack->cnt > 0)
1824
+ memmove(errstack->errs, &errstack->errs[1],
1825
+ sizeof(*errstack->errs) * errstack->cnt);
1826
+
1827
+ return err_rtt;
1828
+ }
1829
+
1830
+
1831
+ /**
1832
+ * @brief Find an error stack based on \p ApiKey
1833
+ */
1834
+ static rd_kafka_mock_error_stack_t *
1835
+ rd_kafka_mock_error_stack_find(const rd_kafka_mock_error_stack_head_t *shead,
1836
+ int16_t ApiKey) {
1837
+ const rd_kafka_mock_error_stack_t *errstack;
1838
+
1839
+ TAILQ_FOREACH(errstack, shead, link)
1840
+ if (errstack->ApiKey == ApiKey)
1841
+ return (rd_kafka_mock_error_stack_t *)errstack;
1842
+
1843
+ return NULL;
1844
+ }
1845
+
1846
+
1847
+
1848
+ /**
1849
+ * @brief Find or create an error stack based on \p ApiKey
1850
+ */
1851
+ static rd_kafka_mock_error_stack_t *
1852
+ rd_kafka_mock_error_stack_get(rd_kafka_mock_error_stack_head_t *shead,
1853
+ int16_t ApiKey) {
1854
+ rd_kafka_mock_error_stack_t *errstack;
1855
+
1856
+ if ((errstack = rd_kafka_mock_error_stack_find(shead, ApiKey)))
1857
+ return errstack;
1858
+
1859
+ errstack = rd_calloc(1, sizeof(*errstack));
1860
+
1861
+ errstack->ApiKey = ApiKey;
1862
+ TAILQ_INSERT_TAIL(shead, errstack, link);
1863
+
1864
+ return errstack;
1865
+ }
1866
+
1867
+
1868
+
1869
+ /**
1870
+ * @brief Removes and returns the next request error for response's ApiKey.
1871
+ *
1872
+ * If the error stack has a corresponding rtt/delay it is set on the
1873
+ * provided response \p resp buffer.
1874
+ */
1875
+ rd_kafka_resp_err_t
1876
+ rd_kafka_mock_next_request_error(rd_kafka_mock_connection_t *mconn,
1877
+ rd_kafka_buf_t *resp) {
1878
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1879
+ rd_kafka_mock_error_stack_t *errstack;
1880
+ rd_kafka_mock_error_rtt_t err_rtt;
1881
+
1882
+ mtx_lock(&mcluster->lock);
1883
+
1884
+ errstack = rd_kafka_mock_error_stack_find(&mconn->broker->errstacks,
1885
+ resp->rkbuf_reqhdr.ApiKey);
1886
+ if (likely(!errstack)) {
1887
+ errstack = rd_kafka_mock_error_stack_find(
1888
+ &mcluster->errstacks, resp->rkbuf_reqhdr.ApiKey);
1889
+ if (likely(!errstack)) {
1890
+ mtx_unlock(&mcluster->lock);
1891
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1892
+ }
1893
+ }
1894
+
1895
+ err_rtt = rd_kafka_mock_error_stack_next(errstack);
1896
+ resp->rkbuf_ts_sent = err_rtt.rtt;
1897
+
1898
+ mtx_unlock(&mcluster->lock);
1899
+
1900
+ /* If the error is ERR__TRANSPORT (a librdkafka-specific error code
1901
+ * that will never be returned by a broker), we close the connection.
1902
+ * This allows closing the connection as soon as a certain
1903
+ * request is seen.
1904
+ * The handler code in rdkafka_mock_handlers.c does not need to
1905
+ * handle this case specifically and will generate a response and
1906
+ * enqueue it, but the connection will be down by the time it will
1907
+ * be sent.
1908
+ * Note: Delayed disconnects (rtt-based) are not supported. */
1909
+ if (err_rtt.err == RD_KAFKA_RESP_ERR__TRANSPORT) {
1910
+ rd_kafka_dbg(
1911
+ mcluster->rk, MOCK, "MOCK",
1912
+ "Broker %" PRId32
1913
+ ": Forcing close of connection "
1914
+ "from %s",
1915
+ mconn->broker->id,
1916
+ rd_sockaddr2str(&mconn->peer, RD_SOCKADDR2STR_F_PORT));
1917
+ rd_kafka_transport_shutdown(mconn->transport);
1918
+ }
1919
+
1920
+
1921
+ return err_rtt.err;
1922
+ }
1923
+
1924
+
1925
+ void rd_kafka_mock_clear_request_errors(rd_kafka_mock_cluster_t *mcluster,
1926
+ int16_t ApiKey) {
1927
+ rd_kafka_mock_error_stack_t *errstack;
1928
+
1929
+ mtx_lock(&mcluster->lock);
1930
+
1931
+ errstack = rd_kafka_mock_error_stack_find(&mcluster->errstacks, ApiKey);
1932
+ if (errstack)
1933
+ errstack->cnt = 0;
1934
+
1935
+ mtx_unlock(&mcluster->lock);
1936
+ }
1937
+
1938
+
1939
+ void rd_kafka_mock_push_request_errors_array(
1940
+ rd_kafka_mock_cluster_t *mcluster,
1941
+ int16_t ApiKey,
1942
+ size_t cnt,
1943
+ const rd_kafka_resp_err_t *errors) {
1944
+ rd_kafka_mock_error_stack_t *errstack;
1945
+ size_t totcnt;
1946
+ size_t i;
1947
+
1948
+ mtx_lock(&mcluster->lock);
1949
+
1950
+ errstack = rd_kafka_mock_error_stack_get(&mcluster->errstacks, ApiKey);
1951
+
1952
+ totcnt = errstack->cnt + cnt;
1953
+
1954
+ if (totcnt > errstack->size) {
1955
+ errstack->size = totcnt + 4;
1956
+ errstack->errs = rd_realloc(
1957
+ errstack->errs, errstack->size * sizeof(*errstack->errs));
1958
+ }
1959
+
1960
+ for (i = 0; i < cnt; i++) {
1961
+ errstack->errs[errstack->cnt].err = errors[i];
1962
+ errstack->errs[errstack->cnt++].rtt = 0;
1963
+ }
1964
+
1965
+ mtx_unlock(&mcluster->lock);
1966
+ }
1967
+
1968
+ void rd_kafka_mock_push_request_errors(rd_kafka_mock_cluster_t *mcluster,
1969
+ int16_t ApiKey,
1970
+ size_t cnt,
1971
+ ...) {
1972
+ va_list ap;
1973
+ rd_kafka_resp_err_t *errors = rd_alloca(sizeof(*errors) * cnt);
1974
+ size_t i;
1975
+
1976
+ va_start(ap, cnt);
1977
+ for (i = 0; i < cnt; i++)
1978
+ errors[i] = va_arg(ap, rd_kafka_resp_err_t);
1979
+ va_end(ap);
1980
+
1981
+ rd_kafka_mock_push_request_errors_array(mcluster, ApiKey, cnt, errors);
1982
+ }
1983
+
1984
+
1985
+ rd_kafka_resp_err_t
1986
+ rd_kafka_mock_broker_push_request_error_rtts(rd_kafka_mock_cluster_t *mcluster,
1987
+ int32_t broker_id,
1988
+ int16_t ApiKey,
1989
+ size_t cnt,
1990
+ ...) {
1991
+ rd_kafka_mock_broker_t *mrkb;
1992
+ va_list ap;
1993
+ rd_kafka_mock_error_stack_t *errstack;
1994
+ size_t totcnt;
1995
+
1996
+ mtx_lock(&mcluster->lock);
1997
+
1998
+ if (!(mrkb = rd_kafka_mock_broker_find(mcluster, broker_id))) {
1999
+ mtx_unlock(&mcluster->lock);
2000
+ return RD_KAFKA_RESP_ERR__UNKNOWN_BROKER;
2001
+ }
2002
+
2003
+ errstack = rd_kafka_mock_error_stack_get(&mrkb->errstacks, ApiKey);
2004
+
2005
+ totcnt = errstack->cnt + cnt;
2006
+
2007
+ if (totcnt > errstack->size) {
2008
+ errstack->size = totcnt + 4;
2009
+ errstack->errs = rd_realloc(
2010
+ errstack->errs, errstack->size * sizeof(*errstack->errs));
2011
+ }
2012
+
2013
+ va_start(ap, cnt);
2014
+ while (cnt-- > 0) {
2015
+ errstack->errs[errstack->cnt].err =
2016
+ va_arg(ap, rd_kafka_resp_err_t);
2017
+ errstack->errs[errstack->cnt++].rtt =
2018
+ ((rd_ts_t)va_arg(ap, int)) * 1000;
2019
+ }
2020
+ va_end(ap);
2021
+
2022
+ mtx_unlock(&mcluster->lock);
2023
+
2024
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2025
+ }
2026
+
2027
+
2028
+ rd_kafka_resp_err_t
2029
+ rd_kafka_mock_broker_error_stack_cnt(rd_kafka_mock_cluster_t *mcluster,
2030
+ int32_t broker_id,
2031
+ int16_t ApiKey,
2032
+ size_t *cntp) {
2033
+ rd_kafka_mock_broker_t *mrkb;
2034
+ rd_kafka_mock_error_stack_t *errstack;
2035
+
2036
+ if (!mcluster || !cntp)
2037
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
2038
+
2039
+ mtx_lock(&mcluster->lock);
2040
+
2041
+ if (!(mrkb = rd_kafka_mock_broker_find(mcluster, broker_id))) {
2042
+ mtx_unlock(&mcluster->lock);
2043
+ return RD_KAFKA_RESP_ERR__UNKNOWN_BROKER;
2044
+ }
2045
+
2046
+ if ((errstack =
2047
+ rd_kafka_mock_error_stack_find(&mrkb->errstacks, ApiKey)))
2048
+ *cntp = errstack->cnt;
2049
+
2050
+ mtx_unlock(&mcluster->lock);
2051
+
2052
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2053
+ }
2054
+
2055
+
2056
+ void rd_kafka_mock_topic_set_error(rd_kafka_mock_cluster_t *mcluster,
2057
+ const char *topic,
2058
+ rd_kafka_resp_err_t err) {
2059
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2060
+
2061
+ rko->rko_u.mock.name = rd_strdup(topic);
2062
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_TOPIC_SET_ERROR;
2063
+ rko->rko_u.mock.err = err;
2064
+
2065
+ rko = rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE);
2066
+ if (rko)
2067
+ rd_kafka_op_destroy(rko);
2068
+ }
2069
+
2070
+
2071
+ rd_kafka_resp_err_t
2072
+ rd_kafka_mock_topic_create(rd_kafka_mock_cluster_t *mcluster,
2073
+ const char *topic,
2074
+ int partition_cnt,
2075
+ int replication_factor) {
2076
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2077
+
2078
+ rko->rko_u.mock.name = rd_strdup(topic);
2079
+ rko->rko_u.mock.lo = partition_cnt;
2080
+ rko->rko_u.mock.hi = replication_factor;
2081
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_TOPIC_CREATE;
2082
+
2083
+ return rd_kafka_op_err_destroy(
2084
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2085
+ }
2086
+
2087
+ rd_kafka_resp_err_t
2088
+ rd_kafka_mock_partition_set_leader(rd_kafka_mock_cluster_t *mcluster,
2089
+ const char *topic,
2090
+ int32_t partition,
2091
+ int32_t broker_id) {
2092
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2093
+
2094
+ rko->rko_u.mock.name = rd_strdup(topic);
2095
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_PART_SET_LEADER;
2096
+ rko->rko_u.mock.partition = partition;
2097
+ rko->rko_u.mock.broker_id = broker_id;
2098
+
2099
+ return rd_kafka_op_err_destroy(
2100
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2101
+ }
2102
+
2103
+ rd_kafka_resp_err_t
2104
+ rd_kafka_mock_partition_set_follower(rd_kafka_mock_cluster_t *mcluster,
2105
+ const char *topic,
2106
+ int32_t partition,
2107
+ int32_t broker_id) {
2108
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2109
+
2110
+ rko->rko_u.mock.name = rd_strdup(topic);
2111
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_PART_SET_FOLLOWER;
2112
+ rko->rko_u.mock.partition = partition;
2113
+ rko->rko_u.mock.broker_id = broker_id;
2114
+
2115
+ return rd_kafka_op_err_destroy(
2116
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2117
+ }
2118
+
2119
+ rd_kafka_resp_err_t
2120
+ rd_kafka_mock_partition_set_follower_wmarks(rd_kafka_mock_cluster_t *mcluster,
2121
+ const char *topic,
2122
+ int32_t partition,
2123
+ int64_t lo,
2124
+ int64_t hi) {
2125
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2126
+
2127
+ rko->rko_u.mock.name = rd_strdup(topic);
2128
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_PART_SET_FOLLOWER_WMARKS;
2129
+ rko->rko_u.mock.partition = partition;
2130
+ rko->rko_u.mock.lo = lo;
2131
+ rko->rko_u.mock.hi = hi;
2132
+
2133
+ return rd_kafka_op_err_destroy(
2134
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2135
+ }
2136
+
2137
+ rd_kafka_resp_err_t
2138
+ rd_kafka_mock_partition_push_leader_response(rd_kafka_mock_cluster_t *mcluster,
2139
+ const char *topic,
2140
+ int partition,
2141
+ int32_t leader_id,
2142
+ int32_t leader_epoch) {
2143
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2144
+ rko->rko_u.mock.name = rd_strdup(topic);
2145
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_PART_PUSH_LEADER_RESPONSE;
2146
+ rko->rko_u.mock.partition = partition;
2147
+ rko->rko_u.mock.leader_id = leader_id;
2148
+ rko->rko_u.mock.leader_epoch = leader_epoch;
2149
+
2150
+ return rd_kafka_op_err_destroy(
2151
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2152
+ }
2153
+
2154
+ rd_kafka_resp_err_t
2155
+ rd_kafka_mock_broker_set_down(rd_kafka_mock_cluster_t *mcluster,
2156
+ int32_t broker_id) {
2157
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2158
+
2159
+ rko->rko_u.mock.broker_id = broker_id;
2160
+ rko->rko_u.mock.lo = rd_false;
2161
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_BROKER_SET_UPDOWN;
2162
+
2163
+ return rd_kafka_op_err_destroy(
2164
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2165
+ }
2166
+
2167
+ rd_kafka_resp_err_t
2168
+ rd_kafka_mock_broker_set_up(rd_kafka_mock_cluster_t *mcluster,
2169
+ int32_t broker_id) {
2170
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2171
+
2172
+ rko->rko_u.mock.broker_id = broker_id;
2173
+ rko->rko_u.mock.lo = rd_true;
2174
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_BROKER_SET_UPDOWN;
2175
+
2176
+ return rd_kafka_op_err_destroy(
2177
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2178
+ }
2179
+
2180
+ rd_kafka_resp_err_t
2181
+ rd_kafka_mock_broker_set_rtt(rd_kafka_mock_cluster_t *mcluster,
2182
+ int32_t broker_id,
2183
+ int rtt_ms) {
2184
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2185
+
2186
+ rko->rko_u.mock.broker_id = broker_id;
2187
+ rko->rko_u.mock.lo = rtt_ms;
2188
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_BROKER_SET_RTT;
2189
+
2190
+ return rd_kafka_op_err_destroy(
2191
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2192
+ }
2193
+
2194
+ rd_kafka_resp_err_t
2195
+ rd_kafka_mock_broker_set_rack(rd_kafka_mock_cluster_t *mcluster,
2196
+ int32_t broker_id,
2197
+ const char *rack) {
2198
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2199
+
2200
+ rko->rko_u.mock.broker_id = broker_id;
2201
+ rko->rko_u.mock.name = rd_strdup(rack);
2202
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_BROKER_SET_RACK;
2203
+
2204
+ return rd_kafka_op_err_destroy(
2205
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2206
+ }
2207
+
2208
+ rd_kafka_resp_err_t
2209
+ rd_kafka_mock_coordinator_set(rd_kafka_mock_cluster_t *mcluster,
2210
+ const char *key_type,
2211
+ const char *key,
2212
+ int32_t broker_id) {
2213
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2214
+
2215
+ rko->rko_u.mock.name = rd_strdup(key_type);
2216
+ rko->rko_u.mock.str = rd_strdup(key);
2217
+ rko->rko_u.mock.broker_id = broker_id;
2218
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_COORD_SET;
2219
+
2220
+ return rd_kafka_op_err_destroy(
2221
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2222
+ }
2223
+
2224
+ rd_kafka_resp_err_t
2225
+ rd_kafka_mock_set_apiversion(rd_kafka_mock_cluster_t *mcluster,
2226
+ int16_t ApiKey,
2227
+ int16_t MinVersion,
2228
+ int16_t MaxVersion) {
2229
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2230
+
2231
+ rko->rko_u.mock.partition = ApiKey;
2232
+ rko->rko_u.mock.lo = MinVersion;
2233
+ rko->rko_u.mock.hi = MaxVersion;
2234
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_APIVERSION_SET;
2235
+
2236
+ return rd_kafka_op_err_destroy(
2237
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2238
+ }
2239
+
2240
+ rd_kafka_resp_err_t
2241
+ rd_kafka_mock_telemetry_set_requested_metrics(rd_kafka_mock_cluster_t *mcluster,
2242
+ char **metrics,
2243
+ size_t metrics_cnt) {
2244
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2245
+
2246
+ rko->rko_u.mock.hi = metrics_cnt;
2247
+ rko->rko_u.mock.metrics = NULL;
2248
+ if (metrics_cnt) {
2249
+ size_t i;
2250
+ rko->rko_u.mock.metrics =
2251
+ rd_calloc(metrics_cnt, sizeof(char *));
2252
+ for (i = 0; i < metrics_cnt; i++)
2253
+ rko->rko_u.mock.metrics[i] = rd_strdup(metrics[i]);
2254
+ }
2255
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_REQUESTED_METRICS_SET;
2256
+
2257
+ return rd_kafka_op_err_destroy(
2258
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2259
+ }
2260
+
2261
+ rd_kafka_resp_err_t
2262
+ rd_kafka_mock_telemetry_set_push_interval(rd_kafka_mock_cluster_t *mcluster,
2263
+ int64_t push_interval_ms) {
2264
+ rd_kafka_op_t *rko = rd_kafka_op_new(RD_KAFKA_OP_MOCK);
2265
+
2266
+ rko->rko_u.mock.hi = push_interval_ms;
2267
+ rko->rko_u.mock.cmd = RD_KAFKA_MOCK_CMD_TELEMETRY_PUSH_INTERVAL_SET;
2268
+
2269
+ return rd_kafka_op_err_destroy(
2270
+ rd_kafka_op_req(mcluster->ops, rko, RD_POLL_INFINITE));
2271
+ }
2272
+
2273
+
2274
+ /**
2275
+ * @brief Apply command to specific broker.
2276
+ *
2277
+ * @locality mcluster thread
2278
+ */
2279
+ static rd_kafka_resp_err_t
2280
+ rd_kafka_mock_broker_cmd(rd_kafka_mock_cluster_t *mcluster,
2281
+ rd_kafka_mock_broker_t *mrkb,
2282
+ rd_kafka_op_t *rko) {
2283
+ switch (rko->rko_u.mock.cmd) {
2284
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_UPDOWN:
2285
+ if ((rd_bool_t)rko->rko_u.mock.lo == mrkb->up)
2286
+ break;
2287
+
2288
+ mrkb->up = (rd_bool_t)rko->rko_u.mock.lo;
2289
+
2290
+ if (!mrkb->up) {
2291
+ rd_kafka_mock_cluster_io_del(mcluster, mrkb->listen_s);
2292
+ rd_socket_close(mrkb->listen_s);
2293
+ /* Re-create the listener right away so we retain the
2294
+ * same port. The listener is not started until
2295
+ * the broker is set up (below). */
2296
+ mrkb->listen_s = rd_kafka_mock_broker_new_listener(
2297
+ mcluster, &mrkb->sin);
2298
+ rd_assert(mrkb->listen_s != -1 ||
2299
+ !*"Failed to-create mock broker listener");
2300
+
2301
+ rd_kafka_mock_broker_close_all(mrkb, "Broker down");
2302
+
2303
+ } else {
2304
+ int r;
2305
+ rd_assert(mrkb->listen_s != -1);
2306
+ r = rd_kafka_mock_broker_start_listener(mrkb);
2307
+ rd_assert(r == 0 || !*"broker_start_listener() failed");
2308
+ }
2309
+ break;
2310
+
2311
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_RTT:
2312
+ mrkb->rtt = (rd_ts_t)rko->rko_u.mock.lo * 1000;
2313
+
2314
+ /* Check if there is anything to send now that the RTT
2315
+ * has changed or if a timer is to be started. */
2316
+ rd_kafka_mock_broker_connections_write_out(mrkb);
2317
+ break;
2318
+
2319
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_RACK:
2320
+ if (mrkb->rack)
2321
+ rd_free(mrkb->rack);
2322
+
2323
+ if (rko->rko_u.mock.name)
2324
+ mrkb->rack = rd_strdup(rko->rko_u.mock.name);
2325
+ else
2326
+ mrkb->rack = NULL;
2327
+ break;
2328
+
2329
+ default:
2330
+ RD_BUG("Unhandled mock cmd %d", rko->rko_u.mock.cmd);
2331
+ break;
2332
+ }
2333
+
2334
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2335
+ }
2336
+
2337
+
2338
+ /**
2339
+ * @brief Apply command to to one or all brokers, depending on the value of
2340
+ * broker_id, where -1 means all, and != -1 means a specific broker.
2341
+ *
2342
+ * @locality mcluster thread
2343
+ */
2344
+ static rd_kafka_resp_err_t
2345
+ rd_kafka_mock_brokers_cmd(rd_kafka_mock_cluster_t *mcluster,
2346
+ rd_kafka_op_t *rko) {
2347
+ rd_kafka_mock_broker_t *mrkb;
2348
+
2349
+ if (rko->rko_u.mock.broker_id != -1) {
2350
+ /* Specific broker */
2351
+ mrkb = rd_kafka_mock_broker_find(mcluster,
2352
+ rko->rko_u.mock.broker_id);
2353
+ if (!mrkb)
2354
+ return RD_KAFKA_RESP_ERR_BROKER_NOT_AVAILABLE;
2355
+
2356
+ return rd_kafka_mock_broker_cmd(mcluster, mrkb, rko);
2357
+ }
2358
+
2359
+ /* All brokers */
2360
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link) {
2361
+ rd_kafka_resp_err_t err;
2362
+
2363
+ if ((err = rd_kafka_mock_broker_cmd(mcluster, mrkb, rko)))
2364
+ return err;
2365
+ }
2366
+
2367
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2368
+ }
2369
+
2370
+
2371
+ /**
2372
+ * @brief Handle command op
2373
+ *
2374
+ * @locality mcluster thread
2375
+ */
2376
+ static rd_kafka_resp_err_t
2377
+ rd_kafka_mock_cluster_cmd(rd_kafka_mock_cluster_t *mcluster,
2378
+ rd_kafka_op_t *rko) {
2379
+ rd_kafka_mock_topic_t *mtopic;
2380
+ rd_kafka_mock_partition_t *mpart;
2381
+ rd_kafka_mock_broker_t *mrkb;
2382
+ size_t i;
2383
+
2384
+ switch (rko->rko_u.mock.cmd) {
2385
+ case RD_KAFKA_MOCK_CMD_TOPIC_CREATE:
2386
+ if (rd_kafka_mock_topic_find(mcluster, rko->rko_u.mock.name))
2387
+ return RD_KAFKA_RESP_ERR_TOPIC_ALREADY_EXISTS;
2388
+
2389
+ if (!rd_kafka_mock_topic_new(mcluster, rko->rko_u.mock.name,
2390
+ /* partition_cnt */
2391
+ (int)rko->rko_u.mock.lo,
2392
+ /* replication_factor */
2393
+ (int)rko->rko_u.mock.hi))
2394
+ return RD_KAFKA_RESP_ERR_TOPIC_EXCEPTION;
2395
+ break;
2396
+
2397
+ case RD_KAFKA_MOCK_CMD_TOPIC_SET_ERROR:
2398
+ mtopic =
2399
+ rd_kafka_mock_topic_get(mcluster, rko->rko_u.mock.name, -1);
2400
+ mtopic->err = rko->rko_u.mock.err;
2401
+ break;
2402
+
2403
+ case RD_KAFKA_MOCK_CMD_PART_SET_LEADER:
2404
+ mpart = rd_kafka_mock_partition_get(
2405
+ mcluster, rko->rko_u.mock.name, rko->rko_u.mock.partition);
2406
+ if (!mpart)
2407
+ return RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2408
+
2409
+ if (rko->rko_u.mock.broker_id != -1) {
2410
+ mrkb = rd_kafka_mock_broker_find(
2411
+ mcluster, rko->rko_u.mock.broker_id);
2412
+ if (!mrkb)
2413
+ return RD_KAFKA_RESP_ERR_BROKER_NOT_AVAILABLE;
2414
+ } else {
2415
+ mrkb = NULL;
2416
+ }
2417
+
2418
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
2419
+ "Set %s [%" PRId32 "] leader to %" PRId32,
2420
+ rko->rko_u.mock.name, rko->rko_u.mock.partition,
2421
+ rko->rko_u.mock.broker_id);
2422
+
2423
+ rd_kafka_mock_partition_set_leader0(mpart, mrkb);
2424
+ break;
2425
+
2426
+ case RD_KAFKA_MOCK_CMD_PART_SET_FOLLOWER:
2427
+ mpart = rd_kafka_mock_partition_get(
2428
+ mcluster, rko->rko_u.mock.name, rko->rko_u.mock.partition);
2429
+ if (!mpart)
2430
+ return RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2431
+
2432
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
2433
+ "Set %s [%" PRId32
2434
+ "] preferred follower "
2435
+ "to %" PRId32,
2436
+ rko->rko_u.mock.name, rko->rko_u.mock.partition,
2437
+ rko->rko_u.mock.broker_id);
2438
+
2439
+ mpart->follower_id = rko->rko_u.mock.broker_id;
2440
+ break;
2441
+
2442
+ case RD_KAFKA_MOCK_CMD_PART_SET_FOLLOWER_WMARKS:
2443
+ mpart = rd_kafka_mock_partition_get(
2444
+ mcluster, rko->rko_u.mock.name, rko->rko_u.mock.partition);
2445
+ if (!mpart)
2446
+ return RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2447
+
2448
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
2449
+ "Set %s [%" PRId32
2450
+ "] follower "
2451
+ "watermark offsets to %" PRId64 "..%" PRId64,
2452
+ rko->rko_u.mock.name, rko->rko_u.mock.partition,
2453
+ rko->rko_u.mock.lo, rko->rko_u.mock.hi);
2454
+
2455
+ if (rko->rko_u.mock.lo == -1) {
2456
+ mpart->follower_start_offset = mpart->start_offset;
2457
+ mpart->update_follower_start_offset = rd_true;
2458
+ } else {
2459
+ mpart->follower_start_offset = rko->rko_u.mock.lo;
2460
+ mpart->update_follower_start_offset = rd_false;
2461
+ }
2462
+
2463
+ if (rko->rko_u.mock.hi == -1) {
2464
+ mpart->follower_end_offset = mpart->end_offset;
2465
+ mpart->update_follower_end_offset = rd_true;
2466
+ } else {
2467
+ mpart->follower_end_offset = rko->rko_u.mock.hi;
2468
+ mpart->update_follower_end_offset = rd_false;
2469
+ }
2470
+ break;
2471
+ case RD_KAFKA_MOCK_CMD_PART_PUSH_LEADER_RESPONSE:
2472
+ mpart = rd_kafka_mock_partition_get(
2473
+ mcluster, rko->rko_u.mock.name, rko->rko_u.mock.partition);
2474
+ if (!mpart)
2475
+ return RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2476
+
2477
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
2478
+ "Push %s [%" PRId32 "] leader response: (%" PRId32
2479
+ ", %" PRId32 ")",
2480
+ rko->rko_u.mock.name, rko->rko_u.mock.partition,
2481
+ rko->rko_u.mock.leader_id,
2482
+ rko->rko_u.mock.leader_epoch);
2483
+
2484
+ rd_kafka_mock_partition_push_leader_response0(
2485
+ mpart, rko->rko_u.mock.leader_id,
2486
+ rko->rko_u.mock.leader_epoch);
2487
+ break;
2488
+
2489
+ /* Broker commands */
2490
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_UPDOWN:
2491
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_RTT:
2492
+ case RD_KAFKA_MOCK_CMD_BROKER_SET_RACK:
2493
+ return rd_kafka_mock_brokers_cmd(mcluster, rko);
2494
+
2495
+ case RD_KAFKA_MOCK_CMD_COORD_SET:
2496
+ if (!rd_kafka_mock_coord_set(mcluster, rko->rko_u.mock.name,
2497
+ rko->rko_u.mock.str,
2498
+ rko->rko_u.mock.broker_id))
2499
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
2500
+ break;
2501
+
2502
+ case RD_KAFKA_MOCK_CMD_APIVERSION_SET:
2503
+ if (rko->rko_u.mock.partition < 0 ||
2504
+ rko->rko_u.mock.partition >= RD_KAFKAP__NUM)
2505
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
2506
+
2507
+ mcluster->api_handlers[(int)rko->rko_u.mock.partition]
2508
+ .MinVersion = (int16_t)rko->rko_u.mock.lo;
2509
+ mcluster->api_handlers[(int)rko->rko_u.mock.partition]
2510
+ .MaxVersion = (int16_t)rko->rko_u.mock.hi;
2511
+ break;
2512
+
2513
+ case RD_KAFKA_MOCK_CMD_REQUESTED_METRICS_SET:
2514
+ mcluster->metrics_cnt = rko->rko_u.mock.hi;
2515
+ if (!mcluster->metrics_cnt)
2516
+ break;
2517
+
2518
+ mcluster->metrics =
2519
+ rd_calloc(mcluster->metrics_cnt, sizeof(char *));
2520
+ for (i = 0; i < mcluster->metrics_cnt; i++)
2521
+ mcluster->metrics[i] =
2522
+ rd_strdup(rko->rko_u.mock.metrics[i]);
2523
+ break;
2524
+
2525
+ case RD_KAFKA_MOCK_CMD_TELEMETRY_PUSH_INTERVAL_SET:
2526
+ mcluster->telemetry_push_interval_ms = rko->rko_u.mock.hi;
2527
+ break;
2528
+
2529
+ default:
2530
+ rd_assert(!*"unknown mock cmd");
2531
+ break;
2532
+ }
2533
+
2534
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2535
+ }
2536
+
2537
+ void rd_kafka_mock_group_initial_rebalance_delay_ms(
2538
+ rd_kafka_mock_cluster_t *mcluster,
2539
+ int32_t delay_ms) {
2540
+ mtx_lock(&mcluster->lock);
2541
+ mcluster->defaults.group_initial_rebalance_delay_ms = delay_ms;
2542
+ mtx_unlock(&mcluster->lock);
2543
+ }
2544
+
2545
+
2546
+ static rd_kafka_op_res_t
2547
+ rd_kafka_mock_cluster_op_serve(rd_kafka_t *rk,
2548
+ rd_kafka_q_t *rkq,
2549
+ rd_kafka_op_t *rko,
2550
+ rd_kafka_q_cb_type_t cb_type,
2551
+ void *opaque) {
2552
+ rd_kafka_mock_cluster_t *mcluster = opaque;
2553
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
2554
+
2555
+ switch ((int)rko->rko_type) {
2556
+ case RD_KAFKA_OP_TERMINATE:
2557
+ mcluster->run = rd_false;
2558
+ break;
2559
+
2560
+ case RD_KAFKA_OP_MOCK:
2561
+ err = rd_kafka_mock_cluster_cmd(mcluster, rko);
2562
+ break;
2563
+
2564
+ default:
2565
+ rd_assert(!"*unhandled op");
2566
+ break;
2567
+ }
2568
+
2569
+ rd_kafka_op_reply(rko, err);
2570
+
2571
+ return RD_KAFKA_OP_RES_HANDLED;
2572
+ }
2573
+
2574
+
2575
+ /**
2576
+ * @brief Destroy cluster (internal)
2577
+ */
2578
+ static void rd_kafka_mock_cluster_destroy0(rd_kafka_mock_cluster_t *mcluster) {
2579
+ rd_kafka_mock_topic_t *mtopic;
2580
+ rd_kafka_mock_broker_t *mrkb;
2581
+ rd_kafka_mock_cgrp_t *mcgrp;
2582
+ rd_kafka_mock_coord_t *mcoord;
2583
+ rd_kafka_mock_error_stack_t *errstack;
2584
+ thrd_t dummy_rkb_thread;
2585
+ int ret;
2586
+ size_t i;
2587
+
2588
+ while ((mtopic = TAILQ_FIRST(&mcluster->topics)))
2589
+ rd_kafka_mock_topic_destroy(mtopic);
2590
+
2591
+ while ((mrkb = TAILQ_FIRST(&mcluster->brokers)))
2592
+ rd_kafka_mock_broker_destroy(mrkb);
2593
+
2594
+ while ((mcgrp = TAILQ_FIRST(&mcluster->cgrps)))
2595
+ rd_kafka_mock_cgrp_destroy(mcgrp);
2596
+
2597
+ while ((mcoord = TAILQ_FIRST(&mcluster->coords)))
2598
+ rd_kafka_mock_coord_destroy(mcluster, mcoord);
2599
+
2600
+ rd_list_destroy(&mcluster->pids);
2601
+
2602
+ while ((errstack = TAILQ_FIRST(&mcluster->errstacks))) {
2603
+ TAILQ_REMOVE(&mcluster->errstacks, errstack, link);
2604
+ rd_kafka_mock_error_stack_destroy(errstack);
2605
+ }
2606
+
2607
+ rd_list_destroy(&mcluster->request_list);
2608
+
2609
+ /*
2610
+ * Destroy dummy broker
2611
+ */
2612
+ rd_kafka_q_enq(mcluster->dummy_rkb->rkb_ops,
2613
+ rd_kafka_op_new(RD_KAFKA_OP_TERMINATE));
2614
+
2615
+ dummy_rkb_thread = mcluster->dummy_rkb->rkb_thread;
2616
+
2617
+ rd_kafka_broker_destroy(mcluster->dummy_rkb);
2618
+
2619
+ if (thrd_join(dummy_rkb_thread, &ret) != thrd_success)
2620
+ rd_assert(!*"failed to join mock dummy broker thread");
2621
+
2622
+
2623
+ rd_kafka_q_destroy_owner(mcluster->ops);
2624
+
2625
+ rd_kafka_timers_destroy(&mcluster->timers);
2626
+
2627
+ if (mcluster->fd_size > 0) {
2628
+ rd_free(mcluster->fds);
2629
+ rd_free(mcluster->handlers);
2630
+ }
2631
+
2632
+ mtx_destroy(&mcluster->lock);
2633
+
2634
+ rd_free(mcluster->bootstraps);
2635
+
2636
+ rd_socket_close(mcluster->wakeup_fds[0]);
2637
+ rd_socket_close(mcluster->wakeup_fds[1]);
2638
+
2639
+ if (mcluster->metrics) {
2640
+ for (i = 0; i < mcluster->metrics_cnt; i++) {
2641
+ rd_free(mcluster->metrics[i]);
2642
+ }
2643
+ rd_free(mcluster->metrics);
2644
+ }
2645
+ }
2646
+
2647
+
2648
+
2649
+ void rd_kafka_mock_cluster_destroy(rd_kafka_mock_cluster_t *mcluster) {
2650
+ int res;
2651
+ rd_kafka_op_t *rko;
2652
+
2653
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK", "Destroying cluster");
2654
+
2655
+ rd_assert(rd_atomic32_get(&mcluster->rk->rk_mock.cluster_cnt) > 0);
2656
+ rd_atomic32_sub(&mcluster->rk->rk_mock.cluster_cnt, 1);
2657
+
2658
+ rko = rd_kafka_op_req2(mcluster->ops, RD_KAFKA_OP_TERMINATE);
2659
+
2660
+ if (rko)
2661
+ rd_kafka_op_destroy(rko);
2662
+
2663
+ if (thrd_join(mcluster->thread, &res) != thrd_success)
2664
+ rd_assert(!*"failed to join mock thread");
2665
+
2666
+ rd_free(mcluster);
2667
+ }
2668
+
2669
+
2670
+
2671
+ rd_kafka_mock_cluster_t *rd_kafka_mock_cluster_new(rd_kafka_t *rk,
2672
+ int broker_cnt) {
2673
+ rd_kafka_mock_cluster_t *mcluster;
2674
+ rd_kafka_mock_broker_t *mrkb;
2675
+ int i, r;
2676
+ size_t bootstraps_len = 0;
2677
+ size_t of;
2678
+
2679
+ mcluster = rd_calloc(1, sizeof(*mcluster));
2680
+ mcluster->rk = rk;
2681
+
2682
+ mcluster->dummy_rkb =
2683
+ rd_kafka_broker_add(rk, RD_KAFKA_INTERNAL, RD_KAFKA_PROTO_PLAINTEXT,
2684
+ "mock", 0, RD_KAFKA_NODEID_UA);
2685
+ rd_snprintf(mcluster->id, sizeof(mcluster->id), "mockCluster%lx",
2686
+ (intptr_t)mcluster >> 2);
2687
+
2688
+ TAILQ_INIT(&mcluster->brokers);
2689
+
2690
+ for (i = 1; i <= broker_cnt; i++) {
2691
+ if (!(mrkb = rd_kafka_mock_broker_new(mcluster, i))) {
2692
+ rd_kafka_mock_cluster_destroy(mcluster);
2693
+ return NULL;
2694
+ }
2695
+
2696
+ /* advertised listener + ":port" + "," */
2697
+ bootstraps_len += strlen(mrkb->advertised_listener) + 6 + 1;
2698
+ }
2699
+
2700
+ mtx_init(&mcluster->lock, mtx_plain);
2701
+
2702
+ TAILQ_INIT(&mcluster->topics);
2703
+ mcluster->defaults.partition_cnt = 4;
2704
+ mcluster->defaults.replication_factor = RD_MIN(3, broker_cnt);
2705
+ mcluster->defaults.group_initial_rebalance_delay_ms = 3000;
2706
+ mcluster->track_requests = rd_false;
2707
+
2708
+ TAILQ_INIT(&mcluster->cgrps);
2709
+
2710
+ TAILQ_INIT(&mcluster->coords);
2711
+
2712
+ rd_list_init(&mcluster->pids, 16, rd_free);
2713
+
2714
+ TAILQ_INIT(&mcluster->errstacks);
2715
+
2716
+ memcpy(mcluster->api_handlers, rd_kafka_mock_api_handlers,
2717
+ sizeof(mcluster->api_handlers));
2718
+
2719
+ rd_list_init(&mcluster->request_list, 0, rd_kafka_mock_request_free);
2720
+
2721
+ /* Use an op queue for controlling the cluster in
2722
+ * a thread-safe manner without locking. */
2723
+ mcluster->ops = rd_kafka_q_new(rk);
2724
+ mcluster->ops->rkq_serve = rd_kafka_mock_cluster_op_serve;
2725
+ mcluster->ops->rkq_opaque = mcluster;
2726
+
2727
+ rd_kafka_timers_init(&mcluster->timers, rk, mcluster->ops);
2728
+
2729
+ if ((r = rd_pipe_nonblocking(mcluster->wakeup_fds)) == -1) {
2730
+ rd_kafka_log(rk, LOG_ERR, "MOCK",
2731
+ "Failed to setup mock cluster wake-up fds: %s",
2732
+ rd_socket_strerror(r));
2733
+ } else {
2734
+ const char onebyte = 1;
2735
+ rd_kafka_q_io_event_enable(mcluster->ops,
2736
+ mcluster->wakeup_fds[1], &onebyte,
2737
+ sizeof(onebyte));
2738
+ }
2739
+
2740
+
2741
+ if (thrd_create(&mcluster->thread, rd_kafka_mock_cluster_thread_main,
2742
+ mcluster) != thrd_success) {
2743
+ rd_kafka_log(rk, LOG_CRIT, "MOCK",
2744
+ "Failed to create mock cluster thread: %s",
2745
+ rd_strerror(errno));
2746
+ rd_kafka_mock_cluster_destroy(mcluster);
2747
+ return NULL;
2748
+ }
2749
+
2750
+
2751
+ /* Construct bootstrap.servers list */
2752
+ mcluster->bootstraps = rd_malloc(bootstraps_len + 1);
2753
+ of = 0;
2754
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link) {
2755
+ r = rd_snprintf(&mcluster->bootstraps[of], bootstraps_len - of,
2756
+ "%s%s:%hu", of > 0 ? "," : "",
2757
+ mrkb->advertised_listener, mrkb->port);
2758
+ of += r;
2759
+ rd_assert(of < bootstraps_len);
2760
+ }
2761
+ mcluster->bootstraps[of] = '\0';
2762
+
2763
+ rd_kafka_dbg(rk, MOCK, "MOCK", "Mock cluster %s bootstrap.servers=%s",
2764
+ mcluster->id, mcluster->bootstraps);
2765
+
2766
+ rd_atomic32_add(&rk->rk_mock.cluster_cnt, 1);
2767
+
2768
+ return mcluster;
2769
+ }
2770
+
2771
+
2772
+ rd_kafka_t *
2773
+ rd_kafka_mock_cluster_handle(const rd_kafka_mock_cluster_t *mcluster) {
2774
+ return (rd_kafka_t *)mcluster->rk;
2775
+ }
2776
+
2777
+ rd_kafka_mock_cluster_t *rd_kafka_handle_mock_cluster(const rd_kafka_t *rk) {
2778
+ return (rd_kafka_mock_cluster_t *)rk->rk_mock.cluster;
2779
+ }
2780
+
2781
+
2782
+ const char *
2783
+ rd_kafka_mock_cluster_bootstraps(const rd_kafka_mock_cluster_t *mcluster) {
2784
+ return mcluster->bootstraps;
2785
+ }
2786
+
2787
+ /**
2788
+ * @struct Represents a request to the mock cluster along with a timestamp.
2789
+ */
2790
+ struct rd_kafka_mock_request_s {
2791
+ int32_t id; /**< Broker id */
2792
+ int16_t api_key; /**< API Key of request */
2793
+ rd_ts_t timestamp /**< Timestamp at which request was received */;
2794
+ };
2795
+
2796
+ /**
2797
+ * @brief Allocate and initialize a rd_kafka_mock_request_t *
2798
+ */
2799
+ static rd_kafka_mock_request_t *
2800
+ rd_kafka_mock_request_new(int32_t id, int16_t api_key, int64_t timestamp_us) {
2801
+ rd_kafka_mock_request_t *request;
2802
+ request = rd_malloc(sizeof(*request));
2803
+ request->id = id;
2804
+ request->api_key = api_key;
2805
+ request->timestamp = timestamp_us;
2806
+ return request;
2807
+ }
2808
+
2809
+ static rd_kafka_mock_request_t *
2810
+ rd_kafka_mock_request_copy(rd_kafka_mock_request_t *mrequest) {
2811
+ rd_kafka_mock_request_t *request;
2812
+ request = rd_malloc(sizeof(*request));
2813
+ request->id = mrequest->id;
2814
+ request->api_key = mrequest->api_key;
2815
+ request->timestamp = mrequest->timestamp;
2816
+ return request;
2817
+ }
2818
+
2819
+ void rd_kafka_mock_request_destroy(rd_kafka_mock_request_t *mrequest) {
2820
+ rd_free(mrequest);
2821
+ }
2822
+
2823
+ void rd_kafka_mock_request_destroy_array(rd_kafka_mock_request_t **mrequests,
2824
+ size_t mrequest_cnt) {
2825
+ size_t i;
2826
+ for (i = 0; i < mrequest_cnt; i++)
2827
+ rd_kafka_mock_request_destroy(mrequests[i]);
2828
+ rd_free(mrequests);
2829
+ }
2830
+
2831
+ static void rd_kafka_mock_request_free(void *element) {
2832
+ rd_kafka_mock_request_destroy(element);
2833
+ }
2834
+
2835
+ void rd_kafka_mock_start_request_tracking(rd_kafka_mock_cluster_t *mcluster) {
2836
+ mtx_lock(&mcluster->lock);
2837
+ mcluster->track_requests = rd_true;
2838
+ rd_list_clear(&mcluster->request_list);
2839
+ mtx_unlock(&mcluster->lock);
2840
+ }
2841
+
2842
+ void rd_kafka_mock_stop_request_tracking(rd_kafka_mock_cluster_t *mcluster) {
2843
+ mtx_lock(&mcluster->lock);
2844
+ mcluster->track_requests = rd_false;
2845
+ rd_list_clear(&mcluster->request_list);
2846
+ mtx_unlock(&mcluster->lock);
2847
+ }
2848
+
2849
+ rd_kafka_mock_request_t **
2850
+ rd_kafka_mock_get_requests(rd_kafka_mock_cluster_t *mcluster, size_t *cntp) {
2851
+ size_t i;
2852
+ rd_kafka_mock_request_t **ret = NULL;
2853
+
2854
+ mtx_lock(&mcluster->lock);
2855
+ *cntp = rd_list_cnt(&mcluster->request_list);
2856
+ if (*cntp > 0) {
2857
+ ret = rd_calloc(*cntp, sizeof(rd_kafka_mock_request_t *));
2858
+ for (i = 0; i < *cntp; i++) {
2859
+ rd_kafka_mock_request_t *mreq =
2860
+ rd_list_elem(&mcluster->request_list, i);
2861
+ ret[i] = rd_kafka_mock_request_copy(mreq);
2862
+ }
2863
+ }
2864
+
2865
+ mtx_unlock(&mcluster->lock);
2866
+ return ret;
2867
+ }
2868
+
2869
+ void rd_kafka_mock_clear_requests(rd_kafka_mock_cluster_t *mcluster) {
2870
+ mtx_lock(&mcluster->lock);
2871
+ rd_list_clear(&mcluster->request_list);
2872
+ mtx_unlock(&mcluster->lock);
2873
+ }
2874
+
2875
+ int32_t rd_kafka_mock_request_id(rd_kafka_mock_request_t *mreq) {
2876
+ return mreq->id;
2877
+ }
2878
+
2879
+ int16_t rd_kafka_mock_request_api_key(rd_kafka_mock_request_t *mreq) {
2880
+ return mreq->api_key;
2881
+ }
2882
+
2883
+ rd_ts_t rd_kafka_mock_request_timestamp(rd_kafka_mock_request_t *mreq) {
2884
+ return mreq->timestamp;
2885
+ }