-
Notifications
You must be signed in to change notification settings - Fork 957
[NOGIL] Fix Producer.close() races with concurrent calls and with itself #2313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev_thread_free_support
Are you sure you want to change the base?
Changes from all commits
db3c515
3bc5ed9
24e926c
b9118ac
85f31c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -27,6 +27,12 @@ | |||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| #include "confluent_kafka.h" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| #ifdef _WIN32 | ||||||||||||||||||||||||||||||||
| #include <windows.h> | ||||||||||||||||||||||||||||||||
| #else | ||||||||||||||||||||||||||||||||
| #include <unistd.h> | ||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * @brief KNOWN ISSUES | ||||||||||||||||||||||||||||||||
|
|
@@ -296,12 +302,11 @@ | |||||||||||||||||||||||||||||||
| if (!dr_cb || dr_cb == Py_None) | ||||||||||||||||||||||||||||||||
| dr_cb = self->u.Producer.default_dr_cb; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) { | ||||||||||||||||||||||||||||||||
| #ifdef RD_KAFKA_V_HEADERS | ||||||||||||||||||||||||||||||||
| if (rd_headers) | ||||||||||||||||||||||||||||||||
| rd_kafka_headers_destroy(rd_headers); | ||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -323,6 +328,8 @@ | |||||||||||||||||||||||||||||||
| key_len, msgstate); | ||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err) { | ||||||||||||||||||||||||||||||||
| if (msgstate) | ||||||||||||||||||||||||||||||||
| Producer_msgstate_destroy(msgstate); | ||||||||||||||||||||||||||||||||
|
|
@@ -421,12 +428,13 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|d", kws, &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| r = Producer_poll0(self, cfl_timeout_ms(tmout)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (r == -1) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -469,10 +477,8 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|d", kws, &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| total_timeout_ms = cfl_timeout_ms(tmout); | ||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
|
|
@@ -507,6 +513,7 @@ | |||||||||||||||||||||||||||||||
| * interruptibility) */ | ||||||||||||||||||||||||||||||||
| chunk_count++; | ||||||||||||||||||||||||||||||||
| if (check_signals_between_chunks(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| return NULL; /* Signal detected */ | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -524,12 +531,16 @@ | |||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) | ||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err) /* Get the queue length on error (timeout) */ | ||||||||||||||||||||||||||||||||
| qlen = rd_kafka_outq_len(self->rk); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return cfl_PyInt_FromInt(qlen); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -542,6 +553,37 @@ | |||||||||||||||||||||||||||||||
| if (!self->rk) | ||||||||||||||||||||||||||||||||
| Py_RETURN_TRUE; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Only one concurrent close() can destroy rk, otherwise, | ||||||||||||||||||||||||||||||||
| * two threads could both reach rd_kafka_destroy() on the | ||||||||||||||||||||||||||||||||
| * same handle (a double-free). The losing thread(s) wait for the | ||||||||||||||||||||||||||||||||
| * winner to finish and then return True, same as a normal close(), | ||||||||||||||||||||||||||||||||
| * rather than racing it. */ | ||||||||||||||||||||||||||||||||
| if (!atomic_int_cas(&self->closing, 0, 1)) { | ||||||||||||||||||||||||||||||||
| while (self->rk) { | ||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
| #ifdef _WIN32 | ||||||||||||||||||||||||||||||||
| Sleep(100); | ||||||||||||||||||||||||||||||||
| #else | ||||||||||||||||||||||||||||||||
| usleep(100000); | ||||||||||||||||||||||||||||||||
|
Check warning on line 567 in src/confluent_kafka/src/Producer.c
|
||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
| CallState_end(self, &cs); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| Py_RETURN_TRUE; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Signal in-flight calls to stop, and wait for them to finish | ||||||||||||||||||||||||||||||||
| * using self->rk before destroying it -- see Handle_enter_rk_use(). | ||||||||||||||||||||||||||||||||
| * New calls will see `closing` and fail with ERR_MSG_PRODUCER_CLOSED. */ | ||||||||||||||||||||||||||||||||
| while (atomic_int_get(&self->active_calls) > 0) { | ||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
| #ifdef _WIN32 | ||||||||||||||||||||||||||||||||
| Sleep(100); | ||||||||||||||||||||||||||||||||
| #else | ||||||||||||||||||||||||||||||||
| usleep(100000); | ||||||||||||||||||||||||||||||||
|
Check warning on line 582 in src/confluent_kafka/src/Producer.c
|
||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
| CallState_end(self, &cs); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Flush any pending messages (wait indefinitely to ensure delivery) */ | ||||||||||||||||||||||||||||||||
|
|
@@ -817,10 +859,8 @@ | |||||||||||||||||||||||||||||||
| return cfl_PyInt_FromInt(0); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Allocate arrays for librdkafka messages and msgstates */ | ||||||||||||||||||||||||||||||||
| rkmessages = calloc(message_cnt, sizeof(*rkmessages)); | ||||||||||||||||||||||||||||||||
|
|
@@ -849,6 +889,8 @@ | |||||||||||||||||||||||||||||||
| messages_list, rkt, partition, rkmessages, msgstates, message_cnt); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| cleanup: | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Cleanup resources */ | ||||||||||||||||||||||||||||||||
| if (rkt) | ||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A concurrent close() frees rk, and rd_kafka_topic_destroy will use rkt->rkt_rk. Can this cause concurrency bug? |
||||||||||||||||||||||||||||||||
| rd_kafka_topic_destroy(rkt); | ||||||||||||||||||||||||||||||||
|
|
@@ -871,21 +913,22 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTuple(args, "|d", &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| error = rd_kafka_init_transactions(self->rk, cfl_timeout_ms(tmout)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| if (error) /* Ignore error in favour of callstate exception */ | ||||||||||||||||||||||||||||||||
| rd_kafka_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_from_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
@@ -897,13 +940,13 @@ | |||||||||||||||||||||||||||||||
| static PyObject *Producer_begin_transaction(Handle *self) { | ||||||||||||||||||||||||||||||||
| rd_kafka_error_t *error; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| error = rd_kafka_begin_transaction(self->rk); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_from_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
@@ -924,16 +967,17 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTuple(args, "OO|d", &offsets, &metadata, &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!(c_offsets = py_to_c_parts(offsets))) | ||||||||||||||||||||||||||||||||
| if (!(c_offsets = py_to_c_parts(offsets))) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Earch exist branch calls Handle_exit_rk_use. Wondering if we could use "goto exit:" semantics to future proof codebase from "new branch missing Handle_exit_rk_use calls" bugs? Eg. go to pattern is used in other parts of codebase confluent-kafka-python/src/confluent_kafka/src/Producer.c Lines 891 to 905 in 85f31c7
|
||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!(cgmd = py_to_c_cgmd(metadata))) { | ||||||||||||||||||||||||||||||||
| rd_kafka_topic_partition_list_destroy(c_offsets); | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -946,11 +990,14 @@ | |||||||||||||||||||||||||||||||
| rd_kafka_topic_partition_list_destroy(c_offsets); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| if (error) /* Ignore error in favour of callstate exception */ | ||||||||||||||||||||||||||||||||
| rd_kafka_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_from_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
@@ -967,21 +1014,22 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTuple(args, "|d", &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| error = rd_kafka_commit_transaction(self->rk, cfl_timeout_ms(tmout)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| if (error) /* Ignore error in favour of callstate exception */ | ||||||||||||||||||||||||||||||||
| rd_kafka_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_from_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
@@ -998,21 +1046,22 @@ | |||||||||||||||||||||||||||||||
| if (!PyArg_ParseTuple(args, "|d", &tmout)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| CallState_begin(self, &cs); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| error = rd_kafka_abort_transaction(self->rk, cfl_timeout_ms(tmout)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!CallState_end(self, &cs)) { | ||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
| if (error) /* Ignore error in favour of callstate exception */ | ||||||||||||||||||||||||||||||||
| rd_kafka_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_from_error_destroy(error); | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
@@ -1034,10 +1083,8 @@ | |||||||||||||||||||||||||||||||
| &in_flight, &blocking)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!self->rk) { | ||||||||||||||||||||||||||||||||
| PyErr_SetString(PyExc_RuntimeError, ERR_MSG_PRODUCER_CLOSED); | ||||||||||||||||||||||||||||||||
| if (!Handle_enter_rk_use(self)) | ||||||||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (in_queue) | ||||||||||||||||||||||||||||||||
| purge_strategy = RD_KAFKA_PURGE_F_QUEUE; | ||||||||||||||||||||||||||||||||
|
|
@@ -1048,6 +1095,8 @@ | |||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| err = rd_kafka_purge(self->rk, purge_strategy); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Handle_exit_rk_use(self); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err) { | ||||||||||||||||||||||||||||||||
| cfl_PyErr_Format(err, "Purge failed: %s", | ||||||||||||||||||||||||||||||||
| rd_kafka_err2str(err)); | ||||||||||||||||||||||||||||||||
|
|
@@ -1403,9 +1452,23 @@ | |||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| static Py_ssize_t Producer__len__(Handle *self) { | ||||||||||||||||||||||||||||||||
| if (!self->rk) | ||||||||||||||||||||||||||||||||
| Py_ssize_t len; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* __len__ must never raise, so we can't use Handle_enter_rk_use() | ||||||||||||||||||||||||||||||||
| * (which sets an exception on failure) -- fall back to returning 0, | ||||||||||||||||||||||||||||||||
| * , if the Handle is closed/closing. */ | ||||||||||||||||||||||||||||||||
| if (atomic_int_get(&self->closing) || !self->rk) | ||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||
| atomic_int_inc(&self->active_calls); | ||||||||||||||||||||||||||||||||
| if (atomic_int_get(&self->closing) || !self->rk) { | ||||||||||||||||||||||||||||||||
| atomic_int_dec(&self->active_calls); | ||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||
| return rd_kafka_outq_len(self->rk); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| len = rd_kafka_outq_len(self->rk); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| atomic_int_dec(&self->active_calls); | ||||||||||||||||||||||||||||||||
| return len; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CallState_end returns 0 when PyErr_CheckSignals() fired or a callback crashed — and it leaves a Python exception set.
Should we check return value of this?