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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (628) hide show
  1. package/CHANGELOG.md +457 -0
  2. package/LICENSE.kafkajs +31 -0
  3. package/LICENSE.node-rdkafka +25 -0
  4. package/LICENSE.txt +20 -0
  5. package/README.md +133 -0
  6. package/binding.gyp +184 -0
  7. package/build/Release/confluent-kafka-javascript.node +0 -0
  8. package/build/deps/librdkafka++.so.1 +0 -0
  9. package/build/deps/librdkafka.Makefile +6 -0
  10. package/build/deps/librdkafka.so.1 +0 -0
  11. package/build/deps/librdkafka.target.mk +55 -0
  12. package/deps/librdkafka/.clang-format +136 -0
  13. package/deps/librdkafka/.clang-format-cpp +103 -0
  14. package/deps/librdkafka/.dir-locals.el +10 -0
  15. package/deps/librdkafka/.formatignore +35 -0
  16. package/deps/librdkafka/.gdbmacros +19 -0
  17. package/deps/librdkafka/CHANGELOG.md +2477 -0
  18. package/deps/librdkafka/CMakeLists.txt +291 -0
  19. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  20. package/deps/librdkafka/CONFIGURATION.md +212 -0
  21. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  22. package/deps/librdkafka/Doxyfile +2375 -0
  23. package/deps/librdkafka/INTRODUCTION.md +2752 -0
  24. package/deps/librdkafka/LICENSE +26 -0
  25. package/deps/librdkafka/LICENSE.cjson +22 -0
  26. package/deps/librdkafka/LICENSE.crc32c +28 -0
  27. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  28. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  29. package/deps/librdkafka/LICENSE.lz4 +26 -0
  30. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  31. package/deps/librdkafka/LICENSE.nanopb +22 -0
  32. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  33. package/deps/librdkafka/LICENSE.pycrc +23 -0
  34. package/deps/librdkafka/LICENSE.queue +31 -0
  35. package/deps/librdkafka/LICENSE.regexp +5 -0
  36. package/deps/librdkafka/LICENSE.snappy +36 -0
  37. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  38. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  39. package/deps/librdkafka/LICENSES.txt +625 -0
  40. package/deps/librdkafka/Makefile +125 -0
  41. package/deps/librdkafka/README.md +201 -0
  42. package/deps/librdkafka/README.win32 +26 -0
  43. package/deps/librdkafka/STATISTICS.md +624 -0
  44. package/deps/librdkafka/configure +214 -0
  45. package/deps/librdkafka/configure.self +341 -0
  46. package/deps/librdkafka/dev-conf.sh +123 -0
  47. package/deps/librdkafka/lds-gen.py +73 -0
  48. package/deps/librdkafka/mainpage.doxy +40 -0
  49. package/deps/librdkafka/mklove/Makefile.base +329 -0
  50. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  51. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  52. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  53. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  54. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  55. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  56. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  57. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  58. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  59. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  60. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  61. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  62. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  63. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  64. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  65. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  66. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  67. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  68. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  69. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  70. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  71. package/deps/librdkafka/service.yml +182 -0
  72. package/deps/librdkafka/src/CMakeLists.txt +379 -0
  73. package/deps/librdkafka/src/Makefile +105 -0
  74. package/deps/librdkafka/src/README.lz4.md +30 -0
  75. package/deps/librdkafka/src/cJSON.c +3191 -0
  76. package/deps/librdkafka/src/cJSON.h +306 -0
  77. package/deps/librdkafka/src/crc32c.c +430 -0
  78. package/deps/librdkafka/src/crc32c.h +38 -0
  79. package/deps/librdkafka/src/generate_proto.sh +66 -0
  80. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  81. package/deps/librdkafka/src/lz4.c +2727 -0
  82. package/deps/librdkafka/src/lz4.h +842 -0
  83. package/deps/librdkafka/src/lz4frame.c +2078 -0
  84. package/deps/librdkafka/src/lz4frame.h +692 -0
  85. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  86. package/deps/librdkafka/src/lz4hc.c +1631 -0
  87. package/deps/librdkafka/src/lz4hc.h +413 -0
  88. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  89. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  90. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  91. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  92. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  93. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  94. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  95. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  96. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  97. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  98. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  99. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  100. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  101. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  102. package/deps/librdkafka/src/queue.h +850 -0
  103. package/deps/librdkafka/src/rd.h +592 -0
  104. package/deps/librdkafka/src/rdaddr.c +255 -0
  105. package/deps/librdkafka/src/rdaddr.h +202 -0
  106. package/deps/librdkafka/src/rdatomic.h +262 -0
  107. package/deps/librdkafka/src/rdavg.h +260 -0
  108. package/deps/librdkafka/src/rdavl.c +210 -0
  109. package/deps/librdkafka/src/rdavl.h +250 -0
  110. package/deps/librdkafka/src/rdbase64.c +200 -0
  111. package/deps/librdkafka/src/rdbase64.h +43 -0
  112. package/deps/librdkafka/src/rdbuf.c +1884 -0
  113. package/deps/librdkafka/src/rdbuf.h +375 -0
  114. package/deps/librdkafka/src/rdcrc32.c +114 -0
  115. package/deps/librdkafka/src/rdcrc32.h +170 -0
  116. package/deps/librdkafka/src/rddl.c +179 -0
  117. package/deps/librdkafka/src/rddl.h +43 -0
  118. package/deps/librdkafka/src/rdendian.h +175 -0
  119. package/deps/librdkafka/src/rdfloat.h +67 -0
  120. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  121. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  122. package/deps/librdkafka/src/rdgz.c +120 -0
  123. package/deps/librdkafka/src/rdgz.h +46 -0
  124. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  125. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  126. package/deps/librdkafka/src/rdhttp.c +831 -0
  127. package/deps/librdkafka/src/rdhttp.h +101 -0
  128. package/deps/librdkafka/src/rdinterval.h +177 -0
  129. package/deps/librdkafka/src/rdkafka.c +7287 -0
  130. package/deps/librdkafka/src/rdkafka.h +11795 -0
  131. package/deps/librdkafka/src/rdkafka_admin.c +10165 -0
  132. package/deps/librdkafka/src/rdkafka_admin.h +658 -0
  133. package/deps/librdkafka/src/rdkafka_assignment.c +1282 -0
  134. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  135. package/deps/librdkafka/src/rdkafka_assignor.c +1800 -0
  136. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  137. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  138. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  139. package/deps/librdkafka/src/rdkafka_background.c +222 -0
  140. package/deps/librdkafka/src/rdkafka_broker.c +6736 -0
  141. package/deps/librdkafka/src/rdkafka_broker.h +851 -0
  142. package/deps/librdkafka/src/rdkafka_buf.c +543 -0
  143. package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
  144. package/deps/librdkafka/src/rdkafka_cert.c +576 -0
  145. package/deps/librdkafka/src/rdkafka_cert.h +62 -0
  146. package/deps/librdkafka/src/rdkafka_cgrp.c +8310 -0
  147. package/deps/librdkafka/src/rdkafka_cgrp.h +589 -0
  148. package/deps/librdkafka/src/rdkafka_conf.c +5177 -0
  149. package/deps/librdkafka/src/rdkafka_conf.h +746 -0
  150. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  151. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  152. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  153. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  154. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  155. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  156. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  157. package/deps/librdkafka/src/rdkafka_feature.c +898 -0
  158. package/deps/librdkafka/src/rdkafka_feature.h +104 -0
  159. package/deps/librdkafka/src/rdkafka_fetcher.c +3820 -0
  160. package/deps/librdkafka/src/rdkafka_fetcher.h +62 -0
  161. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  162. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  163. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  164. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  165. package/deps/librdkafka/src/rdkafka_int.h +1505 -0
  166. package/deps/librdkafka/src/rdkafka_interceptor.c +842 -0
  167. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  168. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  169. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  170. package/deps/librdkafka/src/rdkafka_metadata.c +2347 -0
  171. package/deps/librdkafka/src/rdkafka_metadata.h +350 -0
  172. package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
  173. package/deps/librdkafka/src/rdkafka_mock.c +4514 -0
  174. package/deps/librdkafka/src/rdkafka_mock.h +867 -0
  175. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1877 -0
  176. package/deps/librdkafka/src/rdkafka_mock_handlers.c +5255 -0
  177. package/deps/librdkafka/src/rdkafka_mock_int.h +1005 -0
  178. package/deps/librdkafka/src/rdkafka_mock_sharegrp.c +1207 -0
  179. package/deps/librdkafka/src/rdkafka_msg.c +2619 -0
  180. package/deps/librdkafka/src/rdkafka_msg.h +629 -0
  181. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  182. package/deps/librdkafka/src/rdkafka_msgset.h +105 -0
  183. package/deps/librdkafka/src/rdkafka_msgset_reader.c +2099 -0
  184. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
  185. package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
  186. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  187. package/deps/librdkafka/src/rdkafka_op.c +1219 -0
  188. package/deps/librdkafka/src/rdkafka_op.h +1065 -0
  189. package/deps/librdkafka/src/rdkafka_partition.c +5109 -0
  190. package/deps/librdkafka/src/rdkafka_partition.h +1215 -0
  191. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  192. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  193. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  194. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  195. package/deps/librdkafka/src/rdkafka_proto.h +739 -0
  196. package/deps/librdkafka/src/rdkafka_protocol.h +131 -0
  197. package/deps/librdkafka/src/rdkafka_queue.c +1351 -0
  198. package/deps/librdkafka/src/rdkafka_queue.h +1235 -0
  199. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  200. package/deps/librdkafka/src/rdkafka_request.c +7298 -0
  201. package/deps/librdkafka/src/rdkafka_request.h +761 -0
  202. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  203. package/deps/librdkafka/src/rdkafka_sasl.c +589 -0
  204. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  205. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  206. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  207. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
  208. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  209. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1827 -0
  210. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +52 -0
  211. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  212. package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
  213. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  214. package/deps/librdkafka/src/rdkafka_share_acknowledgement.c +1445 -0
  215. package/deps/librdkafka/src/rdkafka_share_acknowledgement.h +373 -0
  216. package/deps/librdkafka/src/rdkafka_ssl.c +2235 -0
  217. package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
  218. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
  219. package/deps/librdkafka/src/rdkafka_subscription.c +411 -0
  220. package/deps/librdkafka/src/rdkafka_telemetry.c +761 -0
  221. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  222. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1307 -0
  223. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  224. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +1309 -0
  225. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +459 -0
  226. package/deps/librdkafka/src/rdkafka_timer.c +407 -0
  227. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  228. package/deps/librdkafka/src/rdkafka_topic.c +2382 -0
  229. package/deps/librdkafka/src/rdkafka_topic.h +369 -0
  230. package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
  231. package/deps/librdkafka/src/rdkafka_transport.h +99 -0
  232. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  233. package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
  234. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  235. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  236. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  237. package/deps/librdkafka/src/rdlist.c +593 -0
  238. package/deps/librdkafka/src/rdlist.h +444 -0
  239. package/deps/librdkafka/src/rdlog.c +89 -0
  240. package/deps/librdkafka/src/rdlog.h +41 -0
  241. package/deps/librdkafka/src/rdmap.c +508 -0
  242. package/deps/librdkafka/src/rdmap.h +492 -0
  243. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  244. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  245. package/deps/librdkafka/src/rdports.c +61 -0
  246. package/deps/librdkafka/src/rdports.h +38 -0
  247. package/deps/librdkafka/src/rdposix.h +250 -0
  248. package/deps/librdkafka/src/rdrand.c +151 -0
  249. package/deps/librdkafka/src/rdrand.h +72 -0
  250. package/deps/librdkafka/src/rdregex.c +156 -0
  251. package/deps/librdkafka/src/rdregex.h +43 -0
  252. package/deps/librdkafka/src/rdsignal.h +57 -0
  253. package/deps/librdkafka/src/rdstring.c +645 -0
  254. package/deps/librdkafka/src/rdstring.h +98 -0
  255. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  256. package/deps/librdkafka/src/rdtime.h +356 -0
  257. package/deps/librdkafka/src/rdtypes.h +86 -0
  258. package/deps/librdkafka/src/rdunittest.c +564 -0
  259. package/deps/librdkafka/src/rdunittest.h +232 -0
  260. package/deps/librdkafka/src/rdunittest_acknowledge.c +1177 -0
  261. package/deps/librdkafka/src/rdunittest_fetcher.c +1211 -0
  262. package/deps/librdkafka/src/rdunittest_msgset_errors.c +1521 -0
  263. package/deps/librdkafka/src/rdvarint.c +134 -0
  264. package/deps/librdkafka/src/rdvarint.h +165 -0
  265. package/deps/librdkafka/src/rdwin32.h +382 -0
  266. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  267. package/deps/librdkafka/src/rdxxhash.h +328 -0
  268. package/deps/librdkafka/src/regexp.c +1352 -0
  269. package/deps/librdkafka/src/regexp.h +41 -0
  270. package/deps/librdkafka/src/snappy.c +1866 -0
  271. package/deps/librdkafka/src/snappy.h +62 -0
  272. package/deps/librdkafka/src/snappy_compat.h +138 -0
  273. package/deps/librdkafka/src/statistics_schema.json +444 -0
  274. package/deps/librdkafka/src/tinycthread.c +932 -0
  275. package/deps/librdkafka/src/tinycthread.h +503 -0
  276. package/deps/librdkafka/src/tinycthread_extra.c +210 -0
  277. package/deps/librdkafka/src/tinycthread_extra.h +218 -0
  278. package/deps/librdkafka/src/win32_config.h +58 -0
  279. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  280. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  281. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  282. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  283. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  284. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  285. package/deps/librdkafka/src-cpp/Makefile +55 -0
  286. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  287. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  288. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  289. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  290. package/deps/librdkafka/src-cpp/README.md +16 -0
  291. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  292. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  293. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  294. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
  295. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  296. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  297. package/deps/librdkafka/tests/0001-multiobj.c +102 -0
  298. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  299. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  300. package/deps/librdkafka/tests/0004-conf.c +934 -0
  301. package/deps/librdkafka/tests/0005-order.c +133 -0
  302. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  303. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  304. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  305. package/deps/librdkafka/tests/0009-mock_cluster.c +272 -0
  306. package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
  307. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  308. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  309. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  310. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  311. package/deps/librdkafka/tests/0016-client_swname.c +181 -0
  312. package/deps/librdkafka/tests/0017-compression.c +140 -0
  313. package/deps/librdkafka/tests/0018-cgrp_term.c +444 -0
  314. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  315. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  316. package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
  317. package/deps/librdkafka/tests/0022-consume_batch.c +331 -0
  318. package/deps/librdkafka/tests/0025-timers.c +147 -0
  319. package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
  320. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  321. package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
  322. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  323. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  324. package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
  325. package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
  326. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  327. package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
  328. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  329. package/deps/librdkafka/tests/0038-performance.c +121 -0
  330. package/deps/librdkafka/tests/0039-event.c +284 -0
  331. package/deps/librdkafka/tests/0040-io_event.c +257 -0
  332. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
  333. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  334. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  335. package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
  336. package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
  337. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  338. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
  339. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  340. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  341. package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
  342. package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
  343. package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
  344. package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
  345. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  346. package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
  347. package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
  348. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  349. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  350. package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
  351. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  352. package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
  353. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  354. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  355. package/deps/librdkafka/tests/0064-interceptors.c +529 -0
  356. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  357. package/deps/librdkafka/tests/0066-plugins.cpp +143 -0
  358. package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
  359. package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
  360. package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
  361. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  362. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  363. package/deps/librdkafka/tests/0073-headers.c +381 -0
  364. package/deps/librdkafka/tests/0074-producev.c +87 -0
  365. package/deps/librdkafka/tests/0075-retry.c +290 -0
  366. package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
  367. package/deps/librdkafka/tests/0077-compaction.c +366 -0
  368. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  369. package/deps/librdkafka/tests/0079-fork.c +93 -0
  370. package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
  371. package/deps/librdkafka/tests/0081-admin.c +5633 -0
  372. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
  373. package/deps/librdkafka/tests/0083-cb_event.c +233 -0
  374. package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
  375. package/deps/librdkafka/tests/0085-headers.cpp +392 -0
  376. package/deps/librdkafka/tests/0086-purge.c +368 -0
  377. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  378. package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
  379. package/deps/librdkafka/tests/0090-idempotence.c +171 -0
  380. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
  381. package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
  382. package/deps/librdkafka/tests/0093-holb.c +200 -0
  383. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
  384. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  385. package/deps/librdkafka/tests/0097-ssl_verify.cpp +674 -0
  386. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  387. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  388. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  389. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  390. package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
  391. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  392. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
  393. package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
  394. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
  395. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  396. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
  397. package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
  398. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  399. package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
  400. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
  401. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  402. package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
  403. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
  404. package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
  405. package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
  406. package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
  407. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
  408. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  409. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  410. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  411. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  412. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  413. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +1164 -0
  414. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  415. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +217 -0
  416. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
  417. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  418. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  419. package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
  420. package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
  421. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  422. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +279 -0
  423. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  424. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +752 -0
  425. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  426. package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
  427. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  428. package/deps/librdkafka/tests/0142-reauthentication.c +931 -0
  429. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
  430. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  431. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  432. package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
  433. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +1210 -0
  434. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +569 -0
  435. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  436. package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
  437. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  438. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  439. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  440. package/deps/librdkafka/tests/0155-share_group_heartbeat_mock.c +2695 -0
  441. package/deps/librdkafka/tests/0156-share_consumer_fetch_mock.c +1551 -0
  442. package/deps/librdkafka/tests/0157-share_consumer_ack_mock.c +1788 -0
  443. package/deps/librdkafka/tests/0158-share_consumer_transactions_mock.c +467 -0
  444. package/deps/librdkafka/tests/0170-share_consumer_subscription.c +2192 -0
  445. package/deps/librdkafka/tests/0171-share_consumer_consume.c +2150 -0
  446. package/deps/librdkafka/tests/0172-share_consumer_acknowledge.c +1919 -0
  447. package/deps/librdkafka/tests/0173-share_consumer_commit_async.c +2735 -0
  448. package/deps/librdkafka/tests/0174-share_consumer_concurrency.c +1434 -0
  449. package/deps/librdkafka/tests/0175-share_consumer_groups.c +574 -0
  450. package/deps/librdkafka/tests/0176-share_consumer_commit_sync.c +2986 -0
  451. package/deps/librdkafka/tests/0177-share_consumer_transactions.c +1815 -0
  452. package/deps/librdkafka/tests/0178-share_consumer_close.c +2102 -0
  453. package/deps/librdkafka/tests/0179-share_consumer_destroy.c +2482 -0
  454. package/deps/librdkafka/tests/0180-share_consumer_config.c +1677 -0
  455. package/deps/librdkafka/tests/0181-share_consumer_topic_delete.c +354 -0
  456. package/deps/librdkafka/tests/0182-share_consumer_error_handling_mock.c +3358 -0
  457. package/deps/librdkafka/tests/0183-share_consumer_leader_change_mock.c +1234 -0
  458. package/deps/librdkafka/tests/0184-share_consumer_topic_recreate.c +1356 -0
  459. package/deps/librdkafka/tests/0185-share_consumer_max_poll_interval.c +557 -0
  460. package/deps/librdkafka/tests/0186-share_consumer_fatal_error.c +360 -0
  461. package/deps/librdkafka/tests/0190-share_consumer_telemetry.c +387 -0
  462. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  463. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  464. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  465. package/deps/librdkafka/tests/CMakeLists.txt +193 -0
  466. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
  467. package/deps/librdkafka/tests/Makefile +182 -0
  468. package/deps/librdkafka/tests/README.md +514 -0
  469. package/deps/librdkafka/tests/autotest.sh +33 -0
  470. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  471. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  472. package/deps/librdkafka/tests/buildbox.sh +17 -0
  473. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  474. package/deps/librdkafka/tests/cluster_testing.py +203 -0
  475. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  476. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  477. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  478. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  479. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  480. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  481. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  482. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
  483. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  484. package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
  485. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
  486. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  487. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  488. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  489. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  490. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  491. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  492. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  493. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  494. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  495. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  496. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  497. package/deps/librdkafka/tests/java/Makefile +13 -0
  498. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  499. package/deps/librdkafka/tests/java/README.md +14 -0
  500. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  501. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  502. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  503. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  504. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  505. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  506. package/deps/librdkafka/tests/performance_plot.py +115 -0
  507. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  508. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  509. package/deps/librdkafka/tests/requirements.txt +2 -0
  510. package/deps/librdkafka/tests/run-all-tests.sh +81 -0
  511. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  512. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  513. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  514. package/deps/librdkafka/tests/run-test.sh +141 -0
  515. package/deps/librdkafka/tests/rusage.c +249 -0
  516. package/deps/librdkafka/tests/sasl_test.py +289 -0
  517. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  518. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  519. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  520. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  521. package/deps/librdkafka/tests/share_telemetry_verify/share-otel-collector-config.yaml +28 -0
  522. package/deps/librdkafka/tests/sockem.c +801 -0
  523. package/deps/librdkafka/tests/sockem.h +85 -0
  524. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  525. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  526. package/deps/librdkafka/tests/test.c +8376 -0
  527. package/deps/librdkafka/tests/test.conf.example +27 -0
  528. package/deps/librdkafka/tests/test.h +1150 -0
  529. package/deps/librdkafka/tests/testcpp.cpp +131 -0
  530. package/deps/librdkafka/tests/testcpp.h +388 -0
  531. package/deps/librdkafka/tests/testshared.h +416 -0
  532. package/deps/librdkafka/tests/tools/README.md +4 -0
  533. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  534. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  535. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  536. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  537. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  538. package/deps/librdkafka/tests/trivup/trivup-0.15.0.tar.gz +0 -0
  539. package/deps/librdkafka/tests/until-fail.sh +87 -0
  540. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  541. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  542. package/deps/librdkafka/vcpkg.json +23 -0
  543. package/deps/librdkafka/win32/README.md +5 -0
  544. package/deps/librdkafka/win32/build-package.bat +3 -0
  545. package/deps/librdkafka/win32/build.bat +19 -0
  546. package/deps/librdkafka/win32/common.vcxproj +84 -0
  547. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  548. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  549. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  550. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  551. package/deps/librdkafka/win32/librdkafka.vcxproj +282 -0
  552. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  553. package/deps/librdkafka/win32/msbuild.ps1 +58 -0
  554. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  555. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  556. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  557. package/deps/librdkafka/win32/push-package.bat +4 -0
  558. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  559. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  560. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  561. package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
  562. package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
  563. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  564. package/deps/librdkafka/win32/tests/tests.vcxproj +278 -0
  565. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  566. package/deps/librdkafka/win32/wingetopt.c +564 -0
  567. package/deps/librdkafka/win32/wingetopt.h +101 -0
  568. package/deps/librdkafka/win32/wintime.h +33 -0
  569. package/deps/librdkafka.gyp +83 -0
  570. package/deps/windows-install.py +80 -0
  571. package/index.d.ts +3 -0
  572. package/lib/admin.js +732 -0
  573. package/lib/client.js +679 -0
  574. package/lib/error.js +501 -0
  575. package/lib/index.js +8 -0
  576. package/lib/kafka-consumer-stream.js +399 -0
  577. package/lib/kafka-consumer.js +798 -0
  578. package/lib/kafkajs/_admin.js +1052 -0
  579. package/lib/kafkajs/_common.js +887 -0
  580. package/lib/kafkajs/_consumer.js +2156 -0
  581. package/lib/kafkajs/_consumer_cache.js +310 -0
  582. package/lib/kafkajs/_error.js +298 -0
  583. package/lib/kafkajs/_kafka.js +125 -0
  584. package/lib/kafkajs/_linked-list.js +220 -0
  585. package/lib/kafkajs/_producer.js +863 -0
  586. package/lib/kafkajs/index.js +5 -0
  587. package/lib/producer/high-level-producer.js +400 -0
  588. package/lib/producer-stream.js +337 -0
  589. package/lib/producer.js +405 -0
  590. package/lib/rdkafka.js +44 -0
  591. package/lib/tools/ref-counter.js +53 -0
  592. package/lib/topic-partition.js +91 -0
  593. package/lib/topic.js +43 -0
  594. package/lib/util.js +55 -0
  595. package/librdkafka.js +12 -0
  596. package/package.json +85 -0
  597. package/shim/source_location +54 -0
  598. package/src/admin.cc +1597 -0
  599. package/src/admin.h +112 -0
  600. package/src/binding.cc +76 -0
  601. package/src/binding.h +25 -0
  602. package/src/callbacks.cc +676 -0
  603. package/src/callbacks.h +302 -0
  604. package/src/common.cc +1628 -0
  605. package/src/common.h +192 -0
  606. package/src/config.cc +219 -0
  607. package/src/config.h +61 -0
  608. package/src/connection.cc +703 -0
  609. package/src/connection.h +117 -0
  610. package/src/errors.cc +119 -0
  611. package/src/errors.h +60 -0
  612. package/src/kafka-consumer.cc +1539 -0
  613. package/src/kafka-consumer.h +147 -0
  614. package/src/producer.cc +917 -0
  615. package/src/producer.h +124 -0
  616. package/src/topic.cc +173 -0
  617. package/src/topic.h +54 -0
  618. package/src/workers.cc +1714 -0
  619. package/src/workers.h +690 -0
  620. package/types/config.d.ts +1269 -0
  621. package/types/errors.d.ts +373 -0
  622. package/types/kafkajs.d.ts +568 -0
  623. package/types/rdkafka.d.ts +571 -0
  624. package/util/configure.js +32 -0
  625. package/util/generate-docs.sh +18 -0
  626. package/util/get-env.js +6 -0
  627. package/util/test-compile.js +11 -0
  628. package/util/test-producer-delivery.js +100 -0
