remove deadlock from sender (#18438)
* remove deadlock from sender * rrdpush_sender_thread_close_socket() takes sender state as param
Costa Tsaousis committed
Aug 29, 2024 at 19:36 UTC
3465ff45c69fbd86e474020dea79c7ae7f04de67
4 files changed
+72
-82
src/streaming/sender.c
+51
-64
@@ -130,22 +130,14 @@ void rrdpush_sender_after_connect(RRDHOST *host) {
130
rrdpush_sender_thread_send_custom_host_variables(host);
131
}
132
133
-void rrdpush_sender_disconnect_and_cleanup(RRDHOST *host) {
134
- rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
135
-
136
- rrdpush_sender_thread_close_socket(host);
137
-
133
+static void rrdpush_sender_on_disconnect(RRDHOST *host) {
134
// we have been connected to this parent - let's cleanup
135
140
- // do not flush the circular buffer here
141
- // this function is called sometimes with the sender lock, sometimes without the lock
142
-
136
rrdpush_sender_charts_and_replication_reset(host);
137
138
// clear the parent's claim id
139
rrdpush_sender_clear_parent_claim_id(host);
140
rrdpush_receiver_send_node_and_claim_id_to_child(host);
148
-
141
stream_path_parent_disconnected(host);
142
}
143
@@ -179,7 +171,7 @@ static ssize_t attempt_to_send(struct sender_state *s) {
171
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SEND_ERROR);
172
netdata_log_debug(D_STREAM, "STREAM: Send failed - closing socket...");
173
netdata_log_error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", rrdhost_hostname(s->host), s->connected_to, s->sent_bytes_on_this_connection);
182
- rrdpush_sender_disconnect_and_cleanup(s->host);
174
+ rrdpush_sender_thread_close_socket(s);
175
}
176
else
177
netdata_log_debug(D_STREAM, "STREAM: send() returned 0 -> no error but no transmission");
@@ -217,16 +209,11 @@ static ssize_t attempt_read(struct sender_state *s) {
209
netdata_log_error("STREAM %s [send to %s]: error during receive (%zd) - closing connection.", rrdhost_hostname(s->host), s->connected_to, ret);
210
}
211
220
- rrdpush_sender_disconnect_and_cleanup(s->host);
212
+ rrdpush_sender_thread_close_socket(s);
213
214
return ret;
215
}
216
225
-struct rrdpush_sender_thread_data {
226
- RRDHOST *host;
227
- char *pipe_buffer;
228
-};
229
-
217
static bool rrdpush_sender_pipe_close(RRDHOST *host, int *pipe_fds, bool reopen) {
218
static netdata_mutex_t mutex = NETDATA_MUTEX_INITIALIZER;
219
@@ -354,38 +341,6 @@ static bool rrdhost_sender_should_exit(struct sender_state *s) {
341
return false;
342
}
343
357
-static void rrdpush_sender_thread_cleanup_callback(void *pptr) {
358
- struct rrdpush_sender_thread_data *s = CLEANUP_FUNCTION_GET_PTR(pptr);
359
- if(!s) return;
360
-
361
- worker_unregister();
362
-
363
- RRDHOST *host = s->host;
364
-
365
- sender_lock(host->sender);
366
- netdata_log_info("STREAM %s [send]: sending thread exits %s",
367
- rrdhost_hostname(host),
368
- host->sender->exit.reason != STREAM_HANDSHAKE_NEVER ? stream_handshake_error_to_string(host->sender->exit.reason) : "");
369
-
370
- rrdpush_sender_disconnect_and_cleanup(host);
371
- rrdpush_sender_pipe_close(host, host->sender->rrdpush_sender_pipe, false);
372
- rrdpush_sender_execute_commands_cleanup(host->sender);
373
-
374
- rrdhost_clear_sender___while_having_sender_mutex(host);
375
-
376
-#ifdef NETDATA_LOG_STREAM_SENDER
377
- if(host->sender->stream_log_fp) {
378
- fclose(host->sender->stream_log_fp);
379
- host->sender->stream_log_fp = NULL;
380
- }
381
-#endif
382
-
383
- sender_unlock(host->sender);
384
-
385
- freez(s->pipe_buffer);
386
- freez(s);
387
-}
388
-
344
void rrdpush_initialize_ssl_ctx(RRDHOST *host __maybe_unused) {
345
static SPINLOCK sp = NETDATA_SPINLOCK_INITIALIZER;
346
spinlock_lock(&sp);
@@ -546,12 +501,9 @@ void *rrdpush_sender_thread(void *ptr) {
501
return NULL;
502
}
503
549
- struct rrdpush_sender_thread_data *thread_data = callocz(1, sizeof(struct rrdpush_sender_thread_data));
550
- thread_data->pipe_buffer = mallocz(pipe_buffer_size);
551
- thread_data->host = s->host;
552
-
553
- CLEANUP_FUNCTION_REGISTER(rrdpush_sender_thread_cleanup_callback) cleanup_ptr = thread_data;
504
+ char *pipe_buffer = mallocz(pipe_buffer_size);
505
506
+ bool was_connected = false;
507
size_t iterations = 0;
508
time_t now_s = now_monotonic_sec();
509
while(!rrdhost_sender_should_exit(s)) {
@@ -559,6 +511,11 @@ void *rrdpush_sender_thread(void *ptr) {
511
512
// The connection attempt blocks (after which we use the socket in nonblocking)
513
if(unlikely(s->rrdpush_sender_socket == -1)) {
514
+ if(was_connected) {
515
+ rrdpush_sender_on_disconnect(s->host);
516
+ was_connected = false;
517
+ }
518
+
519
worker_is_busy(WORKER_SENDER_JOB_CONNECT);
520
521
now_s = now_monotonic_sec();
@@ -583,6 +540,7 @@ void *rrdpush_sender_thread(void *ptr) {
540
rrdpush_send_host_labels(s->host);
541
rrdpush_send_global_functions(s->host);
542
s->replication.oldest_request_after_t = 0;
543
+ was_connected = true;
544
545
rrdhost_flag_set(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
546
@@ -603,7 +561,7 @@ void *rrdpush_sender_thread(void *ptr) {
561
)) {
562
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
563
netdata_log_error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection via %zu send attempts.", rrdhost_hostname(s->host), s->connected_to, s->timeout, s->sent_bytes_on_this_connection, s->send_attempts);
606
- rrdpush_sender_disconnect_and_cleanup(s->host);
564
+ rrdpush_sender_thread_close_socket(s);
565
continue;
566
}
567
@@ -632,9 +590,9 @@ void *rrdpush_sender_thread(void *ptr) {
590
591
if(unlikely(s->rrdpush_sender_pipe[PIPE_READ] == -1)) {
592
if(!rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, true)) {
635
- netdata_log_error("STREAM %s [send]: cannot create inter-thread communication pipe. Disabling streaming.",
636
- rrdhost_hostname(s->host));
637
- rrdpush_sender_disconnect_and_cleanup(s->host);
593
+ netdata_log_error("STREAM %s [send]: cannot create inter-thread communication pipe. "
594
+ "Disabling streaming.", rrdhost_hostname(s->host));
595
+ rrdpush_sender_thread_close_socket(s);
596
break;
597
}
598
}
@@ -685,7 +643,7 @@ void *rrdpush_sender_thread(void *ptr) {
643
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_POLL_ERROR);
644
netdata_log_error("STREAM %s [send to %s]: failed to poll(). Closing socket.", rrdhost_hostname(s->host), s->connected_to);
645
rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, true);
688
- rrdpush_sender_disconnect_and_cleanup(s->host);
646
+ rrdpush_sender_thread_close_socket(s);
647
continue;
648
}
649
@@ -704,7 +662,7 @@ void *rrdpush_sender_thread(void *ptr) {
662
worker_is_busy(WORKER_SENDER_JOB_PIPE_READ);
663
netdata_log_debug(D_STREAM, "STREAM: Data added to send buffer (current buffer chunk %zu bytes)...", outstanding);
664
707
- if (read(fds[Collector].fd, thread_data->pipe_buffer, pipe_buffer_size) == -1)
665
+ if (read(fds[Collector].fd, pipe_buffer, pipe_buffer_size) == -1)
666
netdata_log_error("STREAM %s [send to %s]: cannot read from internal pipe.", rrdhost_hostname(s->host), s->connected_to);
667
}
668
@@ -734,7 +692,7 @@ void *rrdpush_sender_thread(void *ptr) {
692
if(error) {
693
rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, true);
694
netdata_log_error("STREAM %s [send to %s]: restarting internal pipe: %s.",
737
- rrdhost_hostname(s->host), s->connected_to, error);
695
+ rrdhost_hostname(s->host), s->connected_to, error);
696
}
697
}
698
@@ -751,8 +709,8 @@ void *rrdpush_sender_thread(void *ptr) {
709
if(unlikely(error)) {
710
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SOCKET_ERROR);
711
netdata_log_error("STREAM %s [send to %s]: restarting connection: %s - %zu bytes transmitted.",
754
- rrdhost_hostname(s->host), s->connected_to, error, s->sent_bytes_on_this_connection);
755
- rrdpush_sender_disconnect_and_cleanup(s->host);
712
+ rrdhost_hostname(s->host), s->connected_to, error, s->sent_bytes_on_this_connection);
713
+ rrdpush_sender_thread_close_socket(s);
714
}
715
}
716
@@ -761,12 +719,41 @@ void *rrdpush_sender_thread(void *ptr) {
719
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_OVERFLOW);
720
errno_clear();
721
netdata_log_error("STREAM %s [send to %s]: buffer full (allocated %zu bytes) after sending %zu bytes. Restarting connection",
764
- rrdhost_hostname(s->host), s->connected_to, s->buffer->size, s->sent_bytes_on_this_connection);
765
- rrdpush_sender_disconnect_and_cleanup(s->host);
722
+ rrdhost_hostname(s->host), s->connected_to, s->buffer->size, s->sent_bytes_on_this_connection);
723
+ rrdpush_sender_thread_close_socket(s);
724
}
725
726
worker_set_metric(WORKER_SENDER_JOB_REPLAY_DICT_SIZE, (NETDATA_DOUBLE) dictionary_entries(s->replication.requests));
727
}
728
729
+ if(was_connected)
730
+ rrdpush_sender_on_disconnect(s->host);
731
+
732
+ netdata_log_info("STREAM %s [send]: sending thread exits %s",
733
+ rrdhost_hostname(s->host),
734
+ s->host->sender->exit.reason != STREAM_HANDSHAKE_NEVER ? stream_handshake_error_to_string(s->host->sender->exit.reason) : "");
735
+
736
+ sender_lock(s->host->sender);
737
+ {
738
+ rrdpush_sender_thread_close_socket(s);
739
+ rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, false);
740
+ rrdpush_sender_execute_commands_cleanup(s);
741
+
742
+ rrdhost_clear_sender___while_having_sender_mutex(s->host);
743
+
744
+#ifdef NETDATA_LOG_STREAM_SENDER
745
+ if (s->host->sender->stream_log_fp) {
746
+ fclose(s->host->sender->stream_log_fp);
747
+ s->host->sender->stream_log_fp = NULL;
748
+ }
749
+#endif
750
+ }
751
+ sender_unlock(s->host->sender);
752
+
753
+ freez(pipe_buffer);
754
+ freez(s);
755
+
756
+ worker_unregister();
757
+
758
return NULL;
759
}
src/streaming/sender_commit.c
+1
-1
@@ -118,7 +118,7 @@ void sender_commit(struct sender_state *s, BUFFER *wb, STREAM_TRAFFIC_TYPE type)
118
119
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION);
120
rrdpush_compression_deactivate(s);
121
- rrdpush_sender_disconnect_and_cleanup(s->host);
121
+ rrdpush_sender_thread_close_socket(s);
122
sender_unlock(s);
123
return;
124
}
src/streaming/sender_connect.c
+19
-14
@@ -2,13 +2,18 @@
2
3
#include "sender_internals.h"
4
5
-void rrdpush_sender_thread_close_socket(RRDHOST *host) {
6
- netdata_ssl_close(&host->sender->ssl);
5
+void rrdpush_sender_thread_close_socket(struct sender_state *s) {
6
+ rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
7
+
8
+ netdata_ssl_close(&s->ssl);
9
8
- if(host->sender->rrdpush_sender_socket != -1) {
9
- close(host->sender->rrdpush_sender_socket);
10
- host->sender->rrdpush_sender_socket = -1;
10
+ if(s->rrdpush_sender_socket != -1) {
11
+ close(s->rrdpush_sender_socket);
12
+ s->rrdpush_sender_socket = -1;
13
}
14
+
15
+ // do not flush the circular buffer here
16
+ // this function is called sometimes with the sender lock, sometimes without the lock
17
}
18
19
void rrdpush_encode_variable(stream_encoded_t *se, RRDHOST *host) {
@@ -204,7 +209,7 @@ static inline bool rrdpush_sender_validate_response(RRDHOST *host, struct sender
209
int delay = stream_responses[i].postpone_reconnect_seconds;
210
211
worker_is_busy(worker_job_id);
207
- rrdpush_sender_thread_close_socket(host);
212
+ rrdpush_sender_thread_close_socket(s);
213
host->destination->reason = version;
214
host->destination->postpone_reconnection_until = now_realtime_sec() + delay;
215
@@ -231,9 +236,9 @@ unsigned char alpn_proto_list[] = {
236
237
#define CONN_UPGRADE_VAL "upgrade"
238
234
-static bool rrdpush_sender_connect_ssl(struct sender_state *s __maybe_unused) {
239
+static bool rrdpush_sender_connect_ssl(struct sender_state *s) {
240
RRDHOST *host = s->host;
236
- bool ssl_required = host->destination && host->destination->ssl;
241
+ bool ssl_required = host && host->destination && host->destination->ssl;
242
243
netdata_ssl_close(&host->sender->ssl);
244
@@ -251,7 +256,7 @@ static bool rrdpush_sender_connect_ssl(struct sender_state *s __maybe_unused) {
256
ND_LOG_STACK_PUSH(lgs);
257
258
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR);
254
- rrdpush_sender_thread_close_socket(host);
259
+ rrdpush_sender_thread_close_socket(s);
260
host->destination->reason = STREAM_HANDSHAKE_ERROR_SSL_ERROR;
261
host->destination->postpone_reconnection_until = now_realtime_sec() + 5 * 60;
262
return false;
@@ -269,7 +274,7 @@ static bool rrdpush_sender_connect_ssl(struct sender_state *s __maybe_unused) {
274
275
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR);
276
netdata_log_error("SSL: closing the stream connection, because the server SSL certificate is not valid.");
272
- rrdpush_sender_thread_close_socket(host);
277
+ rrdpush_sender_thread_close_socket(s);
278
host->destination->reason = STREAM_HANDSHAKE_ERROR_INVALID_CERTIFICATE;
279
host->destination->postpone_reconnection_until = now_realtime_sec() + 5 * 60;
280
return false;
@@ -390,7 +395,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
395
};
396
397
// make sure the socket is closed
393
- rrdpush_sender_thread_close_socket(host);
398
+ rrdpush_sender_thread_close_socket(s);
399
400
s->rrdpush_sender_socket = connect_to_one_of_destinations(
401
host
@@ -527,7 +532,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
532
ND_LOG_STACK_PUSH(lgs);
533
534
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_CANT_UPGRADE_CONNECTION);
530
- rrdpush_sender_thread_close_socket(host);
535
+ rrdpush_sender_thread_close_socket(s);
536
host->destination->reason = STREAM_HANDSHAKE_ERROR_HTTP_UPGRADE;
537
host->destination->postpone_reconnection_until = now_realtime_sec() + 1 * 60;
538
return false;
@@ -550,7 +555,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
555
ND_LOG_STACK_PUSH(lgs);
556
557
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
553
- rrdpush_sender_thread_close_socket(host);
558
+ rrdpush_sender_thread_close_socket(s);
559
560
nd_log(NDLS_DAEMON, NDLP_ERR,
561
"STREAM %s [send to %s]: failed to send HTTP header to remote netdata.",
@@ -577,7 +582,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
582
ND_LOG_STACK_PUSH(lgs);
583
584
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
580
- rrdpush_sender_thread_close_socket(host);
585
+ rrdpush_sender_thread_close_socket(s);
586
587
nd_log(NDLS_DAEMON, NDLP_ERR,
588
"STREAM %s [send to %s]: remote netdata does not respond.",
src/streaming/sender_internals.h
+1
-3
@@ -44,9 +44,7 @@ extern char *netdata_ssl_ca_file;
44
bool attempt_to_connect(struct sender_state *state);
45
void rrdpush_sender_on_connect(RRDHOST *host);
46
void rrdpush_sender_after_connect(RRDHOST *host);
47
-void rrdpush_sender_thread_close_socket(RRDHOST *host);
48
-
49
-void rrdpush_sender_disconnect_and_cleanup(RRDHOST *host);
47
+void rrdpush_sender_thread_close_socket(struct sender_state *s);
48
49
void rrdpush_sender_execute_commands_cleanup(struct sender_state *s);
50
void rrdpush_sender_execute_commands(struct sender_state *s);