@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.
- package/CHANGELOG.md +457 -0
- package/LICENSE.kafkajs +31 -0
- package/LICENSE.node-rdkafka +25 -0
- package/LICENSE.txt +20 -0
- package/README.md +133 -0
- package/binding.gyp +184 -0
- package/build/Release/confluent-kafka-javascript.node +0 -0
- package/build/deps/librdkafka++.so.1 +0 -0
- package/build/deps/librdkafka.Makefile +6 -0
- package/build/deps/librdkafka.so.1 +0 -0
- package/build/deps/librdkafka.target.mk +55 -0
- package/deps/librdkafka/.clang-format +136 -0
- package/deps/librdkafka/.clang-format-cpp +103 -0
- package/deps/librdkafka/.dir-locals.el +10 -0
- package/deps/librdkafka/.formatignore +35 -0
- package/deps/librdkafka/.gdbmacros +19 -0
- package/deps/librdkafka/CHANGELOG.md +2477 -0
- package/deps/librdkafka/CMakeLists.txt +291 -0
- package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
- package/deps/librdkafka/CONFIGURATION.md +212 -0
- package/deps/librdkafka/CONTRIBUTING.md +431 -0
- package/deps/librdkafka/Doxyfile +2375 -0
- package/deps/librdkafka/INTRODUCTION.md +2752 -0
- package/deps/librdkafka/LICENSE +26 -0
- package/deps/librdkafka/LICENSE.cjson +22 -0
- package/deps/librdkafka/LICENSE.crc32c +28 -0
- package/deps/librdkafka/LICENSE.fnv1a +18 -0
- package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
- package/deps/librdkafka/LICENSE.lz4 +26 -0
- package/deps/librdkafka/LICENSE.murmur2 +25 -0
- package/deps/librdkafka/LICENSE.nanopb +22 -0
- package/deps/librdkafka/LICENSE.opentelemetry +203 -0
- package/deps/librdkafka/LICENSE.pycrc +23 -0
- package/deps/librdkafka/LICENSE.queue +31 -0
- package/deps/librdkafka/LICENSE.regexp +5 -0
- package/deps/librdkafka/LICENSE.snappy +36 -0
- package/deps/librdkafka/LICENSE.tinycthread +26 -0
- package/deps/librdkafka/LICENSE.wingetopt +49 -0
- package/deps/librdkafka/LICENSES.txt +625 -0
- package/deps/librdkafka/Makefile +125 -0
- package/deps/librdkafka/README.md +201 -0
- package/deps/librdkafka/README.win32 +26 -0
- package/deps/librdkafka/STATISTICS.md +624 -0
- package/deps/librdkafka/configure +214 -0
- package/deps/librdkafka/configure.self +341 -0
- package/deps/librdkafka/dev-conf.sh +123 -0
- package/deps/librdkafka/lds-gen.py +73 -0
- package/deps/librdkafka/mainpage.doxy +40 -0
- package/deps/librdkafka/mklove/Makefile.base +329 -0
- package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
- package/deps/librdkafka/mklove/modules/configure.base +2484 -0
- package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
- package/deps/librdkafka/mklove/modules/configure.cc +186 -0
- package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
- package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
- package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
- package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
- package/deps/librdkafka/mklove/modules/configure.host +132 -0
- package/deps/librdkafka/mklove/modules/configure.lib +49 -0
- package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
- package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
- package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
- package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
- package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
- package/deps/librdkafka/mklove/modules/configure.pic +16 -0
- package/deps/librdkafka/mklove/modules/configure.socket +20 -0
- package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
- package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
- package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
- package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
- package/deps/librdkafka/service.yml +182 -0
- package/deps/librdkafka/src/CMakeLists.txt +379 -0
- package/deps/librdkafka/src/Makefile +105 -0
- package/deps/librdkafka/src/README.lz4.md +30 -0
- package/deps/librdkafka/src/cJSON.c +3191 -0
- package/deps/librdkafka/src/cJSON.h +306 -0
- package/deps/librdkafka/src/crc32c.c +430 -0
- package/deps/librdkafka/src/crc32c.h +38 -0
- package/deps/librdkafka/src/generate_proto.sh +66 -0
- package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
- package/deps/librdkafka/src/lz4.c +2727 -0
- package/deps/librdkafka/src/lz4.h +842 -0
- package/deps/librdkafka/src/lz4frame.c +2078 -0
- package/deps/librdkafka/src/lz4frame.h +692 -0
- package/deps/librdkafka/src/lz4frame_static.h +47 -0
- package/deps/librdkafka/src/lz4hc.c +1631 -0
- package/deps/librdkafka/src/lz4hc.h +413 -0
- package/deps/librdkafka/src/nanopb/pb.h +917 -0
- package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
- package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
- package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
- package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
- package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
- package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
- package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
- package/deps/librdkafka/src/queue.h +850 -0
- package/deps/librdkafka/src/rd.h +592 -0
- package/deps/librdkafka/src/rdaddr.c +255 -0
- package/deps/librdkafka/src/rdaddr.h +202 -0
- package/deps/librdkafka/src/rdatomic.h +262 -0
- package/deps/librdkafka/src/rdavg.h +260 -0
- package/deps/librdkafka/src/rdavl.c +210 -0
- package/deps/librdkafka/src/rdavl.h +250 -0
- package/deps/librdkafka/src/rdbase64.c +200 -0
- package/deps/librdkafka/src/rdbase64.h +43 -0
- package/deps/librdkafka/src/rdbuf.c +1884 -0
- package/deps/librdkafka/src/rdbuf.h +375 -0
- package/deps/librdkafka/src/rdcrc32.c +114 -0
- package/deps/librdkafka/src/rdcrc32.h +170 -0
- package/deps/librdkafka/src/rddl.c +179 -0
- package/deps/librdkafka/src/rddl.h +43 -0
- package/deps/librdkafka/src/rdendian.h +175 -0
- package/deps/librdkafka/src/rdfloat.h +67 -0
- package/deps/librdkafka/src/rdfnv1a.c +113 -0
- package/deps/librdkafka/src/rdfnv1a.h +35 -0
- package/deps/librdkafka/src/rdgz.c +120 -0
- package/deps/librdkafka/src/rdgz.h +46 -0
- package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
- package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
- package/deps/librdkafka/src/rdhttp.c +831 -0
- package/deps/librdkafka/src/rdhttp.h +101 -0
- package/deps/librdkafka/src/rdinterval.h +177 -0
- package/deps/librdkafka/src/rdkafka.c +7287 -0
- package/deps/librdkafka/src/rdkafka.h +11795 -0
- package/deps/librdkafka/src/rdkafka_admin.c +10165 -0
- package/deps/librdkafka/src/rdkafka_admin.h +658 -0
- package/deps/librdkafka/src/rdkafka_assignment.c +1282 -0
- package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
- package/deps/librdkafka/src/rdkafka_assignor.c +1800 -0
- package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
- package/deps/librdkafka/src/rdkafka_aux.c +409 -0
- package/deps/librdkafka/src/rdkafka_aux.h +174 -0
- package/deps/librdkafka/src/rdkafka_background.c +222 -0
- package/deps/librdkafka/src/rdkafka_broker.c +6736 -0
- package/deps/librdkafka/src/rdkafka_broker.h +851 -0
- package/deps/librdkafka/src/rdkafka_buf.c +543 -0
- package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
- package/deps/librdkafka/src/rdkafka_cert.c +576 -0
- package/deps/librdkafka/src/rdkafka_cert.h +62 -0
- package/deps/librdkafka/src/rdkafka_cgrp.c +8310 -0
- package/deps/librdkafka/src/rdkafka_cgrp.h +589 -0
- package/deps/librdkafka/src/rdkafka_conf.c +5177 -0
- package/deps/librdkafka/src/rdkafka_conf.h +746 -0
- package/deps/librdkafka/src/rdkafka_confval.h +97 -0
- package/deps/librdkafka/src/rdkafka_coord.c +623 -0
- package/deps/librdkafka/src/rdkafka_coord.h +132 -0
- package/deps/librdkafka/src/rdkafka_error.c +228 -0
- package/deps/librdkafka/src/rdkafka_error.h +80 -0
- package/deps/librdkafka/src/rdkafka_event.c +502 -0
- package/deps/librdkafka/src/rdkafka_event.h +126 -0
- package/deps/librdkafka/src/rdkafka_feature.c +898 -0
- package/deps/librdkafka/src/rdkafka_feature.h +104 -0
- package/deps/librdkafka/src/rdkafka_fetcher.c +3820 -0
- package/deps/librdkafka/src/rdkafka_fetcher.h +62 -0
- package/deps/librdkafka/src/rdkafka_header.c +220 -0
- package/deps/librdkafka/src/rdkafka_header.h +76 -0
- package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
- package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
- package/deps/librdkafka/src/rdkafka_int.h +1505 -0
- package/deps/librdkafka/src/rdkafka_interceptor.c +842 -0
- package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
- package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
- package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
- package/deps/librdkafka/src/rdkafka_metadata.c +2347 -0
- package/deps/librdkafka/src/rdkafka_metadata.h +350 -0
- package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
- package/deps/librdkafka/src/rdkafka_mock.c +4514 -0
- package/deps/librdkafka/src/rdkafka_mock.h +867 -0
- package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1877 -0
- package/deps/librdkafka/src/rdkafka_mock_handlers.c +5255 -0
- package/deps/librdkafka/src/rdkafka_mock_int.h +1005 -0
- package/deps/librdkafka/src/rdkafka_mock_sharegrp.c +1207 -0
- package/deps/librdkafka/src/rdkafka_msg.c +2619 -0
- package/deps/librdkafka/src/rdkafka_msg.h +629 -0
- package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
- package/deps/librdkafka/src/rdkafka_msgset.h +105 -0
- package/deps/librdkafka/src/rdkafka_msgset_reader.c +2099 -0
- package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
- package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
- package/deps/librdkafka/src/rdkafka_offset.h +150 -0
- package/deps/librdkafka/src/rdkafka_op.c +1219 -0
- package/deps/librdkafka/src/rdkafka_op.h +1065 -0
- package/deps/librdkafka/src/rdkafka_partition.c +5109 -0
- package/deps/librdkafka/src/rdkafka_partition.h +1215 -0
- package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
- package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
- package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
- package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
- package/deps/librdkafka/src/rdkafka_proto.h +739 -0
- package/deps/librdkafka/src/rdkafka_protocol.h +131 -0
- package/deps/librdkafka/src/rdkafka_queue.c +1351 -0
- package/deps/librdkafka/src/rdkafka_queue.h +1235 -0
- package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
- package/deps/librdkafka/src/rdkafka_request.c +7298 -0
- package/deps/librdkafka/src/rdkafka_request.h +761 -0
- package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
- package/deps/librdkafka/src/rdkafka_sasl.c +589 -0
- package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
- package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
- package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1827 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +52 -0
- package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
- package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
- package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
- package/deps/librdkafka/src/rdkafka_share_acknowledgement.c +1445 -0
- package/deps/librdkafka/src/rdkafka_share_acknowledgement.h +373 -0
- package/deps/librdkafka/src/rdkafka_ssl.c +2235 -0
- package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
- package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
- package/deps/librdkafka/src/rdkafka_subscription.c +411 -0
- package/deps/librdkafka/src/rdkafka_telemetry.c +761 -0
- package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1307 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.c +1309 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.h +459 -0
- package/deps/librdkafka/src/rdkafka_timer.c +407 -0
- package/deps/librdkafka/src/rdkafka_timer.h +117 -0
- package/deps/librdkafka/src/rdkafka_topic.c +2382 -0
- package/deps/librdkafka/src/rdkafka_topic.h +369 -0
- package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
- package/deps/librdkafka/src/rdkafka_transport.h +99 -0
- package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
- package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
- package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
- package/deps/librdkafka/src/rdlist.c +593 -0
- package/deps/librdkafka/src/rdlist.h +444 -0
- package/deps/librdkafka/src/rdlog.c +89 -0
- package/deps/librdkafka/src/rdlog.h +41 -0
- package/deps/librdkafka/src/rdmap.c +508 -0
- package/deps/librdkafka/src/rdmap.h +492 -0
- package/deps/librdkafka/src/rdmurmur2.c +167 -0
- package/deps/librdkafka/src/rdmurmur2.h +35 -0
- package/deps/librdkafka/src/rdports.c +61 -0
- package/deps/librdkafka/src/rdports.h +38 -0
- package/deps/librdkafka/src/rdposix.h +250 -0
- package/deps/librdkafka/src/rdrand.c +151 -0
- package/deps/librdkafka/src/rdrand.h +72 -0
- package/deps/librdkafka/src/rdregex.c +156 -0
- package/deps/librdkafka/src/rdregex.h +43 -0
- package/deps/librdkafka/src/rdsignal.h +57 -0
- package/deps/librdkafka/src/rdstring.c +645 -0
- package/deps/librdkafka/src/rdstring.h +98 -0
- package/deps/librdkafka/src/rdsysqueue.h +404 -0
- package/deps/librdkafka/src/rdtime.h +356 -0
- package/deps/librdkafka/src/rdtypes.h +86 -0
- package/deps/librdkafka/src/rdunittest.c +564 -0
- package/deps/librdkafka/src/rdunittest.h +232 -0
- package/deps/librdkafka/src/rdunittest_acknowledge.c +1177 -0
- package/deps/librdkafka/src/rdunittest_fetcher.c +1211 -0
- package/deps/librdkafka/src/rdunittest_msgset_errors.c +1521 -0
- package/deps/librdkafka/src/rdvarint.c +134 -0
- package/deps/librdkafka/src/rdvarint.h +165 -0
- package/deps/librdkafka/src/rdwin32.h +382 -0
- package/deps/librdkafka/src/rdxxhash.c +1030 -0
- package/deps/librdkafka/src/rdxxhash.h +328 -0
- package/deps/librdkafka/src/regexp.c +1352 -0
- package/deps/librdkafka/src/regexp.h +41 -0
- package/deps/librdkafka/src/snappy.c +1866 -0
- package/deps/librdkafka/src/snappy.h +62 -0
- package/deps/librdkafka/src/snappy_compat.h +138 -0
- package/deps/librdkafka/src/statistics_schema.json +444 -0
- package/deps/librdkafka/src/tinycthread.c +932 -0
- package/deps/librdkafka/src/tinycthread.h +503 -0
- package/deps/librdkafka/src/tinycthread_extra.c +210 -0
- package/deps/librdkafka/src/tinycthread_extra.h +218 -0
- package/deps/librdkafka/src/win32_config.h +58 -0
- package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
- package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
- package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
- package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
- package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
- package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
- package/deps/librdkafka/src-cpp/Makefile +55 -0
- package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
- package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
- package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
- package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
- package/deps/librdkafka/src-cpp/README.md +16 -0
- package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
- package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
- package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
- package/deps/librdkafka/tests/0000-unittests.c +72 -0
- package/deps/librdkafka/tests/0001-multiobj.c +102 -0
- package/deps/librdkafka/tests/0002-unkpart.c +244 -0
- package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
- package/deps/librdkafka/tests/0004-conf.c +934 -0
- package/deps/librdkafka/tests/0005-order.c +133 -0
- package/deps/librdkafka/tests/0006-symbols.c +163 -0
- package/deps/librdkafka/tests/0007-autotopic.c +136 -0
- package/deps/librdkafka/tests/0008-reqacks.c +179 -0
- package/deps/librdkafka/tests/0009-mock_cluster.c +272 -0
- package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
- package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
- package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
- package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
- package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
- package/deps/librdkafka/tests/0016-client_swname.c +181 -0
- package/deps/librdkafka/tests/0017-compression.c +140 -0
- package/deps/librdkafka/tests/0018-cgrp_term.c +444 -0
- package/deps/librdkafka/tests/0019-list_groups.c +289 -0
- package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
- package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
- package/deps/librdkafka/tests/0022-consume_batch.c +331 -0
- package/deps/librdkafka/tests/0025-timers.c +147 -0
- package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
- package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
- package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
- package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
- package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
- package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
- package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
- package/deps/librdkafka/tests/0035-api_version.c +73 -0
- package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
- package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
- package/deps/librdkafka/tests/0038-performance.c +121 -0
- package/deps/librdkafka/tests/0039-event.c +284 -0
- package/deps/librdkafka/tests/0040-io_event.c +257 -0
- package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
- package/deps/librdkafka/tests/0042-many_topics.c +252 -0
- package/deps/librdkafka/tests/0043-no_connection.c +77 -0
- package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
- package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
- package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
- package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
- package/deps/librdkafka/tests/0048-partitioner.c +283 -0
- package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
- package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
- package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
- package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
- package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
- package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
- package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
- package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
- package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
- package/deps/librdkafka/tests/0058-log.cpp +123 -0
- package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
- package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
- package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
- package/deps/librdkafka/tests/0062-stats_event.c +126 -0
- package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
- package/deps/librdkafka/tests/0064-interceptors.c +529 -0
- package/deps/librdkafka/tests/0065-yield.cpp +140 -0
- package/deps/librdkafka/tests/0066-plugins.cpp +143 -0
- package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
- package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
- package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
- package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
- package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
- package/deps/librdkafka/tests/0073-headers.c +381 -0
- package/deps/librdkafka/tests/0074-producev.c +87 -0
- package/deps/librdkafka/tests/0075-retry.c +290 -0
- package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
- package/deps/librdkafka/tests/0077-compaction.c +366 -0
- package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
- package/deps/librdkafka/tests/0079-fork.c +93 -0
- package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
- package/deps/librdkafka/tests/0081-admin.c +5633 -0
- package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
- package/deps/librdkafka/tests/0083-cb_event.c +233 -0
- package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
- package/deps/librdkafka/tests/0085-headers.cpp +392 -0
- package/deps/librdkafka/tests/0086-purge.c +368 -0
- package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
- package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
- package/deps/librdkafka/tests/0090-idempotence.c +171 -0
- package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
- package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
- package/deps/librdkafka/tests/0093-holb.c +200 -0
- package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
- package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
- package/deps/librdkafka/tests/0097-ssl_verify.cpp +674 -0
- package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
- package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
- package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
- package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
- package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
- package/deps/librdkafka/tests/0103-transactions.c +1383 -0
- package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
- package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
- package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
- package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
- package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
- package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
- package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
- package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
- package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
- package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
- package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
- package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
- package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
- package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
- package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
- package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
- package/deps/librdkafka/tests/0121-clusterid.c +115 -0
- package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
- package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
- package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
- package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
- package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +1164 -0
- package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
- package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +217 -0
- package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
- package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
- package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
- package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
- package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
- package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
- package/deps/librdkafka/tests/0135-sasl_credentials.cpp +279 -0
- package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
- package/deps/librdkafka/tests/0137-barrier_batch_consume.c +752 -0
- package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
- package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
- package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
- package/deps/librdkafka/tests/0142-reauthentication.c +931 -0
- package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
- package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
- package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
- package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
- package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +1210 -0
- package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +569 -0
- package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
- package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
- package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
- package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
- package/deps/librdkafka/tests/0153-memberid.c +128 -0
- package/deps/librdkafka/tests/0155-share_group_heartbeat_mock.c +2695 -0
- package/deps/librdkafka/tests/0156-share_consumer_fetch_mock.c +1551 -0
- package/deps/librdkafka/tests/0157-share_consumer_ack_mock.c +1788 -0
- package/deps/librdkafka/tests/0158-share_consumer_transactions_mock.c +467 -0
- package/deps/librdkafka/tests/0170-share_consumer_subscription.c +2192 -0
- package/deps/librdkafka/tests/0171-share_consumer_consume.c +2150 -0
- package/deps/librdkafka/tests/0172-share_consumer_acknowledge.c +1919 -0
- package/deps/librdkafka/tests/0173-share_consumer_commit_async.c +2735 -0
- package/deps/librdkafka/tests/0174-share_consumer_concurrency.c +1434 -0
- package/deps/librdkafka/tests/0175-share_consumer_groups.c +574 -0
- package/deps/librdkafka/tests/0176-share_consumer_commit_sync.c +2986 -0
- package/deps/librdkafka/tests/0177-share_consumer_transactions.c +1815 -0
- package/deps/librdkafka/tests/0178-share_consumer_close.c +2102 -0
- package/deps/librdkafka/tests/0179-share_consumer_destroy.c +2482 -0
- package/deps/librdkafka/tests/0180-share_consumer_config.c +1677 -0
- package/deps/librdkafka/tests/0181-share_consumer_topic_delete.c +354 -0
- package/deps/librdkafka/tests/0182-share_consumer_error_handling_mock.c +3358 -0
- package/deps/librdkafka/tests/0183-share_consumer_leader_change_mock.c +1234 -0
- package/deps/librdkafka/tests/0184-share_consumer_topic_recreate.c +1356 -0
- package/deps/librdkafka/tests/0185-share_consumer_max_poll_interval.c +557 -0
- package/deps/librdkafka/tests/0186-share_consumer_fatal_error.c +360 -0
- package/deps/librdkafka/tests/0190-share_consumer_telemetry.c +387 -0
- package/deps/librdkafka/tests/1000-unktopic.c +164 -0
- package/deps/librdkafka/tests/8000-idle.cpp +60 -0
- package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
- package/deps/librdkafka/tests/CMakeLists.txt +193 -0
- package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
- package/deps/librdkafka/tests/Makefile +182 -0
- package/deps/librdkafka/tests/README.md +514 -0
- package/deps/librdkafka/tests/autotest.sh +33 -0
- package/deps/librdkafka/tests/backtrace.gdb +30 -0
- package/deps/librdkafka/tests/broker_version_tests.py +315 -0
- package/deps/librdkafka/tests/buildbox.sh +17 -0
- package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
- package/deps/librdkafka/tests/cluster_testing.py +203 -0
- package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
- package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
- package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
- package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
- package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
- package/deps/librdkafka/tests/fuzzers/README.md +31 -0
- package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
- package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
- package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
- package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
- package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
- package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
- package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
- package/deps/librdkafka/tests/java/Makefile +13 -0
- package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
- package/deps/librdkafka/tests/java/README.md +14 -0
- package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
- package/deps/librdkafka/tests/java/run-class.sh +11 -0
- package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
- package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
- package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
- package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
- package/deps/librdkafka/tests/performance_plot.py +115 -0
- package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
- package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
- package/deps/librdkafka/tests/requirements.txt +2 -0
- package/deps/librdkafka/tests/run-all-tests.sh +81 -0
- package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-test-batches.py +157 -0
- package/deps/librdkafka/tests/run-test.sh +141 -0
- package/deps/librdkafka/tests/rusage.c +249 -0
- package/deps/librdkafka/tests/sasl_test.py +289 -0
- package/deps/librdkafka/tests/scenarios/README.md +6 -0
- package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
- package/deps/librdkafka/tests/scenarios/default.json +5 -0
- package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
- package/deps/librdkafka/tests/share_telemetry_verify/share-otel-collector-config.yaml +28 -0
- package/deps/librdkafka/tests/sockem.c +801 -0
- package/deps/librdkafka/tests/sockem.h +85 -0
- package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
- package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
- package/deps/librdkafka/tests/test.c +8376 -0
- package/deps/librdkafka/tests/test.conf.example +27 -0
- package/deps/librdkafka/tests/test.h +1150 -0
- package/deps/librdkafka/tests/testcpp.cpp +131 -0
- package/deps/librdkafka/tests/testcpp.h +388 -0
- package/deps/librdkafka/tests/testshared.h +416 -0
- package/deps/librdkafka/tests/tools/README.md +4 -0
- package/deps/librdkafka/tests/tools/stats/README.md +21 -0
- package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
- package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
- package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
- package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
- package/deps/librdkafka/tests/trivup/trivup-0.15.0.tar.gz +0 -0
- package/deps/librdkafka/tests/until-fail.sh +87 -0
- package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
- package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
- package/deps/librdkafka/vcpkg.json +23 -0
- package/deps/librdkafka/win32/README.md +5 -0
- package/deps/librdkafka/win32/build-package.bat +3 -0
- package/deps/librdkafka/win32/build.bat +19 -0
- package/deps/librdkafka/win32/common.vcxproj +84 -0
- package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
- package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
- package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
- package/deps/librdkafka/win32/librdkafka.sln +226 -0
- package/deps/librdkafka/win32/librdkafka.vcxproj +282 -0
- package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
- package/deps/librdkafka/win32/msbuild.ps1 +58 -0
- package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
- package/deps/librdkafka/win32/package-zip.ps1 +46 -0
- package/deps/librdkafka/win32/packages/repositories.config +4 -0
- package/deps/librdkafka/win32/push-package.bat +4 -0
- package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
- package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
- package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
- package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
- package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
- package/deps/librdkafka/win32/tests/test.conf.example +25 -0
- package/deps/librdkafka/win32/tests/tests.vcxproj +278 -0
- package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
- package/deps/librdkafka/win32/wingetopt.c +564 -0
- package/deps/librdkafka/win32/wingetopt.h +101 -0
- package/deps/librdkafka/win32/wintime.h +33 -0
- package/deps/librdkafka.gyp +83 -0
- package/deps/windows-install.py +80 -0
- package/index.d.ts +3 -0
- package/lib/admin.js +732 -0
- package/lib/client.js +679 -0
- package/lib/error.js +501 -0
- package/lib/index.js +8 -0
- package/lib/kafka-consumer-stream.js +399 -0
- package/lib/kafka-consumer.js +798 -0
- package/lib/kafkajs/_admin.js +1052 -0
- package/lib/kafkajs/_common.js +887 -0
- package/lib/kafkajs/_consumer.js +2156 -0
- package/lib/kafkajs/_consumer_cache.js +310 -0
- package/lib/kafkajs/_error.js +298 -0
- package/lib/kafkajs/_kafka.js +125 -0
- package/lib/kafkajs/_linked-list.js +220 -0
- package/lib/kafkajs/_producer.js +863 -0
- package/lib/kafkajs/index.js +5 -0
- package/lib/producer/high-level-producer.js +400 -0
- package/lib/producer-stream.js +337 -0
- package/lib/producer.js +405 -0
- package/lib/rdkafka.js +44 -0
- package/lib/tools/ref-counter.js +53 -0
- package/lib/topic-partition.js +91 -0
- package/lib/topic.js +43 -0
- package/lib/util.js +55 -0
- package/librdkafka.js +12 -0
- package/package.json +85 -0
- package/shim/source_location +54 -0
- package/src/admin.cc +1597 -0
- package/src/admin.h +112 -0
- package/src/binding.cc +76 -0
- package/src/binding.h +25 -0
- package/src/callbacks.cc +676 -0
- package/src/callbacks.h +302 -0
- package/src/common.cc +1628 -0
- package/src/common.h +192 -0
- package/src/config.cc +219 -0
- package/src/config.h +61 -0
- package/src/connection.cc +703 -0
- package/src/connection.h +117 -0
- package/src/errors.cc +119 -0
- package/src/errors.h +60 -0
- package/src/kafka-consumer.cc +1539 -0
- package/src/kafka-consumer.h +147 -0
- package/src/producer.cc +917 -0
- package/src/producer.h +124 -0
- package/src/topic.cc +173 -0
- package/src/topic.h +54 -0
- package/src/workers.cc +1714 -0
- package/src/workers.h +690 -0
- package/types/config.d.ts +1269 -0
- package/types/errors.d.ts +373 -0
- package/types/kafkajs.d.ts +568 -0
- package/types/rdkafka.d.ts +571 -0
- package/util/configure.js +32 -0
- package/util/generate-docs.sh +18 -0
- package/util/get-env.js +6 -0
- package/util/test-compile.js +11 -0
- package/util/test-producer-delivery.js +100 -0
|
@@ -0,0 +1,1434 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* librdkafka - Apache Kafka C library
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026, Confluent Inc.
|
|
5
|
+
* All rights reserved.
|
|
6
|
+
*
|
|
7
|
+
* Redistribution and use in source and binary forms, with or without
|
|
8
|
+
* modification, are permitted provided that the following conditions are met:
|
|
9
|
+
*
|
|
10
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
|
11
|
+
* this list of conditions and the following disclaimer.
|
|
12
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
* and/or other materials provided with the distribution.
|
|
15
|
+
*
|
|
16
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
19
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
20
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
21
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
22
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
23
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
24
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
25
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
#include "test.h"
|
|
30
|
+
#include "rdkafka.h"
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @name Share Consumer Concurrency and Stress Tests
|
|
34
|
+
*
|
|
35
|
+
* Tests share consumer behavior under concurrent producer/consumer scenarios.
|
|
36
|
+
* Each test uses a config-based structure. Producers and consumers each run
|
|
37
|
+
* in their own dedicated threads — there is no main-thread round-robin
|
|
38
|
+
* polling. The main test thread orchestrates start/stop and verifies
|
|
39
|
+
* end-state counters. The per-record invariant validated is first-delivery
|
|
40
|
+
* count (each produced record is first-delivered exactly once; redeliveries
|
|
41
|
+
* are counted separately).
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
#define MAX_TOPICS 16
|
|
45
|
+
#define MAX_PARTITIONS 16
|
|
46
|
+
#define MAX_CONSUMERS 16
|
|
47
|
+
#define MAX_PRODUCERS 10
|
|
48
|
+
#define MAX_CONSUMER_POOL 32
|
|
49
|
+
#define BATCH_SIZE 10000
|
|
50
|
+
|
|
51
|
+
/* Save test_curr for threads (test_curr is TLS) */
|
|
52
|
+
static struct test *this_test;
|
|
53
|
+
|
|
54
|
+
/***************************************************************************
|
|
55
|
+
* Test Configuration and State
|
|
56
|
+
***************************************************************************/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @brief Configuration for a concurrent share consumer test
|
|
60
|
+
*/
|
|
61
|
+
typedef struct {
|
|
62
|
+
int consumer_cnt; /**< Number of consumers to create */
|
|
63
|
+
int producer_cnt; /**< Number of producer threads */
|
|
64
|
+
int topic_cnt; /**< Number of topics */
|
|
65
|
+
int partitions[MAX_TOPICS]; /**< Partitions per topic */
|
|
66
|
+
int msgs_per_partition; /**< Messages to produce per partition */
|
|
67
|
+
const char *group_name; /**< Share group name */
|
|
68
|
+
const char *test_name; /**< Test description */
|
|
69
|
+
int max_attempts; /**< Max poll attempts (0 = default) */
|
|
70
|
+
int consumer_delay_ms; /**< Delay between consumer polls */
|
|
71
|
+
int producer_delay_ms; /**< Delay between produces */
|
|
72
|
+
rd_bool_t explicit_ack; /**< Use explicit acknowledgement */
|
|
73
|
+
rd_bool_t staggered_start; /**< Start producers/consumers at
|
|
74
|
+
different times */
|
|
75
|
+
} concurrent_test_config_t;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @brief Shared state for concurrent test threads
|
|
79
|
+
*/
|
|
80
|
+
typedef struct {
|
|
81
|
+
mtx_t lock; /**< Mutex for state access */
|
|
82
|
+
int total_produced; /**< Total messages produced */
|
|
83
|
+
int total_consumed; /**< Total messages consumed
|
|
84
|
+
* (includes redeliveries) */
|
|
85
|
+
int total_first_delivery; /**< Messages with delivery_count == 1 */
|
|
86
|
+
int total_duplicates; /**< Messages with delivery_count > 1 */
|
|
87
|
+
int expected_total; /**< Expected total messages */
|
|
88
|
+
rd_bool_t producers_done; /**< All producers finished */
|
|
89
|
+
int producers_remaining; /**< Producer threads still running */
|
|
90
|
+
rd_bool_t test_failed; /**< Test failure flag */
|
|
91
|
+
char topics[MAX_TOPICS][128]; /**< Topic names */
|
|
92
|
+
int topic_cnt; /**< Number of topics */
|
|
93
|
+
const char *group_name; /**< Share group name */
|
|
94
|
+
rd_bool_t explicit_ack; /**< Use explicit acknowledgement */
|
|
95
|
+
} concurrent_test_state_t;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @brief Arguments for producer thread
|
|
99
|
+
*/
|
|
100
|
+
typedef struct {
|
|
101
|
+
concurrent_test_state_t *state;
|
|
102
|
+
int producer_id;
|
|
103
|
+
int msgs_to_produce;
|
|
104
|
+
int delay_ms;
|
|
105
|
+
int partitions[MAX_TOPICS];
|
|
106
|
+
} producer_thread_args_t;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @brief Per-consumer-thread context.
|
|
110
|
+
*
|
|
111
|
+
* One share consumer per thread; main thread sets @c run to rd_false
|
|
112
|
+
* (under state->lock) to ask the consumer to wind down. The consumer
|
|
113
|
+
* thread sets @c done = rd_true under the same lock right before it
|
|
114
|
+
* returns from consumer_thread_func, so the main thread can poll for a
|
|
115
|
+
* clean exit instead of blocking forever in thrd_join when a consumer
|
|
116
|
+
* is wedged inside librdkafka.
|
|
117
|
+
*/
|
|
118
|
+
typedef struct {
|
|
119
|
+
concurrent_test_state_t *state;
|
|
120
|
+
int consumer_id;
|
|
121
|
+
rd_bool_t run;
|
|
122
|
+
rd_bool_t done; /**< Set true just before consumer thread exits */
|
|
123
|
+
int poll_delay_ms; /**< Sleep between polls (from config) */
|
|
124
|
+
} consumer_thread_args_t;
|
|
125
|
+
|
|
126
|
+
/***************************************************************************
|
|
127
|
+
* Thread Functions
|
|
128
|
+
***************************************************************************/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @brief Producer thread function
|
|
132
|
+
*
|
|
133
|
+
* Produces messages to all topics/partitions in round-robin fashion.
|
|
134
|
+
*/
|
|
135
|
+
static int producer_thread_func(void *arg) {
|
|
136
|
+
producer_thread_args_t *args = (producer_thread_args_t *)arg;
|
|
137
|
+
concurrent_test_state_t *state = args->state;
|
|
138
|
+
rd_kafka_t *producer;
|
|
139
|
+
rd_kafka_conf_t *conf;
|
|
140
|
+
int produced = 0;
|
|
141
|
+
int t, p;
|
|
142
|
+
rd_kafka_resp_err_t err;
|
|
143
|
+
char value[64];
|
|
144
|
+
|
|
145
|
+
/* Restore the TLS test_curr pointer for this thread. The
|
|
146
|
+
* exp_dr_status / ignore_dr_err fields on the struct itself are
|
|
147
|
+
* set once by the main thread before any worker spawns
|
|
148
|
+
* (see run_concurrent_test / do_test_chaos_consumer_lifecycle)
|
|
149
|
+
* — touching them here would race against every other producer
|
|
150
|
+
* thread that aliases the same global tests[] entry. */
|
|
151
|
+
test_curr = this_test;
|
|
152
|
+
|
|
153
|
+
/* Enable idempotent producer so retries do not result in duplicate
|
|
154
|
+
* broker-side writes — without this, transient broker/network jitter
|
|
155
|
+
* under the heavy concurrent load these tests generate (e.g.
|
|
156
|
+
* test_max_concurrent with 10 producers × 5000 msgs) causes the
|
|
157
|
+
* broker to store extra records that the share consumer then
|
|
158
|
+
* receives as new offsets with delivery_count=1, inflating the
|
|
159
|
+
* consumed count above expected_total. */
|
|
160
|
+
test_conf_init(&conf, NULL, 0);
|
|
161
|
+
test_conf_set(conf, "enable.idempotence", "true");
|
|
162
|
+
rd_kafka_conf_set_dr_msg_cb(conf, test_dr_msg_cb);
|
|
163
|
+
producer = test_create_handle(RD_KAFKA_PRODUCER, conf);
|
|
164
|
+
|
|
165
|
+
TEST_SAY("Producer %d: starting, will produce %d messages\n",
|
|
166
|
+
args->producer_id, args->msgs_to_produce);
|
|
167
|
+
|
|
168
|
+
while (produced < args->msgs_to_produce) {
|
|
169
|
+
for (t = 0;
|
|
170
|
+
t < state->topic_cnt && produced < args->msgs_to_produce;
|
|
171
|
+
t++) {
|
|
172
|
+
for (p = 0; p < args->partitions[t] &&
|
|
173
|
+
produced < args->msgs_to_produce;
|
|
174
|
+
p++) {
|
|
175
|
+
snprintf(value, sizeof(value), "prod%d-msg%d",
|
|
176
|
+
args->producer_id, produced);
|
|
177
|
+
|
|
178
|
+
err = rd_kafka_producev(
|
|
179
|
+
producer,
|
|
180
|
+
RD_KAFKA_V_TOPIC(state->topics[t]),
|
|
181
|
+
RD_KAFKA_V_PARTITION(p),
|
|
182
|
+
RD_KAFKA_V_VALUE(value, strlen(value)),
|
|
183
|
+
RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),
|
|
184
|
+
RD_KAFKA_V_END);
|
|
185
|
+
|
|
186
|
+
if (err) {
|
|
187
|
+
TEST_SAY(
|
|
188
|
+
"Producer %d: produce failed: %s\n",
|
|
189
|
+
args->producer_id,
|
|
190
|
+
rd_kafka_err2str(err));
|
|
191
|
+
mtx_lock(&state->lock);
|
|
192
|
+
state->test_failed = rd_true;
|
|
193
|
+
mtx_unlock(&state->lock);
|
|
194
|
+
goto done;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
produced++;
|
|
198
|
+
|
|
199
|
+
if (args->delay_ms > 0 && produced % 100 == 0)
|
|
200
|
+
rd_usleep(args->delay_ms * 1000, NULL);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
rd_kafka_flush(producer, 1000);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
rd_kafka_flush(producer, 10000);
|
|
208
|
+
|
|
209
|
+
TEST_SAY("Producer %d: finished, produced %d messages\n",
|
|
210
|
+
args->producer_id, produced);
|
|
211
|
+
|
|
212
|
+
done:
|
|
213
|
+
mtx_lock(&state->lock);
|
|
214
|
+
state->total_produced += produced;
|
|
215
|
+
if (--state->producers_remaining == 0)
|
|
216
|
+
state->producers_done = rd_true;
|
|
217
|
+
mtx_unlock(&state->lock);
|
|
218
|
+
|
|
219
|
+
rd_kafka_destroy(producer);
|
|
220
|
+
free(args);
|
|
221
|
+
|
|
222
|
+
return thrd_success;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @brief Per-thread share consumer poll loop.
|
|
227
|
+
*
|
|
228
|
+
* One share consumer per thread. Creates the consumer, subscribes to all
|
|
229
|
+
* configured topics, then polls until @c args->run is cleared by the main
|
|
230
|
+
* thread. Records first-time deliveries vs redeliveries via
|
|
231
|
+
* rd_kafka_message_delivery_count() into shared counters.
|
|
232
|
+
*/
|
|
233
|
+
static int consumer_thread_func(void *arg) {
|
|
234
|
+
consumer_thread_args_t *args = (consumer_thread_args_t *)arg;
|
|
235
|
+
concurrent_test_state_t *state = args->state;
|
|
236
|
+
rd_kafka_share_t *consumer;
|
|
237
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
238
|
+
rd_kafka_messages_t *batch = NULL;
|
|
239
|
+
rd_kafka_error_t *err;
|
|
240
|
+
int t;
|
|
241
|
+
size_t m;
|
|
242
|
+
size_t rcvd;
|
|
243
|
+
rd_bool_t keep_running;
|
|
244
|
+
|
|
245
|
+
test_curr = this_test;
|
|
246
|
+
|
|
247
|
+
consumer = test_create_share_consumer(
|
|
248
|
+
state->group_name, state->explicit_ack ? "explicit" : NULL);
|
|
249
|
+
|
|
250
|
+
subs = rd_kafka_topic_partition_list_new(state->topic_cnt);
|
|
251
|
+
for (t = 0; t < state->topic_cnt; t++) {
|
|
252
|
+
rd_kafka_topic_partition_list_add(subs, state->topics[t],
|
|
253
|
+
RD_KAFKA_PARTITION_UA);
|
|
254
|
+
}
|
|
255
|
+
rd_kafka_share_subscribe(consumer, subs);
|
|
256
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
257
|
+
|
|
258
|
+
TEST_SAY("Consumer thread %d: subscribed\n", args->consumer_id);
|
|
259
|
+
|
|
260
|
+
while (1) {
|
|
261
|
+
int acked_in_batch = 0;
|
|
262
|
+
|
|
263
|
+
mtx_lock(&state->lock);
|
|
264
|
+
keep_running = args->run;
|
|
265
|
+
mtx_unlock(&state->lock);
|
|
266
|
+
if (!keep_running)
|
|
267
|
+
break;
|
|
268
|
+
|
|
269
|
+
err = rd_kafka_share_poll(consumer, 500, &batch);
|
|
270
|
+
if (err) {
|
|
271
|
+
TEST_SAY("Consumer thread %d: share_poll error: %s\n",
|
|
272
|
+
args->consumer_id, rd_kafka_error_string(err));
|
|
273
|
+
rd_kafka_error_destroy(err);
|
|
274
|
+
rd_kafka_messages_destroy(batch);
|
|
275
|
+
batch = NULL;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
279
|
+
|
|
280
|
+
/* Per-record atomic step:
|
|
281
|
+
* ACK → process (count into shared state under lock) →
|
|
282
|
+
* destroy. ack + process happen in the same iteration
|
|
283
|
+
* so there is no window where the broker can see an
|
|
284
|
+
* ACK for a record that this application has not also
|
|
285
|
+
* recorded as consumed in total_first_delivery /
|
|
286
|
+
* total_duplicates. The per-batch commit_sync below
|
|
287
|
+
* flushes the acks to the broker. */
|
|
288
|
+
for (m = 0; m < rcvd; m++) {
|
|
289
|
+
rd_kafka_message_t *msg =
|
|
290
|
+
rd_kafka_messages_get(batch, m);
|
|
291
|
+
|
|
292
|
+
if (!msg)
|
|
293
|
+
continue;
|
|
294
|
+
|
|
295
|
+
if (msg->err) {
|
|
296
|
+
const char *msg_topic =
|
|
297
|
+
msg->rkt ? rd_kafka_topic_name(msg->rkt)
|
|
298
|
+
: "(no-topic)";
|
|
299
|
+
TEST_SAY(
|
|
300
|
+
"Consumer thread %d: SKIPPING record "
|
|
301
|
+
"%s[%" PRId32 "] off=%" PRId64
|
|
302
|
+
" because msg->err=%s\n",
|
|
303
|
+
args->consumer_id, msg_topic,
|
|
304
|
+
msg->partition, msg->offset,
|
|
305
|
+
rd_kafka_err2name(msg->err));
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (state->explicit_ack) {
|
|
310
|
+
rd_kafka_resp_err_t ack_err =
|
|
311
|
+
rd_kafka_share_acknowledge_type(
|
|
312
|
+
consumer, msg,
|
|
313
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
314
|
+
if (ack_err != RD_KAFKA_RESP_ERR_NO_ERROR) {
|
|
315
|
+
TEST_SAY(
|
|
316
|
+
"Consumer thread %d: "
|
|
317
|
+
"acknowledge offset %" PRId64
|
|
318
|
+
" failed: %s — skipping count "
|
|
319
|
+
"for this record\n",
|
|
320
|
+
args->consumer_id, msg->offset,
|
|
321
|
+
rd_kafka_err2name(ack_err));
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
acked_in_batch++;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* Process the record at the same instant we
|
|
328
|
+
* acknowledged it. */
|
|
329
|
+
{
|
|
330
|
+
int16_t dc =
|
|
331
|
+
rd_kafka_message_delivery_count(msg);
|
|
332
|
+
mtx_lock(&state->lock);
|
|
333
|
+
if (dc > 1)
|
|
334
|
+
state->total_duplicates++;
|
|
335
|
+
else
|
|
336
|
+
state->total_first_delivery++;
|
|
337
|
+
state->total_consumed++;
|
|
338
|
+
mtx_unlock(&state->lock);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
rd_kafka_messages_destroy(batch);
|
|
343
|
+
batch = NULL;
|
|
344
|
+
|
|
345
|
+
/* Flush the per-record acks to the broker before the
|
|
346
|
+
* next consume_batch or stop check. Per-partition
|
|
347
|
+
* results are inspected for errors. */
|
|
348
|
+
if (state->explicit_ack && acked_in_batch > 0) {
|
|
349
|
+
rd_kafka_topic_partition_list_t *cs_result = NULL;
|
|
350
|
+
rd_kafka_error_t *commit_err =
|
|
351
|
+
rd_kafka_share_commit_sync(consumer, 5000,
|
|
352
|
+
&cs_result);
|
|
353
|
+
if (commit_err) {
|
|
354
|
+
TEST_SAY(
|
|
355
|
+
"Consumer thread %d: commit_sync failed "
|
|
356
|
+
"(acked_in_batch=%d): %s\n",
|
|
357
|
+
args->consumer_id, acked_in_batch,
|
|
358
|
+
rd_kafka_error_string(commit_err));
|
|
359
|
+
rd_kafka_error_destroy(commit_err);
|
|
360
|
+
} else if (cs_result) {
|
|
361
|
+
int i;
|
|
362
|
+
for (i = 0; i < cs_result->cnt; i++) {
|
|
363
|
+
if (cs_result->elems[i].err !=
|
|
364
|
+
RD_KAFKA_RESP_ERR_NO_ERROR) {
|
|
365
|
+
TEST_SAY(
|
|
366
|
+
"Consumer thread %d: "
|
|
367
|
+
"commit_sync per-part "
|
|
368
|
+
"err %s [%" PRId32
|
|
369
|
+
"]: %s\n",
|
|
370
|
+
args->consumer_id,
|
|
371
|
+
cs_result->elems[i].topic,
|
|
372
|
+
cs_result->elems[i]
|
|
373
|
+
.partition,
|
|
374
|
+
rd_kafka_err2name(
|
|
375
|
+
cs_result->elems[i]
|
|
376
|
+
.err));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (cs_result)
|
|
381
|
+
rd_kafka_topic_partition_list_destroy(
|
|
382
|
+
cs_result);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (args->poll_delay_ms > 0)
|
|
386
|
+
rd_usleep(args->poll_delay_ms * 1000, NULL);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
TEST_SAY("Consumer thread %d: closing\n", args->consumer_id);
|
|
390
|
+
test_share_consumer_close(consumer);
|
|
391
|
+
test_share_destroy(consumer);
|
|
392
|
+
|
|
393
|
+
/* Mark this thread as cleanly exited so the main thread's bounded
|
|
394
|
+
* wait can detect it without blocking in thrd_join. */
|
|
395
|
+
mtx_lock(&state->lock);
|
|
396
|
+
args->done = rd_true;
|
|
397
|
+
mtx_unlock(&state->lock);
|
|
398
|
+
|
|
399
|
+
return thrd_success;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/***************************************************************************
|
|
403
|
+
* Test Runner — fully threaded
|
|
404
|
+
*
|
|
405
|
+
* Every share consumer and every producer runs in its own dedicated
|
|
406
|
+
* thread. The main thread only orchestrates start/stop and verifies
|
|
407
|
+
* final counters. No round-robin main-thread polling.
|
|
408
|
+
***************************************************************************/
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @brief Run a concurrent share consumer test with every consumer in its
|
|
412
|
+
* own thread.
|
|
413
|
+
*
|
|
414
|
+
* @c config->max_attempts is interpreted as an upper bound on the total
|
|
415
|
+
* wait-for-completion time, measured in 500ms ticks (so max_attempts=100
|
|
416
|
+
* gives a 50 s bound). When unset (0), the default is 240 ticks = 120 s.
|
|
417
|
+
*/
|
|
418
|
+
static void run_concurrent_test(const concurrent_test_config_t *config) {
|
|
419
|
+
concurrent_test_state_t state = {0};
|
|
420
|
+
thrd_t producer_threads[MAX_PRODUCERS];
|
|
421
|
+
thrd_t consumer_threads[MAX_CONSUMERS];
|
|
422
|
+
consumer_thread_args_t consumer_args[MAX_CONSUMERS];
|
|
423
|
+
rd_kafka_share_t *dummy_consumer;
|
|
424
|
+
int t, c, p;
|
|
425
|
+
int total_partitions = 0;
|
|
426
|
+
int msgs_per_producer;
|
|
427
|
+
int max_wait_ticks;
|
|
428
|
+
int wait_ticks;
|
|
429
|
+
int final_produced;
|
|
430
|
+
int final_consumed;
|
|
431
|
+
int final_first_delivery;
|
|
432
|
+
int final_duplicates;
|
|
433
|
+
rd_bool_t final_failed;
|
|
434
|
+
char unique_suffix[64];
|
|
435
|
+
char unique_group[128];
|
|
436
|
+
char unique_test_name[256];
|
|
437
|
+
|
|
438
|
+
TEST_ASSERT(config->consumer_cnt <= MAX_CONSUMERS,
|
|
439
|
+
"consumer_cnt %d exceeds MAX_CONSUMERS %d",
|
|
440
|
+
config->consumer_cnt, MAX_CONSUMERS);
|
|
441
|
+
|
|
442
|
+
/* Generate a per-invocation unique suffix and append it to both
|
|
443
|
+
* the group name and the displayed test name. Avoids collisions
|
|
444
|
+
* across re-runs / parallel runs that share the same broker. */
|
|
445
|
+
rd_snprintf(unique_suffix, sizeof(unique_suffix), "rnd%" PRIx64,
|
|
446
|
+
test_id_generate());
|
|
447
|
+
rd_snprintf(unique_group, sizeof(unique_group), "%s-%s",
|
|
448
|
+
config->group_name, unique_suffix);
|
|
449
|
+
rd_snprintf(unique_test_name, sizeof(unique_test_name), "%s [%s]",
|
|
450
|
+
config->test_name, unique_suffix);
|
|
451
|
+
|
|
452
|
+
TEST_SAY("\n");
|
|
453
|
+
TEST_SAY(
|
|
454
|
+
"============================================================\n");
|
|
455
|
+
TEST_SAY("=== %s ===\n", unique_test_name);
|
|
456
|
+
TEST_SAY(
|
|
457
|
+
"============================================================\n");
|
|
458
|
+
TEST_SAY(
|
|
459
|
+
"Threaded: %d consumer threads, %d producer threads, %d topics\n",
|
|
460
|
+
config->consumer_cnt, config->producer_cnt, config->topic_cnt);
|
|
461
|
+
|
|
462
|
+
/* Save test context for threads (test_curr is TLS) */
|
|
463
|
+
this_test = test_curr;
|
|
464
|
+
|
|
465
|
+
/* Set the DR-callback expectations on the shared test struct
|
|
466
|
+
* ONCE on the main thread, before spawning any worker threads.
|
|
467
|
+
* test_curr is a TLS pointer but the struct it points at lives
|
|
468
|
+
* in the global tests[] array, so writing these fields from
|
|
469
|
+
* each producer thread (as it used to) is a benign-but-noisy
|
|
470
|
+
* data race that TSAN flags. */
|
|
471
|
+
test_curr->exp_dr_status = (rd_kafka_msg_status_t)-1;
|
|
472
|
+
test_curr->ignore_dr_err = rd_true;
|
|
473
|
+
|
|
474
|
+
/* Initialize state */
|
|
475
|
+
mtx_init(&state.lock, mtx_plain);
|
|
476
|
+
state.topic_cnt = config->topic_cnt;
|
|
477
|
+
state.group_name = unique_group;
|
|
478
|
+
state.explicit_ack = config->explicit_ack;
|
|
479
|
+
state.producers_remaining = config->producer_cnt;
|
|
480
|
+
|
|
481
|
+
for (t = 0; t < config->topic_cnt; t++)
|
|
482
|
+
total_partitions += config->partitions[t];
|
|
483
|
+
state.expected_total = total_partitions * config->msgs_per_partition;
|
|
484
|
+
TEST_SAY(
|
|
485
|
+
"Total partitions: %d, msgs/partition: %d, expected total: %d\n",
|
|
486
|
+
total_partitions, config->msgs_per_partition, state.expected_total);
|
|
487
|
+
|
|
488
|
+
/* Create topics */
|
|
489
|
+
for (t = 0; t < config->topic_cnt; t++) {
|
|
490
|
+
rd_snprintf(state.topics[t], sizeof(state.topics[t]), "%s",
|
|
491
|
+
test_mk_topic_name("0174-concurrent", 1));
|
|
492
|
+
test_create_topic_wait_exists(NULL, state.topics[t],
|
|
493
|
+
config->partitions[t], -1,
|
|
494
|
+
60 * 1000);
|
|
495
|
+
TEST_SAY("Created topic %s with %d partitions\n",
|
|
496
|
+
state.topics[t], config->partitions[t]);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* Apply broker-side share group config (auto.offset.reset=earliest)
|
|
500
|
+
* via a throwaway consumer registration so the alter sticks before
|
|
501
|
+
* any worker subscribes. */
|
|
502
|
+
dummy_consumer = test_create_share_consumer(unique_group, NULL);
|
|
503
|
+
test_share_set_auto_offset_reset(unique_group, "earliest");
|
|
504
|
+
test_share_consumer_close(dummy_consumer);
|
|
505
|
+
test_share_destroy(dummy_consumer);
|
|
506
|
+
|
|
507
|
+
/* Start producer threads */
|
|
508
|
+
msgs_per_producer = state.expected_total / config->producer_cnt;
|
|
509
|
+
for (p = 0; p < config->producer_cnt; p++) {
|
|
510
|
+
producer_thread_args_t *args = rd_calloc(1, sizeof(*args));
|
|
511
|
+
args->state = &state;
|
|
512
|
+
args->producer_id = p;
|
|
513
|
+
args->msgs_to_produce = msgs_per_producer;
|
|
514
|
+
if (p == config->producer_cnt - 1)
|
|
515
|
+
args->msgs_to_produce +=
|
|
516
|
+
state.expected_total % config->producer_cnt;
|
|
517
|
+
args->delay_ms = config->producer_delay_ms;
|
|
518
|
+
for (t = 0; t < config->topic_cnt; t++)
|
|
519
|
+
args->partitions[t] = config->partitions[t];
|
|
520
|
+
|
|
521
|
+
if (thrd_create(&producer_threads[p], producer_thread_func,
|
|
522
|
+
args) != thrd_success) {
|
|
523
|
+
TEST_FAIL("Failed to create producer thread %d", p);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Optional staggered start: give producers a head start before
|
|
528
|
+
* spinning up consumer threads. */
|
|
529
|
+
if (config->staggered_start) {
|
|
530
|
+
TEST_SAY("Staggered start: producers run alone for 2 s\n");
|
|
531
|
+
rd_sleep(2);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* Start consumer threads — one per consumer */
|
|
535
|
+
for (c = 0; c < config->consumer_cnt; c++) {
|
|
536
|
+
consumer_args[c].state = &state;
|
|
537
|
+
consumer_args[c].consumer_id = c;
|
|
538
|
+
consumer_args[c].run = rd_true;
|
|
539
|
+
consumer_args[c].done = rd_false;
|
|
540
|
+
consumer_args[c].poll_delay_ms = config->consumer_delay_ms;
|
|
541
|
+
|
|
542
|
+
if (thrd_create(&consumer_threads[c], consumer_thread_func,
|
|
543
|
+
&consumer_args[c]) != thrd_success) {
|
|
544
|
+
TEST_FAIL("Failed to create consumer thread %d", c);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* Wait for all expected first deliveries, bounded by max_attempts
|
|
549
|
+
* ticks of 500ms each (default 240 ticks = 120 s). */
|
|
550
|
+
max_wait_ticks = config->max_attempts > 0 ? config->max_attempts : 240;
|
|
551
|
+
wait_ticks = max_wait_ticks;
|
|
552
|
+
|
|
553
|
+
while (wait_ticks-- > 0) {
|
|
554
|
+
int first_seen;
|
|
555
|
+
int consumed_so_far;
|
|
556
|
+
int dups;
|
|
557
|
+
rd_bool_t producers_done;
|
|
558
|
+
|
|
559
|
+
mtx_lock(&state.lock);
|
|
560
|
+
first_seen = state.total_first_delivery;
|
|
561
|
+
consumed_so_far = state.total_consumed;
|
|
562
|
+
dups = state.total_duplicates;
|
|
563
|
+
producers_done = state.producers_done;
|
|
564
|
+
mtx_unlock(&state.lock);
|
|
565
|
+
|
|
566
|
+
if (first_seen >= state.expected_total)
|
|
567
|
+
break;
|
|
568
|
+
|
|
569
|
+
if (wait_ticks % 20 == 0)
|
|
570
|
+
TEST_SAY(
|
|
571
|
+
"Progress: consumed %d/%d (first=%d, dup=%d, "
|
|
572
|
+
"producers_done=%d)\n",
|
|
573
|
+
consumed_so_far, state.expected_total, first_seen,
|
|
574
|
+
dups, (int)producers_done);
|
|
575
|
+
|
|
576
|
+
rd_usleep(500 * 1000, NULL);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/* Join producers even if drain timed out. */
|
|
580
|
+
for (p = 0; p < config->producer_cnt; p++)
|
|
581
|
+
thrd_join(producer_threads[p], NULL);
|
|
582
|
+
|
|
583
|
+
/* Tell consumer threads to stop and join. */
|
|
584
|
+
mtx_lock(&state.lock);
|
|
585
|
+
for (c = 0; c < config->consumer_cnt; c++)
|
|
586
|
+
consumer_args[c].run = rd_false;
|
|
587
|
+
mtx_unlock(&state.lock);
|
|
588
|
+
|
|
589
|
+
for (c = 0; c < config->consumer_cnt; c++)
|
|
590
|
+
thrd_join(consumer_threads[c], NULL);
|
|
591
|
+
|
|
592
|
+
/* Snapshot results under lock */
|
|
593
|
+
mtx_lock(&state.lock);
|
|
594
|
+
final_produced = state.total_produced;
|
|
595
|
+
final_consumed = state.total_consumed;
|
|
596
|
+
final_first_delivery = state.total_first_delivery;
|
|
597
|
+
final_duplicates = state.total_duplicates;
|
|
598
|
+
final_failed = state.test_failed;
|
|
599
|
+
mtx_unlock(&state.lock);
|
|
600
|
+
|
|
601
|
+
TEST_SAY(
|
|
602
|
+
"Final: produced=%d, consumed=%d (first=%d, dup=%d), "
|
|
603
|
+
"expected=%d\n",
|
|
604
|
+
final_produced, final_consumed, final_first_delivery,
|
|
605
|
+
final_duplicates, state.expected_total);
|
|
606
|
+
|
|
607
|
+
TEST_ASSERT(final_produced == state.expected_total,
|
|
608
|
+
"Expected to produce %d, actually produced %d",
|
|
609
|
+
state.expected_total, final_produced);
|
|
610
|
+
|
|
611
|
+
/* A record can be redelivered if the broker-side acquisition lock
|
|
612
|
+
* expires before an ACCEPT arrives. We distinguish first
|
|
613
|
+
* deliveries (delivery_count == 1) from redeliveries via
|
|
614
|
+
* rd_kafka_message_delivery_count() and assert strict equality on
|
|
615
|
+
* first deliveries — every produced record must have been
|
|
616
|
+
* delivered at least once. Duplicates are tracked separately so a
|
|
617
|
+
* regression in delivery semantics still shows up in the
|
|
618
|
+
* diagnostic output. */
|
|
619
|
+
TEST_ASSERT(final_first_delivery == state.expected_total,
|
|
620
|
+
"Expected %d first-time deliveries, got %d "
|
|
621
|
+
"(consumed=%d, duplicates=%d)",
|
|
622
|
+
state.expected_total, final_first_delivery, final_consumed,
|
|
623
|
+
final_duplicates);
|
|
624
|
+
TEST_ASSERT(!final_failed, "Producer thread reported failure");
|
|
625
|
+
|
|
626
|
+
TEST_SAY("SUCCESS: %s\n", unique_test_name);
|
|
627
|
+
|
|
628
|
+
mtx_destroy(&state.lock);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/***************************************************************************
|
|
632
|
+
* Test Cases - Basic Concurrency
|
|
633
|
+
***************************************************************************/
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* @brief Single producer, single consumer, single topic
|
|
637
|
+
*/
|
|
638
|
+
static void do_test_1p_1c_1t_1part(void) {
|
|
639
|
+
concurrent_test_config_t config = {
|
|
640
|
+
.consumer_cnt = 1,
|
|
641
|
+
.producer_cnt = 1,
|
|
642
|
+
.topic_cnt = 1,
|
|
643
|
+
.partitions = {1},
|
|
644
|
+
.msgs_per_partition = 5000,
|
|
645
|
+
.group_name = "share-conc-1p1c1t1p",
|
|
646
|
+
.test_name = "1 producer, 1 consumer, 1 topic, 1 partition"};
|
|
647
|
+
|
|
648
|
+
SUB_TEST();
|
|
649
|
+
run_concurrent_test(&config);
|
|
650
|
+
|
|
651
|
+
SUB_TEST_PASS();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* @brief Single producer, multiple consumers, single topic
|
|
656
|
+
*/
|
|
657
|
+
static void do_test_1p_4c_1t_4part(void) {
|
|
658
|
+
concurrent_test_config_t config = {
|
|
659
|
+
.consumer_cnt = 4,
|
|
660
|
+
.producer_cnt = 1,
|
|
661
|
+
.topic_cnt = 1,
|
|
662
|
+
.partitions = {4},
|
|
663
|
+
.msgs_per_partition = 5000,
|
|
664
|
+
.group_name = "share-conc-1p4c1t4p",
|
|
665
|
+
.test_name = "1 producer, 4 consumers, 1 topic, 4 partitions"};
|
|
666
|
+
|
|
667
|
+
SUB_TEST();
|
|
668
|
+
run_concurrent_test(&config);
|
|
669
|
+
|
|
670
|
+
SUB_TEST_PASS();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* @brief Multiple producers, single consumer
|
|
675
|
+
*/
|
|
676
|
+
static void do_test_4p_1c_1t_4part(void) {
|
|
677
|
+
concurrent_test_config_t config = {
|
|
678
|
+
.consumer_cnt = 1,
|
|
679
|
+
.producer_cnt = 4,
|
|
680
|
+
.topic_cnt = 1,
|
|
681
|
+
.partitions = {4},
|
|
682
|
+
.msgs_per_partition = 1250,
|
|
683
|
+
.group_name = "share-conc-4p1c1t4p",
|
|
684
|
+
.test_name = "4 producers, 1 consumer, 1 topic, 4 partitions"};
|
|
685
|
+
|
|
686
|
+
SUB_TEST();
|
|
687
|
+
run_concurrent_test(&config);
|
|
688
|
+
|
|
689
|
+
SUB_TEST_PASS();
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* @brief Multiple producers, multiple consumers, single topic
|
|
694
|
+
*/
|
|
695
|
+
static void do_test_4p_4c_1t_4part(void) {
|
|
696
|
+
concurrent_test_config_t config = {
|
|
697
|
+
.consumer_cnt = 4,
|
|
698
|
+
.producer_cnt = 4,
|
|
699
|
+
.topic_cnt = 1,
|
|
700
|
+
.partitions = {4},
|
|
701
|
+
.msgs_per_partition = 5000,
|
|
702
|
+
.group_name = "share-conc-4p4c1t4p",
|
|
703
|
+
.test_name = "4 producers, 4 consumers, 1 topic, 4 partitions"};
|
|
704
|
+
|
|
705
|
+
SUB_TEST();
|
|
706
|
+
run_concurrent_test(&config);
|
|
707
|
+
|
|
708
|
+
SUB_TEST_PASS();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/***************************************************************************
|
|
712
|
+
* Test Cases - Multi-Topic Concurrency
|
|
713
|
+
***************************************************************************/
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* @brief Multiple topics with concurrent access
|
|
717
|
+
*/
|
|
718
|
+
static void do_test_2p_2c_3t_2part(void) {
|
|
719
|
+
concurrent_test_config_t config = {
|
|
720
|
+
.consumer_cnt = 2,
|
|
721
|
+
.producer_cnt = 2,
|
|
722
|
+
.topic_cnt = 3,
|
|
723
|
+
.partitions = {2, 2, 2},
|
|
724
|
+
.msgs_per_partition = 1666,
|
|
725
|
+
.group_name = "share-conc-2p2c3t2p",
|
|
726
|
+
.test_name =
|
|
727
|
+
"2 producers, 2 consumers, 3 topics, 2 partitions each"};
|
|
728
|
+
|
|
729
|
+
SUB_TEST();
|
|
730
|
+
run_concurrent_test(&config);
|
|
731
|
+
|
|
732
|
+
SUB_TEST_PASS();
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* @brief Many topics with single partition each
|
|
737
|
+
*/
|
|
738
|
+
static void do_test_2p_2c_8t_1part(void) {
|
|
739
|
+
concurrent_test_config_t config = {
|
|
740
|
+
.consumer_cnt = 2,
|
|
741
|
+
.producer_cnt = 2,
|
|
742
|
+
.topic_cnt = 8,
|
|
743
|
+
.partitions = {1, 1, 1, 1, 1, 1, 1, 1},
|
|
744
|
+
.msgs_per_partition = 1250,
|
|
745
|
+
.group_name = "share-conc-2p2c8t1p",
|
|
746
|
+
.test_name = "2 producers, 2 consumers, 8 topics, 1 partition each",
|
|
747
|
+
.max_attempts = 150};
|
|
748
|
+
|
|
749
|
+
SUB_TEST();
|
|
750
|
+
run_concurrent_test(&config);
|
|
751
|
+
|
|
752
|
+
SUB_TEST_PASS();
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/***************************************************************************
|
|
756
|
+
* Test Cases - High Contention
|
|
757
|
+
***************************************************************************/
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* @brief Many consumers competing for single partition
|
|
761
|
+
*/
|
|
762
|
+
static void do_test_1p_8c_1t_1part(void) {
|
|
763
|
+
concurrent_test_config_t config = {
|
|
764
|
+
.consumer_cnt = 8,
|
|
765
|
+
.producer_cnt = 1,
|
|
766
|
+
.topic_cnt = 1,
|
|
767
|
+
.partitions = {1},
|
|
768
|
+
.msgs_per_partition = 10000,
|
|
769
|
+
.group_name = "share-conc-1p8c1t1p",
|
|
770
|
+
.test_name =
|
|
771
|
+
"1 producer, 8 consumers, 1 partition (high contention)"};
|
|
772
|
+
|
|
773
|
+
SUB_TEST();
|
|
774
|
+
run_concurrent_test(&config);
|
|
775
|
+
|
|
776
|
+
SUB_TEST_PASS();
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* @brief More consumers than partitions
|
|
781
|
+
*/
|
|
782
|
+
static void do_test_2p_6c_1t_2part(void) {
|
|
783
|
+
concurrent_test_config_t config = {
|
|
784
|
+
.consumer_cnt = 6,
|
|
785
|
+
.producer_cnt = 2,
|
|
786
|
+
.topic_cnt = 1,
|
|
787
|
+
.partitions = {2},
|
|
788
|
+
.msgs_per_partition = 15000,
|
|
789
|
+
.group_name = "share-conc-2p6c1t2p",
|
|
790
|
+
.test_name =
|
|
791
|
+
"2 producers, 6 consumers, 2 partitions (3:1 consumer ratio)"};
|
|
792
|
+
|
|
793
|
+
SUB_TEST();
|
|
794
|
+
run_concurrent_test(&config);
|
|
795
|
+
|
|
796
|
+
SUB_TEST_PASS();
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/***************************************************************************
|
|
800
|
+
* Test Cases - Explicit Acknowledgement
|
|
801
|
+
***************************************************************************/
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* @brief Concurrent with explicit acknowledgement
|
|
805
|
+
*/
|
|
806
|
+
static void do_test_explicit_ack_4p_4c(void) {
|
|
807
|
+
concurrent_test_config_t config = {
|
|
808
|
+
.consumer_cnt = 4,
|
|
809
|
+
.producer_cnt = 4,
|
|
810
|
+
.topic_cnt = 2,
|
|
811
|
+
.partitions = {2, 2},
|
|
812
|
+
.msgs_per_partition = 5000,
|
|
813
|
+
.group_name = "share-conc-explicit-4p4c",
|
|
814
|
+
.test_name = "4 producers, 4 consumers, explicit ack",
|
|
815
|
+
.explicit_ack = rd_true};
|
|
816
|
+
|
|
817
|
+
SUB_TEST();
|
|
818
|
+
run_concurrent_test(&config);
|
|
819
|
+
|
|
820
|
+
SUB_TEST_PASS();
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/***************************************************************************
|
|
824
|
+
* Test Cases - Staggered Start
|
|
825
|
+
***************************************************************************/
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* @brief Consumers start before producers
|
|
829
|
+
*/
|
|
830
|
+
static void do_test_staggered_start(void) {
|
|
831
|
+
concurrent_test_config_t config = {
|
|
832
|
+
.consumer_cnt = 2,
|
|
833
|
+
.producer_cnt = 2,
|
|
834
|
+
.topic_cnt = 1,
|
|
835
|
+
.partitions = {2},
|
|
836
|
+
.msgs_per_partition = 5000,
|
|
837
|
+
.group_name = "share-conc-staggered",
|
|
838
|
+
.test_name = "Staggered start: consumers before producers",
|
|
839
|
+
.staggered_start = rd_true};
|
|
840
|
+
|
|
841
|
+
SUB_TEST();
|
|
842
|
+
run_concurrent_test(&config);
|
|
843
|
+
|
|
844
|
+
SUB_TEST_PASS();
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/***************************************************************************
|
|
848
|
+
* Test Cases - High Volume Stress
|
|
849
|
+
***************************************************************************/
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* @brief High volume concurrent test
|
|
853
|
+
*/
|
|
854
|
+
static void do_test_high_volume_20k(void) {
|
|
855
|
+
concurrent_test_config_t config = {
|
|
856
|
+
.consumer_cnt = 4,
|
|
857
|
+
.producer_cnt = 4,
|
|
858
|
+
.topic_cnt = 1,
|
|
859
|
+
.partitions = {4},
|
|
860
|
+
.msgs_per_partition = 5000,
|
|
861
|
+
.group_name = "share-conc-highvol-20k",
|
|
862
|
+
.test_name = "High volume: 4p x 4c x 20k messages",
|
|
863
|
+
.max_attempts = 150};
|
|
864
|
+
|
|
865
|
+
SUB_TEST();
|
|
866
|
+
run_concurrent_test(&config);
|
|
867
|
+
|
|
868
|
+
SUB_TEST_PASS();
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* @brief High volume with many partitions
|
|
873
|
+
*/
|
|
874
|
+
static void do_test_high_volume_many_partitions(void) {
|
|
875
|
+
concurrent_test_config_t config = {
|
|
876
|
+
.consumer_cnt = 4,
|
|
877
|
+
.producer_cnt = 4,
|
|
878
|
+
.topic_cnt = 1,
|
|
879
|
+
.partitions = {8},
|
|
880
|
+
.msgs_per_partition = 2500,
|
|
881
|
+
.group_name = "share-conc-highvol-8p",
|
|
882
|
+
.test_name = "High volume: 8 partitions x 2.5k messages each",
|
|
883
|
+
.max_attempts = 150};
|
|
884
|
+
|
|
885
|
+
SUB_TEST();
|
|
886
|
+
run_concurrent_test(&config);
|
|
887
|
+
|
|
888
|
+
SUB_TEST_PASS();
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/***************************************************************************
|
|
892
|
+
* Test Cases - Asymmetric Configurations
|
|
893
|
+
***************************************************************************/
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* @brief Many producers, few consumers
|
|
897
|
+
*/
|
|
898
|
+
static void do_test_8p_2c(void) {
|
|
899
|
+
concurrent_test_config_t config = {
|
|
900
|
+
.consumer_cnt = 2,
|
|
901
|
+
.producer_cnt = 8,
|
|
902
|
+
.topic_cnt = 1,
|
|
903
|
+
.partitions = {4},
|
|
904
|
+
.msgs_per_partition = 2500,
|
|
905
|
+
.group_name = "share-conc-8p2c",
|
|
906
|
+
.test_name = "8 producers, 2 consumers (producer heavy)"};
|
|
907
|
+
|
|
908
|
+
SUB_TEST();
|
|
909
|
+
run_concurrent_test(&config);
|
|
910
|
+
|
|
911
|
+
SUB_TEST_PASS();
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* @brief Few producers, many consumers
|
|
916
|
+
*/
|
|
917
|
+
static void do_test_2p_8c(void) {
|
|
918
|
+
concurrent_test_config_t config = {
|
|
919
|
+
.consumer_cnt = 8,
|
|
920
|
+
.producer_cnt = 2,
|
|
921
|
+
.topic_cnt = 1,
|
|
922
|
+
.partitions = {4},
|
|
923
|
+
.msgs_per_partition = 10000,
|
|
924
|
+
.group_name = "share-conc-2p8c",
|
|
925
|
+
.test_name = "2 producers, 8 consumers (consumer heavy)"};
|
|
926
|
+
|
|
927
|
+
SUB_TEST();
|
|
928
|
+
run_concurrent_test(&config);
|
|
929
|
+
|
|
930
|
+
SUB_TEST_PASS();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/***************************************************************************
|
|
934
|
+
* Test Cases - Complex Multi-Topic Multi-Partition
|
|
935
|
+
***************************************************************************/
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* @brief Complex scenario with varied partition counts
|
|
939
|
+
*/
|
|
940
|
+
static void do_test_complex_varied_partitions(void) {
|
|
941
|
+
concurrent_test_config_t config = {
|
|
942
|
+
.consumer_cnt = 4,
|
|
943
|
+
.producer_cnt = 4,
|
|
944
|
+
.topic_cnt = 4,
|
|
945
|
+
.partitions = {1, 2, 3, 4},
|
|
946
|
+
.msgs_per_partition = 2000,
|
|
947
|
+
.group_name = "share-conc-complex-varied",
|
|
948
|
+
.test_name = "4 topics with 1,2,3,4 partitions respectively",
|
|
949
|
+
.max_attempts = 150};
|
|
950
|
+
|
|
951
|
+
SUB_TEST();
|
|
952
|
+
run_concurrent_test(&config);
|
|
953
|
+
|
|
954
|
+
SUB_TEST_PASS();
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* @brief Maximum concurrent scenario
|
|
959
|
+
*/
|
|
960
|
+
static void do_test_max_concurrent(void) {
|
|
961
|
+
concurrent_test_config_t config = {
|
|
962
|
+
.consumer_cnt = MAX_CONSUMERS,
|
|
963
|
+
.producer_cnt = MAX_PRODUCERS,
|
|
964
|
+
.topic_cnt = 4,
|
|
965
|
+
.partitions = {4, 4, 4, 4},
|
|
966
|
+
.msgs_per_partition = 3125,
|
|
967
|
+
.group_name = "share-conc-max",
|
|
968
|
+
.test_name = "Maximum: 10 producers, 10 consumers, 4 topics",
|
|
969
|
+
.max_attempts = 200};
|
|
970
|
+
|
|
971
|
+
SUB_TEST();
|
|
972
|
+
run_concurrent_test(&config);
|
|
973
|
+
|
|
974
|
+
SUB_TEST_PASS();
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/***************************************************************************
|
|
978
|
+
* Test Cases - Slow Consumer/Producer Scenarios
|
|
979
|
+
***************************************************************************/
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* @brief Slow consumers with fast producers
|
|
983
|
+
*/
|
|
984
|
+
static void do_test_slow_consumers(void) {
|
|
985
|
+
concurrent_test_config_t config = {
|
|
986
|
+
.consumer_cnt = 2,
|
|
987
|
+
.producer_cnt = 4,
|
|
988
|
+
.topic_cnt = 1,
|
|
989
|
+
.partitions = {2},
|
|
990
|
+
.msgs_per_partition = 5000,
|
|
991
|
+
.group_name = "share-conc-slow-consumer",
|
|
992
|
+
.test_name = "Fast producers, slow consumers",
|
|
993
|
+
.consumer_delay_ms = 50,
|
|
994
|
+
.max_attempts = 200};
|
|
995
|
+
|
|
996
|
+
SUB_TEST();
|
|
997
|
+
run_concurrent_test(&config);
|
|
998
|
+
|
|
999
|
+
SUB_TEST_PASS();
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* @brief Fast consumers with slow producers
|
|
1004
|
+
*/
|
|
1005
|
+
static void do_test_slow_producers(void) {
|
|
1006
|
+
concurrent_test_config_t config = {
|
|
1007
|
+
.consumer_cnt = 4,
|
|
1008
|
+
.producer_cnt = 2,
|
|
1009
|
+
.topic_cnt = 1,
|
|
1010
|
+
.partitions = {2},
|
|
1011
|
+
.msgs_per_partition = 500,
|
|
1012
|
+
.group_name = "share-conc-slow-producer",
|
|
1013
|
+
.test_name = "Slow producers, fast consumers",
|
|
1014
|
+
.producer_delay_ms = 10000,
|
|
1015
|
+
.max_attempts = 200};
|
|
1016
|
+
|
|
1017
|
+
SUB_TEST();
|
|
1018
|
+
run_concurrent_test(&config);
|
|
1019
|
+
|
|
1020
|
+
SUB_TEST_PASS();
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* @brief Chaos test: consumer churn during sustained production.
|
|
1025
|
+
*
|
|
1026
|
+
* Setup:
|
|
1027
|
+
* - 4 producers in dedicated threads producing fixed total messages.
|
|
1028
|
+
* - Pool of CONSUMER_POOL slots; only ACTIVE_CONSUMERS run concurrently.
|
|
1029
|
+
* - Initially start ACTIVE_CONSUMERS threads.
|
|
1030
|
+
* - For ITERATIONS rounds: sleep ITERATION_MS, then stop a random number
|
|
1031
|
+
* of the currently running consumers (>= 1) and start the same number
|
|
1032
|
+
* of fresh ones from the pool. Old threads are joined at the very end.
|
|
1033
|
+
* - After iterations, drain remaining messages and shut everyone down.
|
|
1034
|
+
*
|
|
1035
|
+
* Invariant for share consumers: every produced record is first-delivered
|
|
1036
|
+
* exactly once. Records that a closing consumer hadn't acked are released
|
|
1037
|
+
* back to the group and re-delivered with delivery_count > 1 (counted as
|
|
1038
|
+
* duplicates, not first deliveries).
|
|
1039
|
+
*/
|
|
1040
|
+
static void do_test_chaos_consumer_lifecycle(rd_bool_t explicit_ack) {
|
|
1041
|
+
concurrent_test_state_t state = {0};
|
|
1042
|
+
const concurrent_test_config_t config = {
|
|
1043
|
+
.consumer_cnt = 4, /* informational; pool size below */
|
|
1044
|
+
.producer_cnt = 4,
|
|
1045
|
+
.topic_cnt = 1,
|
|
1046
|
+
.partitions = {4},
|
|
1047
|
+
.msgs_per_partition = 1000,
|
|
1048
|
+
.group_name = explicit_ack ? "share-chaos-lifecycle-explicit"
|
|
1049
|
+
: "share-chaos-lifecycle-implicit",
|
|
1050
|
+
.test_name = explicit_ack ? "Chaos (explicit ack): consumer "
|
|
1051
|
+
"churn during production"
|
|
1052
|
+
: "Chaos (implicit ack): consumer "
|
|
1053
|
+
"churn during production",
|
|
1054
|
+
.explicit_ack = explicit_ack};
|
|
1055
|
+
const int ACTIVE_CONSUMERS = 4;
|
|
1056
|
+
const int CONSUMER_POOL = 12;
|
|
1057
|
+
const int ITERATIONS = 3;
|
|
1058
|
+
const int ITERATION_MS = 6000;
|
|
1059
|
+
const int join_poll_ticks = 10; /* 10 * 500ms = 5 s */
|
|
1060
|
+
thrd_t producer_threads[MAX_PRODUCERS];
|
|
1061
|
+
thrd_t consumer_threads[MAX_CONSUMER_POOL];
|
|
1062
|
+
consumer_thread_args_t consumer_args[MAX_CONSUMER_POOL];
|
|
1063
|
+
int started_threads = 0;
|
|
1064
|
+
int first_running = 0;
|
|
1065
|
+
int last_running;
|
|
1066
|
+
int t, c, p, iter;
|
|
1067
|
+
int total_partitions = 0;
|
|
1068
|
+
int msgs_per_producer;
|
|
1069
|
+
int wait_attempts;
|
|
1070
|
+
int dangling = 0;
|
|
1071
|
+
int final_produced;
|
|
1072
|
+
int final_first_delivery;
|
|
1073
|
+
int final_duplicates;
|
|
1074
|
+
int final_consumed;
|
|
1075
|
+
rd_bool_t final_failed;
|
|
1076
|
+
rd_kafka_share_t *dummy_consumer;
|
|
1077
|
+
|
|
1078
|
+
SUB_TEST();
|
|
1079
|
+
|
|
1080
|
+
TEST_ASSERT(CONSUMER_POOL <= MAX_CONSUMER_POOL,
|
|
1081
|
+
"CONSUMER_POOL %d > MAX_CONSUMER_POOL", CONSUMER_POOL);
|
|
1082
|
+
TEST_ASSERT(ACTIVE_CONSUMERS <= CONSUMER_POOL, "ACTIVE > POOL");
|
|
1083
|
+
|
|
1084
|
+
TEST_SAY("\n");
|
|
1085
|
+
TEST_SAY(
|
|
1086
|
+
"============================================================\n");
|
|
1087
|
+
TEST_SAY("=== %s ===\n", config.test_name);
|
|
1088
|
+
TEST_SAY(
|
|
1089
|
+
"============================================================\n");
|
|
1090
|
+
TEST_SAY("Active %d, pool %d, iterations %d × %d ms\n",
|
|
1091
|
+
ACTIVE_CONSUMERS, CONSUMER_POOL, ITERATIONS, ITERATION_MS);
|
|
1092
|
+
|
|
1093
|
+
this_test = test_curr;
|
|
1094
|
+
|
|
1095
|
+
/* See note in run_concurrent_test: set these on the main thread
|
|
1096
|
+
* before spawning worker threads to avoid TSAN-flagged races on
|
|
1097
|
+
* the shared test struct that test_curr aliases. */
|
|
1098
|
+
test_curr->exp_dr_status = (rd_kafka_msg_status_t)-1;
|
|
1099
|
+
test_curr->ignore_dr_err = rd_true;
|
|
1100
|
+
|
|
1101
|
+
mtx_init(&state.lock, mtx_plain);
|
|
1102
|
+
state.topic_cnt = config.topic_cnt;
|
|
1103
|
+
state.group_name = config.group_name;
|
|
1104
|
+
state.explicit_ack = config.explicit_ack;
|
|
1105
|
+
state.producers_remaining = config.producer_cnt;
|
|
1106
|
+
|
|
1107
|
+
for (t = 0; t < config.topic_cnt; t++)
|
|
1108
|
+
total_partitions += config.partitions[t];
|
|
1109
|
+
state.expected_total = total_partitions * config.msgs_per_partition;
|
|
1110
|
+
TEST_SAY("Expected messages: %d\n", state.expected_total);
|
|
1111
|
+
|
|
1112
|
+
for (t = 0; t < config.topic_cnt; t++) {
|
|
1113
|
+
rd_snprintf(state.topics[t], sizeof(state.topics[t]), "%s",
|
|
1114
|
+
test_mk_topic_name("0174-chaos", 1));
|
|
1115
|
+
test_create_topic_wait_exists(
|
|
1116
|
+
NULL, state.topics[t], config.partitions[t], -1, 60 * 1000);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/* Apply broker-side group config (auto.offset.reset=earliest) via
|
|
1120
|
+
* a throwaway consumer registration, so the alter sticks before
|
|
1121
|
+
* any chaos worker subscribes. */
|
|
1122
|
+
dummy_consumer = test_create_share_consumer(config.group_name, NULL);
|
|
1123
|
+
test_share_set_auto_offset_reset(config.group_name, "earliest");
|
|
1124
|
+
test_share_consumer_close(dummy_consumer);
|
|
1125
|
+
test_share_destroy(dummy_consumer);
|
|
1126
|
+
|
|
1127
|
+
/* Producer threads */
|
|
1128
|
+
msgs_per_producer = state.expected_total / config.producer_cnt;
|
|
1129
|
+
for (p = 0; p < config.producer_cnt; p++) {
|
|
1130
|
+
producer_thread_args_t *args = rd_calloc(1, sizeof(*args));
|
|
1131
|
+
args->state = &state;
|
|
1132
|
+
args->producer_id = p;
|
|
1133
|
+
args->msgs_to_produce = msgs_per_producer;
|
|
1134
|
+
if (p == config.producer_cnt - 1)
|
|
1135
|
+
args->msgs_to_produce +=
|
|
1136
|
+
state.expected_total % config.producer_cnt;
|
|
1137
|
+
/* Light pacing so production stretches across the chaos
|
|
1138
|
+
* iterations rather than finishing before the first churn. */
|
|
1139
|
+
args->delay_ms = 5;
|
|
1140
|
+
for (t = 0; t < config.topic_cnt; t++)
|
|
1141
|
+
args->partitions[t] = config.partitions[t];
|
|
1142
|
+
|
|
1143
|
+
if (thrd_create(&producer_threads[p], producer_thread_func,
|
|
1144
|
+
args) != thrd_success) {
|
|
1145
|
+
TEST_FAIL("Failed to create producer thread %d", p);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/* Pre-init the entire pool */
|
|
1150
|
+
for (c = 0; c < CONSUMER_POOL; c++) {
|
|
1151
|
+
consumer_args[c].state = &state;
|
|
1152
|
+
consumer_args[c].consumer_id = c;
|
|
1153
|
+
consumer_args[c].run = rd_false;
|
|
1154
|
+
consumer_args[c].done = rd_false;
|
|
1155
|
+
consumer_args[c].poll_delay_ms = 0;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/* Start the initial active set */
|
|
1159
|
+
for (c = 0; c < ACTIVE_CONSUMERS; c++) {
|
|
1160
|
+
mtx_lock(&state.lock);
|
|
1161
|
+
consumer_args[c].run = rd_true;
|
|
1162
|
+
mtx_unlock(&state.lock);
|
|
1163
|
+
if (thrd_create(&consumer_threads[c], consumer_thread_func,
|
|
1164
|
+
&consumer_args[c]) != thrd_success) {
|
|
1165
|
+
TEST_FAIL(
|
|
1166
|
+
"Failed to create initial consumer "
|
|
1167
|
+
"thread %d",
|
|
1168
|
+
c);
|
|
1169
|
+
}
|
|
1170
|
+
started_threads++;
|
|
1171
|
+
}
|
|
1172
|
+
last_running = ACTIVE_CONSUMERS - 1;
|
|
1173
|
+
|
|
1174
|
+
srand((unsigned int)time(NULL));
|
|
1175
|
+
|
|
1176
|
+
for (iter = 0; iter < ITERATIONS; iter++) {
|
|
1177
|
+
int running;
|
|
1178
|
+
int churn;
|
|
1179
|
+
int can_start;
|
|
1180
|
+
int s;
|
|
1181
|
+
|
|
1182
|
+
TEST_SAY("--- Iteration %d/%d: sleeping %d ms ---\n", iter + 1,
|
|
1183
|
+
ITERATIONS, ITERATION_MS);
|
|
1184
|
+
rd_usleep(ITERATION_MS * 1000, NULL);
|
|
1185
|
+
|
|
1186
|
+
running = last_running - first_running + 1;
|
|
1187
|
+
/* Stop at least 1, at most floor(running/2) for stability */
|
|
1188
|
+
churn = (running > 1) ? (rand() % ((running / 2) + 1) + 1) : 1;
|
|
1189
|
+
TEST_SAY("Iteration %d: stopping %d/%d running consumers\n",
|
|
1190
|
+
iter + 1, churn, running);
|
|
1191
|
+
|
|
1192
|
+
mtx_lock(&state.lock);
|
|
1193
|
+
for (s = 0; s < churn && first_running <= last_running;
|
|
1194
|
+
s++, first_running++) {
|
|
1195
|
+
consumer_args[first_running].run = rd_false;
|
|
1196
|
+
}
|
|
1197
|
+
mtx_unlock(&state.lock);
|
|
1198
|
+
|
|
1199
|
+
/* Replenish with new pool slots (don't reuse stopped slots) */
|
|
1200
|
+
can_start = CONSUMER_POOL - started_threads;
|
|
1201
|
+
if (can_start <= 0) {
|
|
1202
|
+
TEST_SAY(
|
|
1203
|
+
"Pool exhausted (%d threads spawned); no more "
|
|
1204
|
+
"starts this iteration\n",
|
|
1205
|
+
started_threads);
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
if (churn > can_start)
|
|
1209
|
+
churn = can_start;
|
|
1210
|
+
|
|
1211
|
+
TEST_SAY("Iteration %d: starting %d fresh consumers\n",
|
|
1212
|
+
iter + 1, churn);
|
|
1213
|
+
|
|
1214
|
+
for (s = 0; s < churn; s++) {
|
|
1215
|
+
int idx = started_threads;
|
|
1216
|
+
if (idx >= CONSUMER_POOL)
|
|
1217
|
+
break;
|
|
1218
|
+
mtx_lock(&state.lock);
|
|
1219
|
+
consumer_args[idx].run = rd_true;
|
|
1220
|
+
mtx_unlock(&state.lock);
|
|
1221
|
+
if (thrd_create(&consumer_threads[idx],
|
|
1222
|
+
consumer_thread_func,
|
|
1223
|
+
&consumer_args[idx]) != thrd_success) {
|
|
1224
|
+
TEST_FAIL(
|
|
1225
|
+
"Failed to create chaos consumer "
|
|
1226
|
+
"thread %d",
|
|
1227
|
+
idx);
|
|
1228
|
+
}
|
|
1229
|
+
started_threads++;
|
|
1230
|
+
last_running = idx;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
TEST_SAY(
|
|
1235
|
+
"Iterations done; waiting for production to drain, then "
|
|
1236
|
+
"shutting down consumers\n");
|
|
1237
|
+
|
|
1238
|
+
/* Drain loop, bounded so we don't sit for minutes on a stuck
|
|
1239
|
+
* test:
|
|
1240
|
+
* - 60 ticks of 500 ms = 30 s absolute cap
|
|
1241
|
+
* - early exit when producers_done AND first_delivery has not
|
|
1242
|
+
* advanced for 10 consecutive ticks (~5 s of no progress).
|
|
1243
|
+
* If the chaos test has stalled, we report and move on
|
|
1244
|
+
* rather than waiting for the full window. */
|
|
1245
|
+
wait_attempts = 60; /* ~30 seconds absolute cap */
|
|
1246
|
+
int prev_first_seen = -1;
|
|
1247
|
+
int stale_ticks = 0;
|
|
1248
|
+
const int stale_limit = 10; /* ~5 s with no progress */
|
|
1249
|
+
|
|
1250
|
+
while (wait_attempts-- > 0) {
|
|
1251
|
+
int first_seen;
|
|
1252
|
+
rd_bool_t producers_done;
|
|
1253
|
+
|
|
1254
|
+
mtx_lock(&state.lock);
|
|
1255
|
+
first_seen = state.total_first_delivery;
|
|
1256
|
+
producers_done = state.producers_done;
|
|
1257
|
+
mtx_unlock(&state.lock);
|
|
1258
|
+
|
|
1259
|
+
if (producers_done && first_seen >= state.expected_total)
|
|
1260
|
+
break;
|
|
1261
|
+
|
|
1262
|
+
if (first_seen == prev_first_seen) {
|
|
1263
|
+
stale_ticks++;
|
|
1264
|
+
if (producers_done && stale_ticks >= stale_limit) {
|
|
1265
|
+
TEST_SAY(
|
|
1266
|
+
"Drain: no progress for "
|
|
1267
|
+
"~%d s after producers done; "
|
|
1268
|
+
"exiting at %d/%d "
|
|
1269
|
+
"(test will fail in assertion)\n",
|
|
1270
|
+
stale_ticks / 2, first_seen,
|
|
1271
|
+
state.expected_total);
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
} else {
|
|
1275
|
+
stale_ticks = 0;
|
|
1276
|
+
prev_first_seen = first_seen;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (wait_attempts % 10 == 0)
|
|
1280
|
+
TEST_SAY(
|
|
1281
|
+
"Drain: %d/%d first deliveries "
|
|
1282
|
+
"(producers_done=%d)\n",
|
|
1283
|
+
first_seen, state.expected_total,
|
|
1284
|
+
(int)producers_done);
|
|
1285
|
+
|
|
1286
|
+
rd_usleep(500 * 1000, NULL);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/* Join producers - these always exit cleanly so a hard join is
|
|
1290
|
+
* safe. */
|
|
1291
|
+
for (p = 0; p < config.producer_cnt; p++)
|
|
1292
|
+
thrd_join(producer_threads[p], NULL);
|
|
1293
|
+
|
|
1294
|
+
/* Stop all consumer threads. */
|
|
1295
|
+
mtx_lock(&state.lock);
|
|
1296
|
+
for (c = 0; c < started_threads; c++)
|
|
1297
|
+
consumer_args[c].run = rd_false;
|
|
1298
|
+
mtx_unlock(&state.lock);
|
|
1299
|
+
|
|
1300
|
+
/* Bounded wait for consumers to exit cleanly. A wedged consumer
|
|
1301
|
+
* (eg blocked inside consume_batch waiting on a stale share
|
|
1302
|
+
* session) won't return from rd_kafka_share_consumer_close, so
|
|
1303
|
+
* thrd_join would block indefinitely. We poll each consumer's
|
|
1304
|
+
* done flag for up to ~5 s; any thread that hasn't set it by
|
|
1305
|
+
* then is left dangling for the OS to reclaim at process exit
|
|
1306
|
+
* and we move straight to the assertions. This matters only
|
|
1307
|
+
* when the test is failing — once the underlying librdkafka
|
|
1308
|
+
* issue is fixed, every consumer thread reaches its `done = true`
|
|
1309
|
+
* within tens of milliseconds. */
|
|
1310
|
+
for (c = 0; c < started_threads; c++) {
|
|
1311
|
+
rd_bool_t done = rd_false;
|
|
1312
|
+
for (t = 0; t < join_poll_ticks; t++) {
|
|
1313
|
+
mtx_lock(&state.lock);
|
|
1314
|
+
done = consumer_args[c].done;
|
|
1315
|
+
mtx_unlock(&state.lock);
|
|
1316
|
+
if (done)
|
|
1317
|
+
break;
|
|
1318
|
+
rd_usleep(500 * 1000, NULL);
|
|
1319
|
+
}
|
|
1320
|
+
if (done) {
|
|
1321
|
+
thrd_join(consumer_threads[c], NULL);
|
|
1322
|
+
} else {
|
|
1323
|
+
/* Detach so the C runtime won't leak the
|
|
1324
|
+
* thrd_t handle when the process exits;
|
|
1325
|
+
* the OS will tear down the still-running
|
|
1326
|
+
* thread when the process terminates. */
|
|
1327
|
+
thrd_detach(consumer_threads[c]);
|
|
1328
|
+
dangling++;
|
|
1329
|
+
TEST_SAY(
|
|
1330
|
+
"Consumer thread %d: did not exit within "
|
|
1331
|
+
"5 s of stop signal — detaching and "
|
|
1332
|
+
"proceeding (likely wedged inside "
|
|
1333
|
+
"librdkafka close path)\n",
|
|
1334
|
+
consumer_args[c].consumer_id);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
if (dangling > 0)
|
|
1339
|
+
TEST_SAY(
|
|
1340
|
+
"WARNING: %d/%d consumer thread(s) left "
|
|
1341
|
+
"dangling at test exit\n",
|
|
1342
|
+
dangling, started_threads);
|
|
1343
|
+
|
|
1344
|
+
mtx_lock(&state.lock);
|
|
1345
|
+
final_produced = state.total_produced;
|
|
1346
|
+
final_first_delivery = state.total_first_delivery;
|
|
1347
|
+
final_duplicates = state.total_duplicates;
|
|
1348
|
+
final_consumed = state.total_consumed;
|
|
1349
|
+
final_failed = state.test_failed;
|
|
1350
|
+
mtx_unlock(&state.lock);
|
|
1351
|
+
|
|
1352
|
+
TEST_SAY(
|
|
1353
|
+
"Chaos final: produced=%d, consumed=%d (first=%d, dup=%d), "
|
|
1354
|
+
"expected=%d, threads spawned=%d\n",
|
|
1355
|
+
final_produced, final_consumed, final_first_delivery,
|
|
1356
|
+
final_duplicates, state.expected_total, started_threads);
|
|
1357
|
+
|
|
1358
|
+
TEST_ASSERT(final_produced == state.expected_total,
|
|
1359
|
+
"Expected to produce %d, actually produced %d",
|
|
1360
|
+
state.expected_total, final_produced);
|
|
1361
|
+
TEST_ASSERT(final_first_delivery == state.expected_total,
|
|
1362
|
+
"Expected %d first-time deliveries, got %d "
|
|
1363
|
+
"(consumed=%d, duplicates=%d)",
|
|
1364
|
+
state.expected_total, final_first_delivery, final_consumed,
|
|
1365
|
+
final_duplicates);
|
|
1366
|
+
TEST_ASSERT(!final_failed, "Producer thread reported failure");
|
|
1367
|
+
TEST_SAY(
|
|
1368
|
+
"SUCCESS: chaos test - %d threads churned, "
|
|
1369
|
+
"every record first-delivered exactly once\n",
|
|
1370
|
+
started_threads);
|
|
1371
|
+
|
|
1372
|
+
mtx_destroy(&state.lock);
|
|
1373
|
+
|
|
1374
|
+
SUB_TEST_PASS();
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
/***************************************************************************
|
|
1379
|
+
* Main Entry Point
|
|
1380
|
+
***************************************************************************/
|
|
1381
|
+
|
|
1382
|
+
int main_0174_share_consumer_concurrency(int argc, char **argv) {
|
|
1383
|
+
|
|
1384
|
+
test_timeout_set(1500);
|
|
1385
|
+
|
|
1386
|
+
/* Every test below runs producers AND consumers in dedicated
|
|
1387
|
+
* threads via run_concurrent_test(). There is no main-thread
|
|
1388
|
+
* polling — consumer_thread_func handles the poll loop per
|
|
1389
|
+
* consumer. */
|
|
1390
|
+
|
|
1391
|
+
/* Basic concurrency tests */
|
|
1392
|
+
do_test_1p_1c_1t_1part(); /* Baseline: 1 producer, 1 consumer */
|
|
1393
|
+
do_test_1p_4c_1t_4part(); /* Fan out: 1 producer, 4 consumers */
|
|
1394
|
+
do_test_4p_1c_1t_4part(); /* Fan in: 4 producers, 1 consumer */
|
|
1395
|
+
do_test_4p_4c_1t_4part(); /* Symmetric: 4 producers, 4 consumers */
|
|
1396
|
+
|
|
1397
|
+
/* Multi-topic tests */
|
|
1398
|
+
do_test_2p_2c_3t_2part(); /* Multiple topics */
|
|
1399
|
+
do_test_2p_2c_8t_1part(); /* Many topics */
|
|
1400
|
+
|
|
1401
|
+
/* High contention tests */
|
|
1402
|
+
do_test_1p_8c_1t_1part(); /* Many consumers, 1 partition */
|
|
1403
|
+
do_test_2p_6c_1t_2part(); /* More consumers than partitions */
|
|
1404
|
+
|
|
1405
|
+
/* Explicit acknowledgement */
|
|
1406
|
+
do_test_explicit_ack_4p_4c();
|
|
1407
|
+
|
|
1408
|
+
/* Staggered start */
|
|
1409
|
+
do_test_staggered_start();
|
|
1410
|
+
|
|
1411
|
+
/* High volume stress tests */
|
|
1412
|
+
do_test_high_volume_20k();
|
|
1413
|
+
do_test_high_volume_many_partitions();
|
|
1414
|
+
|
|
1415
|
+
/* Asymmetric configurations */
|
|
1416
|
+
do_test_8p_2c(); /* Producer heavy */
|
|
1417
|
+
do_test_2p_8c(); /* Consumer heavy */
|
|
1418
|
+
|
|
1419
|
+
/* Complex scenarios */
|
|
1420
|
+
do_test_complex_varied_partitions();
|
|
1421
|
+
do_test_max_concurrent();
|
|
1422
|
+
|
|
1423
|
+
/* Slow consumer/producer scenarios */
|
|
1424
|
+
do_test_slow_consumers();
|
|
1425
|
+
do_test_slow_producers();
|
|
1426
|
+
|
|
1427
|
+
/* Chaos test: consumer lifecycle churn during sustained production.
|
|
1428
|
+
* Run once with explicit acknowledgement and once with implicit
|
|
1429
|
+
* acknowledgement to cover both ack flows under churn. */
|
|
1430
|
+
do_test_chaos_consumer_lifecycle(rd_true);
|
|
1431
|
+
do_test_chaos_consumer_lifecycle(rd_false);
|
|
1432
|
+
|
|
1433
|
+
return 0;
|
|
1434
|
+
}
|