replication fixes 9 (#14079)
* replication fixes 9 * no room metric is now absolute * decrement senders full and flip the actions on sender full and sender available * finer timings * execute all requests, unconditionally, once they are in the replication queue; worker charts are now sorted * remove left-over debug message * log verification of replication completion only when there are no pending requests any more * use up to 50% of the sender buffer for replication responses
Costa Tsaousis committed
Dec 2, 2022 at 11:03 UTC
b53dccd58881f2c6f060e50c5414564d3cde8d9c
4 files changed
+136
-99
daemon/global_statistics.c
+4
-4
@@ -2322,7 +2322,7 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
2322
snprintf(context, RRD_ID_LENGTH_MAX, "netdata.workers.%s.value.%s", wu->name_lowercase, job_name_sanitized);
2323
2324
char title[1000 + 1];
2325
- snprintf(title, 1000, "Netdata Workers %s Value of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
2325
+ snprintf(title, 1000, "Netdata Workers %s value of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
2326
2327
wu->per_job_type[i].st = rrdset_create_localhost(
2328
"netdata"
@@ -2334,7 +2334,7 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
2334
, (wu->per_job_type[i].units)?string2str(wu->per_job_type[i].units):"value"
2335
, "netdata"
2336
, "stats"
2337
- , wu->priority + 5
2337
+ , wu->priority + 5 + i
2338
, localhost->rrd_update_every
2339
, RRDSET_TYPE_LINE
2340
);
@@ -2378,7 +2378,7 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
2378
snprintf(context, RRD_ID_LENGTH_MAX, "netdata.workers.%s.rate.%s", wu->name_lowercase, job_name_sanitized);
2379
2380
char title[1000 + 1];
2381
- snprintf(title, 1000, "Netdata Workers %s Rate of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
2381
+ snprintf(title, 1000, "Netdata Workers %s rate of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
2382
2383
wu->per_job_type[i].st = rrdset_create_localhost(
2384
"netdata"
@@ -2390,7 +2390,7 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
2390
, (wu->per_job_type[i].units)?string2str(wu->per_job_type[i].units):"rate"
2391
, "netdata"
2392
, "stats"
2393
- , wu->priority + 5
2393
+ , wu->priority + 5 + i
2394
, localhost->rrd_update_every
2395
, RRDSET_TYPE_LINE
2396
);
database/rrdcontext.c
-2
@@ -3253,8 +3253,6 @@ static void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker_jo
3253
"RRDCONTEXT: context '%s' of host '%s', deleted from rrdmetrics dictionary.",
3254
string2str(rc->id),
3255
rrdhost_hostname(host));
3256
-
3257
- fprintf(stderr, "RRDCONTEXT: deleted context '%s'", string2str(rc->id));
3256
}
3257
3258
// the item is referenced in the dictionary
streaming/replication.c
+126
-87
@@ -4,7 +4,7 @@
4
#include "Judy.h"
5
6
#define STREAMING_START_MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED 50
7
-#define MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED 20
7
+#define MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED 50
8
#define MIN_SENDER_BUFFER_PERCENTAGE_ALLOWED 10
9
10
#define WORKER_JOB_FIND_NEXT 1
@@ -14,17 +14,17 @@
14
#define WORKER_JOB_CHECK_CONSISTENCY 5
15
#define WORKER_JOB_BUFFER_COMMIT 6
16
#define WORKER_JOB_CLEANUP 7
17
+#define WORKER_JOB_WAIT 8
18
19
// master thread worker jobs
19
-#define WORKER_JOB_STATISTICS 8
20
-#define WORKER_JOB_CUSTOM_METRIC_PENDING_REQUESTS 9
21
-#define WORKER_JOB_CUSTOM_METRIC_COMPLETION 10
22
-#define WORKER_JOB_CUSTOM_METRIC_ADDED 11
23
-#define WORKER_JOB_CUSTOM_METRIC_DONE 12
24
-#define WORKER_JOB_CUSTOM_METRIC_SKIPPED_NOT_CONNECTED 13
25
-#define WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM 14
26
-#define WORKER_JOB_CUSTOM_METRIC_WAITS 15
27
-#define WORKER_JOB_CUSTOM_METRIC_SENDER_RESETS 16
20
+#define WORKER_JOB_STATISTICS 9
21
+#define WORKER_JOB_CUSTOM_METRIC_PENDING_REQUESTS 10
22
+#define WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM 11
23
+#define WORKER_JOB_CUSTOM_METRIC_COMPLETION 12
24
+#define WORKER_JOB_CUSTOM_METRIC_ADDED 13
25
+#define WORKER_JOB_CUSTOM_METRIC_DONE 14
26
+#define WORKER_JOB_CUSTOM_METRIC_SENDER_RESETS 15
27
+#define WORKER_JOB_CUSTOM_METRIC_SENDER_FULL 16
28
29
#define ITERATIONS_IDLE_WITHOUT_PENDING_TO_RUN_SENDER_VERIFICATION 30
30
#define SECONDS_TO_RESET_POINT_IN_TIME 10
@@ -591,6 +591,7 @@ struct replication_request {
591
Word_t unique_id; // auto-increment, later requests have bigger
592
bool found; // used as a result boolean for the find call
593
bool indexed_in_judy; // true when the request is indexed in judy
594
+ bool not_indexed_buffer_full; // true when the request is not indexed because the sender is full
595
};
596
597
// replication sort entry in JudyL array
@@ -605,7 +606,7 @@ struct replication_sort_entry {
606
607
// the global variables for the replication thread
608
static struct replication_thread {
608
- netdata_mutex_t mutex;
609
+ SPINLOCK spinlock;
610
611
struct {
612
size_t pending; // number of requests pending in the queue
@@ -614,9 +615,8 @@ static struct replication_thread {
615
// statistics
616
size_t added; // number of requests added to the queue
617
size_t removed; // number of requests removed from the queue
617
- size_t skipped_not_connected; // number of requests skipped, because the sender is not connected to a parent
618
- size_t skipped_no_room; // number of requests skipped, because the sender has no room for responses
619
-// size_t skipped_no_room_since_last_reset;
618
+ size_t pending_no_room; // number of requests skipped, because the sender has no room for responses
619
+ size_t senders_full; // number of times a sender reset our last position in the queue
620
size_t sender_resets; // number of times a sender reset our last position in the queue
621
time_t first_time_t; // the minimum 'after' we encountered
622
@@ -634,7 +634,6 @@ static struct replication_thread {
634
} atomic; // access should be with atomic operations
635
636
struct {
637
- size_t waits;
637
size_t last_executed; // caching of the atomic.executed to report number of requests executed since last time
638
639
netdata_thread_t **threads_ptrs;
@@ -642,17 +641,16 @@ static struct replication_thread {
641
} main_thread; // access is allowed only by the main thread
642
643
} replication_globals = {
645
- .mutex = NETDATA_MUTEX_INITIALIZER,
644
+ .spinlock = NETDATA_SPINLOCK_INITIALIZER,
645
.unsafe = {
646
.pending = 0,
647
.unique_id = 0,
648
649
.added = 0,
650
.removed = 0,
652
- .skipped_not_connected = 0,
653
- .skipped_no_room = 0,
654
-// .skipped_no_room_since_last_reset = 0,
651
+ .pending_no_room = 0,
652
.sender_resets = 0,
653
+ .senders_full = 0,
654
655
.first_time_t = 0,
656
@@ -667,7 +665,6 @@ static struct replication_thread {
665
.latest_first_time = 0,
666
},
667
.main_thread = {
670
- .waits = 0,
668
.last_executed = 0,
669
.threads = 0,
670
.threads_ptrs = NULL,
@@ -682,11 +679,11 @@ static inline bool replication_recursive_lock_mode(char mode) {
679
680
if(mode == 'L') { // (L)ock
681
if(++recursions == 1)
685
- netdata_mutex_lock(&replication_globals.mutex);
682
+ netdata_spinlock_lock(&replication_globals.spinlock);
683
}
684
else if(mode == 'U') { // (U)nlock
685
if(--recursions == 0)
689
- netdata_mutex_unlock(&replication_globals.mutex);
686
+ netdata_spinlock_unlock(&replication_globals.spinlock);
687
}
688
else if(mode == 'C') { // (C)heck
689
if(recursions > 0)
@@ -736,6 +733,7 @@ static struct replication_sort_entry *replication_sort_entry_create_unsafe(struc
733
// save the unique id into the request, to be able to delete it later
734
rq->unique_id = rse->unique_id;
735
rq->indexed_in_judy = false;
736
+ rq->not_indexed_buffer_full = false;
737
return rse;
738
}
739
@@ -743,9 +741,20 @@ static void replication_sort_entry_destroy(struct replication_sort_entry *rse) {
741
freez(rse);
742
}
743
746
-static struct replication_sort_entry *replication_sort_entry_add(struct replication_request *rq) {
744
+static void replication_sort_entry_add(struct replication_request *rq) {
745
replication_recursive_lock();
746
747
+ if(rrdpush_sender_replication_buffer_full_get(rq->sender)) {
748
+ rq->indexed_in_judy = false;
749
+ rq->not_indexed_buffer_full = true;
750
+ replication_globals.unsafe.pending_no_room++;
751
+ replication_recursive_unlock();
752
+ return;
753
+ }
754
+
755
+ if(rq->not_indexed_buffer_full)
756
+ replication_globals.unsafe.pending_no_room--;
757
+
758
struct replication_sort_entry *rse = replication_sort_entry_create_unsafe(rq);
759
760
// if(rq->after < (time_t)replication_globals.protected.queue.after &&
@@ -770,13 +779,12 @@ static struct replication_sort_entry *replication_sort_entry_add(struct replicat
779
Pvoid_t *item = JudyLIns(inner_judy_ptr, rq->unique_id, PJE0);
780
*item = rse;
781
rq->indexed_in_judy = true;
782
+ rq->not_indexed_buffer_full = false;
783
784
if(!replication_globals.unsafe.first_time_t || rq->after < replication_globals.unsafe.first_time_t)
785
replication_globals.unsafe.first_time_t = rq->after;
786
787
replication_recursive_unlock();
778
-
779
- return rse;
788
}
789
790
static bool replication_sort_entry_unlink_and_free_unsafe(struct replication_sort_entry *rse, Pvoid_t **inner_judy_ppptr) {
@@ -806,7 +814,7 @@ static bool replication_sort_entry_unlink_and_free_unsafe(struct replication_sor
814
return inner_judy_deleted;
815
}
816
809
-static void replication_sort_entry_del(struct replication_request *rq) {
817
+static void replication_sort_entry_del(struct replication_request *rq, bool buffer_full) {
818
Pvoid_t *inner_judy_pptr;
819
struct replication_sort_entry *rse_to_delete = NULL;
820
@@ -819,6 +827,11 @@ static void replication_sort_entry_del(struct replication_request *rq) {
827
if (our_item_pptr) {
828
rse_to_delete = *our_item_pptr;
829
replication_sort_entry_unlink_and_free_unsafe(rse_to_delete, &inner_judy_pptr);
830
+
831
+ if(buffer_full) {
832
+ replication_globals.unsafe.pending_no_room++;
833
+ rq->not_indexed_buffer_full = true;
834
+ }
835
}
836
}
837
@@ -877,44 +890,17 @@ static struct replication_request replication_request_get_first_available() {
890
while (!rq_to_return.found && (our_item_pptr = JudyLNext(*inner_judy_pptr, &replication_globals.unsafe.queue.unique_id, PJE0))) {
891
struct replication_sort_entry *rse = *our_item_pptr;
892
struct replication_request *rq = rse->rq;
880
- struct sender_state *s = rq->sender;
881
-
882
- if (likely(rrdpush_sender_get_buffer_used_percent(s) <= MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED)) {
883
- // there is room for this request in the sender buffer
884
-
885
- bool sender_is_connected =
886
- rrdhost_flag_check(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED);
887
-
888
- bool sender_has_been_flushed_since_this_request =
889
- rq->sender_last_flush_ut != rrdpush_sender_get_flush_time(s);
893
891
- if (unlikely(!sender_is_connected || sender_has_been_flushed_since_this_request)) {
892
- // skip this request, the sender is not connected, or it has reconnected
894
+ // copy the request to return it
895
+ rq_to_return = *rq;
896
+ rq_to_return.chart_id = string_dup(rq_to_return.chart_id);
897
894
- replication_globals.unsafe.skipped_not_connected++;
895
- if (replication_sort_entry_unlink_and_free_unsafe(rse, &inner_judy_pptr))
896
- // we removed the item from the outer JudyL
897
- break;
898
- }
899
- else {
900
- // this request is good to execute
898
+ // set the return result to found
899
+ rq_to_return.found = true;
900
902
- // copy the request to return it
903
- rq_to_return = *rq;
904
- rq_to_return.chart_id = string_dup(rq_to_return.chart_id);
905
-
906
- // set the return result to found
907
- rq_to_return.found = true;
908
-
909
- if (replication_sort_entry_unlink_and_free_unsafe(rse, &inner_judy_pptr))
910
- // we removed the item from the outer JudyL
911
- break;
912
- }
913
- }
914
- else {
915
- replication_globals.unsafe.skipped_no_room++;
916
-// replication_globals.protected.skipped_no_room_since_last_reset++;
917
- }
901
+ if (replication_sort_entry_unlink_and_free_unsafe(rse, &inner_judy_pptr))
902
+ // we removed the item from the outer JudyL
903
+ break;
904
}
905
906
// call JudyLNext from now on
@@ -959,7 +945,20 @@ static bool replication_request_conflict_callback(const DICTIONARY_ITEM *item __
945
946
replication_recursive_lock();
947
962
- if(!rq->indexed_in_judy) {
948
+ if(!rq->indexed_in_judy && rq->not_indexed_buffer_full) {
949
+ // we can replace this command
950
+ internal_error(
951
+ true,
952
+ "STREAM %s [send to %s]: REPLAY: 'host:%s/chart:%s' replacing duplicate replication command received (existing from %llu to %llu [%s], new from %llu to %llu [%s])",
953
+ rrdhost_hostname(s->host), s->connected_to, rrdhost_hostname(s->host), dictionary_acquired_item_name(item),
954
+ (unsigned long long)rq->after, (unsigned long long)rq->before, rq->start_streaming ? "true" : "false",
955
+ (unsigned long long)rq_new->after, (unsigned long long)rq_new->before, rq_new->start_streaming ? "true" : "false");
956
+
957
+ rq->after = rq_new->after;
958
+ rq->before = rq_new->before;
959
+ rq->start_streaming = rq_new->start_streaming;
960
+ }
961
+ else if(!rq->indexed_in_judy) {
962
replication_sort_entry_add(rq);
963
internal_error(
964
true,
@@ -991,7 +990,13 @@ static void replication_request_delete_callback(const DICTIONARY_ITEM *item __ma
990
rrdpush_sender_replicating_charts_minus_one(rq->sender);
991
992
if(rq->indexed_in_judy)
994
- replication_sort_entry_del(rq);
993
+ replication_sort_entry_del(rq, false);
994
+
995
+ else if(rq->not_indexed_buffer_full) {
996
+ replication_recursive_lock();
997
+ replication_globals.unsafe.pending_no_room--;
998
+ replication_recursive_unlock();
999
+ }
1000
1001
string_freez(rq->chart_id);
1002
}
@@ -1046,6 +1051,7 @@ static bool replication_execute_request(struct replication_request *rq, bool wor
1051
1052
cleanup:
1053
string_freez(rq->chart_id);
1054
+ worker_is_idle();
1055
return ret;
1056
}
1057
@@ -1060,6 +1066,8 @@ void replication_add_request(struct sender_state *sender, const char *chart_id,
1066
.before = before,
1067
.start_streaming = start_streaming,
1068
.sender_last_flush_ut = rrdpush_sender_get_flush_time(sender),
1069
+ .indexed_in_judy = false,
1070
+ .not_indexed_buffer_full = false,
1071
};
1072
1073
if(start_streaming && rrdpush_sender_get_buffer_used_percent(sender) <= STREAMING_START_MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED)
@@ -1094,15 +1102,36 @@ void replication_recalculate_buffer_used_ratio_unsafe(struct sender_state *s) {
1102
size_t available = cbuffer_available_size_unsafe(s->host->sender->buffer);
1103
size_t percentage = (s->buffer->max_size - available) * 100 / s->buffer->max_size;
1104
1097
- if(percentage > MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED)
1098
- s->replication.unsafe.reached_max = true;
1105
+ if(unlikely(percentage > MAX_SENDER_BUFFER_PERCENTAGE_ALLOWED && !rrdpush_sender_replication_buffer_full_get(s))) {
1106
+ rrdpush_sender_replication_buffer_full_set(s, true);
1107
+
1108
+ struct replication_request *rq;
1109
+ dfe_start_read(s->replication.requests, rq) {
1110
+ if(rq->indexed_in_judy && !rq->not_indexed_buffer_full) {
1111
+ replication_sort_entry_del(rq, true);
1112
+ }
1113
+ }
1114
+ dfe_done(rq);
1115
1100
- if(s->replication.unsafe.reached_max &&
1101
- percentage <= MIN_SENDER_BUFFER_PERCENTAGE_ALLOWED) {
1102
- s->replication.unsafe.reached_max = false;
1116
replication_recursive_lock();
1104
-// replication_set_next_point_in_time(0, 0);
1117
+ replication_globals.unsafe.senders_full++;
1118
+ replication_recursive_unlock();
1119
+ }
1120
+ else if(unlikely(percentage < MIN_SENDER_BUFFER_PERCENTAGE_ALLOWED && rrdpush_sender_replication_buffer_full_get(s))) {
1121
+ rrdpush_sender_replication_buffer_full_set(s, false);
1122
+
1123
+ struct replication_request *rq;
1124
+ dfe_start_read(s->replication.requests, rq) {
1125
+ if(!rq->indexed_in_judy && rq->not_indexed_buffer_full) {
1126
+ replication_sort_entry_add(rq);
1127
+ }
1128
+ }
1129
+ dfe_done(rq);
1130
+
1131
+ replication_recursive_lock();
1132
+ replication_globals.unsafe.senders_full--;
1133
replication_globals.unsafe.sender_resets++;
1134
+ // replication_set_next_point_in_time(0, 0);
1135
replication_recursive_unlock();
1136
}
1137
@@ -1188,17 +1217,17 @@ static void replication_initialize_workers(bool master) {
1217
worker_register_job_name(WORKER_JOB_CHECK_CONSISTENCY, "check consistency");
1218
worker_register_job_name(WORKER_JOB_BUFFER_COMMIT, "commit");
1219
worker_register_job_name(WORKER_JOB_CLEANUP, "cleanup");
1220
+ worker_register_job_name(WORKER_JOB_WAIT, "wait");
1221
1222
if(master) {
1223
worker_register_job_name(WORKER_JOB_STATISTICS, "statistics");
1224
worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_PENDING_REQUESTS, "pending requests", "requests", WORKER_METRIC_ABSOLUTE);
1225
+ worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM, "no room requests", "requests", WORKER_METRIC_ABSOLUTE);
1226
worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_COMPLETION, "completion", "%", WORKER_METRIC_ABSOLUTE);
1227
worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_ADDED, "added requests", "requests/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1228
worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_DONE, "finished requests", "requests/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1198
- worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NOT_CONNECTED, "not connected requests", "requests/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1199
- worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM, "no room requests", "requests/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1229
worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_SENDER_RESETS, "sender resets", "resets/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1201
- worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_WAITS, "waits", "waits/s", WORKER_METRIC_INCREMENTAL_TOTAL);
1230
+ worker_register_job_custom_metric(WORKER_JOB_CUSTOM_METRIC_SENDER_FULL, "senders full", "senders", WORKER_METRIC_ABSOLUTE);
1231
}
1232
}
1233
@@ -1210,8 +1239,10 @@ static int replication_execute_next_pending_request(void) {
1239
worker_is_busy(WORKER_JOB_FIND_NEXT);
1240
struct replication_request rq = replication_request_get_first_available();
1241
1213
- if(unlikely(!rq.found))
1242
+ if(unlikely(!rq.found)) {
1243
+ worker_is_idle();
1244
return REQUEST_QUEUE_EMPTY;
1245
+ }
1246
1247
// delete the request from the dictionary
1248
worker_is_busy(WORKER_JOB_DELETE_ENTRY);
@@ -1221,9 +1252,12 @@ static int replication_execute_next_pending_request(void) {
1252
1253
replication_set_latest_first_time(rq.after);
1254
1224
- if(unlikely(!replication_execute_request(&rq, true)))
1255
+ if(unlikely(!replication_execute_request(&rq, true))) {
1256
+ worker_is_idle();
1257
return REQUEST_CHART_NOT_FOUND;
1258
+ }
1259
1260
+ worker_is_idle();
1261
return REQUEST_OK;
1262
}
1263
@@ -1238,6 +1272,7 @@ static void *replication_worker_thread(void *ptr) {
1272
1273
while(!netdata_exit) {
1274
if(unlikely(replication_execute_next_pending_request() == REQUEST_QUEUE_EMPTY)) {
1275
+ worker_is_busy(WORKER_JOB_WAIT);
1276
worker_is_idle();
1277
sleep_usec(1 * USEC_PER_SEC);
1278
}
@@ -1305,6 +1340,7 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1340
if(unlikely(now_mono_ut - last_now_mono_ut > default_rrd_update_every * USEC_PER_SEC)) {
1341
last_now_mono_ut = now_mono_ut;
1342
1343
+ worker_is_busy(WORKER_JOB_STATISTICS);
1344
replication_recursive_lock();
1345
1346
size_t current_executed = __atomic_load_n(&replication_globals.atomic.executed, __ATOMIC_RELAXED);
@@ -1321,19 +1357,21 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1357
replication_reset_next_point_in_time_countdown = SECONDS_TO_RESET_POINT_IN_TIME;
1358
}
1359
1324
- if(!replication_globals.unsafe.pending && --run_verification_countdown == 0) {
1325
- // reset the statistics about completion percentage
1326
- replication_globals.unsafe.first_time_t = 0;
1327
- replication_set_latest_first_time(0);
1360
+ if(--run_verification_countdown == 0) {
1361
+ if (!replication_globals.unsafe.pending && !replication_globals.unsafe.pending_no_room) {
1362
+ // reset the statistics about completion percentage
1363
+ replication_globals.unsafe.first_time_t = 0;
1364
+ replication_set_latest_first_time(0);
1365
1329
- verify_all_hosts_charts_are_streaming_now();
1366
+ verify_all_hosts_charts_are_streaming_now();
1367
1331
- run_verification_countdown = LONG_MAX;
1332
- slow = true;
1368
+ run_verification_countdown = LONG_MAX;
1369
+ slow = true;
1370
+ }
1371
+ else
1372
+ run_verification_countdown = ITERATIONS_IDLE_WITHOUT_PENDING_TO_RUN_SENDER_VERIFICATION;
1373
}
1374
1335
- worker_is_busy(WORKER_JOB_STATISTICS);
1336
-
1375
time_t latest_first_time_t = replication_get_latest_first_time();
1376
if(latest_first_time_t && replication_globals.unsafe.pending) {
1377
// completion percentage statistics
@@ -1349,15 +1387,17 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1387
worker_set_metric(WORKER_JOB_CUSTOM_METRIC_PENDING_REQUESTS, (NETDATA_DOUBLE)replication_globals.unsafe.pending);
1388
worker_set_metric(WORKER_JOB_CUSTOM_METRIC_ADDED, (NETDATA_DOUBLE)replication_globals.unsafe.added);
1389
worker_set_metric(WORKER_JOB_CUSTOM_METRIC_DONE, (NETDATA_DOUBLE)__atomic_load_n(&replication_globals.atomic.executed, __ATOMIC_RELAXED));
1352
- worker_set_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NOT_CONNECTED, (NETDATA_DOUBLE)replication_globals.unsafe.skipped_not_connected);
1353
- worker_set_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM, (NETDATA_DOUBLE)replication_globals.unsafe.skipped_no_room);
1390
+ worker_set_metric(WORKER_JOB_CUSTOM_METRIC_SKIPPED_NO_ROOM, (NETDATA_DOUBLE)replication_globals.unsafe.pending_no_room);
1391
worker_set_metric(WORKER_JOB_CUSTOM_METRIC_SENDER_RESETS, (NETDATA_DOUBLE)replication_globals.unsafe.sender_resets);
1355
- worker_set_metric(WORKER_JOB_CUSTOM_METRIC_WAITS, (NETDATA_DOUBLE)replication_globals.main_thread.waits);
1392
+ worker_set_metric(WORKER_JOB_CUSTOM_METRIC_SENDER_FULL, (NETDATA_DOUBLE)replication_globals.unsafe.senders_full);
1393
1394
replication_recursive_unlock();
1395
+ worker_is_idle();
1396
}
1397
1398
if(unlikely(replication_execute_next_pending_request() == REQUEST_QUEUE_EMPTY)) {
1399
+
1400
+ worker_is_busy(WORKER_JOB_WAIT);
1401
replication_recursive_lock();
1402
1403
// the timeout also defines now frequently we will traverse all the pending requests
@@ -1388,7 +1428,6 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1428
last_sender_resets = replication_globals.unsafe.sender_resets;
1429
}
1430
1391
- replication_globals.main_thread.waits++;
1431
replication_recursive_unlock();
1432
1433
worker_is_idle();
streaming/rrdpush.h
+6
-6
@@ -168,12 +168,9 @@ struct sender_state {
168
struct {
169
size_t pending_requests; // the currently outstanding replication requests
170
size_t charts_replicating; // the number of unique charts having pending replication requests (on every request one is added and is removed when we finish it - it does not track completion of the replication for this chart)
171
+ bool reached_max; // true when the sender buffer should not get more replication responses
172
} atomic;
173
173
- struct {
174
- bool reached_max; // used to avoid resetting the replication thread too frequently
175
- } unsafe; // protected by sender mutex
176
-
174
} replication;
175
176
struct {
@@ -182,10 +179,13 @@ struct sender_state {
179
} atomic;
180
};
181
185
-#define rrdpush_sender_set_buffer_used_percent(sender, value) __atomic_store_n(&((sender)->atomic.buffer_used_percentage), value, __ATOMIC_RELAXED);
182
+#define rrdpush_sender_replication_buffer_full_set(sender, value) __atomic_store_n(&((sender)->replication.atomic.reached_max), value, __ATOMIC_SEQ_CST)
183
+#define rrdpush_sender_replication_buffer_full_get(sender) __atomic_load_n(&((sender)->replication.atomic.reached_max), __ATOMIC_SEQ_CST)
184
+
185
+#define rrdpush_sender_set_buffer_used_percent(sender, value) __atomic_store_n(&((sender)->atomic.buffer_used_percentage), value, __ATOMIC_RELAXED)
186
#define rrdpush_sender_get_buffer_used_percent(sender) __atomic_load_n(&((sender)->atomic.buffer_used_percentage), __ATOMIC_RELAXED)
187
188
-#define rrdpush_sender_set_flush_time(sender) __atomic_store_n(&((sender)->atomic.last_flush_time_ut), now_realtime_usec(), __ATOMIC_RELAXED);
188
+#define rrdpush_sender_set_flush_time(sender) __atomic_store_n(&((sender)->atomic.last_flush_time_ut), now_realtime_usec(), __ATOMIC_RELAXED)
189
#define rrdpush_sender_get_flush_time(sender) __atomic_load_n(&((sender)->atomic.last_flush_time_ut), __ATOMIC_RELAXED)
190
191
#define rrdpush_sender_replicating_charts(sender) __atomic_load_n(&((sender)->replication.atomic.charts_replicating), __ATOMIC_RELAXED)