@@ -0,0 +1,2099 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2017-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
+ * @name MessageSet reader interface
32
+ *
33
+ * Parses FetchResponse for Messages
34
+ *
35
+ *
36
+ * @remark
37
+ * The broker may send partial messages, when this happens we bail out
38
+ * silently and keep the messages that we successfully parsed.
39
+ *
40
+ * "A Guide To The Kafka Protocol" states:
41
+ * "As an optimization the server is allowed to
42
+ * return a partial message at the end of the
43
+ * message set.
44
+ * Clients should handle this case."
45
+ *
46
+ * We're handling it by not passing the error upstream.
47
+ * This is why most err_parse: goto labels (that are called from buf parsing
48
+ * macros) suppress the error message and why log_decode_errors is off
49
+ * unless PROTOCOL debugging is enabled.
50
+ *
51
+ * When a FetchResponse contains multiple partitions, each partition's
52
+ * MessageSet may be partial, regardless of the other partitions.
53
+ * To make sure the next partition can be parsed, each partition parse
54
+ * uses its own sub-slice of only that partition's MessageSetSize length.
55
+ */
56
+
57
+ #include "rd.h"
58
+ #include "rdunittest.h"
59
+ #include "rdavl.h"
60
+ #include "rdlist.h"
61
+ #include "rdkafka_int.h"
62
+ #include "rdkafka_msg.h"
63
+ #include "rdkafka_msgset.h"
64
+ #include "rdkafka_topic.h"
65
+ #include "rdkafka_partition.h"
66
+ #include "rdkafka_header.h"
67
+ #include "rdkafka_lz4.h"
68
+
69
+ #include "rdvarint.h"
70
+ #include "crc32c.h"
71
+
72
+ #if WITH_ZLIB
73
+ #include "rdgz.h"
74
+ #endif
75
+ #if WITH_SNAPPY
76
+ #include "snappy.h"
77
+ #endif
78
+ #if WITH_ZSTD
79
+ #include "rdkafka_zstd.h"
80
+ #endif
81
+
82
+
83
+ static RD_INLINE int64_t
84
+ rd_kafka_aborted_txns_pop_offset(rd_kafka_aborted_txns_t *aborted_txns,
85
+ int64_t pid,
86
+ int64_t max_offset);
87
+ static RD_INLINE int64_t
88
+ rd_kafka_aborted_txns_get_offset(const rd_kafka_aborted_txns_t *aborted_txns,
89
+ int64_t pid);
90
+
91
+
92
+ struct msgset_v2_hdr {
93
+ int64_t BaseOffset;
94
+ int32_t Length;
95
+ int32_t PartitionLeaderEpoch;
96
+ int8_t MagicByte;
97
+ int32_t Crc;
98
+ int16_t Attributes;
99
+ int32_t LastOffsetDelta;
100
+ int64_t BaseTimestamp;
101
+ int64_t MaxTimestamp;
102
+ int64_t PID;
103
+ int16_t ProducerEpoch;
104
+ int32_t BaseSequence;
105
+ int32_t RecordCount;
106
+ };
107
+
108
+
109
+ /**
110
+ * @struct rd_kafka_aborted_txn_start_offsets_t
111
+ *
112
+ * @brief A sorted list of aborted transaction start offsets
113
+ * (ascending) for a PID, and an offset into that list.
114
+ */
115
+ typedef struct rd_kafka_aborted_txn_start_offsets_s {
116
+ rd_avl_node_t avl_node;
117
+ int64_t pid;
118
+ int offsets_idx;
119
+ rd_list_t offsets;
120
+ } rd_kafka_aborted_txn_start_offsets_t;
121
+
122
+
123
+ typedef struct rd_kafka_msgset_reader_s {
124
+ rd_kafka_buf_t *msetr_rkbuf; /**< Response read buffer */
125
+
126
+ int msetr_relative_offsets; /**< Bool: using relative offsets */
127
+
128
+ /**< Outer/wrapper Message fields. */
129
+ struct {
130
+ int64_t offset; /**< Relative_offsets: outer message's
131
+ * Offset (last offset) */
132
+ rd_kafka_timestamp_type_t tstype; /**< Compressed
133
+ * MessageSet's
134
+ * timestamp type. */
135
+ int64_t timestamp; /**< ... timestamp*/
136
+ } msetr_outer;
137
+
138
+ struct msgset_v2_hdr *msetr_v2_hdr; /**< MessageSet v2 header */
139
+
140
+ /*
141
+ * Aborted Transaction Start Offsets. These are arranged in a map
142
+ * (ABORTED_TXN_OFFSETS), with PID as the key and value as follows:
143
+ * - OFFSETS: sorted list of aborted transaction start offsets
144
+ * (ascending)
145
+ * - IDX: an index into OFFSETS list, initialized to 0.
146
+ *
147
+ * The logic for processing fetched data is as follows (note: this is
148
+ * different from the Java client):
149
+ *
150
+ * 1. If the message is a transaction control message and the status is
151
+ * ABORT then increment ABORTED_TXN_OFFSETS(PID).IDX. note: sanity check
152
+ * that OFFSETS[ABORTED_TXN_OFFSETS(PID).IDX] is less than the current
153
+ * offset before incrementing. If the status is COMMIT, do nothing.
154
+ *
155
+ * 2. If the message is a normal message, find the corresponding OFFSETS
156
+ * list in ABORTED_TXN_OFFSETS. If it doesn't exist, then keep the
157
+ * message. If the PID does exist, compare ABORTED_TXN_OFFSETS(PID).IDX
158
+ * with len(OFFSETS). If it's >= then the message should be kept. If
159
+ * not, compare the message offset with
160
+ * OFFSETS[ABORTED_TXN_OFFSETS(PID).IDX]. If it's greater than or equal
161
+ * to this value, then the message should be ignored. If it's less than,
162
+ * then the message should be kept.
163
+ *
164
+ * Note: A MessageSet comprises messages from at most one transaction,
165
+ * so the logic in step 2 is done at the message set level.
166
+ */
167
+ rd_kafka_aborted_txns_t *msetr_aborted_txns;
168
+
169
+ const struct rd_kafka_toppar_ver *msetr_tver; /**< Toppar op version of
170
+ * request. */
171
+
172
+ int32_t msetr_leader_epoch; /**< Current MessageSet's partition
173
+ * leader epoch (or -1). */
174
+
175
+ int32_t msetr_broker_id; /**< Broker id (of msetr_rkb) */
176
+ rd_kafka_broker_t *msetr_rkb; /* @warning Not a refcounted
177
+ * reference! */
178
+ rd_kafka_toppar_t *msetr_rktp; /* @warning Not a refcounted
179
+ * reference! */
180
+
181
+ int msetr_msgcnt; /**< Number of messages in rkq */
182
+ int64_t msetr_msg_bytes; /**< Number of bytes in rkq */
183
+ rd_kafka_q_t msetr_rkq; /**< Temp Message and error queue */
184
+ rd_kafka_q_t *msetr_par_rkq; /**< Parent message and error queue,
185
+ * the temp msetr_rkq will be moved
186
+ * to this queue when parsing
187
+ * is done.
188
+ * Refcount is not increased. */
189
+
190
+ int64_t msetr_next_offset; /**< Next offset to fetch after
191
+ * this reader run is done.
192
+ * Optional: only used for special
193
+ * cases where the per-message offset
194
+ * can't be relied on for next
195
+ * fetch offset, such as with
196
+ * compacted topics. */
197
+
198
+ int msetr_ctrl_cnt; /**< Number of control messages
199
+ * or MessageSets received. */
200
+
201
+ int msetr_aborted_cnt; /**< Number of aborted MessageSets
202
+ * encountered. */
203
+
204
+ const char *msetr_srcname; /**< Optional message source string,
205
+ * used in debug logging to
206
+ * indicate messages were
207
+ * from an inner compressed
208
+ * message set.
209
+ * Not freed (use const memory).
210
+ * Add trailing space. */
211
+
212
+ rd_kafka_compression_t msetr_compression; /**< Compression codec */
213
+ } rd_kafka_msgset_reader_t;
214
+
215
+
216
+
217
+ /* Forward declarations */
218
+ static rd_kafka_resp_err_t
219
+ rd_kafka_msgset_reader_run(rd_kafka_msgset_reader_t *msetr);
220
+ static rd_kafka_resp_err_t
221
+ rd_kafka_msgset_reader_msgs_v2(rd_kafka_msgset_reader_t *msetr);
222
+
223
+
224
+ /**
225
+ * @brief Set up a MessageSet reader but don't start reading messages.
226
+ */
227
+ static void rd_kafka_msgset_reader_init(rd_kafka_msgset_reader_t *msetr,
228
+ rd_kafka_buf_t *rkbuf,
229
+ rd_kafka_toppar_t *rktp,
230
+ const struct rd_kafka_toppar_ver *tver,
231
+ rd_kafka_aborted_txns_t *aborted_txns,
232
+ rd_kafka_q_t *par_rkq) {
233
+
234
+ memset(msetr, 0, sizeof(*msetr));
235
+
236
+ msetr->msetr_rkb = rkbuf->rkbuf_rkb;
237
+ msetr->msetr_leader_epoch = -1;
238
+ msetr->msetr_broker_id = rd_kafka_broker_id(msetr->msetr_rkb);
239
+ msetr->msetr_rktp = rktp;
240
+ msetr->msetr_aborted_txns = aborted_txns;
241
+ msetr->msetr_tver = tver;
242
+ msetr->msetr_rkbuf = rkbuf;
243
+ msetr->msetr_srcname = "";
244
+
245
+ rkbuf->rkbuf_uflow_mitigation = "truncated response from broker (ok)";
246
+
247
+ /* All parsed messages are put on this temporary op
248
+ * queue first and then moved in one go to the real op queue. */
249
+ rd_kafka_q_init(&msetr->msetr_rkq, msetr->msetr_rkb->rkb_rk);
250
+
251
+ /* Make sure enqueued ops get the correct serve/opaque reflecting the
252
+ * original queue. */
253
+ msetr->msetr_rkq.rkq_serve = par_rkq->rkq_serve;
254
+ msetr->msetr_rkq.rkq_opaque = par_rkq->rkq_opaque;
255
+
256
+ /* Keep (non-refcounted) reference to parent queue for
257
+ * moving the messages and events in msetr_rkq to when
258
+ * parsing is done. */
259
+ msetr->msetr_par_rkq = par_rkq;
260
+ }
261
+
262
+
263
+
264
+ /**
265
+ * @brief Decompress MessageSet, pass the uncompressed MessageSet to
266
+ * the MessageSet reader.
267
+ */
268
+ static rd_kafka_resp_err_t
269
+ rd_kafka_msgset_reader_decompress(rd_kafka_msgset_reader_t *msetr,
270
+ int MsgVersion,
271
+ int Attributes,
272
+ int64_t Timestamp,
273
+ int64_t Offset,
274
+ const void *compressed,
275
+ size_t compressed_size) {
276
+ struct iovec iov = {.iov_base = NULL, .iov_len = 0};
277
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
278
+ int codec = Attributes & RD_KAFKA_MSG_ATTR_COMPRESSION_MASK;
279
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
280
+ rd_kafka_buf_t *rkbufz;
281
+
282
+ msetr->msetr_compression = codec;
283
+
284
+ switch (codec) {
285
+ #if WITH_ZLIB
286
+ case RD_KAFKA_COMPRESSION_GZIP: {
287
+ uint64_t outlenx = 0;
288
+
289
+ /* Decompress Message payload */
290
+ iov.iov_base = rd_gz_decompress(compressed,
291
+ (int)compressed_size, &outlenx);
292
+ if (unlikely(!iov.iov_base)) {
293
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "GZIP",
294
+ "Failed to decompress Gzip "
295
+ "message at offset %" PRId64 " of %" PRIusz
296
+ " bytes: "
297
+ "ignoring message",
298
+ Offset, compressed_size);
299
+ err = RD_KAFKA_RESP_ERR__BAD_COMPRESSION;
300
+ goto err;
301
+ }
302
+
303
+ iov.iov_len = (size_t)outlenx;
304
+ } break;
305
+ #endif
306
+
307
+ #if WITH_SNAPPY
308
+ case RD_KAFKA_COMPRESSION_SNAPPY: {
309
+ const char *inbuf = compressed;
310
+ size_t inlen = compressed_size;
311
+ int r;
312
+ static const unsigned char snappy_java_magic[] = {
313
+ 0x82, 'S', 'N', 'A', 'P', 'P', 'Y', 0};
314
+ static const size_t snappy_java_hdrlen = 8 + 4 + 4;
315
+
316
+ /* snappy-java adds its own header (SnappyCodec)
317
+ * which is not compatible with the official Snappy
318
+ * implementation.
319
+ * 8: magic, 4: version, 4: compatible
320
+ * followed by any number of chunks:
321
+ * 4: length
322
+ * ...: snappy-compressed data. */
323
+ if (likely(inlen > snappy_java_hdrlen + 4 &&
324
+ !memcmp(inbuf, snappy_java_magic, 8))) {
325
+ /* snappy-java framing */
326
+ char errstr[128];
327
+
328
+ inbuf = inbuf + snappy_java_hdrlen;
329
+ inlen -= snappy_java_hdrlen;
330
+ iov.iov_base = rd_kafka_snappy_java_uncompress(
331
+ inbuf, inlen, &iov.iov_len, errstr, sizeof(errstr));
332
+
333
+ if (unlikely(!iov.iov_base)) {
334
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "SNAPPY",
335
+ "%s [%" PRId32
336
+ "]: "
337
+ "Snappy decompression for message "
338
+ "at offset %" PRId64
339
+ " failed: %s: "
340
+ "ignoring message",
341
+ rktp->rktp_rkt->rkt_topic->str,
342
+ rktp->rktp_partition, Offset,
343
+ errstr);
344
+ err = RD_KAFKA_RESP_ERR__BAD_COMPRESSION;
345
+ goto err;
346
+ }
347
+
348
+
349
+ } else {
350
+ /* No framing */
351
+
352
+ /* Acquire uncompressed length */
353
+ if (unlikely(!rd_kafka_snappy_uncompressed_length(
354
+ inbuf, inlen, &iov.iov_len))) {
355
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "SNAPPY",
356
+ "Failed to get length of Snappy "
357
+ "compressed payload "
358
+ "for message at offset %" PRId64
359
+ " (%" PRIusz
360
+ " bytes): "
361
+ "ignoring message",
362
+ Offset, inlen);
363
+ err = RD_KAFKA_RESP_ERR__BAD_COMPRESSION;
364
+ goto err;
365
+ }
366
+
367
+ /* Allocate output buffer for uncompressed data */
368
+ iov.iov_base = rd_malloc(iov.iov_len);
369
+ if (unlikely(!iov.iov_base)) {
370
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "SNAPPY",
371
+ "Failed to allocate Snappy "
372
+ "decompress buffer of size %" PRIusz
373
+ "for message at offset %" PRId64
374
+ " (%" PRIusz
375
+ " bytes): %s: "
376
+ "ignoring message",
377
+ iov.iov_len, Offset, inlen,
378
+ rd_strerror(errno));
379
+ err = RD_KAFKA_RESP_ERR__CRIT_SYS_RESOURCE;
380
+ goto err;
381
+ }
382
+
383
+ /* Uncompress to outbuf */
384
+ if (unlikely((r = rd_kafka_snappy_uncompress(
385
+ inbuf, inlen, iov.iov_base)))) {
386
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "SNAPPY",
387
+ "Failed to decompress Snappy "
388
+ "payload for message at offset "
389
+ "%" PRId64 " (%" PRIusz
390
+ " bytes): %s: "
391
+ "ignoring message",
392
+ Offset, inlen,
393
+ rd_strerror(-r /*negative errno*/));
394
+ rd_free(iov.iov_base);
395
+ err = RD_KAFKA_RESP_ERR__BAD_COMPRESSION;
396
+ goto err;
397
+ }
398
+ }
399
+
400
+ } break;
401
+ #endif
402
+
403
+ case RD_KAFKA_COMPRESSION_LZ4: {
404
+ err =
405
+ rd_kafka_lz4_decompress(msetr->msetr_rkb,
406
+ /* Proper HC? */
407
+ MsgVersion >= 1 ? 1 : 0, Offset,
408
+ /* @warning Will modify compressed
409
+ * if no proper HC */
410
+ (char *)compressed, compressed_size,
411
+ &iov.iov_base, &iov.iov_len);
412
+ if (err)
413
+ goto err;
414
+ } break;
415
+
416
+ #if WITH_ZSTD
417
+ case RD_KAFKA_COMPRESSION_ZSTD: {
418
+ err = rd_kafka_zstd_decompress(
419
+ msetr->msetr_rkb, (char *)compressed, compressed_size,
420
+ &iov.iov_base, &iov.iov_len);
421
+ if (err)
422
+ goto err;
423
+ } break;
424
+ #endif
425
+
426
+ default:
427
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "CODEC",
428
+ "%s [%" PRId32 "]: Message at offset %" PRId64
429
+ " with unsupported "
430
+ "compression codec 0x%x: message ignored",
431
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
432
+ Offset, (int)codec);
433
+
434
+ err = RD_KAFKA_RESP_ERR__NOT_IMPLEMENTED;
435
+ goto err;
436
+ }
437
+
438
+
439
+ rd_assert(iov.iov_base);
440
+
441
+ /*
442
+ * Decompression successful
443
+ */
444
+
445
+ /* Create a new buffer pointing to the uncompressed
446
+ * allocated buffer (outbuf) and let messages keep a reference to
447
+ * this new buffer. */
448
+ rkbufz = rd_kafka_buf_new_shadow(iov.iov_base, iov.iov_len, rd_free);
449
+ rkbufz->rkbuf_rkb = msetr->msetr_rkbuf->rkbuf_rkb;
450
+ rd_kafka_broker_keep(rkbufz->rkbuf_rkb);
451
+
452
+
453
+ /* In MsgVersion v0..1 the decompressed data contains
454
+ * an inner MessageSet, pass it to a new MessageSet reader.
455
+ *
456
+ * For MsgVersion v2 the decompressed data are the list of messages.
457
+ */
458
+
459
+ if (MsgVersion <= 1) {
460
+ /* Pass decompressed data (inner Messageset)
461
+ * to new instance of the MessageSet parser. */
462
+ rd_kafka_msgset_reader_t inner_msetr;
463
+ rd_kafka_msgset_reader_init(
464
+ &inner_msetr, rkbufz, msetr->msetr_rktp, msetr->msetr_tver,
465
+ /* there is no aborted transaction
466
+ * support for MsgVersion < 2 */
467
+ NULL, &msetr->msetr_rkq);
468
+
469
+ inner_msetr.msetr_srcname = "compressed ";
470
+
471
+ if (MsgVersion == 1) {
472
+ /* postproc() will convert relative to
473
+ * absolute offsets */
474
+ inner_msetr.msetr_relative_offsets = 1;
475
+ inner_msetr.msetr_outer.offset = Offset;
476
+
477
+ /* Apply single LogAppendTime timestamp for
478
+ * all messages. */
479
+ if (Attributes & RD_KAFKA_MSG_ATTR_LOG_APPEND_TIME) {
480
+ inner_msetr.msetr_outer.tstype =
481
+ RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME;
482
+ inner_msetr.msetr_outer.timestamp = Timestamp;
483
+ }
484
+ }
485
+
486
+ /* Parse the inner MessageSet */
487
+ err = rd_kafka_msgset_reader_run(&inner_msetr);
488
+
489
+ /* Transfer message count from inner to outer */
490
+ msetr->msetr_msgcnt += inner_msetr.msetr_msgcnt;
491
+ msetr->msetr_msg_bytes += inner_msetr.msetr_msg_bytes;
492
+
493
+
494
+ } else {
495
+ /* MsgVersion 2 */
496
+ rd_kafka_buf_t *orig_rkbuf = msetr->msetr_rkbuf;
497
+
498
+ rkbufz->rkbuf_uflow_mitigation =
499
+ "truncated response from broker (ok)";
500
+
501
+ /* Temporarily replace read buffer with uncompressed buffer */
502
+ msetr->msetr_rkbuf = rkbufz;
503
+
504
+ /* Read messages */
505
+ err = rd_kafka_msgset_reader_msgs_v2(msetr);
506
+
507
+ /* Restore original buffer */
508
+ msetr->msetr_rkbuf = orig_rkbuf;
509
+ }
510
+
511
+ /* Loose our refcnt of the uncompressed rkbuf.
512
+ * Individual messages/rko's will have their own reference. */
513
+ rd_kafka_buf_destroy(rkbufz);
514
+
515
+ return err;
516
+
517
+ err:
518
+ /* Enqueue error messsage:
519
+ * Create op and push on temporary queue. */
520
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
521
+ /* Regular consumer */
522
+ rd_kafka_consumer_err(
523
+ &msetr->msetr_rkq, msetr->msetr_broker_id, err,
524
+ msetr->msetr_tver->version, NULL, rktp, Offset,
525
+ "Decompression (codec 0x%x) of message at %" PRIu64
526
+ " of %" PRIusz " bytes failed: %s",
527
+ codec, Offset, compressed_size, rd_kafka_err2str(err));
528
+ return err;
529
+ } else {
530
+ /**
531
+ * v0/v1 MessageSet: single error
532
+ * TODO KIP-932: Check the handling in case of v0/v1 messages
533
+ * for Share Consumers.
534
+ */
535
+ if (msetr->msetr_v2_hdr == NULL) {
536
+ rd_kafka_consumer_err(
537
+ &msetr->msetr_rkq, msetr->msetr_broker_id, err,
538
+ msetr->msetr_tver->version, NULL, rktp, Offset,
539
+ "Decompression (codec 0x%x) of message at %" PRIu64
540
+ " of %" PRIusz " bytes failed: %s",
541
+ codec, Offset, compressed_size,
542
+ rd_kafka_err2str(err));
543
+ } else {
544
+ /* Share consumer with MessageSet v2: report error for
545
+ * the entire batch with RELEASE acknowledgement —
546
+ * decompression capability varies by consumer, so
547
+ * another consumer might succeed on the same batch. */
548
+ int64_t LastOffset =
549
+ msetr->msetr_v2_hdr->BaseOffset +
550
+ msetr->msetr_v2_hdr->LastOffsetDelta;
551
+
552
+ /**
553
+ * TODO KIP-932: Add a TODO to translate errors inside
554
+ * this function. _BAD_COMPRESSION and _BAD_MSG should
555
+ * be sent as INVALID_MSG, and _CRIT_SYS_RESOURCE should
556
+ * be sent as _CRIT_SYS_RESOURCE.
557
+ */
558
+ rd_kafka_share_msgset_err_ops(
559
+ &msetr->msetr_rkq, msetr->msetr_broker_id, err,
560
+ msetr->msetr_tver->version, rktp,
561
+ msetr->msetr_v2_hdr->BaseOffset, LastOffset,
562
+ RD_KAFKA_SHARE_INTERNAL_ACK_RELEASE,
563
+ "Decompression (codec 0x%x) of MessageSet at "
564
+ "offsets "
565
+ "%" PRId64 "-%" PRId64 " of %" PRIusz
566
+ " bytes failed: %s",
567
+ codec, msetr->msetr_v2_hdr->BaseOffset, LastOffset,
568
+ compressed_size, rd_kafka_err2str(err));
569
+ }
570
+ }
571
+
572
+ /**
573
+ * In case of Share Consumers the errors are propagated
574
+ * as ops on the queue, but we return no error to make sure the
575
+ * MessageSet parser continues parsing the next messagesets, which might
576
+ * succeed even if this one failed.
577
+ */
578
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
579
+ }
580
+
581
+
582
+
583
+ /**
584
+ * @brief Message parser for MsgVersion v0..1
585
+ *
586
+ * @returns RD_KAFKA_RESP_ERR_NO_ERROR on success or on single-message errors,
587
+ * or any other error code when the MessageSet parser should stop
588
+ * parsing (such as for partial Messages).
589
+ * TODO KIP-932: We might need to check the handling of error ops
590
+ * for share consumers with v0/v1 messagesets.
591
+ */
592
+ static rd_kafka_resp_err_t
593
+ rd_kafka_msgset_reader_msg_v0_1(rd_kafka_msgset_reader_t *msetr) {
594
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
595
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
596
+ rd_kafka_broker_t *rkb = msetr->msetr_rkb;
597
+ struct {
598
+ int64_t Offset; /* MessageSet header */
599
+ int32_t MessageSize; /* MessageSet header */
600
+ int32_t Crc;
601
+ int8_t MagicByte; /* MsgVersion */
602
+ int8_t Attributes;
603
+ int64_t Timestamp; /* v1 */
604
+ } hdr; /* Message header */
605
+ rd_kafkap_bytes_t Key;
606
+ rd_kafkap_bytes_t Value;
607
+ int32_t Value_len;
608
+ rd_kafka_op_t *rko;
609
+ size_t hdrsize = 6; /* Header size following MessageSize */
610
+ rd_slice_t crc_slice;
611
+ rd_kafka_msg_t *rkm;
612
+ int relative_offsets = 0;
613
+ const char *reloff_str = "";
614
+ /* Only log decoding errors if protocol debugging enabled. */
615
+ int log_decode_errors =
616
+ (rkbuf->rkbuf_rkb->rkb_rk->rk_conf.debug & RD_KAFKA_DBG_PROTOCOL)
617
+ ? LOG_DEBUG
618
+ : 0;
619
+ size_t message_end;
620
+
621
+ rd_kafka_buf_read_i64(rkbuf, &hdr.Offset);
622
+ rd_kafka_buf_read_i32(rkbuf, &hdr.MessageSize);
623
+ message_end = rd_slice_offset(&rkbuf->rkbuf_reader) + hdr.MessageSize;
624
+
625
+ rd_kafka_buf_read_i32(rkbuf, &hdr.Crc);
626
+ if (!rd_slice_narrow_copy_relative(&rkbuf->rkbuf_reader, &crc_slice,
627
+ hdr.MessageSize - 4))
628
+ rd_kafka_buf_check_len(rkbuf, hdr.MessageSize - 4);
629
+
630
+ rd_kafka_buf_read_i8(rkbuf, &hdr.MagicByte);
631
+ rd_kafka_buf_read_i8(rkbuf, &hdr.Attributes);
632
+
633
+ if (hdr.MagicByte == 1) { /* MsgVersion */
634
+ rd_kafka_buf_read_i64(rkbuf, &hdr.Timestamp);
635
+ hdrsize += 8;
636
+ /* MsgVersion 1 has relative offsets for compressed
637
+ * MessageSets*/
638
+ if (!(hdr.Attributes & RD_KAFKA_MSG_ATTR_COMPRESSION_MASK) &&
639
+ msetr->msetr_relative_offsets) {
640
+ relative_offsets = 1;
641
+ reloff_str = "relative ";
642
+ }
643
+ } else
644
+ hdr.Timestamp = 0;
645
+
646
+ /* Verify MessageSize */
647
+ if (unlikely(hdr.MessageSize < (ssize_t)hdrsize))
648
+ rd_kafka_buf_parse_fail(
649
+ rkbuf,
650
+ "Message at %soffset %" PRId64 " MessageSize %" PRId32
651
+ " < hdrsize %" PRIusz,
652
+ reloff_str, hdr.Offset, hdr.MessageSize, hdrsize);
653
+
654
+ /* Early check for partial messages */
655
+ rd_kafka_buf_check_len(rkbuf, hdr.MessageSize - hdrsize);
656
+
657
+ if (rkb->rkb_rk->rk_conf.check_crcs) {
658
+ /* Verify CRC32 if desired. */
659
+ uint32_t calc_crc;
660
+
661
+ calc_crc = rd_slice_crc32(&crc_slice);
662
+ rd_dassert(rd_slice_remains(&crc_slice) == 0);
663
+
664
+ if (unlikely(hdr.Crc != (int32_t)calc_crc)) {
665
+ /* Propagate CRC error to application and
666
+ * continue with next message. */
667
+ rd_kafka_consumer_err(
668
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
669
+ RD_KAFKA_RESP_ERR__BAD_MSG,
670
+ msetr->msetr_tver->version, NULL, rktp, hdr.Offset,
671
+ "Message at %soffset %" PRId64 " (%" PRId32
672
+ " bytes) "
673
+ "failed CRC32 check "
674
+ "(original 0x%" PRIx32
675
+ " != "
676
+ "calculated 0x%" PRIx32 ")",
677
+ reloff_str, hdr.Offset, hdr.MessageSize, hdr.Crc,
678
+ calc_crc);
679
+ rd_kafka_buf_skip_to(rkbuf, message_end);
680
+ rd_atomic64_add(&rkb->rkb_c.rx_err, 1);
681
+ /* Continue with next message */
682
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
683
+ }
684
+ }
685
+
686
+
687
+ /* Extract key */
688
+ rd_kafka_buf_read_kbytes(rkbuf, &Key);
689
+
690
+ /* Extract Value */
691
+ rd_kafka_buf_read_kbytes(rkbuf, &Value);
692
+ Value_len = RD_KAFKAP_BYTES_LEN(&Value);
693
+
694
+ /* MessageSets may contain offsets earlier than we
695
+ * requested (compressed MessageSets in particular),
696
+ * drop the earlier messages.
697
+ * Note: the inner offset may only be trusted for
698
+ * absolute offsets. KIP-31 introduced
699
+ * ApiVersion 2 that maintains relative offsets
700
+ * of compressed messages and the base offset
701
+ * in the outer message is the offset of
702
+ * the *LAST* message in the MessageSet.
703
+ * This requires us to assign offsets
704
+ * after all messages have been read from
705
+ * the messageset, and it also means
706
+ * we cant perform this offset check here
707
+ * in that case. */
708
+ if (!relative_offsets &&
709
+ hdr.Offset < rktp->rktp_offsets.fetch_pos.offset &&
710
+ !RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk))
711
+ return RD_KAFKA_RESP_ERR_NO_ERROR; /* Continue with next msg */
712
+
713
+ /* Handle compressed MessageSet */
714
+ if (unlikely(hdr.Attributes & RD_KAFKA_MSG_ATTR_COMPRESSION_MASK))
715
+ return rd_kafka_msgset_reader_decompress(
716
+ msetr, hdr.MagicByte, hdr.Attributes, hdr.Timestamp,
717
+ hdr.Offset, Value.data, Value_len);
718
+
719
+
720
+ /* Pure uncompressed message, this is the innermost
721
+ * handler after all compression and cascaded
722
+ * MessageSets have been peeled off. */
723
+
724
+ /* Create op/message container for message. */
725
+ rko = rd_kafka_op_new_fetch_msg(
726
+ &rkm, rktp, msetr->msetr_tver->version, rkbuf,
727
+ RD_KAFKA_FETCH_POS(hdr.Offset, msetr->msetr_leader_epoch),
728
+ (size_t)RD_KAFKAP_BYTES_LEN(&Key),
729
+ RD_KAFKAP_BYTES_IS_NULL(&Key) ? NULL : Key.data,
730
+ (size_t)RD_KAFKAP_BYTES_LEN(&Value),
731
+ RD_KAFKAP_BYTES_IS_NULL(&Value) ? NULL : Value.data);
732
+
733
+ rkm->rkm_broker_id = msetr->msetr_broker_id;
734
+
735
+ /* Assign message timestamp.
736
+ * If message was in a compressed MessageSet and the outer/wrapper
737
+ * Message.Attribute had a LOG_APPEND_TIME set, use the
738
+ * outer timestamp */
739
+ if (msetr->msetr_outer.tstype == RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME) {
740
+ rkm->rkm_timestamp = msetr->msetr_outer.timestamp;
741
+ rkm->rkm_tstype = msetr->msetr_outer.tstype;
742
+
743
+ } else if (hdr.MagicByte >= 1 && hdr.Timestamp) {
744
+ rkm->rkm_timestamp = hdr.Timestamp;
745
+ if (hdr.Attributes & RD_KAFKA_MSG_ATTR_LOG_APPEND_TIME)
746
+ rkm->rkm_tstype = RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME;
747
+ else
748
+ rkm->rkm_tstype = RD_KAFKA_TIMESTAMP_CREATE_TIME;
749
+ }
750
+
751
+ /* Enqueue message on temporary queue */
752
+ rd_kafka_q_enq(&msetr->msetr_rkq, rko);
753
+ msetr->msetr_msgcnt++;
754
+ msetr->msetr_msg_bytes += rkm->rkm_key_len + rkm->rkm_len;
755
+
756
+ return RD_KAFKA_RESP_ERR_NO_ERROR; /* Continue */
757
+
758
+ err_parse:
759
+ /* Count all parse errors as partial message errors. */
760
+ rd_atomic64_add(&msetr->msetr_rkb->rkb_c.rx_partial, 1);
761
+ return rkbuf->rkbuf_err;
762
+ }
763
+
764
+
765
+
766
+ /**
767
+ * @brief Message parser for MsgVersion v2
768
+ */
769
+ static rd_kafka_resp_err_t
770
+ rd_kafka_msgset_reader_msg_v2(rd_kafka_msgset_reader_t *msetr) {
771
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
772
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
773
+ struct {
774
+ int64_t Length;
775
+ int8_t MsgAttributes;
776
+ int64_t TimestampDelta;
777
+ int64_t OffsetDelta;
778
+ int64_t Offset; /* Absolute offset */
779
+ rd_kafkap_bytes_t Key;
780
+ rd_kafkap_bytes_t Value;
781
+ rd_kafkap_bytes_t Headers;
782
+ } hdr;
783
+ rd_kafka_op_t *rko;
784
+ rd_kafka_msg_t *rkm;
785
+ /* Only log decoding errors if protocol debugging enabled. */
786
+ int log_decode_errors =
787
+ (rkbuf->rkbuf_rkb->rkb_rk->rk_conf.debug & RD_KAFKA_DBG_PROTOCOL)
788
+ ? LOG_DEBUG
789
+ : 0;
790
+ size_t message_end;
791
+ size_t record_start_pos;
792
+ rd_kafka_fetch_pos_t msetr_pos;
793
+
794
+ /* Capture buffer position before reading length varint so we can
795
+ * compute the total wire-format size of this record (length varint
796
+ * size + body bytes) for share consumer fetch.size telemetry. */
797
+ record_start_pos = rd_slice_offset(&rkbuf->rkbuf_reader);
798
+
799
+ rd_kafka_buf_read_varint(rkbuf, &hdr.Length);
800
+ message_end =
801
+ rd_slice_offset(&rkbuf->rkbuf_reader) + (size_t)hdr.Length;
802
+ rd_kafka_buf_read_i8(rkbuf, &hdr.MsgAttributes);
803
+
804
+ rd_kafka_buf_read_varint(rkbuf, &hdr.TimestampDelta);
805
+ rd_kafka_buf_read_varint(rkbuf, &hdr.OffsetDelta);
806
+ hdr.Offset = msetr->msetr_v2_hdr->BaseOffset + hdr.OffsetDelta;
807
+ msetr_pos = RD_KAFKA_FETCH_POS(hdr.Offset, msetr->msetr_leader_epoch);
808
+
809
+ /* Skip message if outdated.
810
+ * Don't check offset leader epoch, just log it, as if current leader
811
+ * epoch is different the fetch will fail (KIP-320) and if offset leader
812
+ * epoch is different it'll return an empty fetch (KIP-595). If we
813
+ * checked it, it's possible to have a loop when moving from a broker
814
+ * that supports leader epoch to one that doesn't.
815
+ * Share consumers may receive re-delivered records at earlier offsets
816
+ * after RELEASE, so skip this check for them. */
817
+ if (hdr.Offset < rktp->rktp_offsets.fetch_pos.offset &&
818
+ !RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
819
+ rd_rkb_dbg(
820
+ msetr->msetr_rkb, MSG, "MSG",
821
+ "%s [%" PRId32
822
+ "]: "
823
+ "Skip %s < fetch %s",
824
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
825
+ rd_kafka_fetch_pos2str(msetr_pos),
826
+ rd_kafka_fetch_pos2str(rktp->rktp_offsets.fetch_pos));
827
+ rd_kafka_buf_skip_to(rkbuf, message_end);
828
+ return RD_KAFKA_RESP_ERR_NO_ERROR; /* Continue with next msg */
829
+ }
830
+
831
+ /**
832
+ * Handle control messages
833
+ * TODO KIP-932: GA: This branch shouldn't hit for share consumers,
834
+ * as we skip control messages for share consumers.
835
+ */
836
+ if (msetr->msetr_v2_hdr->Attributes & RD_KAFKA_MSGSET_V2_ATTR_CONTROL) {
837
+ struct {
838
+ int64_t KeySize;
839
+ int16_t Version;
840
+ int16_t Type;
841
+ } ctrl_data;
842
+ int64_t aborted_txn_start_offset;
843
+
844
+ rd_kafka_buf_read_varint(rkbuf, &ctrl_data.KeySize);
845
+
846
+ if (unlikely(ctrl_data.KeySize < 2))
847
+ rd_kafka_buf_parse_fail(
848
+ rkbuf,
849
+ "%s [%" PRId32
850
+ "]: "
851
+ "Ctrl message at %s"
852
+ " has invalid key size %" PRId64,
853
+ rktp->rktp_rkt->rkt_topic->str,
854
+ rktp->rktp_partition,
855
+ rd_kafka_fetch_pos2str(msetr_pos),
856
+ ctrl_data.KeySize);
857
+
858
+ rd_kafka_buf_read_i16(rkbuf, &ctrl_data.Version);
859
+
860
+ if (ctrl_data.Version != 0) {
861
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "MSG",
862
+ "%s [%" PRId32
863
+ "]: "
864
+ "Skipping ctrl msg with "
865
+ "unsupported version %" PRId16 " at %s",
866
+ rktp->rktp_rkt->rkt_topic->str,
867
+ rktp->rktp_partition, ctrl_data.Version,
868
+ rd_kafka_fetch_pos2str(msetr_pos));
869
+ rd_kafka_buf_skip_to(rkbuf, message_end);
870
+ return RD_KAFKA_RESP_ERR_NO_ERROR; /* Continue with next
871
+ msg */
872
+ }
873
+
874
+ if (unlikely(ctrl_data.KeySize != 4))
875
+ rd_kafka_buf_parse_fail(
876
+ rkbuf,
877
+ "%s [%" PRId32
878
+ "]: "
879
+ "Ctrl message at %s"
880
+ " has invalid key size %" PRId64,
881
+ rktp->rktp_rkt->rkt_topic->str,
882
+ rktp->rktp_partition,
883
+ rd_kafka_fetch_pos2str(msetr_pos),
884
+ ctrl_data.KeySize);
885
+
886
+ rd_kafka_buf_read_i16(rkbuf, &ctrl_data.Type);
887
+
888
+ /* Client is uninterested in value of commit marker */
889
+ rd_kafka_buf_skip(
890
+ rkbuf, (int32_t)(message_end -
891
+ rd_slice_offset(&rkbuf->rkbuf_reader)));
892
+
893
+ switch (ctrl_data.Type) {
894
+ case RD_KAFKA_CTRL_MSG_COMMIT:
895
+ /* always ignore. */
896
+ break;
897
+
898
+ case RD_KAFKA_CTRL_MSG_ABORT:
899
+ if (msetr->msetr_rkb->rkb_rk->rk_conf.isolation_level !=
900
+ RD_KAFKA_READ_COMMITTED)
901
+ break;
902
+
903
+ if (unlikely(!msetr->msetr_aborted_txns)) {
904
+ rd_rkb_dbg(msetr->msetr_rkb,
905
+ MSG | RD_KAFKA_DBG_EOS, "TXN",
906
+ "%s [%" PRId32
907
+ "] received abort txn "
908
+ "ctrl msg at %s"
909
+ " for "
910
+ "PID %" PRId64
911
+ ", but there are no "
912
+ "known aborted transactions: "
913
+ "ignoring",
914
+ rktp->rktp_rkt->rkt_topic->str,
915
+ rktp->rktp_partition,
916
+ rd_kafka_fetch_pos2str(msetr_pos),
917
+ msetr->msetr_v2_hdr->PID);
918
+ break;
919
+ }
920
+
921
+ /* This marks the end of this (aborted) transaction,
922
+ * advance to next aborted transaction in list */
923
+ aborted_txn_start_offset =
924
+ rd_kafka_aborted_txns_pop_offset(
925
+ msetr->msetr_aborted_txns,
926
+ msetr->msetr_v2_hdr->PID, msetr_pos.offset);
927
+
928
+ if (unlikely(aborted_txn_start_offset == -1)) {
929
+ rd_rkb_dbg(msetr->msetr_rkb,
930
+ MSG | RD_KAFKA_DBG_EOS, "TXN",
931
+ "%s [%" PRId32
932
+ "] received abort txn "
933
+ "ctrl msg at %s"
934
+ " for "
935
+ "PID %" PRId64
936
+ ", but this offset is "
937
+ "not listed as an aborted "
938
+ "transaction: aborted transaction "
939
+ "was possibly empty: ignoring",
940
+ rktp->rktp_rkt->rkt_topic->str,
941
+ rktp->rktp_partition,
942
+ rd_kafka_fetch_pos2str(msetr_pos),
943
+ msetr->msetr_v2_hdr->PID);
944
+ break;
945
+ }
946
+ break;
947
+
948
+
949
+ default:
950
+ rd_rkb_dbg(msetr->msetr_rkb, MSG,
951
+ "TXN"
952
+ "%s [%" PRId32
953
+ "]: "
954
+ "Unsupported ctrl message "
955
+ "type %" PRId16
956
+ " at "
957
+ " %s: ignoring",
958
+ rktp->rktp_rkt->rkt_topic->str,
959
+ rktp->rktp_partition, ctrl_data.Type,
960
+ rd_kafka_fetch_pos2str(msetr_pos));
961
+ break;
962
+ }
963
+
964
+ rko = rd_kafka_op_new_ctrl_msg(rktp, msetr->msetr_tver->version,
965
+ rkbuf, msetr_pos);
966
+ rd_kafka_q_enq(&msetr->msetr_rkq, rko);
967
+ msetr->msetr_msgcnt++;
968
+
969
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
970
+ }
971
+
972
+ /* Regular message */
973
+
974
+ /* Note: messages in aborted transactions are skipped at the MessageSet
975
+ * level */
976
+
977
+ rd_kafka_buf_read_kbytes_varint(rkbuf, &hdr.Key);
978
+ rd_kafka_buf_read_kbytes_varint(rkbuf, &hdr.Value);
979
+
980
+ /* We parse the Headers later, just store the size (possibly truncated)
981
+ * and pointer to the headers. */
982
+ hdr.Headers.len =
983
+ (int32_t)(message_end - rd_slice_offset(&rkbuf->rkbuf_reader));
984
+ rd_kafka_buf_read_ptr(rkbuf, &hdr.Headers.data, hdr.Headers.len);
985
+
986
+ /* Create op/message container for message. */
987
+ rko = rd_kafka_op_new_fetch_msg(
988
+ &rkm, rktp, msetr->msetr_tver->version, rkbuf, msetr_pos,
989
+ (size_t)RD_KAFKAP_BYTES_LEN(&hdr.Key),
990
+ RD_KAFKAP_BYTES_IS_NULL(&hdr.Key) ? NULL : hdr.Key.data,
991
+ (size_t)RD_KAFKAP_BYTES_LEN(&hdr.Value),
992
+ RD_KAFKAP_BYTES_IS_NULL(&hdr.Value) ? NULL : hdr.Value.data);
993
+
994
+ rkm->rkm_broker_id = msetr->msetr_broker_id;
995
+
996
+ /* Store pointer to unparsed message headers, they will
997
+ * be parsed on the first access.
998
+ * This pointer points to the rkbuf payload.
999
+ * Note: can't perform struct copy here due to const fields (MSVC) */
1000
+ rkm->rkm_u.consumer.binhdrs.len = hdr.Headers.len;
1001
+ rkm->rkm_u.consumer.binhdrs.data = hdr.Headers.data;
1002
+
1003
+ /* Set timestamp.
1004
+ *
1005
+ * When broker assigns the timestamps (LOG_APPEND_TIME) it will
1006
+ * assign the same timestamp for all messages in a MessageSet
1007
+ * using MaxTimestamp.
1008
+ */
1009
+ if ((msetr->msetr_v2_hdr->Attributes &
1010
+ RD_KAFKA_MSG_ATTR_LOG_APPEND_TIME) ||
1011
+ (hdr.MsgAttributes & RD_KAFKA_MSG_ATTR_LOG_APPEND_TIME)) {
1012
+ rkm->rkm_tstype = RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME;
1013
+ rkm->rkm_timestamp = msetr->msetr_v2_hdr->MaxTimestamp;
1014
+ } else {
1015
+ rkm->rkm_tstype = RD_KAFKA_TIMESTAMP_CREATE_TIME;
1016
+ rkm->rkm_timestamp =
1017
+ msetr->msetr_v2_hdr->BaseTimestamp + hdr.TimestampDelta;
1018
+ }
1019
+
1020
+
1021
+ /* Cache the wire-format size of this record (length varint +
1022
+ * body) on the rkm.
1023
+ * Used by share consumer fetch.size telemetry. */
1024
+ rkm->rkm_u.consumer.wire_size =
1025
+ (int32_t)(message_end - record_start_pos);
1026
+
1027
+ /* Enqueue message on temporary queue */
1028
+ rd_kafka_q_enq(&msetr->msetr_rkq, rko);
1029
+ msetr->msetr_msgcnt++;
1030
+ msetr->msetr_msg_bytes += rkm->rkm_key_len + rkm->rkm_len;
1031
+
1032
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1033
+
1034
+ err_parse:
1035
+ /* Count all parse errors as partial message errors. */
1036
+ rd_atomic64_add(&msetr->msetr_rkb->rkb_c.rx_partial, 1);
1037
+ return rkbuf->rkbuf_err;
1038
+ }
1039
+
1040
+
1041
+ /**
1042
+ * @brief Read v2 messages from current buffer position.
1043
+ */
1044
+ static rd_kafka_resp_err_t
1045
+ rd_kafka_msgset_reader_msgs_v2(rd_kafka_msgset_reader_t *msetr) {
1046
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
1047
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
1048
+ /* Only log decoding errors if protocol debugging enabled. */
1049
+ int log_decode_errors =
1050
+ (rkbuf->rkbuf_rkb->rkb_rk->rk_conf.debug & RD_KAFKA_DBG_PROTOCOL)
1051
+ ? LOG_DEBUG
1052
+ : 0;
1053
+
1054
+ if (msetr->msetr_aborted_txns != NULL &&
1055
+ (msetr->msetr_v2_hdr->Attributes &
1056
+ (RD_KAFKA_MSGSET_V2_ATTR_TRANSACTIONAL |
1057
+ RD_KAFKA_MSGSET_V2_ATTR_CONTROL)) ==
1058
+ RD_KAFKA_MSGSET_V2_ATTR_TRANSACTIONAL) {
1059
+ /* Transactional non-control MessageSet:
1060
+ * check if it is part of an aborted transaction. */
1061
+ int64_t txn_start_offset = rd_kafka_aborted_txns_get_offset(
1062
+ msetr->msetr_aborted_txns, msetr->msetr_v2_hdr->PID);
1063
+
1064
+ if (txn_start_offset != -1 &&
1065
+ msetr->msetr_v2_hdr->BaseOffset >= txn_start_offset) {
1066
+ /* MessageSet is part of aborted transaction */
1067
+ rd_rkb_dbg(msetr->msetr_rkb, MSG, "MSG",
1068
+ "%s [%" PRId32
1069
+ "]: "
1070
+ "Skipping %" PRId32
1071
+ " message(s) "
1072
+ "in aborted transaction "
1073
+ "at offset %" PRId64 " for PID %" PRId64,
1074
+ rktp->rktp_rkt->rkt_topic->str,
1075
+ rktp->rktp_partition,
1076
+ msetr->msetr_v2_hdr->RecordCount,
1077
+ txn_start_offset, msetr->msetr_v2_hdr->PID);
1078
+ rd_kafka_buf_skip(
1079
+ msetr->msetr_rkbuf,
1080
+ rd_slice_remains(
1081
+ &msetr->msetr_rkbuf->rkbuf_reader));
1082
+ msetr->msetr_aborted_cnt++;
1083
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1084
+ }
1085
+ }
1086
+
1087
+ while (rd_kafka_buf_read_remain(msetr->msetr_rkbuf)) {
1088
+ rd_kafka_resp_err_t err;
1089
+ err = rd_kafka_msgset_reader_msg_v2(msetr);
1090
+ if (unlikely(err))
1091
+ return err;
1092
+ }
1093
+
1094
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1095
+
1096
+ err_parse:
1097
+ /* Count all parse errors as partial message errors. */
1098
+ rd_atomic64_add(&msetr->msetr_rkb->rkb_c.rx_partial, 1);
1099
+ msetr->msetr_v2_hdr = NULL;
1100
+ return rkbuf->rkbuf_err;
1101
+ }
1102
+
1103
+
1104
+
1105
+ /**
1106
+ * @brief MessageSet reader for MsgVersion v2 (FetchRequest v4)
1107
+ */
1108
+ static rd_kafka_resp_err_t
1109
+ rd_kafka_msgset_reader_v2(rd_kafka_msgset_reader_t *msetr) {
1110
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
1111
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
1112
+ struct msgset_v2_hdr hdr;
1113
+ rd_slice_t save_slice;
1114
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
1115
+ size_t len_start;
1116
+ size_t payload_size;
1117
+ int64_t LastOffset; /* Last absolute Offset in MessageSet header */
1118
+ /* Only log decoding errors if protocol debugging enabled. */
1119
+ int log_decode_errors =
1120
+ (rkbuf->rkbuf_rkb->rkb_rk->rk_conf.debug & RD_KAFKA_DBG_PROTOCOL)
1121
+ ? LOG_DEBUG
1122
+ : 0;
1123
+
1124
+ rd_kafka_buf_read_i64(rkbuf, &hdr.BaseOffset);
1125
+ rd_kafka_buf_read_i32(rkbuf, &hdr.Length);
1126
+ len_start = rd_slice_offset(&rkbuf->rkbuf_reader);
1127
+
1128
+ if (unlikely(hdr.Length < RD_KAFKAP_MSGSET_V2_SIZE - 8 - 4))
1129
+ rd_kafka_buf_parse_fail(rkbuf,
1130
+ "%s [%" PRId32
1131
+ "] "
1132
+ "MessageSet at offset %" PRId64
1133
+ " length %" PRId32 " < header size %d",
1134
+ rktp->rktp_rkt->rkt_topic->str,
1135
+ rktp->rktp_partition, hdr.BaseOffset,
1136
+ hdr.Length,
1137
+ RD_KAFKAP_MSGSET_V2_SIZE - 8 - 4);
1138
+
1139
+ rd_kafka_buf_read_i32(rkbuf, &hdr.PartitionLeaderEpoch);
1140
+ msetr->msetr_leader_epoch = hdr.PartitionLeaderEpoch;
1141
+
1142
+ rd_kafka_buf_read_i8(rkbuf, &hdr.MagicByte);
1143
+ rd_kafka_buf_read_i32(rkbuf, &hdr.Crc);
1144
+
1145
+ if (msetr->msetr_rkb->rkb_rk->rk_conf.check_crcs) {
1146
+ /* Verify CRC32C if desired. */
1147
+ uint32_t calc_crc;
1148
+ rd_slice_t crc_slice;
1149
+ size_t crc_len = hdr.Length - 4 - 1 - 4;
1150
+
1151
+ if (!rd_slice_narrow_copy_relative(&rkbuf->rkbuf_reader,
1152
+ &crc_slice, crc_len))
1153
+ rd_kafka_buf_check_len(rkbuf, crc_len);
1154
+
1155
+ calc_crc = rd_slice_crc32c(&crc_slice);
1156
+
1157
+ if (unlikely((uint32_t)hdr.Crc != calc_crc)) {
1158
+ /* Propagate CRC error to application and
1159
+ * continue with next message. */
1160
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(
1161
+ msetr->msetr_rkb->rkb_rk)) {
1162
+ rd_kafka_consumer_err(
1163
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
1164
+ RD_KAFKA_RESP_ERR__BAD_MSG,
1165
+ msetr->msetr_tver->version, NULL, rktp,
1166
+ hdr.BaseOffset,
1167
+ "MessageSet at offset %" PRId64 " (%" PRId32
1168
+ " bytes) "
1169
+ "failed CRC32C check "
1170
+ "(original 0x%" PRIx32
1171
+ " != "
1172
+ "calculated 0x%" PRIx32 ")",
1173
+ hdr.BaseOffset, hdr.Length, hdr.Crc,
1174
+ calc_crc);
1175
+ /* Skip to end of MessageSet */
1176
+ /**
1177
+ * FIXME: `crc_len` is a byte *length*
1178
+ * (Length - 4 - 1 - 4), but
1179
+ * rd_kafka_buf_skip_to() interprets its
1180
+ * argument as an absolute slice position.
1181
+ * The current call leaves the reader 21
1182
+ * bytes short of the end of the MessageSet
1183
+ * (when the slice base offset is 0), and
1184
+ * for any subsequent MessageSet within
1185
+ * the same slice the size_t subtraction
1186
+ * inside skip_to underflows and triggers
1187
+ * a spurious __UNDERFLOW. The intended
1188
+ * target is end-of-MessageSet, i.e.
1189
+ * `len_start + hdr.Length` — see the
1190
+ * share-consumer branch below which does
1191
+ * this correctly. Replace with:
1192
+ * rd_kafka_buf_skip_to(rkbuf,
1193
+ * len_start + hdr.Length);
1194
+ */
1195
+ rd_kafka_buf_skip_to(rkbuf, crc_len);
1196
+
1197
+ } else {
1198
+ int16_t Attributes;
1199
+ int32_t LastOffsetDelta;
1200
+
1201
+ /* Read LastOffsetDelta to
1202
+ * determine full offset range.
1203
+ *
1204
+ * TODO KIP-932: These bytes come from
1205
+ * within the CRC-covered region of the
1206
+ * MessageSet body, and the CRC has
1207
+ * just failed — so `Attributes` and
1208
+ * `LastOffsetDelta` may be corrupt. A
1209
+ * garbage `LastOffsetDelta` can:
1210
+ * - be huge → fan-out emits millions of
1211
+ * error ops for offsets that don't
1212
+ * exist (memory/queue blowup);
1213
+ * - be negative → `LastOffset <
1214
+ * BaseOffset`, fan-out loop is a
1215
+ * silent no-op (no error surfaced);
1216
+ * - look valid but be off → REJECT ops
1217
+ * issued for the wrong offset range.
1218
+ */
1219
+ rd_kafka_buf_read_i16(rkbuf, &Attributes);
1220
+ rd_kafka_buf_read_i32(rkbuf, &LastOffsetDelta);
1221
+ LastOffset = hdr.BaseOffset + LastOffsetDelta;
1222
+
1223
+ rd_kafka_share_msgset_err_ops(
1224
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
1225
+ RD_KAFKA_RESP_ERR__BAD_MSG,
1226
+ msetr->msetr_tver->version, rktp,
1227
+ hdr.BaseOffset, LastOffset,
1228
+ RD_KAFKA_SHARE_INTERNAL_ACK_REJECT,
1229
+ "MessageSet at offsets %" PRId64 "-%" PRId64
1230
+ " (%" PRId32
1231
+ " bytes) "
1232
+ "failed CRC32C check "
1233
+ "(original 0x%" PRIx32
1234
+ " != "
1235
+ "calculated 0x%" PRIx32 ")",
1236
+ hdr.BaseOffset, LastOffset, hdr.Length,
1237
+ hdr.Crc, calc_crc);
1238
+ /* Skip to end of MessageSet */
1239
+ rd_kafka_buf_skip_to(rkbuf,
1240
+ len_start + hdr.Length);
1241
+ }
1242
+
1243
+ rd_atomic64_add(&msetr->msetr_rkb->rkb_c.rx_err, 1);
1244
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1245
+ }
1246
+ }
1247
+
1248
+ rd_kafka_buf_read_i16(rkbuf, &hdr.Attributes);
1249
+ rd_kafka_buf_read_i32(rkbuf, &hdr.LastOffsetDelta);
1250
+ LastOffset = hdr.BaseOffset + hdr.LastOffsetDelta;
1251
+ rd_kafka_buf_read_i64(rkbuf, &hdr.BaseTimestamp);
1252
+ rd_kafka_buf_read_i64(rkbuf, &hdr.MaxTimestamp);
1253
+ rd_kafka_buf_read_i64(rkbuf, &hdr.PID);
1254
+ rd_kafka_buf_read_i16(rkbuf, &hdr.ProducerEpoch);
1255
+ rd_kafka_buf_read_i32(rkbuf, &hdr.BaseSequence);
1256
+ rd_kafka_buf_read_i32(rkbuf, &hdr.RecordCount);
1257
+
1258
+ /* Payload size is hdr.Length - MessageSet headers */
1259
+ payload_size =
1260
+ hdr.Length - (rd_slice_offset(&rkbuf->rkbuf_reader) - len_start);
1261
+
1262
+ if (unlikely(payload_size > rd_kafka_buf_read_remain(rkbuf)))
1263
+ rd_kafka_buf_underflow_fail(
1264
+ rkbuf, payload_size,
1265
+ "%s [%" PRId32
1266
+ "] "
1267
+ "MessageSet at offset %" PRId64 " payload size %" PRIusz,
1268
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
1269
+ hdr.BaseOffset, payload_size);
1270
+
1271
+ /* If entire MessageSet contains old outdated offsets, skip it.
1272
+ * Share consumers may receive re-delivered records at earlier offsets
1273
+ * after RELEASE, so skip this check for them. */
1274
+ if (LastOffset < rktp->rktp_offsets.fetch_pos.offset &&
1275
+ !RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
1276
+ rd_kafka_buf_skip(rkbuf, payload_size);
1277
+ goto done;
1278
+ }
1279
+
1280
+ if (hdr.Attributes & RD_KAFKA_MSGSET_V2_ATTR_CONTROL)
1281
+ msetr->msetr_ctrl_cnt++;
1282
+
1283
+ msetr->msetr_v2_hdr = &hdr;
1284
+
1285
+ /* Handle compressed MessageSet */
1286
+ if (hdr.Attributes & RD_KAFKA_MSG_ATTR_COMPRESSION_MASK) {
1287
+ const void *compressed;
1288
+
1289
+ compressed =
1290
+ rd_slice_ensure_contig(&rkbuf->rkbuf_reader, payload_size);
1291
+ rd_assert(compressed);
1292
+
1293
+ err = rd_kafka_msgset_reader_decompress(
1294
+ msetr, 2 /*MsgVersion v2*/, hdr.Attributes,
1295
+ hdr.BaseTimestamp, hdr.BaseOffset, compressed,
1296
+ payload_size);
1297
+ if (err)
1298
+ goto err;
1299
+
1300
+ } else {
1301
+ /* Read uncompressed messages */
1302
+
1303
+ /* Save original slice, reduce size of the current one to
1304
+ * be limited by the MessageSet.Length, and then start reading
1305
+ * messages until the lesser slice is exhausted. */
1306
+ if (!rd_slice_narrow_relative(&rkbuf->rkbuf_reader, &save_slice,
1307
+ payload_size))
1308
+ rd_kafka_buf_check_len(rkbuf, payload_size);
1309
+
1310
+ /* Read messages */
1311
+ err = rd_kafka_msgset_reader_msgs_v2(msetr);
1312
+
1313
+ /* Restore wider slice */
1314
+ rd_slice_widen(&rkbuf->rkbuf_reader, &save_slice);
1315
+
1316
+ if (unlikely(err))
1317
+ goto err;
1318
+ }
1319
+
1320
+
1321
+ done:
1322
+ /* Set the next fetch offset to the MessageSet header's last offset + 1
1323
+ * to avoid getting stuck on compacted MessageSets where the last
1324
+ * Message in the MessageSet has an Offset < MessageSet header's
1325
+ * last offset. See KAFKA-5443 */
1326
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk))
1327
+ msetr->msetr_next_offset = LastOffset + 1;
1328
+
1329
+ msetr->msetr_v2_hdr = NULL;
1330
+
1331
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1332
+
1333
+ err_parse:
1334
+ /* Count all parse errors as partial message errors. */
1335
+ rd_atomic64_add(&msetr->msetr_rkb->rkb_c.rx_partial, 1);
1336
+ err = rkbuf->rkbuf_err;
1337
+ /* FALLTHRU */
1338
+ err:
1339
+ msetr->msetr_v2_hdr = NULL;
1340
+ return err;
1341
+ }
1342
+
1343
+
1344
+ /**
1345
+ * @brief Peek into the next MessageSet to find the MsgVersion.
1346
+ *
1347
+ * @param MagicBytep the MsgVersion is returned here on success.
1348
+ *
1349
+ * @returns an error on read underflow or if the MsgVersion is
1350
+ * unsupported.
1351
+ */
1352
+ static rd_kafka_resp_err_t
1353
+ rd_kafka_msgset_reader_peek_msg_version(rd_kafka_msgset_reader_t *msetr,
1354
+ int8_t *MagicBytep) {
1355
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
1356
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
1357
+ /* Only log decoding errors if protocol debugging enabled. */
1358
+ int log_decode_errors =
1359
+ (rkbuf->rkbuf_rkb->rkb_rk->rk_conf.debug & RD_KAFKA_DBG_PROTOCOL)
1360
+ ? LOG_DEBUG
1361
+ : 0;
1362
+ size_t read_offset = rd_slice_offset(&rkbuf->rkbuf_reader);
1363
+
1364
+ rd_kafka_buf_peek_i8(rkbuf, read_offset + 8 + 4 + 4, MagicBytep);
1365
+
1366
+ if (unlikely(*MagicBytep < 0 || *MagicBytep > 2)) {
1367
+ int64_t Offset; /* For error logging */
1368
+ int32_t Length;
1369
+
1370
+ rd_kafka_buf_read_i64(rkbuf, &Offset);
1371
+
1372
+ rd_rkb_dbg(msetr->msetr_rkb,
1373
+ MSG | RD_KAFKA_DBG_PROTOCOL | RD_KAFKA_DBG_FETCH,
1374
+ "MAGICBYTE",
1375
+ "%s [%" PRId32
1376
+ "]: "
1377
+ "Unsupported Message(Set) MagicByte %d at "
1378
+ "offset %" PRId64
1379
+ " "
1380
+ "(buffer position %" PRIusz "/%" PRIusz
1381
+ "): skipping",
1382
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
1383
+ (int)*MagicBytep, Offset, read_offset,
1384
+ rd_slice_size(&rkbuf->rkbuf_reader));
1385
+
1386
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
1387
+ if (Offset >=
1388
+ msetr->msetr_rktp->rktp_offsets.fetch_pos.offset) {
1389
+ rd_kafka_consumer_err(
1390
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
1391
+ RD_KAFKA_RESP_ERR__NOT_IMPLEMENTED,
1392
+ msetr->msetr_tver->version, NULL, rktp,
1393
+ Offset,
1394
+ "Unsupported Message(Set) MagicByte %d "
1395
+ "at offset %" PRId64,
1396
+ (int)*MagicBytep, Offset);
1397
+ /* Skip message(set) */
1398
+ msetr->msetr_rktp->rktp_offsets.fetch_pos
1399
+ .offset = Offset + 1;
1400
+ }
1401
+
1402
+ /* Skip this Message(Set).
1403
+ * If the message is malformed, the skip may trigger
1404
+ * err_parse and return ERR__BAD_MSG. */
1405
+ rd_kafka_buf_read_i32(rkbuf, &Length);
1406
+ rd_kafka_buf_skip(rkbuf, Length);
1407
+ } else {
1408
+ /* Share consumer: peek further into the MessageSet v2
1409
+ * header so we can compute the full offset range,
1410
+ * emit a REJECT range-error op, and skip the
1411
+ * remainder. Speculatively assumes the v2 header
1412
+ * layout is preserved for any future MessageSet
1413
+ * version above v2 (the only versions reaching this
1414
+ * branch — v0/v1 are filtered by the MagicByte
1415
+ * bounds check above).
1416
+ * TODO KIP-932: Check if this handling is correct as
1417
+ * we dont know the magic byte, and we are assuming
1418
+ * its v2.*/
1419
+ int32_t PartitionLeaderEpoch;
1420
+ int8_t MagicByteActual;
1421
+ int32_t Crc;
1422
+ int16_t Attributes;
1423
+ int32_t LastOffsetDelta;
1424
+ int64_t LastOffset;
1425
+ /* Bytes consumed below from the MessageSet body
1426
+ * (everything counted by Length): PartitionLeaderEpoch
1427
+ * (4) + MagicByte (1) + Crc (4) + Attributes (2) +
1428
+ * LastOffsetDelta (4). */
1429
+ const size_t header_bytes_read = 4 + 1 + 4 + 2 + 4;
1430
+
1431
+ rd_kafka_buf_read_i32(rkbuf, &Length);
1432
+ rd_kafka_buf_read_i32(rkbuf, &PartitionLeaderEpoch);
1433
+ rd_kafka_buf_read_i8(rkbuf, &MagicByteActual);
1434
+ rd_kafka_buf_read_i32(rkbuf, &Crc);
1435
+ rd_kafka_buf_read_i16(rkbuf, &Attributes);
1436
+ rd_kafka_buf_read_i32(rkbuf, &LastOffsetDelta);
1437
+
1438
+ /* Skip remaining bytes in MessageSet. */
1439
+ rd_kafka_buf_skip(rkbuf, Length - header_bytes_read);
1440
+
1441
+ LastOffset = Offset + LastOffsetDelta;
1442
+
1443
+ rd_kafka_share_msgset_err_ops(
1444
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
1445
+ RD_KAFKA_RESP_ERR__NOT_IMPLEMENTED,
1446
+ msetr->msetr_tver->version, rktp, Offset,
1447
+ LastOffset, RD_KAFKA_SHARE_INTERNAL_ACK_REJECT,
1448
+ "Unsupported Message(Set) MagicByte %d at offsets "
1449
+ "%" PRId64 "-%" PRId64,
1450
+ (int)MagicByteActual, Offset, LastOffset);
1451
+ }
1452
+
1453
+ return RD_KAFKA_RESP_ERR__NOT_IMPLEMENTED;
1454
+ }
1455
+
1456
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1457
+
1458
+ err_parse:
1459
+ return RD_KAFKA_RESP_ERR__BAD_MSG;
1460
+ }
1461
+
1462
+
1463
+ /**
1464
+ * @brief Parse and read messages from msgset reader buffer.
1465
+ */
1466
+ static rd_kafka_resp_err_t
1467
+ rd_kafka_msgset_reader(rd_kafka_msgset_reader_t *msetr) {
1468
+ rd_kafka_buf_t *rkbuf = msetr->msetr_rkbuf;
1469
+ rd_kafka_resp_err_t (*reader[])(rd_kafka_msgset_reader_t *) = {
1470
+ /* Indexed by MsgVersion/MagicByte, pointing to
1471
+ * a Msg(Set)Version reader */
1472
+ [0] = rd_kafka_msgset_reader_msg_v0_1,
1473
+ [1] = rd_kafka_msgset_reader_msg_v0_1,
1474
+ [2] = rd_kafka_msgset_reader_v2};
1475
+ rd_kafka_resp_err_t err;
1476
+
1477
+ /* Parse MessageSets until the slice is exhausted or an
1478
+ * error occurs (typically a partial message). */
1479
+ do {
1480
+ int8_t MagicByte;
1481
+
1482
+ /* We dont know the MsgVersion at this point, peek where the
1483
+ * MagicByte resides both in MsgVersion v0..1 and v2 to
1484
+ * know which MessageSet reader to use. */
1485
+ err =
1486
+ rd_kafka_msgset_reader_peek_msg_version(msetr, &MagicByte);
1487
+ if (unlikely(err)) {
1488
+ if (err == RD_KAFKA_RESP_ERR__BAD_MSG)
1489
+ /* Read underflow, not an error.
1490
+ * Broker may return a partial Fetch response
1491
+ * due to its use of sendfile(2). */
1492
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1493
+
1494
+ /* For share consumer: continue on unsupported
1495
+ * MsgVersions, the MessageSet will be skipped. Reset
1496
+ * error so loop continues parsing remaining
1497
+ * MessageSets. For regular consumer: stop parsing (old
1498
+ * behavior). */
1499
+ if (RD_KAFKA_IS_SHARE_CONSUMER(
1500
+ msetr->msetr_rkb->rkb_rk) &&
1501
+ err == RD_KAFKA_RESP_ERR__NOT_IMPLEMENTED) {
1502
+ err = RD_KAFKA_RESP_ERR_NO_ERROR;
1503
+ }
1504
+ continue;
1505
+ }
1506
+
1507
+ /* Use MsgVersion-specific reader */
1508
+ err = reader[(int)MagicByte](msetr);
1509
+
1510
+ } while (!err && rd_slice_remains(&rkbuf->rkbuf_reader) > 0);
1511
+
1512
+ return err;
1513
+ }
1514
+
1515
+
1516
+
1517
+ /**
1518
+ * @brief MessageSet post-processing.
1519
+ *
1520
+ * @param last_offsetp will be set to the offset of the last message in the set,
1521
+ * or -1 if not applicable.
1522
+ */
1523
+ static void rd_kafka_msgset_reader_postproc(rd_kafka_msgset_reader_t *msetr,
1524
+ int64_t *last_offsetp) {
1525
+ rd_kafka_op_t *rko;
1526
+
1527
+ rko = rd_kafka_q_last(&msetr->msetr_rkq, RD_KAFKA_OP_FETCH,
1528
+ 0 /* no error ops */);
1529
+ if (rko) {
1530
+ *last_offsetp = rko->rko_u.fetch.rkm.rkm_offset;
1531
+
1532
+ /*
1533
+ * TODO KIP-932: Though we shouldn't reach here for share
1534
+ * consumers as msetr_relative_offsets is set to true only
1535
+ * for MsgVersion v1 but still check if MsgVersion v1 is
1536
+ * possible with share consumer. If not, this handling can
1537
+ * be skipped safely. If yes, then we should use negative
1538
+ * offset in place of min_offset instead of fetch_pos.offset.
1539
+ */
1540
+ if (*last_offsetp != -1 && msetr->msetr_relative_offsets) {
1541
+ /* Update messages to absolute offsets
1542
+ * and purge any messages older than the current
1543
+ * fetch offset. */
1544
+ rd_kafka_q_fix_offsets(
1545
+ &msetr->msetr_rkq,
1546
+ msetr->msetr_rktp->rktp_offsets.fetch_pos.offset,
1547
+ msetr->msetr_outer.offset - *last_offsetp);
1548
+ }
1549
+ }
1550
+ }
1551
+
1552
+
1553
+
1554
+ /**
1555
+ * @brief Run the MessageSet reader, read messages until buffer is
1556
+ * exhausted (or error encountered), enqueue parsed messages on
1557
+ * partition queue.
1558
+ *
1559
+ * @returns RD_KAFKA_RESP_ERR_NO_ERROR if MessageSet was successfully
1560
+ * or partially parsed. When other error codes are returned it
1561
+ * indicates a semi-permanent error (such as unsupported MsgVersion)
1562
+ * and the fetcher should back off this partition to avoid
1563
+ * busy-looping.
1564
+ */
1565
+ static rd_kafka_resp_err_t
1566
+ rd_kafka_msgset_reader_run(rd_kafka_msgset_reader_t *msetr) {
1567
+ rd_kafka_toppar_t *rktp = msetr->msetr_rktp;
1568
+ rd_kafka_resp_err_t err;
1569
+ int64_t last_offset = -1;
1570
+
1571
+ /* Parse MessageSets and messages */
1572
+ err = rd_kafka_msgset_reader(msetr);
1573
+
1574
+ if (unlikely(rd_kafka_q_len(&msetr->msetr_rkq) == 0)) {
1575
+ /* The message set didn't contain at least one full message
1576
+ * or no error was posted on the response queue.
1577
+ * This means the size limit perhaps was too tight,
1578
+ * increase it automatically.
1579
+ * If there was at least one control message there
1580
+ * is probably not a size limit and nothing is done.
1581
+ * If there were aborted messagesets and no underflow then
1582
+ * there is no error either (#2993).
1583
+ *
1584
+ * Also; avoid propagating underflow errors, which cause
1585
+ * backoffs, since we'll want to continue fetching the
1586
+ * remaining truncated messages as soon as possible.
1587
+ */
1588
+ if (msetr->msetr_ctrl_cnt > 0) {
1589
+ /* Noop */
1590
+ if (err == RD_KAFKA_RESP_ERR__UNDERFLOW)
1591
+ err = RD_KAFKA_RESP_ERR_NO_ERROR;
1592
+
1593
+ } else if (rktp->rktp_fetch_msg_max_bytes < (1 << 30)) {
1594
+ /* TODO KIP-932: Skip this branch for share consumers.
1595
+ * ShareFetch has no per-partition MaxBytes field, so
1596
+ * growing rktp_fetch_msg_max_bytes never changes what
1597
+ * the broker returns.
1598
+ */
1599
+ rktp->rktp_fetch_msg_max_bytes *= 2;
1600
+ rd_rkb_dbg(msetr->msetr_rkb, FETCH, "CONSUME",
1601
+ "Topic %s [%" PRId32
1602
+ "]: Increasing "
1603
+ "max fetch bytes to %" PRId32,
1604
+ rktp->rktp_rkt->rkt_topic->str,
1605
+ rktp->rktp_partition,
1606
+ rktp->rktp_fetch_msg_max_bytes);
1607
+
1608
+ if (err == RD_KAFKA_RESP_ERR__UNDERFLOW)
1609
+ err = RD_KAFKA_RESP_ERR_NO_ERROR;
1610
+
1611
+ } else if (!err && msetr->msetr_aborted_cnt == 0) {
1612
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(
1613
+ msetr->msetr_rkb->rkb_rk)) {
1614
+ rd_kafka_consumer_err(
1615
+ &msetr->msetr_rkq, msetr->msetr_broker_id,
1616
+ RD_KAFKA_RESP_ERR_MSG_SIZE_TOO_LARGE,
1617
+ msetr->msetr_tver->version, NULL, rktp,
1618
+ rktp->rktp_offsets.fetch_pos.offset,
1619
+ "Message at offset %" PRId64
1620
+ " might be too large to fetch, try "
1621
+ "increasing receive.message.max.bytes",
1622
+ rktp->rktp_offsets.fetch_pos.offset);
1623
+ } else {
1624
+ /* Share consumer: fetch_pos.offset is not
1625
+ * meaningful, and the temp_fetchq
1626
+ * acquired-range filter would drop any op
1627
+ * without a valid offset. Enqueue the error
1628
+ * directly onto the cgrp queue served by
1629
+ * rd_kafka_share_poll so the app
1630
+ * sees the partition-level failure. */
1631
+ rd_kafka_consumer_err(
1632
+ msetr->msetr_rkb->rkb_rk->rk_cgrp->rkcg_q,
1633
+ msetr->msetr_broker_id,
1634
+ RD_KAFKA_RESP_ERR_MSG_SIZE_TOO_LARGE,
1635
+ msetr->msetr_tver->version, NULL, rktp,
1636
+ RD_KAFKA_OFFSET_INVALID,
1637
+ "Message might be too large to fetch, "
1638
+ "try increasing "
1639
+ "receive.message.max.bytes");
1640
+ }
1641
+
1642
+ } else if (msetr->msetr_aborted_cnt > 0) {
1643
+ /* Noop */
1644
+ if (err == RD_KAFKA_RESP_ERR__UNDERFLOW)
1645
+ err = RD_KAFKA_RESP_ERR_NO_ERROR;
1646
+ }
1647
+
1648
+ } else {
1649
+ /* MessageSet post-processing. */
1650
+ rd_kafka_msgset_reader_postproc(msetr, &last_offset);
1651
+
1652
+ /* Ignore parse errors if there was at least one
1653
+ * good message since it probably indicates a
1654
+ * partial response rather than an erroneous one. */
1655
+ if (err == RD_KAFKA_RESP_ERR__UNDERFLOW &&
1656
+ msetr->msetr_msgcnt > 0)
1657
+ err = RD_KAFKA_RESP_ERR_NO_ERROR;
1658
+ }
1659
+
1660
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
1661
+ rd_rkb_dbg(
1662
+ msetr->msetr_rkb, MSG | RD_KAFKA_DBG_FETCH, "CONSUME",
1663
+ "Enqueue %i %smessage(s) (%" PRId64
1664
+ " bytes, %d ops) on %s [%" PRId32
1665
+ "] fetch queue (qlen %d, v%d, last_offset %" PRId64
1666
+ ", %d ctrl msgs, %d aborted msgsets, %s)",
1667
+ msetr->msetr_msgcnt, msetr->msetr_srcname,
1668
+ msetr->msetr_msg_bytes, rd_kafka_q_len(&msetr->msetr_rkq),
1669
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
1670
+ rd_kafka_q_len(msetr->msetr_par_rkq),
1671
+ msetr->msetr_tver->version, last_offset,
1672
+ msetr->msetr_ctrl_cnt, msetr->msetr_aborted_cnt,
1673
+ msetr->msetr_compression
1674
+ ? rd_kafka_compression2str(msetr->msetr_compression)
1675
+ : "uncompressed");
1676
+ } else {
1677
+ rd_rkb_dbg(
1678
+ msetr->msetr_rkb, MSG | RD_KAFKA_DBG_FETCH, "CONSUME",
1679
+ "Enqueue %i %smessage(s) (%" PRId64
1680
+ " bytes, %d ops) on %s [%" PRId32
1681
+ "] temp fetchq (qlen %d, last_offset %" PRId64
1682
+ ", %d ctrl msgs, %s)",
1683
+ msetr->msetr_msgcnt, msetr->msetr_srcname,
1684
+ msetr->msetr_msg_bytes, rd_kafka_q_len(&msetr->msetr_rkq),
1685
+ rktp->rktp_rkt->rkt_topic->str, rktp->rktp_partition,
1686
+ rd_kafka_q_len(msetr->msetr_par_rkq), last_offset,
1687
+ msetr->msetr_ctrl_cnt,
1688
+ msetr->msetr_compression
1689
+ ? rd_kafka_compression2str(msetr->msetr_compression)
1690
+ : "uncompressed");
1691
+ }
1692
+
1693
+ /* Concat all messages&errors onto the parent's queue
1694
+ * (the partition's fetch queue) */
1695
+ if (rd_kafka_q_concat(msetr->msetr_par_rkq, &msetr->msetr_rkq) != -1) {
1696
+ /* Update partition's fetch offset based on
1697
+ * last message's offest. */
1698
+ if (likely(last_offset != -1) &&
1699
+ !RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk))
1700
+ rktp->rktp_offsets.fetch_pos.offset = last_offset + 1;
1701
+ }
1702
+
1703
+ /* Adjust next fetch offset if outlier code has indicated
1704
+ * an even later next offset. */
1705
+ if (!RD_KAFKA_IS_SHARE_CONSUMER(msetr->msetr_rkb->rkb_rk)) {
1706
+ if (msetr->msetr_next_offset >
1707
+ rktp->rktp_offsets.fetch_pos.offset)
1708
+ rktp->rktp_offsets.fetch_pos.offset =
1709
+ msetr->msetr_next_offset;
1710
+
1711
+ rktp->rktp_offsets.fetch_pos.leader_epoch =
1712
+ msetr->msetr_leader_epoch;
1713
+ }
1714
+
1715
+ rd_kafka_q_destroy_owner(&msetr->msetr_rkq);
1716
+
1717
+ /* Skip remaining part of slice so caller can continue
1718
+ * with next partition. */
1719
+ rd_slice_read(&msetr->msetr_rkbuf->rkbuf_reader, NULL,
1720
+ rd_slice_remains(&msetr->msetr_rkbuf->rkbuf_reader));
1721
+ return err;
1722
+ }
1723
+
1724
+
1725
+
1726
+ /**
1727
+ * @brief Parse one MessageSet at the current buffer read position,
1728
+ * enqueueing messages, propagating errors, etc.
1729
+ * @remark The current rkbuf_reader slice must be limited to the MessageSet size
1730
+ *
1731
+ * @returns see rd_kafka_msgset_reader_run()
1732
+ */
1733
+ rd_kafka_resp_err_t
1734
+ rd_kafka_msgset_parse(rd_kafka_buf_t *rkbuf,
1735
+ rd_kafka_buf_t *request,
1736
+ rd_kafka_toppar_t *rktp,
1737
+ rd_kafka_aborted_txns_t *aborted_txns,
1738
+ const struct rd_kafka_toppar_ver *tver) {
1739
+ rd_kafka_msgset_reader_t msetr;
1740
+ rd_kafka_resp_err_t err;
1741
+
1742
+ rd_kafka_msgset_reader_init(&msetr, rkbuf, rktp, tver, aborted_txns,
1743
+ rktp->rktp_fetchq);
1744
+
1745
+ /* Parse and handle the message set */
1746
+ err = rd_kafka_msgset_reader_run(&msetr);
1747
+
1748
+ rd_atomic64_add(&rktp->rktp_c.rx_msgs, msetr.msetr_msgcnt);
1749
+ rd_atomic64_add(&rktp->rktp_c.rx_msg_bytes, msetr.msetr_msg_bytes);
1750
+
1751
+ rd_avg_add(&rktp->rktp_rkt->rkt_avg_batchcnt,
1752
+ (int64_t)msetr.msetr_msgcnt);
1753
+ rd_avg_add(&rktp->rktp_rkt->rkt_avg_batchsize,
1754
+ (int64_t)msetr.msetr_msg_bytes);
1755
+
1756
+ return err;
1757
+ }
1758
+
1759
+
1760
+ /**
1761
+ * @brief Parse one MessageSet at the current buffer read position,
1762
+ * enqueueing messages, propagating errors, etc.
1763
+ * @remark The current rkbuf_reader slice must be limited to the MessageSet size
1764
+ *
1765
+ * @returns see rd_kafka_msgset_reader_run()
1766
+ */
1767
+ rd_kafka_resp_err_t
1768
+ rd_kafka_share_msgset_parse(rd_kafka_buf_t *rkbuf,
1769
+ rd_kafka_toppar_t *rktp,
1770
+ rd_kafka_aborted_txns_t *aborted_txns,
1771
+ const struct rd_kafka_toppar_ver *tver,
1772
+ rd_kafka_q_t *response_message_q) {
1773
+ rd_kafka_msgset_reader_t msetr;
1774
+ rd_kafka_resp_err_t err;
1775
+
1776
+ rd_kafka_msgset_reader_init(&msetr, rkbuf, rktp, tver, aborted_txns,
1777
+ response_message_q);
1778
+
1779
+ /* Parse and handle the message set */
1780
+ err = rd_kafka_msgset_reader_run(&msetr);
1781
+
1782
+ rd_atomic64_add(&rktp->rktp_c.rx_msgs, msetr.msetr_msgcnt);
1783
+ rd_atomic64_add(&rktp->rktp_c.rx_msg_bytes, msetr.msetr_msg_bytes);
1784
+
1785
+ rd_avg_add(&rktp->rktp_rkt->rkt_avg_batchcnt,
1786
+ (int64_t)msetr.msetr_msgcnt);
1787
+ rd_avg_add(&rktp->rktp_rkt->rkt_avg_batchsize,
1788
+ (int64_t)msetr.msetr_msg_bytes);
1789
+
1790
+ return err;
1791
+ }
1792
+
1793
+
1794
+ /**
1795
+ * @brief Offset comparator
1796
+ */
1797
+ static int rd_kafka_offset_cmp(const void *_a, const void *_b) {
1798
+ const int64_t *a = _a, *b = _b;
1799
+ return (*a > *b) - (*a < *b);
1800
+ }
1801
+
1802
+
1803
+ /**
1804
+ * @brief Pid comparator for rd_kafka_aborted_txn_start_offsets_t
1805
+ */
1806
+ static int rd_kafka_aborted_txn_cmp_by_pid(const void *_a, const void *_b) {
1807
+ const rd_kafka_aborted_txn_start_offsets_t *a = _a, *b = _b;
1808
+ return (a->pid > b->pid) - (a->pid < b->pid);
1809
+ }
1810
+
1811
+
1812
+ /**
1813
+ * @brief Free resources associated with an AVL tree node.
1814
+ */
1815
+ static void rd_kafka_aborted_txn_node_destroy(void *_node_ptr) {
1816
+ rd_kafka_aborted_txn_start_offsets_t *node_ptr = _node_ptr;
1817
+ rd_list_destroy(&node_ptr->offsets);
1818
+ rd_free(node_ptr);
1819
+ }
1820
+
1821
+
1822
+ /**
1823
+ * @brief Allocate memory for, and initialize a new
1824
+ * rd_kafka_aborted_txns_t struct.
1825
+ */
1826
+ rd_kafka_aborted_txns_t *rd_kafka_aborted_txns_new(int32_t txn_cnt) {
1827
+ rd_kafka_aborted_txns_t *aborted_txns;
1828
+ aborted_txns = rd_malloc(sizeof(*aborted_txns));
1829
+ rd_avl_init(&aborted_txns->avl, rd_kafka_aborted_txn_cmp_by_pid, 0);
1830
+ rd_list_init(&aborted_txns->list, txn_cnt,
1831
+ rd_kafka_aborted_txn_node_destroy);
1832
+ aborted_txns->cnt = txn_cnt;
1833
+ return aborted_txns;
1834
+ }
1835
+
1836
+
1837
+ /**
1838
+ * @brief Free all resources associated with a
1839
+ * rd_kafka_aborted_txns_t struct.
1840
+ */
1841
+ void rd_kafka_aborted_txns_destroy(rd_kafka_aborted_txns_t *aborted_txns) {
1842
+ rd_list_destroy(&aborted_txns->list);
1843
+ rd_avl_destroy(&aborted_txns->avl);
1844
+ rd_free(aborted_txns);
1845
+ }
1846
+
1847
+
1848
+ /**
1849
+ * @brief Get the abort txn start offsets corresponding to
1850
+ * the specified pid.
1851
+ */
1852
+ static RD_INLINE rd_kafka_aborted_txn_start_offsets_t *
1853
+ rd_kafka_aborted_txns_offsets_for_pid(rd_kafka_aborted_txns_t *aborted_txns,
1854
+ int64_t pid) {
1855
+ rd_kafka_aborted_txn_start_offsets_t node;
1856
+ node.pid = pid;
1857
+ return RD_AVL_FIND(&aborted_txns->avl, &node);
1858
+ }
1859
+
1860
+
1861
+ /**
1862
+ * @brief Get the next aborted transaction start
1863
+ * offset for the specified pid.
1864
+ *
1865
+ * @param increment_idx if true, the offset index will be incremented.
1866
+ * @param max_offset If the next aborted offset is greater than \p max_offset
1867
+ * then the index is not incremented (regardless of
1868
+ * \p increment_idx) and the function returns -1.
1869
+ * This may be the case for empty aborted transactions
1870
+ * that have an ABORT marker but are not listed in the
1871
+ * AbortedTxns list.
1872
+ *
1873
+ *
1874
+ * @returns the start offset or -1 if there is none.
1875
+ */
1876
+ static int64_t
1877
+ rd_kafka_aborted_txns_next_offset(rd_kafka_aborted_txns_t *aborted_txns,
1878
+ int64_t pid,
1879
+ rd_bool_t increment_idx,
1880
+ int64_t max_offset) {
1881
+ int64_t abort_start_offset;
1882
+ rd_kafka_aborted_txn_start_offsets_t *node_ptr =
1883
+ rd_kafka_aborted_txns_offsets_for_pid(aborted_txns, pid);
1884
+
1885
+ if (node_ptr == NULL)
1886
+ return -1;
1887
+
1888
+ if (unlikely(node_ptr->offsets_idx >= rd_list_cnt(&node_ptr->offsets)))
1889
+ return -1;
1890
+
1891
+ abort_start_offset = *(
1892
+ (int64_t *)rd_list_elem(&node_ptr->offsets, node_ptr->offsets_idx));
1893
+
1894
+ if (unlikely(abort_start_offset > max_offset))
1895
+ return -1;
1896
+
1897
+ if (increment_idx)
1898
+ node_ptr->offsets_idx++;
1899
+
1900
+ return abort_start_offset;
1901
+ }
1902
+
1903
+
1904
+ /**
1905
+ * @brief Get the next aborted transaction start
1906
+ * offset for the specified pid and progress the
1907
+ * current index to the next one.
1908
+ *
1909
+ * @param max_offset If the next aborted offset is greater than \p max_offset
1910
+ * then no offset is popped and the function returns -1.
1911
+ * This may be the case for empty aborted transactions
1912
+ * that have an ABORT marker but are not listed in the
1913
+ * AbortedTxns list.
1914
+ *
1915
+ * @returns the start offset or -1 if there is none.
1916
+ */
1917
+ static RD_INLINE int64_t
1918
+ rd_kafka_aborted_txns_pop_offset(rd_kafka_aborted_txns_t *aborted_txns,
1919
+ int64_t pid,
1920
+ int64_t max_offset) {
1921
+ return rd_kafka_aborted_txns_next_offset(aborted_txns, pid, rd_true,
1922
+ max_offset);
1923
+ }
1924
+
1925
+
1926
+ /**
1927
+ * @brief Get the next aborted transaction start
1928
+ * offset for the specified pid.
1929
+ *
1930
+ * @returns the start offset or -1 if there is none.
1931
+ */
1932
+ static RD_INLINE int64_t
1933
+ rd_kafka_aborted_txns_get_offset(const rd_kafka_aborted_txns_t *aborted_txns,
1934
+ int64_t pid) {
1935
+ return rd_kafka_aborted_txns_next_offset(
1936
+ (rd_kafka_aborted_txns_t *)aborted_txns, pid, rd_false, INT64_MAX);
1937
+ }
1938
+
1939
+
1940
+ /**
1941
+ * @brief Add a transaction start offset corresponding
1942
+ * to the specified pid to the aborted_txns collection.
1943
+ */
1944
+ void rd_kafka_aborted_txns_add(rd_kafka_aborted_txns_t *aborted_txns,
1945
+ int64_t pid,
1946
+ int64_t first_offset) {
1947
+ int64_t *v;
1948
+ rd_kafka_aborted_txn_start_offsets_t *node_ptr =
1949
+ rd_kafka_aborted_txns_offsets_for_pid(aborted_txns, pid);
1950
+
1951
+ if (!node_ptr) {
1952
+ node_ptr = rd_malloc(sizeof(*node_ptr));
1953
+ node_ptr->pid = pid;
1954
+ node_ptr->offsets_idx = 0;
1955
+ rd_list_init(&node_ptr->offsets, 0, NULL);
1956
+ /* Each PID list has no more than AbortedTxnCnt elements */
1957
+ rd_list_prealloc_elems(&node_ptr->offsets, sizeof(int64_t),
1958
+ aborted_txns->cnt, 0);
1959
+ RD_AVL_INSERT(&aborted_txns->avl, node_ptr, avl_node);
1960
+ rd_list_add(&aborted_txns->list, node_ptr);
1961
+ }
1962
+
1963
+ v = rd_list_add(&node_ptr->offsets, NULL);
1964
+ *v = first_offset;
1965
+ }
1966
+
1967
+
1968
+ /**
1969
+ * @brief Sort each of the abort transaction start
1970
+ * offset lists for each pid.
1971
+ */
1972
+ void rd_kafka_aborted_txns_sort(rd_kafka_aborted_txns_t *aborted_txns) {
1973
+ int k;
1974
+ for (k = 0; k < rd_list_cnt(&aborted_txns->list); k++) {
1975
+ rd_kafka_aborted_txn_start_offsets_t *el =
1976
+ rd_list_elem(&aborted_txns->list, k);
1977
+ rd_list_sort(&el->offsets, rd_kafka_offset_cmp);
1978
+ }
1979
+ }
1980
+
1981
+
1982
+ /**
1983
+ * @brief Unit tests for all functions that operate on
1984
+ * rd_kafka_aborted_txns_t
1985
+ */
1986
+ int unittest_aborted_txns(void) {
1987
+ rd_kafka_aborted_txns_t *aborted_txns = NULL;
1988
+ int64_t start_offset;
1989
+
1990
+ aborted_txns = rd_kafka_aborted_txns_new(7);
1991
+ rd_kafka_aborted_txns_add(aborted_txns, 1, 42);
1992
+ rd_kafka_aborted_txns_add(aborted_txns, 1, 44);
1993
+ rd_kafka_aborted_txns_add(aborted_txns, 1, 10);
1994
+ rd_kafka_aborted_txns_add(aborted_txns, 1, 100);
1995
+ rd_kafka_aborted_txns_add(aborted_txns, 2, 11);
1996
+ rd_kafka_aborted_txns_add(aborted_txns, 2, 7);
1997
+ rd_kafka_aborted_txns_add(aborted_txns, 1, 3);
1998
+ rd_kafka_aborted_txns_sort(aborted_txns);
1999
+
2000
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2001
+ RD_UT_ASSERT(3 == start_offset,
2002
+ "queried start offset was %" PRId64
2003
+ ", "
2004
+ "expected 3",
2005
+ start_offset);
2006
+
2007
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2008
+ RD_UT_ASSERT(3 == start_offset,
2009
+ "queried start offset was %" PRId64
2010
+ ", "
2011
+ "expected 3",
2012
+ start_offset);
2013
+
2014
+ start_offset =
2015
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 1, INT64_MAX);
2016
+ RD_UT_ASSERT(3 == start_offset,
2017
+ "queried start offset was %" PRId64
2018
+ ", "
2019
+ "expected 3",
2020
+ start_offset);
2021
+
2022
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2023
+ RD_UT_ASSERT(10 == start_offset,
2024
+ "queried start offset was %" PRId64
2025
+ ", "
2026
+ "expected 10",
2027
+ start_offset);
2028
+
2029
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 2);
2030
+ RD_UT_ASSERT(7 == start_offset,
2031
+ "queried start offset was %" PRId64
2032
+ ", "
2033
+ "expected 7",
2034
+ start_offset);
2035
+
2036
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 1, INT64_MAX);
2037
+
2038
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2039
+ RD_UT_ASSERT(42 == start_offset,
2040
+ "queried start offset was %" PRId64
2041
+ ", "
2042
+ "expected 42",
2043
+ start_offset);
2044
+
2045
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 1, INT64_MAX);
2046
+
2047
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2048
+ RD_UT_ASSERT(44 == start_offset,
2049
+ "queried start offset was %" PRId64
2050
+ ", "
2051
+ "expected 44",
2052
+ start_offset);
2053
+
2054
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 2);
2055
+ RD_UT_ASSERT(7 == start_offset,
2056
+ "queried start offset was %" PRId64
2057
+ ", "
2058
+ "expected 7",
2059
+ start_offset);
2060
+
2061
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 2, INT64_MAX);
2062
+
2063
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 2);
2064
+ RD_UT_ASSERT(11 == start_offset,
2065
+ "queried start offset was %" PRId64
2066
+ ", "
2067
+ "expected 11",
2068
+ start_offset);
2069
+
2070
+ /* error cases */
2071
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 3);
2072
+ RD_UT_ASSERT(-1 == start_offset,
2073
+ "queried start offset was %" PRId64
2074
+ ", "
2075
+ "expected -1",
2076
+ start_offset);
2077
+
2078
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 1, INT64_MAX);
2079
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 1, INT64_MAX);
2080
+ rd_kafka_aborted_txns_pop_offset(aborted_txns, 2, INT64_MAX);
2081
+
2082
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 1);
2083
+ RD_UT_ASSERT(-1 == start_offset,
2084
+ "queried start offset was %" PRId64
2085
+ ", "
2086
+ "expected -1",
2087
+ start_offset);
2088
+
2089
+ start_offset = rd_kafka_aborted_txns_get_offset(aborted_txns, 2);
2090
+ RD_UT_ASSERT(-1 == start_offset,
2091
+ "queried start offset was %" PRId64
2092
+ ", "
2093
+ "expected -1",
2094
+ start_offset);
2095
+
2096
+ rd_kafka_aborted_txns_destroy(aborted_txns);
2097
+
2098
+ RD_UT_PASS();
2099
+ }