@cryptotaxi247 / netdata-1 / commits / 9232bfb6a

track memory footprint of Netdata (#14294)

* track memory footprint of Netdata * track db modes alloc/ram/save/map * track system info; track sender and receiver * fixes * more fixes * track workers memory, onewayalloc memory; unify judyhs size estimation * track replication structures and buffers * Properly clear host RRDHOST_FLAG_METADATA_UPDATE flag * flush the replication buffer every 1000 times the circular buffer is found empty * dont take timestamp too frequently in sender loop * sender buffers are not used by the same thread as the sender, so they were never recreated - fixed it * free sender thread buffer on replication threads when replication is idle * use the last sender flag as a timestamp of the last buffer recreation * free cbuffer before reconnecting * recreate cbuffer on every flush * timings for journal v2 loading * inlining of metric and cache functions * aral likely/unlikely * free left-over thread buffers * fix NULL pointer dereference in replication * free sender thread buffer on sender thread too * mark ctx as used before flushing * better logging on ctx datafiles closing Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>

Costa Tsaousis committed Jan 20, 2023 at 00:50 UTC 9232bfb6a072155388578dc4e1338c6002afb515
83 files changed +923 -445
aclk/aclk.c
+1 -1
@@ -947,7 +947,7 @@ char *aclk_state(void)
947 #ifndef ENABLE_ACLK
948 return strdupz("ACLK Available: No");
949 #else
950 - BUFFER *wb = buffer_create(1024);
950 + BUFFER *wb = buffer_create(1024, &netdata_buffers_statistics.buffers_aclk);
951 struct tm *tmptr, tmbuf;
952 char *ret;
953
aclk/aclk_otp.c
+4 -4
@@ -314,7 +314,7 @@ int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **
314 https_req_t req = HTTPS_REQ_T_INITIALIZER;
315 https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
316
317 - BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20);
317 + BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
318
319 req.host = target->host;
320 req.port = target->port;
@@ -394,8 +394,8 @@ int aclk_send_otp_response(const char *agent_id, const unsigned char *response,
394
395 base64_encode_helper(base64, &len, response, response_bytes);
396
397 - BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20);
398 - BUFFER *resp_json = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20);
397 + BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
398 + BUFFER *resp_json = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
399
400 buffer_sprintf(url, "%s/node/%s/password", target->path, agent_id);
401 buffer_sprintf(resp_json, "{\"response\":\"%s\"}", base64);
@@ -814,7 +814,7 @@ exit:
814 }
815
816 int aclk_get_env(aclk_env_t *env, const char* aclk_hostname, int aclk_port) {
817 - BUFFER *buf = buffer_create(1024);
817 + BUFFER *buf = buffer_create(1024, &netdata_buffers_statistics.buffers_aclk);
818
819 https_req_t req = HTTPS_REQ_T_INITIALIZER;
820 https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
aclk/aclk_query.c
+6 -6
@@ -62,19 +62,19 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
62 int retval = 0;
63 usec_t t;
64 BUFFER *local_buffer = NULL;
65 - BUFFER *log_buffer = buffer_create(NETDATA_WEB_REQUEST_URL_SIZE);
65 + BUFFER *log_buffer = buffer_create(NETDATA_WEB_REQUEST_URL_SIZE, &netdata_buffers_statistics.buffers_aclk);
66 RRDHOST *query_host = localhost;
67
68 #ifdef NETDATA_WITH_ZLIB
69 int z_ret;
70 - BUFFER *z_buffer = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
70 + BUFFER *z_buffer = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_aclk);
71 char *start, *end;
72 #endif
73
74 struct web_client *w = (struct web_client *)callocz(1, sizeof(struct web_client));
75 - w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
76 - w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
77 - w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
75 + w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_aclk);
76 + w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE, &netdata_buffers_statistics.buffers_aclk);
77 + w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE, &netdata_buffers_statistics.buffers_aclk);
78 strcpy(w->origin, "*"); // Simulate web_client_create_on_fd()
79 w->cookie1[0] = 0; // Simulate web_client_create_on_fd()
80 w->cookie2[0] = 0; // Simulate web_client_create_on_fd()
@@ -191,7 +191,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
191
192 w->response.data->date = w->tv_ready.tv_sec;
193 web_client_build_http_header(w);
194 - local_buffer = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
194 + local_buffer = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_aclk);
195 local_buffer->contenttype = CT_APPLICATION_JSON;
196
197 buffer_strcat(local_buffer, w->response.header_output->buffer);
aclk/https_client.c
+3 -1
@@ -8,6 +8,8 @@
8
9 #include "aclk_util.h"
10
11 +#include "daemon/global_statistics.h"
12 +
13 enum http_parse_state {
14 HTTP_PARSE_INITIAL = 0,
15 HTTP_PARSE_HEADERS,
@@ -354,7 +356,7 @@ static int read_parse_response(https_req_ctx_t *ctx) {
356 #define TX_BUFFER_SIZE 8192
357 #define RX_BUFFER_SIZE (TX_BUFFER_SIZE*2)
358 static int handle_http_request(https_req_ctx_t *ctx) {
357 - BUFFER *hdr = buffer_create(TX_BUFFER_SIZE);
359 + BUFFER *hdr = buffer_create(TX_BUFFER_SIZE, &netdata_buffers_statistics.buffers_aclk);
360 int rc = 0;
361
362 http_parse_ctx_clear(&ctx->parse_ctx);
collectors/apps.plugin/apps_plugin.c
+1 -1
@@ -4396,7 +4396,7 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4396 unsigned int memory_divisor = 1024;
4397 unsigned int io_divisor = 1024 * RATES_DETAIL;
4398
4399 - BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX);
4399 + BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
4400 buffer_sprintf(wb,
4401 "{"
4402 "\n \"status\":%d"
collectors/diskspace.plugin/plugin_diskspace.c
+1 -1
@@ -319,7 +319,7 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
319 , SIMPLE_PATTERN_EXACT
320 );
321
322 - dict_mountpoints = dictionary_create(DICT_OPTION_NONE);
322 + dict_mountpoints = dictionary_create_advanced(DICT_OPTION_NONE, &dictionary_stats_category_collectors);
323 }
324
325 struct mount_point_metadata *m = dictionary_get(dict_mountpoints, mi->mount_point);
collectors/plugins.d/pluginsd_parser.c
+1 -1
@@ -530,7 +530,7 @@ static void inflight_functions_delete_callback(const DICTIONARY_ITEM *item __may
530 }
531
532 void inflight_functions_init(PARSER *parser) {
533 - parser->inflight.functions = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
533 + parser->inflight.functions = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_functions);
534 dictionary_register_insert_callback(parser->inflight.functions, inflight_functions_insert_callback, parser);
535 dictionary_register_delete_callback(parser->inflight.functions, inflight_functions_delete_callback, parser);
536 dictionary_register_conflict_callback(parser->inflight.functions, inflight_functions_conflict_callback, parser);
collectors/proc.plugin/proc_self_mountinfo.c
+3 -2
@@ -227,8 +227,9 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
227 struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
228
229 // create a dictionary to track uniqueness
230 - DICTIONARY *dict = dictionary_create(
231 - DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_NAME_LINK_DONT_CLONE);
230 + DICTIONARY *dict = dictionary_create_advanced(
231 + DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_NAME_LINK_DONT_CLONE,
232 + &dictionary_stats_category_collectors);
233
234 unsigned long l, lines = procfile_lines(ff);
235 for(l = 0; l < lines ;l++) {
collectors/proc.plugin/proc_spl_kstat_zfs.c
+1 -1
@@ -322,7 +322,7 @@ int do_proc_spl_kstat_zfs_pool_state(int update_every, usec_t dt)
322 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/spl/kstat/zfs");
323 dirname = config_get("plugin:proc:" ZFS_PROC_POOLS, "directory to monitor", filename);
324
325 - zfs_pools = dictionary_create(DICT_OPTION_SINGLE_THREADED);
325 + zfs_pools = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors);
326
327 do_zfs_pool_state = 1;
328 }
collectors/proc.plugin/sys_block_zram.c
+1 -1
@@ -267,7 +267,7 @@ int do_sys_block_zram(int update_every, usec_t dt) {
267 }
268 procfile_close(ff);
269
270 - devices = dictionary_create(DICT_OPTION_SINGLE_THREADED);
270 + devices = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors);
271 device_count = init_devices(devices, (unsigned int)zram_id, update_every);
272 }
273
collectors/statsd.plugin/statsd.c
+10 -10
@@ -595,7 +595,7 @@ static inline void statsd_process_set(STATSD_METRIC *m, const char *value) {
595 }
596
597 if (unlikely(!m->set.dict)) {
598 - m->set.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
598 + m->set.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
599 dictionary_register_insert_callback(m->set.dict, dictionary_metric_set_value_insert_callback, m);
600 m->set.unique = 0;
601 }
@@ -635,7 +635,7 @@ static inline void statsd_process_dictionary(STATSD_METRIC *m, const char *value
635 statsd_reset_metric(m);
636
637 if (unlikely(!m->dictionary.dict)) {
638 - m->dictionary.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
638 + m->dictionary.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
639 dictionary_register_insert_callback(m->dictionary.dict, dictionary_metric_dict_value_insert_callback, m);
640 m->dictionary.unique = 0;
641 }
@@ -1337,7 +1337,7 @@ static int statsd_readfile(const char *filename, STATSD_APP *app, STATSD_APP_CHA
1337 else if(app) {
1338 if(!strcmp(s, "dictionary")) {
1339 if(!app->dict)
1340 - app->dict = dictionary_create(DICT_OPTION_SINGLE_THREADED);
1340 + app->dict = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors);
1341
1342 dict = app->dict;
1343 }
@@ -2422,13 +2422,13 @@ void *statsd_main(void *ptr) {
2422
2423 netdata_thread_cleanup_push(statsd_main_cleanup, ptr);
2424
2425 - statsd.gauges.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2426 - statsd.meters.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2427 - statsd.counters.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2428 - statsd.histograms.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2429 - statsd.dictionaries.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2430 - statsd.sets.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2431 - statsd.timers.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS);
2425 + statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2426 + statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2427 + statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2428 + statsd.histograms.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2429 + statsd.dictionaries.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2430 + statsd.sets.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2431 + statsd.timers.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors);
2432
2433 dictionary_register_insert_callback(statsd.gauges.dict, dictionary_metric_insert_callback, &statsd.gauges);
2434 dictionary_register_insert_callback(statsd.meters.dict, dictionary_metric_insert_callback, &statsd.meters);
collectors/tc.plugin/plugin_tc.c
+4 -3
@@ -98,7 +98,7 @@ static bool tc_class_conflict_callback(const DICTIONARY_ITEM *item __maybe_unuse
98
99 static void tc_class_index_init(struct tc_device *d) {
100 if(!d->classes) {
101 - d->classes = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED);
101 + d->classes = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors);
102
103 dictionary_register_delete_callback(d->classes, tc_class_free_callback, d);
104 dictionary_register_conflict_callback(d->classes, tc_class_conflict_callback, d);
@@ -144,8 +144,9 @@ static void tc_device_free_callback(const DICTIONARY_ITEM *item __maybe_unused,
144
145 static void tc_device_index_init() {
146 if(!tc_device_root_index) {
147 - tc_device_root_index = dictionary_create(
148 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_ADD_IN_FRONT);
147 + tc_device_root_index = dictionary_create_advanced(
148 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_ADD_IN_FRONT,
149 + &dictionary_stats_category_collectors);
150
151 dictionary_register_insert_callback(tc_device_root_index, tc_device_add_callback, NULL);
152 dictionary_register_delete_callback(tc_device_root_index, tc_device_free_callback, NULL);
daemon/analytics.c
+6 -6
@@ -241,7 +241,7 @@ void analytics_exporters(void)
241 {
242 //when no exporters are available, an empty string will be sent
243 //decide if something else is more suitable (but probably not null)
244 - BUFFER *bi = buffer_create(1000);
244 + BUFFER *bi = buffer_create(1000, NULL);
245 analytics_exporting_connectors(bi);
246 analytics_set_data_str(&analytics_data.netdata_exporting_connectors, (char *)buffer_tostring(bi));
247 buffer_free(bi);
@@ -278,7 +278,7 @@ void analytics_collectors(void)
278 RRDSET *st;
279 DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED);
280 char name[500];
281 - BUFFER *bt = buffer_create(1000);
281 + BUFFER *bt = buffer_create(1000, NULL);
282
283 rrdset_foreach_read(st, localhost) {
284 if(!rrdset_is_available_for_viewers(st))
@@ -333,7 +333,7 @@ void analytics_alarms_notifications(void)
333
334 debug(D_ANALYTICS, "Executing %s", script);
335
336 - BUFFER *b = buffer_create(1000);
336 + BUFFER *b = buffer_create(1000, NULL);
337 int cnt = 0;
338 FILE *fp_child_input;
339 FILE *fp_child_output = netdata_popen(script, &command_pid, &fp_child_input);
@@ -380,7 +380,7 @@ void analytics_get_install_type(void)
380 */
381 void analytics_https(void)
382 {
383 - BUFFER *b = buffer_create(30);
383 + BUFFER *b = buffer_create(30, NULL);
384 #ifdef ENABLE_HTTPS
385 analytics_exporting_connectors_ssl(b);
386 buffer_strcat(b, netdata_ssl_client_ctx && rrdhost_flag_check(localhost, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED) && localhost->sender->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE ? "streaming|" : "|");
@@ -675,7 +675,7 @@ void set_late_global_environment()
675 analytics_set_data_str(&analytics_data.netdata_config_release_channel, (char *)get_release_channel());
676
677 {
678 - BUFFER *bi = buffer_create(1000);
678 + BUFFER *bi = buffer_create(1000, NULL);
679 analytics_build_info(bi);
680 analytics_set_data_str(&analytics_data.netdata_buildinfo, (char *)buffer_tostring(bi));
681 buffer_free(bi);
@@ -836,7 +836,7 @@ void set_global_environment()
836 setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
837
838 {
839 - BUFFER *user_plugins_dirs = buffer_create(FILENAME_MAX);
839 + BUFFER *user_plugins_dirs = buffer_create(FILENAME_MAX, NULL);
840
841 for (size_t i = 1; i < PLUGINSD_MAX_DIRECTORIES && plugin_directories[i]; i++) {
842 if (i > 1)
daemon/commands.c
+1 -1
@@ -220,7 +220,7 @@ static cmd_status_t cmd_reload_labels_execute(char *args, char **message)
220 info("COMMAND: reloading host labels.");
221 reload_host_labels();
222
223 - BUFFER *wb = buffer_create(10);
223 + BUFFER *wb = buffer_create(10, NULL);
224 rrdlabels_log_to_buffer(localhost->rrdlabels, wb);
225 (*message)=strdupz(buffer_tostring(wb));
226 buffer_free(wb);
daemon/global_statistics.c
+215 -42
@@ -20,6 +20,11 @@
20
21 bool global_statistics_enabled = true;
22
23 +struct netdata_buffers_statistics netdata_buffers_statistics = {};
24 +
25 +static size_t dbengine_total_memory = 0;
26 +size_t rrddim_db_memory_size = 0;
27 +
28 static struct global_statistics {
29 uint16_t connected_clients;
30
@@ -214,6 +219,9 @@ static inline void global_statistics_copy(struct global_statistics *gs, uint8_t
219 }
220 }
221
222 +#define dictionary_stats_memory_total(stats) \
223 + ((stats).memory.dict + (stats).memory.values + (stats).memory.index)
224 +
225 static void global_statistics_charts(void) {
226 static unsigned long long old_web_requests = 0,
227 old_web_usec = 0,
@@ -270,23 +278,168 @@ static void global_statistics_charts(void) {
278 // ----------------------------------------------------------------
279
280 {
273 - static RRDSET *st_uptime = NULL;
274 - static RRDDIM *rd_uptime = NULL;
281 + static RRDSET *st_memory = NULL;
282 + static RRDDIM *rd_database = NULL;
283 + static RRDDIM *rd_collectors = NULL;
284 + static RRDDIM *rd_hosts = NULL;
285 + static RRDDIM *rd_rrd = NULL;
286 + static RRDDIM *rd_contexts = NULL;
287 + static RRDDIM *rd_health = NULL;
288 + static RRDDIM *rd_functions = NULL;
289 + static RRDDIM *rd_labels = NULL;
290 + static RRDDIM *rd_strings = NULL;
291 + static RRDDIM *rd_streaming = NULL;
292 + static RRDDIM *rd_replication = NULL;
293 + static RRDDIM *rd_buffers = NULL;
294 + static RRDDIM *rd_workers = NULL;
295 + static RRDDIM *rd_other = NULL;
296 +
297 + if (unlikely(!st_memory)) {
298 + st_memory = rrdset_create_localhost(
299 + "netdata",
300 + "memory",
301 + NULL,
302 + "netdata",
303 + NULL,
304 + "Netdata Memory",
305 + "bytes",
306 + "netdata",
307 + "stats",
308 + 130100,
309 + localhost->rrd_update_every,
310 + RRDSET_TYPE_STACKED);
311
276 - if (unlikely(!st_uptime)) {
277 - st_uptime = rrdset_create_localhost(
312 + rd_database = rrddim_add(st_memory, "db", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
313 + rd_collectors = rrddim_add(st_memory, "collectors", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
314 + rd_hosts = rrddim_add(st_memory, "hosts", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
315 + rd_rrd = rrddim_add(st_memory, "rrdset rrddim", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
316 + rd_contexts = rrddim_add(st_memory, "contexts", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
317 + rd_health = rrddim_add(st_memory, "health", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
318 + rd_functions = rrddim_add(st_memory, "functions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
319 + rd_labels = rrddim_add(st_memory, "labels", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
320 + rd_strings = rrddim_add(st_memory, "strings", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
321 + rd_streaming = rrddim_add(st_memory, "streaming", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
322 + rd_replication = rrddim_add(st_memory, "replication", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
323 + rd_buffers = rrddim_add(st_memory, "buffers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
324 + rd_workers = rrddim_add(st_memory, "workers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
325 + rd_other = rrddim_add(st_memory, "other", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
326 + }
327 +
328 + size_t buffers =
329 + netdata_buffers_statistics.query_targets_size +
330 + netdata_buffers_statistics.rrdset_done_rda_size +
331 + netdata_buffers_statistics.buffers_aclk +
332 + netdata_buffers_statistics.buffers_api +
333 + netdata_buffers_statistics.buffers_functions +
334 + netdata_buffers_statistics.buffers_sqlite +
335 + netdata_buffers_statistics.buffers_exporters +
336 + netdata_buffers_statistics.buffers_health +
337 + netdata_buffers_statistics.buffers_streaming +
338 + netdata_buffers_statistics.cbuffers_streaming +
339 + netdata_buffers_statistics.buffers_web +
340 + replication_allocated_buffers();
341 +
342 + size_t strings = 0;
343 + string_statistics(NULL, NULL, NULL, NULL, NULL, &strings, NULL, NULL);
344 +
345 + rrddim_set_by_pointer(st_memory, rd_database, (collected_number)dbengine_total_memory + (collected_number)rrddim_db_memory_size);
346 + rrddim_set_by_pointer(st_memory, rd_collectors, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_collectors));
347 + rrddim_set_by_pointer(st_memory, rd_hosts, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_rrdhost) + (collected_number)netdata_buffers_statistics.rrdhost_allocations_size);
348 + rrddim_set_by_pointer(st_memory, rd_rrd, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_rrdset_rrddim));
349 + rrddim_set_by_pointer(st_memory, rd_contexts, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_rrdcontext));
350 + rrddim_set_by_pointer(st_memory, rd_health, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_rrdhealth));
351 + rrddim_set_by_pointer(st_memory, rd_functions, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_functions));
352 + rrddim_set_by_pointer(st_memory, rd_labels, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_rrdlabels));
353 + rrddim_set_by_pointer(st_memory, rd_strings, (collected_number)strings);
354 + rrddim_set_by_pointer(st_memory, rd_streaming, (collected_number)netdata_buffers_statistics.rrdhost_senders + (collected_number)netdata_buffers_statistics.rrdhost_receivers);
355 + rrddim_set_by_pointer(st_memory, rd_replication, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_replication) + (collected_number)replication_allocated_memory());
356 + rrddim_set_by_pointer(st_memory, rd_buffers, (collected_number)buffers);
357 + rrddim_set_by_pointer(st_memory, rd_workers, (collected_number) workers_allocated_memory());
358 + rrddim_set_by_pointer(st_memory, rd_other, (collected_number)dictionary_stats_memory_total(dictionary_stats_category_other));
359 +
360 + rrdset_done(st_memory);
361 + }
362 +
363 + {
364 + static RRDSET *st_memory_buffers = NULL;
365 + static RRDDIM *rd_queries = NULL;
366 + static RRDDIM *rd_collectors = NULL;
367 + static RRDDIM *rd_buffers_aclk = NULL;
368 + static RRDDIM *rd_buffers_api = NULL;
369 + static RRDDIM *rd_buffers_functions = NULL;
370 + static RRDDIM *rd_buffers_sqlite = NULL;
371 + static RRDDIM *rd_buffers_exporters = NULL;
372 + static RRDDIM *rd_buffers_health = NULL;
373 + static RRDDIM *rd_buffers_streaming = NULL;
374 + static RRDDIM *rd_cbuffers_streaming = NULL;
375 + static RRDDIM *rd_buffers_replication = NULL;
376 + static RRDDIM *rd_buffers_web = NULL;
377 +
378 + if (unlikely(!st_memory_buffers)) {
379 + st_memory_buffers = rrdset_create_localhost(
380 "netdata",
279 - "uptime",
381 + "memory_buffers",
382 NULL,
383 "netdata",
384 NULL,
283 - "Netdata uptime",
284 - "seconds",
385 + "Netdata Memory Buffers",
386 + "bytes",
387 "netdata",
388 "stats",
287 - 130100,
389 + 130101,
390 localhost->rrd_update_every,
289 - RRDSET_TYPE_LINE);
391 + RRDSET_TYPE_STACKED);
392 +
393 + rd_queries = rrddim_add(st_memory_buffers, "queries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
394 + rd_collectors = rrddim_add(st_memory_buffers, "collection", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
395 + rd_buffers_aclk = rrddim_add(st_memory_buffers, "aclk", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
396 + rd_buffers_api = rrddim_add(st_memory_buffers, "api", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
397 + rd_buffers_functions = rrddim_add(st_memory_buffers, "functions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
398 + rd_buffers_sqlite = rrddim_add(st_memory_buffers, "sqlite", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
399 + rd_buffers_exporters = rrddim_add(st_memory_buffers, "exporters", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
400 + rd_buffers_health = rrddim_add(st_memory_buffers, "health", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
401 + rd_buffers_streaming = rrddim_add(st_memory_buffers, "streaming", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
402 + rd_cbuffers_streaming = rrddim_add(st_memory_buffers, "streaming cbuf", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
403 + rd_buffers_replication = rrddim_add(st_memory_buffers, "replication", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
404 + rd_buffers_web = rrddim_add(st_memory_buffers, "web", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
405 + }
406 +
407 + rrddim_set_by_pointer(st_memory_buffers, rd_queries, (collected_number)netdata_buffers_statistics.query_targets_size + (collected_number) onewayalloc_allocated_memory());
408 + rrddim_set_by_pointer(st_memory_buffers, rd_collectors, (collected_number)netdata_buffers_statistics.rrdset_done_rda_size);
409 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_aclk, (collected_number)netdata_buffers_statistics.buffers_aclk);
410 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_api, (collected_number)netdata_buffers_statistics.buffers_api);
411 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_functions, (collected_number)netdata_buffers_statistics.buffers_functions);
412 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_sqlite, (collected_number)netdata_buffers_statistics.buffers_sqlite);
413 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_exporters, (collected_number)netdata_buffers_statistics.buffers_exporters);
414 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_health, (collected_number)netdata_buffers_statistics.buffers_health);
415 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_streaming, (collected_number)netdata_buffers_statistics.buffers_streaming);
416 + rrddim_set_by_pointer(st_memory_buffers, rd_cbuffers_streaming, (collected_number)netdata_buffers_statistics.cbuffers_streaming);
417 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_replication, (collected_number)replication_allocated_buffers());
418 + rrddim_set_by_pointer(st_memory_buffers, rd_buffers_web, (collected_number)netdata_buffers_statistics.buffers_web);
419 +
420 + rrdset_done(st_memory_buffers);
421 + }
422 +
423 + // ----------------------------------------------------------------
424 +
425 + {
426 + static RRDSET *st_uptime = NULL;
427 + static RRDDIM *rd_uptime = NULL;
428 +
429 + if (unlikely(!st_uptime)) {
430 + st_uptime = rrdset_create_localhost(
431 + "netdata",
432 + "uptime",
433 + NULL,
434 + "netdata",
435 + NULL,
436 + "Netdata uptime",
437 + "seconds",
438 + "netdata",
439 + "stats",
440 + 130150,
441 + localhost->rrd_update_every,
442 + RRDSET_TYPE_LINE);
443
444 rd_uptime = rrddim_add(st_uptime, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
445 }
@@ -1076,13 +1229,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1229
1230 {
1231 if (unlikely(!ptrs->st_cache_hit_ratio)) {
1079 - BUFFER *id = buffer_create(100);
1232 + BUFFER *id = buffer_create(100, NULL);
1233 buffer_sprintf(id, "dbengine_%s_cache_hit_ratio", name);
1234
1082 - BUFFER *family = buffer_create(100);
1235 + BUFFER *family = buffer_create(100, NULL);
1236 buffer_sprintf(family, "dbengine %s cache", name);
1237
1085 - BUFFER *title = buffer_create(100);
1238 + BUFFER *title = buffer_create(100, NULL);
1239 buffer_sprintf(title, "Netdata %s Cache Hit Ratio", name);
1240
1241 ptrs->st_cache_hit_ratio = rrdset_create_localhost(
@@ -1124,13 +1277,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1277
1278 {
1279 if (unlikely(!ptrs->st_operations)) {
1127 - BUFFER *id = buffer_create(100);
1280 + BUFFER *id = buffer_create(100, NULL);
1281 buffer_sprintf(id, "dbengine_%s_cache_operations", name);
1282
1130 - BUFFER *family = buffer_create(100);
1283 + BUFFER *family = buffer_create(100, NULL);
1284 buffer_sprintf(family, "dbengine %s cache", name);
1285
1133 - BUFFER *title = buffer_create(100);
1286 + BUFFER *title = buffer_create(100, NULL);
1287 buffer_sprintf(title, "Netdata %s Cache Operations", name);
1288
1289 ptrs->st_operations = rrdset_create_localhost(
@@ -1178,13 +1331,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1331
1332 {
1333 if (unlikely(!ptrs->st_pgc_memory)) {
1181 - BUFFER *id = buffer_create(100);
1334 + BUFFER *id = buffer_create(100, NULL);
1335 buffer_sprintf(id, "dbengine_%s_cache_memory", name);
1336
1184 - BUFFER *family = buffer_create(100);
1337 + BUFFER *family = buffer_create(100, NULL);
1338 buffer_sprintf(family, "dbengine %s cache", name);
1339
1187 - BUFFER *title = buffer_create(100);
1340 + BUFFER *title = buffer_create(100, NULL);
1341 buffer_sprintf(title, "Netdata %s Cache Memory", name);
1342
1343 ptrs->st_pgc_memory = rrdset_create_localhost(
@@ -1232,13 +1385,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1385
1386 {
1387 if (unlikely(!ptrs->st_pgc_tm)) {
1235 - BUFFER *id = buffer_create(100);
1388 + BUFFER *id = buffer_create(100, NULL);
1389 buffer_sprintf(id, "dbengine_%s_target_memory", name);
1390
1238 - BUFFER *family = buffer_create(100);
1391 + BUFFER *family = buffer_create(100, NULL);
1392 buffer_sprintf(family, "dbengine %s cache", name);
1393
1241 - BUFFER *title = buffer_create(100);
1394 + BUFFER *title = buffer_create(100, NULL);
1395 buffer_sprintf(title, "Netdata %s Target Cache Memory", name);
1396
1397 ptrs->st_pgc_tm = rrdset_create_localhost(
@@ -1282,13 +1435,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1435
1436 {
1437 if (unlikely(!ptrs->st_pgc_pages)) {
1285 - BUFFER *id = buffer_create(100);
1438 + BUFFER *id = buffer_create(100, NULL);
1439 buffer_sprintf(id, "dbengine_%s_cache_pages", name);
1440
1288 - BUFFER *family = buffer_create(100);
1441 + BUFFER *family = buffer_create(100, NULL);
1442 buffer_sprintf(family, "dbengine %s cache", name);
1443
1291 - BUFFER *title = buffer_create(100);
1444 + BUFFER *title = buffer_create(100, NULL);
1445 buffer_sprintf(title, "Netdata %s Cache Pages", name);
1446
1447 ptrs->st_pgc_pages = rrdset_create_localhost(
@@ -1326,13 +1479,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1479
1480 {
1481 if (unlikely(!ptrs->st_pgc_memory_changes)) {
1329 - BUFFER *id = buffer_create(100);
1482 + BUFFER *id = buffer_create(100, NULL);
1483 buffer_sprintf(id, "dbengine_%s_cache_memory_changes", name);
1484
1332 - BUFFER *family = buffer_create(100);
1485 + BUFFER *family = buffer_create(100, NULL);
1486 buffer_sprintf(family, "dbengine %s cache", name);
1487
1335 - BUFFER *title = buffer_create(100);
1488 + BUFFER *title = buffer_create(100, NULL);
1489 buffer_sprintf(title, "Netdata %s Cache Memory Changes", name);
1490
1491 ptrs->st_pgc_memory_changes = rrdset_create_localhost(
@@ -1368,13 +1521,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1521
1522 {
1523 if (unlikely(!ptrs->st_pgc_memory_migrations)) {
1371 - BUFFER *id = buffer_create(100);
1524 + BUFFER *id = buffer_create(100, NULL);
1525 buffer_sprintf(id, "dbengine_%s_cache_memory_migrations", name);
1526
1374 - BUFFER *family = buffer_create(100);
1527 + BUFFER *family = buffer_create(100, NULL);
1528 buffer_sprintf(family, "dbengine %s cache", name);
1529
1377 - BUFFER *title = buffer_create(100);
1530 + BUFFER *title = buffer_create(100, NULL);
1531 buffer_sprintf(title, "Netdata %s Cache Memory Migrations", name);
1532
1533 ptrs->st_pgc_memory_migrations = rrdset_create_localhost(
@@ -1408,13 +1561,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1561
1562 {
1563 if (unlikely(!ptrs->st_pgc_memory_events)) {
1411 - BUFFER *id = buffer_create(100);
1564 + BUFFER *id = buffer_create(100, NULL);
1565 buffer_sprintf(id, "dbengine_%s_cache_events", name);
1566
1414 - BUFFER *family = buffer_create(100);
1567 + BUFFER *family = buffer_create(100, NULL);
1568 buffer_sprintf(family, "dbengine %s cache", name);
1569
1417 - BUFFER *title = buffer_create(100);
1570 + BUFFER *title = buffer_create(100, NULL);
1571 buffer_sprintf(title, "Netdata %s Cache Events", name);
1572
1573 ptrs->st_pgc_memory_events = rrdset_create_localhost(
@@ -1450,13 +1603,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1603
1604 {
1605 if (unlikely(!ptrs->st_pgc_waste)) {
1453 - BUFFER *id = buffer_create(100);
1606 + BUFFER *id = buffer_create(100, NULL);
1607 buffer_sprintf(id, "dbengine_%s_waste_events", name);
1608
1456 - BUFFER *family = buffer_create(100);
1609 + BUFFER *family = buffer_create(100, NULL);
1610 buffer_sprintf(family, "dbengine %s cache", name);
1611
1459 - BUFFER *title = buffer_create(100);
1612 + BUFFER *title = buffer_create(100, NULL);
1613 buffer_sprintf(title, "Netdata %s Waste Events", name);
1614
1615 ptrs->st_pgc_waste = rrdset_create_localhost(
@@ -1502,13 +1655,13 @@ static void dbengine2_cache_statistics_charts(struct dbengine2_cache_pointers *p
1655
1656 {
1657 if (unlikely(!ptrs->st_pgc_workers)) {
1505 - BUFFER *id = buffer_create(100);
1658 + BUFFER *id = buffer_create(100, NULL);
1659 buffer_sprintf(id, "dbengine_%s_cache_workers", name);
1660
1508 - BUFFER *family = buffer_create(100);
1661 + BUFFER *family = buffer_create(100, NULL);
1662 buffer_sprintf(family, "dbengine %s cache", name);
1663
1511 - BUFFER *title = buffer_create(100);
1664 + BUFFER *title = buffer_create(100, NULL);
1665 buffer_sprintf(title, "Netdata %s Cache Workers", name);
1666
1667 ptrs->st_pgc_workers = rrdset_create_localhost(
@@ -1587,6 +1740,8 @@ static void dbengine2_statistics_charts(void) {
1740 buffers_total_size += buffers.julyl;
1741 #endif
1742
1743 + dbengine_total_memory = pgc_main_stats.size + pgc_open_stats.size + pgc_extent_stats.size + mrg_stats.size + buffers_total_size;
1744 +
1745 size_t priority = 135000;
1746
1747 {
@@ -1620,6 +1775,7 @@ static void dbengine2_statistics_charts(void) {
1775 }
1776 priority++;
1777
1778 +
1779 rrddim_set_by_pointer(st_pgc_memory, rd_pgc_memory_main, (collected_number)pgc_main_stats.size);
1780 rrddim_set_by_pointer(st_pgc_memory, rd_pgc_memory_open, (collected_number)pgc_open_stats.size);
1781 rrddim_set_by_pointer(st_pgc_memory, rd_pgc_memory_extent, (collected_number)pgc_extent_stats.size);
@@ -2549,6 +2705,15 @@ static void update_heartbeat_charts() {
2705 // ---------------------------------------------------------------------------------------------------------------------
2706 // dictionary statistics
2707
2708 +struct dictionary_stats dictionary_stats_category_collectors = { .name = "collectors" };
2709 +struct dictionary_stats dictionary_stats_category_rrdhost = { .name = "rrdhost" };
2710 +struct dictionary_stats dictionary_stats_category_rrdset_rrddim = { .name = "rrdset_rrddim" };
2711 +struct dictionary_stats dictionary_stats_category_rrdcontext = { .name = "context" };
2712 +struct dictionary_stats dictionary_stats_category_rrdlabels = { .name = "labels" };
2713 +struct dictionary_stats dictionary_stats_category_rrdhealth = { .name = "health" };
2714 +struct dictionary_stats dictionary_stats_category_functions = { .name = "functions" };
2715 +struct dictionary_stats dictionary_stats_category_replication = { .name = "replication" };
2716 +
2717 struct dictionary_categories {
2718 struct dictionary_stats *stats;
2719 const char *family;
@@ -2594,7 +2759,15 @@ struct dictionary_categories {
2759 RRDDIM *rd_spins_delete;
2760
2761 } dictionary_categories[] = {
2597 - { .stats = &dictionary_stats_category_other, "dictionaries", "dictionaries", 900000 },
2762 + { .stats = &dictionary_stats_category_collectors, "dictionaries collectors", "dictionaries", 900000 },
2763 + { .stats = &dictionary_stats_category_rrdhost, "dictionaries hosts", "dictionaries", 900000 },
2764 + { .stats = &dictionary_stats_category_rrdset_rrddim, "dictionaries rrd", "dictionaries", 900000 },
2765 + { .stats = &dictionary_stats_category_rrdcontext, "dictionaries contexts", "dictionaries", 900000 },
2766 + { .stats = &dictionary_stats_category_rrdlabels, "dictionaries labels", "dictionaries", 900000 },
2767 + { .stats = &dictionary_stats_category_rrdhealth, "dictionaries health", "dictionaries", 900000 },
2768 + { .stats = &dictionary_stats_category_functions, "dictionaries functions", "dictionaries", 900000 },
2769 + { .stats = &dictionary_stats_category_replication, "dictionaries replication", "dictionaries", 900000 },
2770 + { .stats = &dictionary_stats_category_other, "dictionaries other", "dictionaries", 900000 },
2771
2772 // terminator
2773 { .stats = NULL, NULL, NULL, 0 },
@@ -2804,7 +2977,7 @@ static void update_dictionary_category_charts(struct dictionary_categories *c) {
2977 // ------------------------------------------------------------------------
2978
2979 total = 0;
2807 - load_dictionary_stats_entry(memory.indexed);
2980 + load_dictionary_stats_entry(memory.index);
2981 load_dictionary_stats_entry(memory.values);
2982 load_dictionary_stats_entry(memory.dict);
2983
@@ -2838,7 +3011,7 @@ static void update_dictionary_category_charts(struct dictionary_categories *c) {
3011 rrdlabels_add(c->st_memory->rrdlabels, "category", stats.name, RRDLABEL_SRC_AUTO);
3012 }
3013
2841 - rrddim_set_by_pointer(c->st_memory, c->rd_memory_indexed, (collected_number)stats.memory.indexed);
3014 + rrddim_set_by_pointer(c->st_memory, c->rd_memory_indexed, (collected_number)stats.memory.index);
3015 rrddim_set_by_pointer(c->st_memory, c->rd_memory_values, (collected_number)stats.memory.values);
3016 rrddim_set_by_pointer(c->st_memory, c->rd_memory_dict, (collected_number)stats.memory.dict);
3017
daemon/global_statistics.h
+28
@@ -5,6 +5,34 @@
5
6 #include "database/rrd.h"
7
8 +extern struct netdata_buffers_statistics {
9 + size_t rrdhost_allocations_size;
10 + size_t rrdhost_senders;
11 + size_t rrdhost_receivers;
12 + size_t query_targets_size;
13 + size_t rrdset_done_rda_size;
14 + size_t buffers_aclk;
15 + size_t buffers_api;
16 + size_t buffers_functions;
17 + size_t buffers_sqlite;
18 + size_t buffers_exporters;
19 + size_t buffers_health;
20 + size_t buffers_streaming;
21 + size_t cbuffers_streaming;
22 + size_t buffers_web;
23 +} netdata_buffers_statistics;
24 +
25 +extern struct dictionary_stats dictionary_stats_category_collectors;
26 +extern struct dictionary_stats dictionary_stats_category_rrdhost;
27 +extern struct dictionary_stats dictionary_stats_category_rrdset_rrddim;
28 +extern struct dictionary_stats dictionary_stats_category_rrdcontext;
29 +extern struct dictionary_stats dictionary_stats_category_rrdlabels;
30 +extern struct dictionary_stats dictionary_stats_category_rrdhealth;
31 +extern struct dictionary_stats dictionary_stats_category_functions;
32 +extern struct dictionary_stats dictionary_stats_category_replication;
33 +
34 +extern size_t rrddim_db_memory_size;
35 +
36 // ----------------------------------------------------------------------------
37 // global statistics
38
daemon/main.c
+3 -2
@@ -174,8 +174,8 @@ static void service_to_buffer(BUFFER *wb, SERVICE_TYPE service) {
174 }
175
176 static bool service_wait_exit(SERVICE_TYPE service, usec_t timeout_ut) {
177 - BUFFER *service_list = buffer_create(1024);
178 - BUFFER *thread_list = buffer_create(1024);
177 + BUFFER *service_list = buffer_create(1024, NULL);
178 + BUFFER *thread_list = buffer_create(1024, NULL);
179 usec_t started_ut = now_monotonic_usec(), ended_ut;
180 size_t running;
181 SERVICE_TYPE running_services = 0;
@@ -1926,6 +1926,7 @@ int main(int argc, char **argv) {
1926
1927 netdata_anonymous_statistics_enabled=-1;
1928 struct rrdhost_system_info *system_info = callocz(1, sizeof(struct rrdhost_system_info));
1929 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
1930 get_system_info(system_info);
1931 system_info->hops = 0;
1932 get_install_type(&system_info->install_type, &system_info->prebuilt_arch, &system_info->prebuilt_dist);
daemon/service.c
+3 -3
@@ -52,13 +52,13 @@ static void svc_rrddim_obsolete_to_archive(RRDDIM *rd) {
52
53 size_t tiers_available = 0, tiers_said_no_retention = 0;
54 for(size_t tier = 0; tier < storage_tiers ;tier++) {
55 - if(rd->tiers[tier]) {
55 + if(rd->tiers[tier].db_collection_handle) {
56 tiers_available++;
57
58 - if(rd->tiers[tier]->collect_ops->finalize(rd->tiers[tier]->db_collection_handle))
58 + if(rd->tiers[tier].collect_ops->finalize(rd->tiers[tier].db_collection_handle))
59 tiers_said_no_retention++;
60
61 - rd->tiers[tier]->db_collection_handle = NULL;
61 + rd->tiers[tier].db_collection_handle = NULL;
62 }
63 }
64
daemon/unit_test.c
+15 -15
@@ -439,7 +439,7 @@ int unit_test_str2ld() {
439 }
440
441 int unit_test_buffer() {
442 - BUFFER *wb = buffer_create(1);
442 + BUFFER *wb = buffer_create(1, NULL);
443 char string[2048 + 1];
444 char final[9000 + 1];
445 int i;
@@ -1349,7 +1349,7 @@ static int test_variable_renames(void) {
1349 rrddim_reset_name(st, rd2, "DIM2NAME2");
1350 fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rrddim_id(rd2), rrddim_name(rd2));
1351
1352 - BUFFER *buf = buffer_create(1);
1352 + BUFFER *buf = buffer_create(1, NULL);
1353 health_api_v1_chart_variables2json(st, buf);
1354 fprintf(stderr, "%s", buffer_tostring(buf));
1355 buffer_free(buf);
@@ -1604,7 +1604,7 @@ int test_sqlite(void) {
1604 return 1;
1605 }
1606
1607 - BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE);
1607 + BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, NULL);
1608 char *uuid_str = "0000_000";
1609
1610 buffer_sprintf(sql, TABLE_ACLK_ALERT, uuid_str);
@@ -1861,7 +1861,7 @@ static void test_dbengine_create_charts(RRDHOST *host, RRDSET *st[CHARTS], RRDDI
1861 // Fluh pages for subsequent real values
1862 for (i = 0 ; i < CHARTS ; ++i) {
1863 for (j = 0; j < DIMS; ++j) {
1864 - rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0]->db_collection_handle);
1864 + rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0].db_collection_handle);
1865 }
1866 }
1867 }
@@ -1880,7 +1880,7 @@ static time_t test_dbengine_create_metrics(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS
1880 // feed it with the test data
1881 for (i = 0 ; i < CHARTS ; ++i) {
1882 for (j = 0 ; j < DIMS ; ++j) {
1883 - rd[i][j]->tiers[0]->collect_ops->change_collection_frequency(rd[i][j]->tiers[0]->db_collection_handle, update_every);
1883 + rd[i][j]->tiers[0].collect_ops->change_collection_frequency(rd[i][j]->tiers[0].db_collection_handle, update_every);
1884
1885 rd[i][j]->last_collected_time.tv_sec =
1886 st[i]->last_collected_time.tv_sec = st[i]->last_updated.tv_sec = time_now;
@@ -1931,13 +1931,13 @@ static int test_dbengine_check_metrics(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DI
1931 time_now = time_start + (c + 1) * update_every;
1932 for (i = 0 ; i < CHARTS ; ++i) {
1933 for (j = 0; j < DIMS; ++j) {
1934 - rd[i][j]->tiers[0]->query_ops->init(rd[i][j]->tiers[0]->db_metric_handle, &handle, time_now, time_now + QUERY_BATCH * update_every, STORAGE_PRIORITY_NORMAL);
1934 + rd[i][j]->tiers[0].query_ops->init(rd[i][j]->tiers[0].db_metric_handle, &handle, time_now, time_now + QUERY_BATCH * update_every, STORAGE_PRIORITY_NORMAL);
1935 for (k = 0; k < QUERY_BATCH; ++k) {
1936 last = ((collected_number)i * DIMS) * REGION_POINTS[current_region] +
1937 j * REGION_POINTS[current_region] + c + k;
1938 expected = unpack_storage_number(pack_storage_number((NETDATA_DOUBLE)last, SN_DEFAULT_FLAGS));
1939
1940 - STORAGE_POINT sp = rd[i][j]->tiers[0]->query_ops->next_metric(&handle);
1940 + STORAGE_POINT sp = rd[i][j]->tiers[0].query_ops->next_metric(&handle);
1941 value = sp.sum;
1942 time_retrieved = sp.start_time_s;
1943 end_time = sp.end_time_s;
@@ -1959,7 +1959,7 @@ static int test_dbengine_check_metrics(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DI
1959 errors++;
1960 }
1961 }
1962 - rd[i][j]->tiers[0]->query_ops->finalize(&handle);
1962 + rd[i][j]->tiers[0].query_ops->finalize(&handle);
1963 }
1964 }
1965 }
@@ -2084,7 +2084,7 @@ int test_dbengine(void)
2084 for (i = 0 ; i < CHARTS ; ++i) {
2085 st[i]->update_every = update_every;
2086 for (j = 0; j < DIMS; ++j) {
2087 - rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0]->db_collection_handle);
2087 + rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0].db_collection_handle);
2088 }
2089 }
2090
@@ -2103,7 +2103,7 @@ int test_dbengine(void)
2103 for (i = 0 ; i < CHARTS ; ++i) {
2104 st[i]->update_every = update_every;
2105 for (j = 0; j < DIMS; ++j) {
2106 - rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0]->db_collection_handle);
2106 + rrdeng_store_metric_flush_current_page((rd[i][j])->tiers[0].db_collection_handle);
2107 }
2108 }
2109
@@ -2270,7 +2270,7 @@ static void generate_dbengine_chart(void *arg)
2270 thread_info->time_max = time_current;
2271 }
2272 for (j = 0; j < DSET_DIMS; ++j) {
2273 - rrdeng_store_metric_finalize((rd[j])->tiers[0]->db_collection_handle);
2273 + rrdeng_store_metric_finalize((rd[j])->tiers[0].db_collection_handle);
2274 }
2275 }
2276
@@ -2390,13 +2390,13 @@ static void query_dbengine_chart(void *arg)
2390 time_before = MIN(time_after + duration, time_max); /* up to 1 hour queries */
2391 }
2392
2393 - rd->tiers[0]->query_ops->init(rd->tiers[0]->db_metric_handle, &handle, time_after, time_before, STORAGE_PRIORITY_NORMAL);
2393 + rd->tiers[0].query_ops->init(rd->tiers[0].db_metric_handle, &handle, time_after, time_before, STORAGE_PRIORITY_NORMAL);
2394 ++thread_info->queries_nr;
2395 for (time_now = time_after ; time_now <= time_before ; time_now += update_every) {
2396 generatedv = generate_dbengine_chart_value(i, j, time_now);
2397 expected = unpack_storage_number(pack_storage_number((NETDATA_DOUBLE) generatedv, SN_DEFAULT_FLAGS));
2398
2399 - if (unlikely(rd->tiers[0]->query_ops->is_finished(&handle))) {
2399 + if (unlikely(rd->tiers[0].query_ops->is_finished(&handle))) {
2400 if (!thread_info->delete_old_data) { /* data validation only when we don't delete */
2401 fprintf(stderr, " DB-engine stresstest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
2402 ", found data gap, ### E R R O R ###\n",
@@ -2406,7 +2406,7 @@ static void query_dbengine_chart(void *arg)
2406 break;
2407 }
2408
2409 - STORAGE_POINT sp = rd->tiers[0]->query_ops->next_metric(&handle);
2409 + STORAGE_POINT sp = rd->tiers[0].query_ops->next_metric(&handle);
2410 value = sp.sum;
2411 time_retrieved = sp.start_time_s;
2412 end_time = sp.end_time_s;
@@ -2444,7 +2444,7 @@ static void query_dbengine_chart(void *arg)
2444 }
2445 }
2446 }
2447 - rd->tiers[0]->query_ops->finalize(&handle);
2447 + rd->tiers[0].query_ops->finalize(&handle);
2448 } while(!thread_info->done);
2449
2450 if(value_errors)
database/engine/cache.c
+25 -18
@@ -92,6 +92,7 @@ struct pgc {
92 size_t additional_bytes_per_page;
93 free_clean_page_callback pgc_free_clean_cb;
94 save_dirty_page_callback pgc_save_dirty_cb;
95 + save_dirty_init_callback pgc_save_init_cb;
96 PGC_OPTIONS options;
97
98 size_t severe_pressure_per1000;
@@ -205,7 +206,7 @@ static inline void pointer_del(PGC *cache __maybe_unused, PGC_PAGE *page __maybe
206 // ----------------------------------------------------------------------------
207 // locking
208
208 -static size_t pgc_indexing_partition(PGC *cache, Word_t metric_id) {
209 +static inline size_t pgc_indexing_partition(PGC *cache, Word_t metric_id) {
210 static __thread Word_t last_metric_id = 0;
211 static __thread size_t last_partition = 0;
212
@@ -218,19 +219,19 @@ static size_t pgc_indexing_partition(PGC *cache, Word_t metric_id) {
219 return last_partition;
220 }
221
221 -static void pgc_index_read_lock(PGC *cache, size_t partition) {
222 +static inline void pgc_index_read_lock(PGC *cache, size_t partition) {
223 netdata_rwlock_rdlock(&cache->index[partition].rwlock);
224 }
224 -static void pgc_index_read_unlock(PGC *cache, size_t partition) {
225 +static inline void pgc_index_read_unlock(PGC *cache, size_t partition) {
226 netdata_rwlock_unlock(&cache->index[partition].rwlock);
227 }
227 -//static bool pgc_index_write_trylock(PGC *cache, size_t partition) {
228 +//static inline bool pgc_index_write_trylock(PGC *cache, size_t partition) {
229 // return !netdata_rwlock_trywrlock(&cache->index[partition].rwlock);
230 //}
230 -static void pgc_index_write_lock(PGC *cache, size_t partition) {
231 +static inline void pgc_index_write_lock(PGC *cache, size_t partition) {
232 netdata_rwlock_wrlock(&cache->index[partition].rwlock);
233 }
233 -static void pgc_index_write_unlock(PGC *cache, size_t partition) {
234 +static inline void pgc_index_write_unlock(PGC *cache, size_t partition) {
235 netdata_rwlock_unlock(&cache->index[partition].rwlock);
236 }
237
@@ -382,11 +383,11 @@ static inline bool flushing_critical(PGC *cache) {
383 // ----------------------------------------------------------------------------
384 // helpers
385
385 -static size_t page_assumed_size(PGC *cache, size_t size) {
386 +static inline size_t page_assumed_size(PGC *cache, size_t size) {
387 return size + (sizeof(PGC_PAGE) + cache->config.additional_bytes_per_page + sizeof(Word_t) * 3);
388 }
389
389 -static size_t page_size_from_assumed_size(PGC *cache, size_t assumed_size) {
390 +static inline size_t page_size_from_assumed_size(PGC *cache, size_t assumed_size) {
391 return assumed_size - (sizeof(PGC_PAGE) + cache->config.additional_bytes_per_page + sizeof(Word_t) * 3);
392 }
393
@@ -422,7 +423,7 @@ static ARAL section_pages_aral = {
423 .requested_element_size = sizeof(struct section_pages),
424 };
425
425 -static void pgc_stats_ll_judy_change(PGC *cache, struct pgc_linked_list *ll, size_t mem_before_judyl, size_t mem_after_judyl) {
426 +static inline void pgc_stats_ll_judy_change(PGC *cache, struct pgc_linked_list *ll, size_t mem_before_judyl, size_t mem_after_judyl) {
427 if(mem_after_judyl > mem_before_judyl) {
428 __atomic_add_fetch(&ll->stats->size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
429 __atomic_add_fetch(&cache->stats.size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
@@ -433,7 +434,7 @@ static void pgc_stats_ll_judy_change(PGC *cache, struct pgc_linked_list *ll, siz
434 }
435 }
436
436 -static void pgc_stats_index_judy_change(PGC *cache, size_t mem_before_judyl, size_t mem_after_judyl) {
437 +static inline void pgc_stats_index_judy_change(PGC *cache, size_t mem_before_judyl, size_t mem_after_judyl) {
438 if(mem_after_judyl > mem_before_judyl) {
439 __atomic_add_fetch(&cache->stats.size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
440 }
@@ -556,7 +557,7 @@ static void pgc_ll_del(PGC *cache __maybe_unused, struct pgc_linked_list *ll, PG
557 pgc_ll_unlock(cache, ll);
558 }
559
559 -static void page_has_been_accessed(PGC *cache, PGC_PAGE *page) {
560 +static inline void page_has_been_accessed(PGC *cache, PGC_PAGE *page) {
561 PGC_PAGE_FLAGS flags = page_flag_check(page, PGC_PAGE_CLEAN | PGC_PAGE_HAS_NO_DATA_IGNORE_ACCESSES);
562
563 if (!(flags & PGC_PAGE_HAS_NO_DATA_IGNORE_ACCESSES)) {
@@ -604,7 +605,7 @@ static inline void page_set_clean(PGC *cache, PGC_PAGE *page, bool having_transi
605 page_transition_unlock(cache, page);
606 }
607
607 -static void page_set_dirty(PGC *cache, PGC_PAGE *page, bool having_hot_lock) {
608 +static inline void page_set_dirty(PGC *cache, PGC_PAGE *page, bool having_hot_lock) {
609 if(!having_hot_lock)
610 // to avoid deadlocks, we have to get the hot lock before the page transition
611 // since this is what all_hot_to_dirty() does
@@ -830,7 +831,7 @@ static inline bool acquired_page_get_for_deletion_or_release_it(PGC *cache __may
831 // ----------------------------------------------------------------------------
832 // Indexing
833
833 -static void free_this_page(PGC *cache, PGC_PAGE *page) {
834 +static inline void free_this_page(PGC *cache, PGC_PAGE *page) {
835 // call the callback to free the user supplied memory
836 cache->config.pgc_free_clean_cb(cache, (PGC_ENTRY){
837 .section = page->section,
@@ -916,7 +917,7 @@ static void remove_this_page_from_index_unsafe(PGC *cache, PGC_PAGE *page, size_
917 pointer_del(cache, page);
918 }
919
919 -static void remove_and_free_page_not_in_any_queue_and_acquired_for_deletion(PGC *cache, PGC_PAGE *page) {
920 +static inline void remove_and_free_page_not_in_any_queue_and_acquired_for_deletion(PGC *cache, PGC_PAGE *page) {
921 size_t partition = pgc_indexing_partition(cache, page->metric_id);
922 pgc_index_write_lock(cache, partition);
923 remove_this_page_from_index_unsafe(cache, page, partition);
@@ -924,7 +925,7 @@ static void remove_and_free_page_not_in_any_queue_and_acquired_for_deletion(PGC
925 free_this_page(cache, page);
926 }
927
927 -static bool make_acquired_page_clean_and_evict_or_page_release(PGC *cache, PGC_PAGE *page) {
928 +static inline bool make_acquired_page_clean_and_evict_or_page_release(PGC *cache, PGC_PAGE *page) {
929 pointer_check(cache, page);
930
931 page_transition_lock(cache, page);
@@ -1632,6 +1633,9 @@ static bool flush_pages(PGC *cache, size_t max_flushes, Word_t section, bool wai
1633 continue;
1634 }
1635
1636 + if(cache->config.pgc_save_init_cb)
1637 + cache->config.pgc_save_init_cb(cache, last_section);
1638 +
1639 pgc_ll_unlock(cache, &cache->dirty);
1640 have_dirty_lock = false;
1641
@@ -1704,7 +1708,9 @@ void free_all_unreferenced_clean_pages(PGC *cache) {
1708 // public API
1709
1710 PGC *pgc_create(size_t clean_size_bytes, free_clean_page_callback pgc_free_cb,
1707 - size_t max_dirty_pages_per_flush, save_dirty_page_callback pgc_save_dirty_cb,
1711 + size_t max_dirty_pages_per_flush,
1712 + save_dirty_init_callback pgc_save_init_cb,
1713 + save_dirty_page_callback pgc_save_dirty_cb,
1714 size_t max_pages_per_inline_eviction, size_t max_inline_evictors,
1715 size_t max_skip_pages_per_inline_eviction,
1716 size_t max_flushes_inline,
@@ -1723,7 +1729,8 @@ PGC *pgc_create(size_t clean_size_bytes, free_clean_page_callback pgc_free_cb,
1729 cache->config.options = options;
1730 cache->config.clean_size = (clean_size_bytes < 1 * 1024 * 1024) ? 1 * 1024 * 1024 : clean_size_bytes;
1731 cache->config.pgc_free_clean_cb = pgc_free_cb;
1726 - cache->config.max_dirty_pages_per_call = max_dirty_pages_per_flush,
1732 + cache->config.max_dirty_pages_per_call = max_dirty_pages_per_flush;
1733 + cache->config.pgc_save_init_cb = pgc_save_init_cb;
1734 cache->config.pgc_save_dirty_cb = pgc_save_dirty_cb;
1735 cache->config.max_pages_per_inline_eviction = (max_pages_per_inline_eviction < 2) ? 2 : max_pages_per_inline_eviction;
1736 cache->config.max_skip_pages_per_inline_eviction = (max_skip_pages_per_inline_eviction < 2) ? 2 : max_skip_pages_per_inline_eviction;
@@ -2579,7 +2586,7 @@ void unittest_stress_test(void) {
2586
2587 int pgc_unittest(void) {
2588 PGC *cache = pgc_create(32 * 1024 * 1024, unittest_free_clean_page_callback,
2582 - 64, unittest_save_dirty_page_callback,
2589 + 64, NULL, unittest_save_dirty_page_callback,
2590 10, 10, 1000, 10,
2591 PGC_OPTIONS_DEFAULT, 1, 11);
2592
database/engine/cache.h
+2 -2
@@ -160,10 +160,10 @@ struct pgc_statistics {
160
161 typedef void (*free_clean_page_callback)(PGC *cache, PGC_ENTRY entry);
162 typedef void (*save_dirty_page_callback)(PGC *cache, PGC_ENTRY *entries_array, PGC_PAGE **pages_array, size_t entries);
163 -
163 +typedef void (*save_dirty_init_callback)(PGC *cache, Word_t section);
164 // create a cache
165 PGC *pgc_create(size_t clean_size_bytes, free_clean_page_callback pgc_free_clean_cb,
166 - size_t max_dirty_pages_per_flush, save_dirty_page_callback pgc_save_dirty_cb,
166 + size_t max_dirty_pages_per_flush, save_dirty_init_callback pgc_save_init_cb, save_dirty_page_callback pgc_save_dirty_cb,
167 size_t max_pages_per_inline_eviction, size_t max_inline_evictors,
168 size_t max_skip_pages_per_inline_eviction,
169 size_t max_flushes_inline,
database/engine/datafile.c
+26 -4
@@ -560,15 +560,34 @@ int init_data_files(struct rrdengine_instance *ctx)
560
561 void finalize_data_files(struct rrdengine_instance *ctx)
562 {
563 + bool logged = false;
564 +
565 do {
566 struct rrdengine_datafile *datafile = ctx->datafiles.first;
567 struct rrdengine_journalfile *journalfile = datafile->journalfile;
568
569 + logged = false;
570 + if(datafile == ctx->datafiles.first->prev) {
571 + // this is the last file
572 + while(__atomic_load_n(&ctx->worker_config.atomics.extents_currently_being_flushed, __ATOMIC_RELAXED)) {
573 + if(!logged) {
574 + info("Waiting for inflight flush to finish on tier %d to close last datafile %u...", ctx->tier, datafile->fileno);
575 + logged = true;
576 + }
577 + sleep_usec(100 * USEC_PER_MS);
578 + }
579 + }
580 +
581 + logged = false;
582 while(!datafile_acquire_for_deletion(datafile) && datafile != ctx->datafiles.first->prev) {
568 - info("Waiting to acquire data file %u of tier %d to close it...", datafile->fileno, ctx->tier);
569 - sleep_usec(500 * USEC_PER_MS);
583 + if(!logged) {
584 + info("Waiting to acquire data file %u of tier %d to close it...", datafile->fileno, ctx->tier);
585 + logged = true;
586 + }
587 + sleep_usec(100 * USEC_PER_MS);
588 }
589
590 + logged = false;
591 bool available = false;
592 do {
593 uv_rwlock_wrlock(&ctx->datafiles.rwlock);
@@ -578,8 +597,11 @@ void finalize_data_files(struct rrdengine_instance *ctx)
597 if(!available) {
598 netdata_spinlock_unlock(&datafile->writers.spinlock);
599 uv_rwlock_wrunlock(&ctx->datafiles.rwlock);
581 - info("Waiting for writers to data file %u of tier %d to finish...", datafile->fileno, ctx->tier);
582 - sleep_usec(500 * USEC_PER_MS);
600 + if(!logged) {
601 + info("Waiting for writers to data file %u of tier %d to finish...", datafile->fileno, ctx->tier);
602 + logged = true;
603 + }
604 + sleep_usec(100 * USEC_PER_MS);
605 }
606 } while(!available);
607
database/engine/journalfile.c
+17 -10
@@ -9,7 +9,7 @@ static void update_metric_retention_and_granularity_by_uuid(
9 time_t first_time_s, time_t last_time_s,
10 time_t update_every_s, time_t now_s)
11 {
12 - if(last_time_s > now_s) {
12 + if(unlikely(last_time_s > now_s)) {
13 error_limit_static_global_var(erl, 1, 0);
14 error_limit(&erl, "DBENGINE JV2: wrong last time on-disk (%ld - %ld, now %ld), "
15 "fixing last time to now",
@@ -17,7 +17,7 @@ static void update_metric_retention_and_granularity_by_uuid(
17 last_time_s = now_s;
18 }
19
20 - if(first_time_s > last_time_s) {
20 + if(unlikely(first_time_s > last_time_s)) {
21 error_limit_static_global_var(erl, 1, 0);
22 error_limit(&erl, "DBENGINE JV2: wrong first time on-disk (%ld - %ld, now %ld), "
23 "fixing first time to last time",
@@ -26,9 +26,7 @@ static void update_metric_retention_and_granularity_by_uuid(
26 first_time_s = last_time_s;
27 }
28
29 - if(first_time_s == 0 ||
30 - last_time_s == 0
31 - ) {
29 + if(unlikely(first_time_s == 0 || last_time_s == 0)) {
30 error_limit_static_global_var(erl, 1, 0);
31 error_limit(&erl, "DBENGINE JV2: zero on-disk timestamps (%ld - %ld, now %ld), "
32 "using them as-is",
@@ -949,7 +947,7 @@ int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journal
947 return 1;
948 }
949
952 - usec_t start_loading = now_realtime_usec();
950 + usec_t mmap_start_ut = now_monotonic_usec();
951 uint8_t *data_start = mmap(NULL, journal_v2_file_size, PROT_READ, MAP_SHARED, fd, 0);
952 if (data_start == MAP_FAILED) {
953 close(fd);
@@ -957,6 +955,7 @@ int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journal
955 }
956
957 info("DBENGINE: checking integrity of '%s'", path_v2);
958 + usec_t validation_start_ut = now_monotonic_usec();
959 int rc = journalfile_v2_validate(data_start, journal_v2_file_size, journal_v1_file_size);
960 if (unlikely(rc)) {
961 if (rc == 2)
@@ -987,10 +986,9 @@ int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journal
986 madvise_dontfork(data_start, journal_v2_file_size);
987 madvise_dontdump(data_start, journal_v2_file_size);
988
989 + usec_t mrg_start_ut = now_monotonic_usec();
990 struct journal_metric_list *metric = (struct journal_metric_list *) (data_start + j2_header->metric_offset);
991 -
991 time_t header_start_time_s = (time_t) (j2_header->start_time_ut / USEC_PER_SEC);
993 -
992 time_t now_s = now_realtime_sec();
993 for (size_t i=0; i < entries; i++) {
994 time_t start_time_s = header_start_time_s + metric->delta_start_s;
@@ -1007,8 +1005,17 @@ int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journal
1005 metric++;
1006 }
1007
1010 - info("DBENGINE: journal file '%s' loaded (size:%"PRIu64") with %u metrics in %d ms", path_v2, journal_v2_file_size, entries,
1011 - (int) ((now_realtime_usec() - start_loading) / USEC_PER_MS));
1008 + usec_t finished_ut = now_monotonic_usec();
1009 +
1010 + info("DBENGINE: journal v2 '%s' loaded, size: %0.2f MiB, metrics: %0.2f k, "
1011 + "mmap: %0.2f ms, validate: %0.2f ms, populate: %0.2f ms"
1012 + , path_v2
1013 + , (double)journal_v2_file_size / 1024 / 1024
1014 + , (double)entries / 1000
1015 + , ((double)(validation_start_ut - mmap_start_ut) / USEC_PER_MS)
1016 + , ((double)(mrg_start_ut - validation_start_ut) / USEC_PER_MS)
1017 + , ((double)(finished_ut - mrg_start_ut) / USEC_PER_MS)
1018 + );
1019
1020 // Initialize the journal file to be able to access the data
1021 journalfile_v2_data_set(journalfile, fd, data_start, journal_v2_file_size);
database/engine/metric.c
+18 -18
@@ -54,16 +54,16 @@ static inline void MRG_STATS_DELETE_MISS(MRG *mrg) {
54 __atomic_add_fetch(&mrg->stats.delete_misses, 1, __ATOMIC_RELAXED);
55 }
56
57 -static void mrg_index_read_lock(MRG *mrg) {
57 +static inline void mrg_index_read_lock(MRG *mrg) {
58 netdata_rwlock_rdlock(&mrg->index.rwlock);
59 }
60 -static void mrg_index_read_unlock(MRG *mrg) {
60 +static inline void mrg_index_read_unlock(MRG *mrg) {
61 netdata_rwlock_unlock(&mrg->index.rwlock);
62 }
63 -static void mrg_index_write_lock(MRG *mrg) {
63 +static inline void mrg_index_write_lock(MRG *mrg) {
64 netdata_rwlock_wrlock(&mrg->index.rwlock);
65 }
66 -static void mrg_index_write_unlock(MRG *mrg) {
66 +static inline void mrg_index_write_unlock(MRG *mrg) {
67 netdata_rwlock_unlock(&mrg->index.rwlock);
68 }
69
@@ -75,11 +75,11 @@ static inline void mrg_stats_size_judyl_change(MRG *mrg, size_t mem_before_judyl
75 }
76
77 static inline void mrg_stats_size_judyhs_added_uuid(MRG *mrg) {
78 - __atomic_add_fetch(&mrg->stats.size, sizeof(uuid_t) * 3, __ATOMIC_RELAXED);
78 + __atomic_add_fetch(&mrg->stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
79 }
80
81 static inline void mrg_stats_size_judyhs_removed_uuid(MRG *mrg) {
82 - __atomic_sub_fetch(&mrg->stats.size, sizeof(uuid_t) * 3, __ATOMIC_RELAXED);
82 + __atomic_sub_fetch(&mrg->stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
83 }
84
85 static METRIC *metric_add(MRG *mrg, MRG_ENTRY *entry, bool *ret) {
@@ -88,10 +88,10 @@ static METRIC *metric_add(MRG *mrg, MRG_ENTRY *entry, bool *ret) {
88 size_t mem_before_judyl, mem_after_judyl;
89
90 Pvoid_t *sections_judy_pptr = JudyHSIns(&mrg->index.uuid_judy, &entry->uuid, sizeof(uuid_t), PJE0);
91 - if(!sections_judy_pptr || sections_judy_pptr == PJERR)
91 + if(unlikely(!sections_judy_pptr || sections_judy_pptr == PJERR))
92 fatal("DBENGINE METRIC: corrupted UUIDs JudyHS array");
93
94 - if(!*sections_judy_pptr)
94 + if(unlikely(!*sections_judy_pptr))
95 mrg_stats_size_judyhs_added_uuid(mrg);
96
97 mem_before_judyl = JudyLMemUsed(*sections_judy_pptr);
@@ -99,7 +99,7 @@ static METRIC *metric_add(MRG *mrg, MRG_ENTRY *entry, bool *ret) {
99 mem_after_judyl = JudyLMemUsed(*sections_judy_pptr);
100 mrg_stats_size_judyl_change(mrg, mem_before_judyl, mem_after_judyl);
101
102 - if(!PValue || PValue == PJERR)
102 + if(unlikely(!PValue || PValue == PJERR))
103 fatal("DBENGINE METRIC: corrupted section JudyL array");
104
105 if(*PValue != NULL) {
@@ -137,14 +137,14 @@ static METRIC *metric_get(MRG *mrg, uuid_t *uuid, Word_t section) {
137 mrg_index_read_lock(mrg);
138
139 Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index.uuid_judy, uuid, sizeof(uuid_t));
140 - if(!sections_judy_pptr) {
140 + if(unlikely(!sections_judy_pptr)) {
141 mrg_index_read_unlock(mrg);
142 MRG_STATS_SEARCH_MISS(mrg);
143 return NULL;
144 }
145
146 Pvoid_t *PValue = JudyLGet(*sections_judy_pptr, section, PJE0);
147 - if(!PValue) {
147 + if(unlikely(!PValue)) {
148 mrg_index_read_unlock(mrg);
149 MRG_STATS_SEARCH_MISS(mrg);
150 return NULL;
@@ -164,7 +164,7 @@ static bool metric_del(MRG *mrg, METRIC *metric) {
164 mrg_index_write_lock(mrg);
165
166 Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index.uuid_judy, &metric->uuid, sizeof(uuid_t));
167 - if(!sections_judy_pptr || !*sections_judy_pptr) {
167 + if(unlikely(!sections_judy_pptr || !*sections_judy_pptr)) {
168 mrg_index_write_unlock(mrg);
169 MRG_STATS_DELETE_MISS(mrg);
170 return false;
@@ -175,7 +175,7 @@ static bool metric_del(MRG *mrg, METRIC *metric) {
175 mem_after_judyl = JudyLMemUsed(*sections_judy_pptr);
176 mrg_stats_size_judyl_change(mrg, mem_before_judyl, mem_after_judyl);
177
178 - if(!rc) {
178 + if(unlikely(!rc)) {
179 mrg_index_write_unlock(mrg);
180 MRG_STATS_DELETE_MISS(mrg);
181 return false;
@@ -183,7 +183,7 @@ static bool metric_del(MRG *mrg, METRIC *metric) {
183
184 if(!*sections_judy_pptr) {
185 rc = JudyHSDel(&mrg->index.uuid_judy, &metric->uuid, sizeof(uuid_t), PJE0);
186 - if(!rc)
186 + if(unlikely(!rc))
187 fatal("DBENGINE METRIC: cannot delete UUID from JudyHS");
188 mrg_stats_size_judyhs_removed_uuid(mrg);
189 }
@@ -277,16 +277,16 @@ void mrg_metric_expand_retention(MRG *mrg __maybe_unused, METRIC *metric, time_t
277
278 netdata_spinlock_lock(&metric->timestamps_lock);
279
280 - if(first_time_s && (!metric->first_time_s || first_time_s < metric->first_time_s))
280 + if(unlikely(first_time_s && (!metric->first_time_s || first_time_s < metric->first_time_s)))
281 metric->first_time_s = first_time_s;
282
283 - if(last_time_s && (!metric->latest_time_s_clean || last_time_s > metric->latest_time_s_clean)) {
283 + if(likely(last_time_s && (!metric->latest_time_s_clean || last_time_s > metric->latest_time_s_clean))) {
284 metric->latest_time_s_clean = last_time_s;
285
286 - if(update_every_s)
286 + if(likely(update_every_s))
287 metric->latest_update_every_s = update_every_s;
288 }
289 - else if(!metric->latest_update_every_s && update_every_s)
289 + else if(unlikely(!metric->latest_update_every_s && update_every_s))
290 metric->latest_update_every_s = update_every_s;
291
292 netdata_spinlock_unlock(&metric->timestamps_lock);
database/engine/pagecache.c
+9 -3
@@ -14,14 +14,17 @@ static void main_cache_free_clean_page_callback(PGC *cache __maybe_unused, PGC_E
14 // Release storage associated with the page
15 dbengine_page_free(entry.data, entry.size);
16 }
17 +static void main_cache_flush_dirty_page_init_callback(PGC *cache __maybe_unused, Word_t section) {
18 + struct rrdengine_instance *ctx = (struct rrdengine_instance *) section;
19 +
20 + // mark ctx as having flushing in progress
21 + __atomic_add_fetch(&ctx->worker_config.atomics.extents_currently_being_flushed, 1, __ATOMIC_RELAXED);
22 +}
23
24 static void main_cache_flush_dirty_page_callback(PGC *cache __maybe_unused, PGC_ENTRY *entries_array __maybe_unused, PGC_PAGE **pages_array __maybe_unused, size_t entries __maybe_unused)
25 {
26 struct rrdengine_instance *ctx = (struct rrdengine_instance *) entries_array[0].section;
27
22 - // mark ctx as having flushing in progress
23 - __atomic_add_fetch(&ctx->worker_config.atomics.extents_currently_being_flushed, 1, __ATOMIC_RELAXED);
24 -
28 size_t bytes_per_point = PAGE_POINT_CTX_SIZE_BYTES(ctx);
29
30 struct page_descr_with_data *base = NULL;
@@ -1023,6 +1026,7 @@ void init_page_cache(void)
1026 main_cache_size,
1027 main_cache_free_clean_page_callback,
1028 (size_t) rrdeng_pages_per_extent,
1029 + main_cache_flush_dirty_page_init_callback,
1030 main_cache_flush_dirty_page_callback,
1031 10,
1032 10240, // if there are that many threads, evict so many at once!
@@ -1037,6 +1041,7 @@ void init_page_cache(void)
1041 open_cache_size, // the default is 1MB
1042 open_cache_free_clean_page_callback,
1043 1,
1044 + NULL,
1045 open_cache_flush_dirty_page_callback,
1046 10,
1047 10240, // if there are that many threads, evict that many at once!
@@ -1052,6 +1057,7 @@ void init_page_cache(void)
1057 extent_cache_size,
1058 extent_cache_free_clean_page_callback,
1059 1,
1060 + NULL,
1061 extent_cache_flush_dirty_page_callback,
1062 5,
1063 10, // it will lose up to that extents at once!
database/ram/rrddim_mem.c
+9
@@ -60,6 +60,7 @@ rrddim_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *db_instance __maybe_un
60 mh->refcount = 1;
61 update_metric_handle_from_rrddim(mh, rd);
62 *PValue = mh;
63 + __atomic_add_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
64 }
65 else {
66 if(__atomic_add_fetch(&mh->refcount, 1, __ATOMIC_RELAXED) <= 0)
@@ -108,6 +109,9 @@ void rrddim_metric_release(STORAGE_METRIC_HANDLE *db_metric_handle __maybe_unuse
109 netdata_rwlock_wrlock(&rrddim_JudyHS_rwlock);
110 JudyHSDel(&rrddim_JudyHS_array, &rd->metric_uuid, sizeof(uuid_t), PJE0);
111 netdata_rwlock_unlock(&rrddim_JudyHS_rwlock);
112 +
113 + freez(mh);
114 + __atomic_sub_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
115 }
116 }
117 }
@@ -142,6 +146,8 @@ STORAGE_COLLECT_HANDLE *rrddim_collect_init(STORAGE_METRIC_HANDLE *db_metric_han
146 ch->rd = rd;
147 ch->db_metric_handle = db_metric_handle;
148
149 + __atomic_add_fetch(&rrddim_db_memory_size, sizeof(struct mem_collect_handle), __ATOMIC_RELAXED);
150 +
151 return (STORAGE_COLLECT_HANDLE *)ch;
152 }
153
@@ -228,6 +234,7 @@ void rrddim_collect_store_metric(STORAGE_COLLECT_HANDLE *collection_handle,
234
235 int rrddim_collect_finalize(STORAGE_COLLECT_HANDLE *collection_handle) {
236 freez(collection_handle);
237 + __atomic_sub_fetch(&rrddim_db_memory_size, sizeof(struct mem_collect_handle), __ATOMIC_RELAXED);
238 return 0;
239 }
240
@@ -346,6 +353,7 @@ void rrddim_query_init(STORAGE_METRIC_HANDLE *db_metric_handle, struct storage_e
353
354 // info("RRDDIM QUERY INIT: start %ld, end %ld, next %ld, first %ld, last %ld, dt %ld", start_time, end_time, h->next_timestamp, h->slot_timestamp, h->last_timestamp, h->dt);
355
356 + __atomic_add_fetch(&rrddim_db_memory_size, sizeof(struct mem_query_handle), __ATOMIC_RELAXED);
357 handle->handle = (STORAGE_QUERY_HANDLE *)h;
358 }
359
@@ -406,6 +414,7 @@ void rrddim_query_finalize(struct storage_engine_query_handle *handle) {
414 error("QUERY: query for chart '%s' dimension '%s' has been stopped unfinished", rrdset_id(mh->rd->rrdset), rrddim_name(mh->rd));
415 #endif
416 freez(handle->handle);
417 + __atomic_sub_fetch(&rrddim_db_memory_size, sizeof(struct mem_query_handle), __ATOMIC_RELAXED);
418 }
419
420 time_t rrddim_query_align_to_optimal_before(struct storage_engine_query_handle *rrddim_handle) {
database/rrd.h
+22 -22
@@ -120,8 +120,8 @@ typedef struct storage_point {
120 time_t start_time_s; // the time the point starts
121 time_t end_time_s; // the time the point ends
122
123 - unsigned count; // the number of original points aggregated
124 - unsigned anomaly_count; // the number of original points found anomalous
123 + size_t count; // the number of original points aggregated
124 + size_t anomaly_count; // the number of original points found anomalous
125
126 SN_FLAGS flags; // flags stored with the point
127 } STORAGE_POINT;
@@ -301,6 +301,25 @@ int rrdlabels_unittest(void);
301 // unfortunately this break when defined in exporting_engine.h
302 bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data);
303
304 +// ----------------------------------------------------------------------------
305 +// engine-specific iterator state for dimension data collection
306 +typedef struct storage_collect_handle STORAGE_COLLECT_HANDLE;
307 +
308 +// ----------------------------------------------------------------------------
309 +// Storage tier data for every dimension
310 +
311 +struct rrddim_tier {
312 + STORAGE_POINT virtual_point;
313 + size_t tier_grouping;
314 + time_t next_point_time_s;
315 + STORAGE_METRIC_HANDLE *db_metric_handle; // the metric handle inside the database
316 + STORAGE_COLLECT_HANDLE *db_collection_handle; // the data collection handle
317 + struct storage_engine_collect_ops *collect_ops;
318 + struct storage_engine_query_ops *query_ops;
319 +};
320 +
321 +void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s);
322 +
323 // ----------------------------------------------------------------------------
324 // RRD DIMENSION - this is a metric
325
@@ -343,7 +362,7 @@ struct rrddim {
362 // ------------------------------------------------------------------------
363 // data collection members
364
346 - struct rrddim_tier *tiers[RRD_STORAGE_TIERS]; // our tiers of databases
365 + struct rrddim_tier tiers[RRD_STORAGE_TIERS]; // our tiers of databases
366
367 struct timeval last_collected_time; // when was this dimension last updated
368 // this is actual date time we updated the last_collected_value
@@ -417,10 +436,6 @@ void rrddim_memory_file_save(RRDDIM *rd);
436 #define storage_point_is_unset(x) (!(x).count)
437 #define storage_point_is_empty(x) (!netdata_double_isnumber((x).sum))
438
420 -// ----------------------------------------------------------------------------
421 -// engine-specific iterator state for dimension data collection
422 -typedef struct storage_collect_handle STORAGE_COLLECT_HANDLE;
423 -
439 // ------------------------------------------------------------------------
440 // function pointers that handle data collection
441 struct storage_engine_collect_ops {
@@ -497,21 +512,6 @@ struct storage_engine {
512 STORAGE_ENGINE* storage_engine_get(RRD_MEMORY_MODE mmode);
513 STORAGE_ENGINE* storage_engine_find(const char* name);
514
500 -// ----------------------------------------------------------------------------
501 -// Storage tier data for every dimension
502 -
503 -struct rrddim_tier {
504 - size_t tier_grouping;
505 - STORAGE_METRIC_HANDLE *db_metric_handle; // the metric handle inside the database
506 - STORAGE_COLLECT_HANDLE *db_collection_handle; // the data collection handle
507 - STORAGE_POINT virtual_point;
508 - time_t next_point_time_s;
509 - struct storage_engine_collect_ops *collect_ops;
510 - struct storage_engine_query_ops *query_ops;
511 -};
512 -
513 -void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s);
514 -
515 // ----------------------------------------------------------------------------
516 // these loop macros make sure the linked list is accessed with the right lock
517
database/rrdcalc.c
+1 -1
@@ -627,7 +627,7 @@ static void rrdcalc_rrdhost_delete_callback(const DICTIONARY_ITEM *item __maybe_
627
628 void rrdcalc_rrdhost_index_init(RRDHOST *host) {
629 if(!host->rrdcalc_root_index) {
630 - host->rrdcalc_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
630 + host->rrdcalc_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
631
632 dictionary_register_insert_callback(host->rrdcalc_root_index, rrdcalc_rrdhost_insert_callback, NULL);
633 dictionary_register_conflict_callback(host->rrdcalc_root_index, rrdcalc_rrdhost_conflict_callback, NULL);
database/rrdcalctemplate.c
+1 -1
@@ -189,7 +189,7 @@ static void rrdcalctemplate_delete_callback(const DICTIONARY_ITEM *item __maybe_
189
190 void rrdcalctemplate_index_init(RRDHOST *host) {
191 if(!host->rrdcalctemplate_root_index) {
192 - host->rrdcalctemplate_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
192 + host->rrdcalctemplate_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
193
194 dictionary_register_insert_callback(host->rrdcalctemplate_root_index, rrdcalctemplate_insert_callback, NULL);
195 dictionary_register_delete_callback(host->rrdcalctemplate_root_index, rrdcalctemplate_delete_callback, host);
database/rrdcontext.c
+59 -32
@@ -611,7 +611,7 @@ static void rrdmetrics_create_in_rrdinstance(RRDINSTANCE *ri) {
611 if(unlikely(!ri)) return;
612 if(likely(ri->rrdmetrics)) return;
613
614 - ri->rrdmetrics = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
614 + ri->rrdmetrics = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdcontext);
615 dictionary_register_insert_callback(ri->rrdmetrics, rrdmetric_insert_callback, ri);
616 dictionary_register_delete_callback(ri->rrdmetrics, rrdmetric_delete_callback, ri);
617 dictionary_register_conflict_callback(ri->rrdmetrics, rrdmetric_conflict_callback, ri);
@@ -914,7 +914,7 @@ static void rrdinstance_react_callback(const DICTIONARY_ITEM *item __maybe_unuse
914 void rrdinstances_create_in_rrdcontext(RRDCONTEXT *rc) {
915 if(unlikely(!rc || rc->rrdinstances)) return;
916
917 - rc->rrdinstances = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
917 + rc->rrdinstances = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdcontext);
918 dictionary_register_insert_callback(rc->rrdinstances, rrdinstance_insert_callback, rc);
919 dictionary_register_delete_callback(rc->rrdinstances, rrdinstance_delete_callback, rc);
920 dictionary_register_conflict_callback(rc->rrdinstances, rrdinstance_conflict_callback, rc);
@@ -1392,18 +1392,18 @@ void rrdhost_create_rrdcontexts(RRDHOST *host) {
1392 if(unlikely(!host)) return;
1393 if(likely(host->rrdctx)) return;
1394
1395 - host->rrdctx = (RRDCONTEXTS *)dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
1395 + host->rrdctx = (RRDCONTEXTS *)dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdcontext);
1396 dictionary_register_insert_callback((DICTIONARY *)host->rrdctx, rrdcontext_insert_callback, host);
1397 dictionary_register_delete_callback((DICTIONARY *)host->rrdctx, rrdcontext_delete_callback, host);
1398 dictionary_register_conflict_callback((DICTIONARY *)host->rrdctx, rrdcontext_conflict_callback, host);
1399 dictionary_register_react_callback((DICTIONARY *)host->rrdctx, rrdcontext_react_callback, host);
1400
1401 - host->rrdctx_hub_queue = (RRDCONTEXTS *)dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE);
1401 + host->rrdctx_hub_queue = (RRDCONTEXTS *)dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE, &dictionary_stats_category_rrdcontext);
1402 dictionary_register_insert_callback((DICTIONARY *)host->rrdctx_hub_queue, rrdcontext_hub_queue_insert_callback, NULL);
1403 dictionary_register_delete_callback((DICTIONARY *)host->rrdctx_hub_queue, rrdcontext_hub_queue_delete_callback, NULL);
1404 dictionary_register_conflict_callback((DICTIONARY *)host->rrdctx_hub_queue, rrdcontext_hub_queue_conflict_callback, NULL);
1405
1406 - host->rrdctx_post_processing_queue = (RRDCONTEXTS *)dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE);
1406 + host->rrdctx_post_processing_queue = (RRDCONTEXTS *)dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE, &dictionary_stats_category_rrdcontext);
1407 dictionary_register_insert_callback((DICTIONARY *)host->rrdctx_post_processing_queue, rrdcontext_post_processing_queue_insert_callback, NULL);
1408 dictionary_register_delete_callback((DICTIONARY *)host->rrdctx_post_processing_queue, rrdcontext_post_processing_queue_delete_callback, NULL);
1409 dictionary_register_conflict_callback((DICTIONARY *)host->rrdctx_post_processing_queue, rrdcontext_post_processing_queue_conflict_callback, NULL);
@@ -1845,7 +1845,7 @@ static inline int rrdinstance_to_json_callback(const DICTIONARY_ITEM *item, void
1845 BUFFER *wb_metrics = NULL;
1846 if(options & RRDCONTEXT_OPTION_SHOW_METRICS || t_parent->chart_dimensions) {
1847
1848 - wb_metrics = buffer_create(4096);
1848 + wb_metrics = buffer_create(4096, &netdata_buffers_statistics.buffers_api);
1849
1850 struct rrdcontext_to_json t_metrics = {
1851 .wb = wb_metrics,
@@ -1983,7 +1983,7 @@ static inline int rrdcontext_to_json_callback(const DICTIONARY_ITEM *item, void
1983 || t_parent->chart_labels_filter
1984 || t_parent->chart_dimensions) {
1985
1986 - wb_instances = buffer_create(4096);
1986 + wb_instances = buffer_create(4096, &netdata_buffers_statistics.buffers_api);
1987
1988 struct rrdcontext_to_json t_instances = {
1989 .wb = wb_instances,
@@ -2211,7 +2211,7 @@ DICTIONARY *rrdcontext_all_metrics_to_dict(RRDHOST *host, SIMPLE_PATTERN *contex
2211 if(!host || !host->rrdctx)
2212 return NULL;
2213
2214 - DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
2214 + DICTIONARY *dict = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdcontext);
2215 dictionary_register_insert_callback(dict, metric_entry_insert_callback, NULL);
2216 dictionary_register_delete_callback(dict, metric_entry_delete_callback, NULL);
2217 dictionary_register_conflict_callback(dict, metric_entry_conflict_callback, NULL);
@@ -2380,28 +2380,35 @@ void query_target_release(QUERY_TARGET *qt) {
2380 qt->used = false;
2381 }
2382 void query_target_free(void) {
2383 - if(thread_query_target.used)
2384 - query_target_release(&thread_query_target);
2383 + QUERY_TARGET *qt = &thread_query_target;
2384
2386 - freez(thread_query_target.query.array);
2387 - thread_query_target.query.array = NULL;
2388 - thread_query_target.query.size = 0;
2385 + if(qt->used)
2386 + query_target_release(qt);
2387
2390 - freez(thread_query_target.metrics.array);
2391 - thread_query_target.metrics.array = NULL;
2392 - thread_query_target.metrics.size = 0;
2388 + __atomic_sub_fetch(&netdata_buffers_statistics.query_targets_size, qt->query.size * sizeof(QUERY_METRIC), __ATOMIC_RELAXED);
2389 + freez(qt->query.array);
2390 + qt->query.array = NULL;
2391 + qt->query.size = 0;
2392
2394 - freez(thread_query_target.instances.array);
2395 - thread_query_target.instances.array = NULL;
2396 - thread_query_target.instances.size = 0;
2393 + __atomic_sub_fetch(&netdata_buffers_statistics.query_targets_size, qt->metrics.size * sizeof(RRDMETRIC_ACQUIRED *), __ATOMIC_RELAXED);
2394 + freez(qt->metrics.array);
2395 + qt->metrics.array = NULL;
2396 + qt->metrics.size = 0;
2397
2398 - freez(thread_query_target.contexts.array);
2399 - thread_query_target.contexts.array = NULL;
2400 - thread_query_target.contexts.size = 0;
2398 + __atomic_sub_fetch(&netdata_buffers_statistics.query_targets_size, qt->instances.size * sizeof(RRDINSTANCE_ACQUIRED *), __ATOMIC_RELAXED);
2399 + freez(qt->instances.array);
2400 + qt->instances.array = NULL;
2401 + qt->instances.size = 0;
2402
2402 - freez(thread_query_target.hosts.array);
2403 - thread_query_target.hosts.array = NULL;
2404 - thread_query_target.hosts.size = 0;
2403 + __atomic_sub_fetch(&netdata_buffers_statistics.query_targets_size, qt->contexts.size * sizeof(RRDCONTEXT_ACQUIRED *), __ATOMIC_RELAXED);
2404 + freez(qt->contexts.array);
2405 + qt->contexts.array = NULL;
2406 + qt->contexts.size = 0;
2407 +
2408 + __atomic_sub_fetch(&netdata_buffers_statistics.query_targets_size, qt->hosts.size * sizeof(RRDHOST *), __ATOMIC_RELAXED);
2409 + freez(qt->hosts.array);
2410 + qt->hosts.array = NULL;
2411 + qt->hosts.size = 0;
2412 }
2413
2414 static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED *rma, RRDINSTANCE *ri,
@@ -2413,8 +2420,12 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2420 return;
2421
2422 if(qt->metrics.used == qt->metrics.size) {
2423 + size_t old_mem = qt->metrics.size * sizeof(RRDMETRIC_ACQUIRED *);
2424 qt->metrics.size = (qt->metrics.size) ? qt->metrics.size * 2 : 1;
2417 - qt->metrics.array = reallocz(qt->metrics.array, qt->metrics.size * sizeof(RRDMETRIC_ACQUIRED *));
2425 + size_t new_mem = qt->metrics.size * sizeof(RRDMETRIC_ACQUIRED *);
2426 + qt->metrics.array = reallocz(qt->metrics.array, new_mem);
2427 +
2428 + __atomic_add_fetch(&netdata_buffers_statistics.query_targets_size, new_mem - old_mem, __ATOMIC_RELAXED);
2429 }
2430 qt->metrics.array[qt->metrics.used++] = rrdmetric_acquired_dup(rma);
2431
@@ -2438,8 +2449,8 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2449 tier_retention[tier].eng = eng;
2450 tier_retention[tier].db_update_every_s = (time_t) (qtl->host->db[tier].tier_grouping * ri->update_every_s);
2451
2441 - if(rm->rrddim && rm->rrddim->tiers[tier] && rm->rrddim->tiers[tier]->db_metric_handle)
2442 - tier_retention[tier].db_metric_handle = eng->api.metric_dup(rm->rrddim->tiers[tier]->db_metric_handle);
2452 + if(rm->rrddim && rm->rrddim->tiers[tier].db_metric_handle)
2453 + tier_retention[tier].db_metric_handle = eng->api.metric_dup(rm->rrddim->tiers[tier].db_metric_handle);
2454 else
2455 tier_retention[tier].db_metric_handle = eng->api.metric_get(qtl->host->db[tier].instance, &rm->uuid);
2456
@@ -2523,8 +2534,12 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2534 ri->rrdset->last_accessed_time_s = qtl->start_s;
2535
2536 if (qt->query.used == qt->query.size) {
2537 + size_t old_mem = qt->query.size * sizeof(QUERY_METRIC);
2538 qt->query.size = (qt->query.size) ? qt->query.size * 2 : 1;
2527 - qt->query.array = reallocz(qt->query.array, qt->query.size * sizeof(QUERY_METRIC));
2539 + size_t new_mem = qt->query.size * sizeof(QUERY_METRIC);
2540 + qt->query.array = reallocz(qt->query.array, new_mem);
2541 +
2542 + __atomic_add_fetch(&netdata_buffers_statistics.query_targets_size, new_mem - old_mem, __ATOMIC_RELAXED);
2543 }
2544 QUERY_METRIC *qm = &qt->query.array[qt->query.used++];
2545
@@ -2578,8 +2593,12 @@ static void query_target_add_instance(QUERY_TARGET_LOCALS *qtl, RRDINSTANCE_ACQU
2593 return;
2594
2595 if(qt->instances.used == qt->instances.size) {
2596 + size_t old_mem = qt->instances.size * sizeof(RRDINSTANCE_ACQUIRED *);
2597 qt->instances.size = (qt->instances.size) ? qt->instances.size * 2 : 1;
2582 - qt->instances.array = reallocz(qt->instances.array, qt->instances.size * sizeof(RRDINSTANCE_ACQUIRED *));
2598 + size_t new_mem = qt->instances.size * sizeof(RRDINSTANCE_ACQUIRED *);
2599 + qt->instances.array = reallocz(qt->instances.array, new_mem);
2600 +
2601 + __atomic_add_fetch(&netdata_buffers_statistics.query_targets_size, new_mem - old_mem, __ATOMIC_RELAXED);
2602 }
2603
2604 qtl->ria = qt->instances.array[qt->instances.used++] = rrdinstance_acquired_dup(ria);
@@ -2622,8 +2641,12 @@ static void query_target_add_context(QUERY_TARGET_LOCALS *qtl, RRDCONTEXT_ACQUIR
2641 return;
2642
2643 if(qt->contexts.used == qt->contexts.size) {
2644 + size_t old_mem = qt->contexts.size * sizeof(RRDCONTEXT_ACQUIRED *);
2645 qt->contexts.size = (qt->contexts.size) ? qt->contexts.size * 2 : 1;
2626 - qt->contexts.array = reallocz(qt->contexts.array, qt->contexts.size * sizeof(RRDCONTEXT_ACQUIRED *));
2646 + size_t new_mem = qt->contexts.size * sizeof(RRDCONTEXT_ACQUIRED *);
2647 + qt->contexts.array = reallocz(qt->contexts.array, new_mem);
2648 +
2649 + __atomic_add_fetch(&netdata_buffers_statistics.query_targets_size, new_mem - old_mem, __ATOMIC_RELAXED);
2650 }
2651 qtl->rca = qt->contexts.array[qt->contexts.used++] = rrdcontext_acquired_dup(rca);
2652
@@ -2662,8 +2685,12 @@ static void query_target_add_host(QUERY_TARGET_LOCALS *qtl, RRDHOST *host) {
2685 QUERY_TARGET *qt = qtl->qt;
2686
2687 if(qt->hosts.used == qt->hosts.size) {
2688 + size_t old_mem = qt->hosts.size * sizeof(RRDHOST *);
2689 qt->hosts.size = (qt->hosts.size) ? qt->hosts.size * 2 : 1;
2666 - qt->hosts.array = reallocz(qt->hosts.array, qt->hosts.size * sizeof(RRDHOST *));
2690 + size_t new_mem = qt->hosts.size * sizeof(RRDHOST *);
2691 + qt->hosts.array = reallocz(qt->hosts.array, new_mem);
2692 +
2693 + __atomic_add_fetch(&netdata_buffers_statistics.query_targets_size, new_mem - old_mem, __ATOMIC_RELAXED);
2694 }
2695 qtl->host = qt->hosts.array[qt->hosts.used++] = host;
2696
database/rrddim.c
+33 -27
@@ -69,7 +69,10 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
69 info("Failed to use memory mode ram for chart '%s', dimension '%s', falling back to alloc", rrdset_name(st), rrddim_name(rd));
70 ctr->memory_mode = RRD_MEMORY_MODE_ALLOC;
71 }
72 - else rd->memsize = entries * sizeof(storage_number);
72 + else {
73 + rd->memsize = entries * sizeof(storage_number);
74 + __atomic_add_fetch(&rrddim_db_memory_size, rd->memsize, __ATOMIC_RELAXED);
75 + }
76 }
77
78 if(ctr->memory_mode == RRD_MEMORY_MODE_ALLOC || ctr->memory_mode == RRD_MEMORY_MODE_NONE) {
@@ -78,6 +81,7 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
81
82 rd->db = rrddim_alloc_db(entries);
83 rd->memsize = entries * sizeof(storage_number);
84 + __atomic_add_fetch(&rrddim_db_memory_size, rd->memsize, __ATOMIC_RELAXED);
85 }
86
87 rd->rrd_memory_mode = ctr->memory_mode;
@@ -108,12 +112,11 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
112 size_t initialized = 0;
113 for(size_t tier = 0; tier < storage_tiers ; tier++) {
114 STORAGE_ENGINE *eng = host->db[tier].eng;
111 - rd->tiers[tier] = callocz(1, sizeof(struct rrddim_tier));
112 - rd->tiers[tier]->tier_grouping = host->db[tier].tier_grouping;
113 - rd->tiers[tier]->collect_ops = &eng->api.collect_ops;
114 - rd->tiers[tier]->query_ops = &eng->api.query_ops;
115 - rd->tiers[tier]->db_metric_handle = eng->api.metric_get_or_create(rd, host->db[tier].instance);
116 - storage_point_unset(rd->tiers[tier]->virtual_point);
115 + rd->tiers[tier].tier_grouping = host->db[tier].tier_grouping;
116 + rd->tiers[tier].collect_ops = &eng->api.collect_ops;
117 + rd->tiers[tier].query_ops = &eng->api.query_ops;
118 + rd->tiers[tier].db_metric_handle = eng->api.metric_get_or_create(rd, host->db[tier].instance);
119 + storage_point_unset(rd->tiers[tier].virtual_point);
120 initialized++;
121
122 // internal_error(true, "TIER GROUPING of chart '%s', dimension '%s' for tier %d is set to %d", rd->rrdset->name, rd->name, tier, rd->tiers[tier]->tier_grouping);
@@ -122,7 +125,7 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
125 if(!initialized)
126 error("Failed to initialize all db tiers for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
127
125 - if(!rd->tiers[0])
128 + if(!rd->tiers[0].db_metric_handle)
129 error("Failed to initialize the first db tier for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
130 }
131
@@ -130,8 +133,8 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
133 {
134 size_t initialized = 0;
135 for (size_t tier = 0; tier < storage_tiers; tier++) {
133 - if (rd->tiers[tier]) {
134 - rd->tiers[tier]->db_collection_handle = rd->tiers[tier]->collect_ops->init(rd->tiers[tier]->db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->storage_metrics_groups[tier]);
136 + if (rd->tiers[tier].db_metric_handle) {
137 + rd->tiers[tier].db_collection_handle = rd->tiers[tier].collect_ops->init(rd->tiers[tier].db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->storage_metrics_groups[tier]);
138 initialized++;
139 }
140 }
@@ -197,13 +200,13 @@ static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
200
201 size_t tiers_available = 0, tiers_said_no_retention = 0;
202 for(size_t tier = 0; tier < storage_tiers ;tier++) {
200 - if(rd->tiers[tier] && rd->tiers[tier]->db_collection_handle) {
203 + if(rd->tiers[tier].db_collection_handle) {
204 tiers_available++;
205
203 - if(rd->tiers[tier]->collect_ops->finalize(rd->tiers[tier]->db_collection_handle))
206 + if(rd->tiers[tier].collect_ops->finalize(rd->tiers[tier].db_collection_handle))
207 tiers_said_no_retention++;
208
206 - rd->tiers[tier]->db_collection_handle = NULL;
209 + rd->tiers[tier].db_collection_handle = NULL;
210 }
211 }
212
@@ -224,16 +227,16 @@ static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
227 rrddim_memory_file_free(rd);
228
229 for(size_t tier = 0; tier < storage_tiers ;tier++) {
227 - if(!rd->tiers[tier]) continue;
230 + if(!rd->tiers[tier].db_metric_handle) continue;
231
232 STORAGE_ENGINE* eng = host->db[tier].eng;
230 - eng->api.metric_release(rd->tiers[tier]->db_metric_handle);
231 -
232 - freez(rd->tiers[tier]);
233 - rd->tiers[tier] = NULL;
233 + eng->api.metric_release(rd->tiers[tier].db_metric_handle);
234 + rd->tiers[tier].db_metric_handle = NULL;
235 }
236
237 if(rd->db) {
238 + __atomic_sub_fetch(&rrddim_db_memory_size, rd->memsize, __ATOMIC_RELAXED);
239 +
240 if(rd->rrd_memory_mode == RRD_MEMORY_MODE_RAM)
241 netdata_munmap(rd->db, rd->memsize);
242 else
@@ -259,9 +262,9 @@ static bool rrddim_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused,
262 rc += rrddim_set_divisor(st, rd, ctr->divisor);
263
264 for(size_t tier = 0; tier < storage_tiers ;tier++) {
262 - if (rd->tiers[tier] && !rd->tiers[tier]->db_collection_handle)
263 - rd->tiers[tier]->db_collection_handle =
264 - rd->tiers[tier]->collect_ops->init(rd->tiers[tier]->db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->storage_metrics_groups[tier]);
265 + if (!rd->tiers[tier].db_collection_handle)
266 + rd->tiers[tier].db_collection_handle =
267 + rd->tiers[tier].collect_ops->init(rd->tiers[tier].db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->storage_metrics_groups[tier]);
268 }
269
270 if(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
@@ -299,7 +302,7 @@ static void rrddim_react_callback(const DICTIONARY_ITEM *item __maybe_unused, vo
302
303 void rrddim_index_init(RRDSET *st) {
304 if(!st->rrddim_root_index) {
302 - st->rrddim_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
305 + st->rrddim_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdset_rrddim);
306
307 dictionary_register_insert_callback(st->rrddim_root_index, rrddim_insert_callback, NULL);
308 dictionary_register_conflict_callback(st->rrddim_root_index, rrddim_conflict_callback, NULL);
@@ -420,10 +423,10 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
423 // ----------------------------------------------------------------------------
424
425 time_t rrddim_last_entry_s_of_tier(RRDDIM *rd, size_t tier) {
423 - if(unlikely(tier > storage_tiers || !rd->tiers[tier]))
426 + if(unlikely(tier > storage_tiers || !rd->tiers[tier].db_metric_handle))
427 return 0;
428
426 - return rd->tiers[tier]->query_ops->latest_time_s(rd->tiers[tier]->db_metric_handle);
429 + return rd->tiers[tier].query_ops->latest_time_s(rd->tiers[tier].db_metric_handle);
430 }
431
432 // get the timestamp of the last entry in the round-robin database
@@ -431,7 +434,7 @@ time_t rrddim_last_entry_s(RRDDIM *rd) {
434 time_t latest_time_s = rrddim_last_entry_s_of_tier(rd, 0);
435
436 for(size_t tier = 1; tier < storage_tiers ;tier++) {
434 - if(unlikely(!rd->tiers[tier])) continue;
437 + if(unlikely(!rd->tiers[tier].db_metric_handle)) continue;
438
439 time_t t = rrddim_last_entry_s_of_tier(rd, tier);
440 if(t > latest_time_s)
@@ -442,10 +445,10 @@ time_t rrddim_last_entry_s(RRDDIM *rd) {
445 }
446
447 time_t rrddim_first_entry_s_of_tier(RRDDIM *rd, size_t tier) {
445 - if(unlikely(tier > storage_tiers || !rd->tiers[tier]))
448 + if(unlikely(tier > storage_tiers || !rd->tiers[tier].db_metric_handle))
449 return 0;
450
448 - return rd->tiers[tier]->query_ops->oldest_time_s(rd->tiers[tier]->db_metric_handle);
451 + return rd->tiers[tier].query_ops->oldest_time_s(rd->tiers[tier].db_metric_handle);
452 }
453
454 time_t rrddim_first_entry_s(RRDDIM *rd) {
@@ -657,6 +660,7 @@ void rrddim_memory_file_free(RRDDIM *rd) {
660 rrddim_memory_file_update(rd);
661
662 struct rrddim_map_save_v019 *rd_on_file = rd->rd_on_file;
663 + __atomic_sub_fetch(&rrddim_db_memory_size, rd_on_file->memsize + strlen(rd_on_file->cache_filename), __ATOMIC_RELAXED);
664 freez(rd_on_file->cache_filename);
665 netdata_munmap(rd_on_file, rd_on_file->memsize);
666
@@ -754,6 +758,8 @@ bool rrddim_memory_load_or_create_map_save(RRDSET *st, RRDDIM *rd, RRD_MEMORY_MO
758 rd_on_file->rrd_memory_mode = memory_mode;
759 rd_on_file->cache_filename = strdupz(fullfilename);
760
761 + __atomic_add_fetch(&rrddim_db_memory_size, rd_on_file->memsize + strlen(rd_on_file->cache_filename), __ATOMIC_RELAXED);
762 +
763 rd->db = &rd_on_file->values[0];
764 rd->rd_on_file = rd_on_file;
765 rd->memsize = size;
database/rrddimvar.c
+1 -1
@@ -214,7 +214,7 @@ static void rrddimvar_delete_callback(const DICTIONARY_ITEM *item __maybe_unused
214
215 void rrddimvar_index_init(RRDSET *st) {
216 if(!st->rrddimvar_root_index) {
217 - st->rrddimvar_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
217 + st->rrddimvar_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
218
219 dictionary_register_insert_callback(st->rrddimvar_root_index, rrddimvar_insert_callback, NULL);
220 dictionary_register_conflict_callback(st->rrddimvar_root_index, rrddimvar_conflict_callback, NULL);
database/rrdfamily.c
+1 -1
@@ -33,7 +33,7 @@ static void rrdfamily_delete_callback(const DICTIONARY_ITEM *item __maybe_unused
33
34 void rrdfamily_index_init(RRDHOST *host) {
35 if(!host->rrdfamily_root_index) {
36 - host->rrdfamily_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
36 + host->rrdfamily_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
37
38 dictionary_register_insert_callback(host->rrdfamily_root_index, rrdfamily_insert_callback, NULL);
39 dictionary_register_delete_callback(host->rrdfamily_root_index, rrdfamily_delete_callback, host);
database/rrdfunctions.c
+2 -2
@@ -424,7 +424,7 @@ static bool rrd_functions_conflict_callback(const DICTIONARY_ITEM *item __maybe_
424 void rrdfunctions_init(RRDHOST *host) {
425 if(host->functions) return;
426
427 - host->functions = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
427 + host->functions = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_functions);
428 dictionary_register_insert_callback(host->functions, rrd_functions_insert_callback, host);
429 dictionary_register_delete_callback(host->functions, rrd_functions_delete_callback, host);
430 dictionary_register_conflict_callback(host->functions, rrd_functions_conflict_callback, host);
@@ -629,7 +629,7 @@ int rrd_call_function_and_wait(RRDHOST *host, BUFFER *wb, int timeout, const cha
629 pthread_cond_init(&tmp->cond, NULL);
630
631 bool we_should_free = true;
632 - BUFFER *temp_wb = buffer_create(PLUGINSD_LINE_MAX + 1); // we need it because we may give up on it
632 + BUFFER *temp_wb = buffer_create(PLUGINSD_LINE_MAX + 1, &netdata_buffers_statistics.buffers_functions); // we need it because we may give up on it
633 temp_wb->contenttype = wb->contenttype;
634 code = rdcf->function(temp_wb, timeout, key, rdcf->collector_data, rrd_call_function_signal_when_ready, tmp);
635 if (code == HTTP_RESP_OK) {
database/rrdhost.c
+16 -5
@@ -51,13 +51,15 @@ static DICTIONARY *rrdhost_root_index_hostname = NULL;
51
52 static inline void rrdhost_init() {
53 if(unlikely(!rrdhost_root_index)) {
54 - rrdhost_root_index = dictionary_create(
55 - DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
54 + rrdhost_root_index = dictionary_create_advanced(
55 + DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE,
56 + &dictionary_stats_category_rrdhost);
57 }
58
59 if(unlikely(!rrdhost_root_index_hostname)) {
59 - rrdhost_root_index_hostname = dictionary_create(
60 - DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
60 + rrdhost_root_index_hostname = dictionary_create_advanced(
61 + DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE,
62 + &dictionary_stats_category_rrdhost);
63 }
64 }
65
@@ -273,6 +275,7 @@ int is_legacy = 1;
275
276 int is_in_multihost = (memory_mode == RRD_MEMORY_MODE_DBENGINE && !is_legacy);
277 RRDHOST *host = callocz(1, sizeof(RRDHOST));
278 + __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(RRDHOST), __ATOMIC_RELAXED);
279
280 strncpyz(host->machine_guid, guid, GUID_LEN + 1);
281
@@ -988,6 +991,8 @@ int rrd_init(char *hostname, struct rrdhost_system_info *system_info, bool unitt
991
992 void rrdhost_system_info_free(struct rrdhost_system_info *system_info) {
993 if(likely(system_info)) {
994 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
995 +
996 freez(system_info->cloud_provider_type);
997 freez(system_info->cloud_instance_type);
998 freez(system_info->cloud_instance_region);
@@ -1028,8 +1033,10 @@ static void rrdhost_streaming_sender_structures_init(RRDHOST *host)
1033 return;
1034
1035 host->sender = callocz(1, sizeof(*host->sender));
1036 + __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_senders, sizeof(*host->sender), __ATOMIC_RELAXED);
1037 +
1038 host->sender->host = host;
1032 - host->sender->buffer = cbuffer_new(CBUFFER_INITIAL_SIZE, 1024 * 1024);
1039 + host->sender->buffer = cbuffer_new(CBUFFER_INITIAL_SIZE, 1024 * 1024, &netdata_buffers_statistics.cbuffers_streaming);
1040 host->sender->capabilities = STREAM_OUR_CAPABILITIES;
1041
1042 host->sender->rrdpush_sender_pipe[PIPE_READ] = -1;
@@ -1063,6 +1070,9 @@ static void rrdhost_streaming_sender_structures_free(RRDHOST *host)
1070 host->sender->compressor->destroy(&host->sender->compressor);
1071 #endif
1072 replication_cleanup_sender(host->sender);
1073 +
1074 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_senders, sizeof(*host->sender), __ATOMIC_RELAXED);
1075 +
1076 freez(host->sender);
1077 host->sender = NULL;
1078 rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_INITIALIZED);
@@ -1187,6 +1197,7 @@ void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host, bool force) {
1197 rrdhost_destroy_rrdcontexts(host);
1198
1199 string_freez(host->hostname);
1200 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(RRDHOST), __ATOMIC_RELAXED);
1201 freez(host);
1202 #ifdef ENABLE_ACLK
1203 if (wc)
database/rrdlabels.c
+1 -1
@@ -533,7 +533,7 @@ static bool rrdlabel_conflict_callback(const DICTIONARY_ITEM *item __maybe_unuse
533 }
534
535 DICTIONARY *rrdlabels_create(void) {
536 - DICTIONARY *dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
536 + DICTIONARY *dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdlabels);
537 dictionary_register_insert_callback(dict, rrdlabel_insert_callback, dict);
538 dictionary_register_delete_callback(dict, rrdlabel_delete_callback, dict);
539 dictionary_register_conflict_callback(dict, rrdlabel_conflict_callback, dict);
database/rrdset.c
+22 -13
@@ -401,7 +401,7 @@ static void rrdset_react_callback(const DICTIONARY_ITEM *item __maybe_unused, vo
401
402 void rrdset_index_init(RRDHOST *host) {
403 if(!host->rrdset_root_index) {
404 - host->rrdset_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
404 + host->rrdset_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdset_rrddim);
405
406 dictionary_register_insert_callback(host->rrdset_root_index, rrdset_insert_callback, NULL);
407 dictionary_register_conflict_callback(host->rrdset_root_index, rrdset_conflict_callback, NULL);
@@ -410,8 +410,9 @@ void rrdset_index_init(RRDHOST *host) {
410 }
411
412 if(!host->rrdset_root_index_name) {
413 - host->rrdset_root_index_name = dictionary_create(
414 - DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
413 + host->rrdset_root_index_name = dictionary_create_advanced(
414 + DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE,
415 + &dictionary_stats_category_rrdset_rrddim);
416
417 dictionary_register_insert_callback(host->rrdset_root_index_name, rrdset_name_insert_callback, host);
418 dictionary_register_delete_callback(host->rrdset_root_index_name, rrdset_name_delete_callback, host);
@@ -735,8 +736,8 @@ void rrdset_reset(RRDSET *st) {
736
737 if(!rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
738 for(size_t tier = 0; tier < storage_tiers ;tier++) {
738 - if(rd->tiers[tier])
739 - rd->tiers[tier]->collect_ops->flush(rd->tiers[tier]->db_collection_handle);
739 + if(rd->tiers[tier].db_collection_handle)
740 + rd->tiers[tier].collect_ops->flush(rd->tiers[tier].db_collection_handle);
741 }
742 }
743 }
@@ -1193,7 +1194,7 @@ void rrddim_store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n,
1194 #endif // NETDATA_LOG_COLLECTION_ERRORS
1195
1196 // store the metric on tier 0
1196 - rd->tiers[0]->collect_ops->store_metric(rd->tiers[0]->db_collection_handle, point_end_time_ut, n, 0, 0, 1, 0, flags);
1197 + rd->tiers[0].collect_ops->store_metric(rd->tiers[0].db_collection_handle, point_end_time_ut, n, 0, 0, 1, 0, flags);
1198 rrdset_done_statistics_points_stored_per_tier[0]++;
1199
1200 time_t now_s = (time_t)(point_end_time_ut / USEC_PER_SEC);
@@ -1210,9 +1211,9 @@ void rrddim_store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n,
1211 };
1212
1213 for(size_t tier = 1; tier < storage_tiers ;tier++) {
1213 - if(unlikely(!rd->tiers[tier])) continue;
1214 + if(unlikely(!rd->tiers[tier].db_metric_handle)) continue;
1215
1215 - struct rrddim_tier *t = rd->tiers[tier];
1216 + struct rrddim_tier *t = &rd->tiers[tier];
1217
1218 if(!rrddim_option_check(rd, RRDDIM_OPTION_BACKFILLED_HIGH_TIERS)) {
1219 // we have not collected this tier before
@@ -1238,12 +1239,16 @@ struct rda_item {
1239 static __thread struct rda_item *thread_rda = NULL;
1240 static __thread size_t thread_rda_entries = 0;
1241
1241 -struct rda_item *rrdset_thread_rda(size_t *dimensions) {
1242 +struct rda_item *rrdset_thread_rda_get(size_t *dimensions) {
1243
1244 if(unlikely(!thread_rda || (*dimensions) > thread_rda_entries)) {
1245 + size_t old_mem = thread_rda_entries * sizeof(struct rda_item);
1246 freez(thread_rda);
1245 - thread_rda = mallocz((*dimensions) * sizeof(struct rda_item));
1247 thread_rda_entries = *dimensions;
1248 + size_t new_mem = thread_rda_entries * sizeof(struct rda_item);
1249 + thread_rda = mallocz(new_mem);
1250 +
1251 + __atomic_add_fetch(&netdata_buffers_statistics.rrdset_done_rda_size, new_mem - old_mem, __ATOMIC_RELAXED);
1252 }
1253
1254 *dimensions = thread_rda_entries;
@@ -1251,6 +1256,8 @@ struct rda_item *rrdset_thread_rda(size_t *dimensions) {
1256 }
1257
1258 void rrdset_thread_rda_free(void) {
1259 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdset_done_rda_size, thread_rda_entries * sizeof(struct rda_item), __ATOMIC_RELAXED);
1260 +
1261 freez(thread_rda);
1262 thread_rda = NULL;
1263 thread_rda_entries = 0;
@@ -1585,7 +1592,7 @@ after_first_database_work:
1592 uint32_t has_reset_value = 0;
1593
1594 size_t rda_slots = dictionary_entries(st->rrddim_root_index);
1588 - struct rda_item *rda_base = rrdset_thread_rda(&rda_slots);
1595 + struct rda_item *rda_base = rrdset_thread_rda_get(&rda_slots);
1596
1597 size_t dim_id;
1598 size_t dimensions = 0;
@@ -1956,8 +1963,8 @@ time_t rrdset_set_update_every_s(RRDSET *st, time_t update_every_s) {
1963 RRDDIM *rd;
1964 rrddim_foreach_read(rd, st) {
1965 for (size_t tier = 0; tier < storage_tiers; tier++) {
1959 - if (rd->tiers[tier] && rd->tiers[tier]->db_collection_handle)
1960 - rd->tiers[tier]->collect_ops->change_collection_frequency(rd->tiers[tier]->db_collection_handle, (int)(st->rrdhost->db[tier].tier_grouping * st->update_every));
1966 + if (rd->tiers[tier].db_collection_handle)
1967 + rd->tiers[tier].collect_ops->change_collection_frequency(rd->tiers[tier].db_collection_handle, (int)(st->rrdhost->db[tier].tier_grouping * st->update_every));
1968 }
1969
1970 assert(rd->update_every == prev_update_every_s &&
@@ -2069,6 +2076,7 @@ void rrdset_memory_file_free(RRDSET *st) {
2076 rrdset_memory_file_update(st);
2077
2078 struct rrdset_map_save_v019 *st_on_file = st->st_on_file;
2079 + __atomic_sub_fetch(&rrddim_db_memory_size, st_on_file->memsize, __ATOMIC_RELAXED);
2080 netdata_munmap(st_on_file, st_on_file->memsize);
2081
2082 // remove the pointers from the RRDDIM
@@ -2165,5 +2173,6 @@ bool rrdset_memory_load_or_create_map_save(RRDSET *st, RRD_MEMORY_MODE memory_mo
2173 // copy the useful values back to st_on_file
2174 rrdset_memory_file_update(st);
2175
2176 + __atomic_add_fetch(&rrddim_db_memory_size, st_on_file->memsize, __ATOMIC_RELAXED);
2177 return true;
2178 }
database/rrdsetvar.c
+1 -1
@@ -189,7 +189,7 @@ static void rrdsetvar_delete_callback(const DICTIONARY_ITEM *item __maybe_unused
189
190 void rrdsetvar_index_init(RRDSET *st) {
191 if(!st->rrdsetvar_root_index) {
192 - st->rrdsetvar_root_index = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
192 + st->rrdsetvar_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
193
194 dictionary_register_insert_callback(st->rrdsetvar_root_index, rrdsetvar_insert_callback, NULL);
195 dictionary_register_conflict_callback(st->rrdsetvar_root_index, rrdsetvar_conflict_callback, NULL);
database/rrdvar.c
+1 -1
@@ -84,7 +84,7 @@ static void rrdvar_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
84 }
85
86 DICTIONARY *rrdvariables_create(void) {
87 - DICTIONARY *dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
87 + DICTIONARY *dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_rrdhealth);
88
89 dictionary_register_insert_callback(dict, rrdvar_insert_callback, NULL);
90 dictionary_register_delete_callback(dict, rrdvar_delete_callback, NULL);
database/sqlite/sqlite_aclk.c
+5 -3
@@ -45,7 +45,7 @@ static void sql_maint_aclk_sync_database(struct aclk_database_worker_config *wc,
45
46 debug(D_ACLK, "Checking database for %s", wc->host_guid);
47
48 - BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE);
48 + BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, &netdata_buffers_statistics.buffers_sqlite);
49
50 buffer_sprintf(sql,"DELETE FROM aclk_alert_%s WHERE date_submitted IS NOT NULL AND "
51 "CAST(date_cloud_ack AS INT) < unixepoch()-%d;", wc->uuid_str, ACLK_DELETE_ACK_ALERTS_INTERNAL);
@@ -120,7 +120,7 @@ void sql_delete_aclk_table_list(struct aclk_database_worker_config *wc, struct a
120 debug(D_ACLK_SYNC, "Host %s does NOT exist, can delete aclk sync tables", host_str);
121
122 sqlite3_stmt *res = NULL;
123 - BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE);
123 + BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, &netdata_buffers_statistics.buffers_sqlite);
124
125 buffer_sprintf(sql,"SELECT 'drop '||type||' IF EXISTS '||name||';' FROM sqlite_schema " \
126 "WHERE name LIKE 'aclk_%%_%s' AND type IN ('table', 'trigger', 'index');", uuid_str);
@@ -355,6 +355,8 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
355 uuid_unparse_lower(*(uuid_t *)argv[IDX_HOST_ID], guid);
356
357 struct rrdhost_system_info *system_info = callocz(1, sizeof(struct rrdhost_system_info));
358 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
359 +
360 system_info->hops = str2i((const char *) argv[IDX_HOPS]);
361
362 sql_build_host_system_info((uuid_t *)argv[IDX_HOST_ID], system_info);
@@ -731,7 +733,7 @@ void sql_create_aclk_table(RRDHOST *host, uuid_t *host_uuid, uuid_t *node_id)
733
734 uuid_unparse_lower(*host_uuid, host_guid);
735
734 - BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE);
736 + BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, &netdata_buffers_statistics.buffers_sqlite);
737
738 buffer_sprintf(sql, TABLE_ACLK_ALERT, uuid_str);
739 db_execute(buffer_tostring(sql));
database/sqlite/sqlite_aclk_alert.c
+9 -9
@@ -156,7 +156,7 @@ int sql_queue_alarm_to_aclk(RRDHOST *host, ALARM_ENTRY *ae, int skip_filter)
156 char uuid_str[GUID_LEN + 1];
157 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
158
159 - BUFFER *sql = buffer_create(1024);
159 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
160
161 buffer_sprintf(
162 sql,
@@ -245,7 +245,7 @@ void aclk_push_alert_event(struct aclk_database_worker_config *wc, struct aclk_d
245 return;
246 }
247
248 - BUFFER *sql = buffer_create(1024);
248 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
249
250 if (wc->alerts_start_seq_id != 0) {
251 buffer_sprintf(
@@ -410,7 +410,7 @@ void sql_queue_existing_alerts_to_aclk(RRDHOST *host)
410 {
411 char uuid_str[GUID_LEN + 1];
412 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
413 - BUFFER *sql = buffer_create(1024);
413 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
414
415 buffer_sprintf(sql,"delete from aclk_alert_%s; " \
416 "insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
@@ -487,7 +487,7 @@ void aclk_push_alarm_health_log(struct aclk_database_worker_config *wc, struct a
487 struct timeval first_timestamp;
488 struct timeval last_timestamp;
489
490 - BUFFER *sql = buffer_create(1024);
490 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
491
492 sqlite3_stmt *res = NULL;
493
@@ -656,7 +656,7 @@ int aclk_push_alert_config_event(struct aclk_database_worker_config *wc, struct
656 alarm_config.p_db_lookup_dimensions = sqlite3_column_bytes(res, 27) > 0 ? strdupz((char *)sqlite3_column_text(res, 27)) : NULL;
657 alarm_config.p_db_lookup_method = sqlite3_column_bytes(res, 28) > 0 ? strdupz((char *)sqlite3_column_text(res, 28)) : NULL;
658
659 - BUFFER *tmp_buf = buffer_create(1024);
659 + BUFFER *tmp_buf = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
660 buffer_data_options2string(tmp_buf, sqlite3_column_int(res, 29));
661 alarm_config.p_db_lookup_options = strdupz((char *)buffer_tostring(tmp_buf));
662 buffer_free(tmp_buf);
@@ -740,7 +740,7 @@ void sql_process_queue_removed_alerts_to_aclk(struct aclk_database_worker_config
740 {
741 UNUSED(cmd);
742
743 - BUFFER *sql = buffer_create(1024);
743 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
744
745 buffer_sprintf(sql,"insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
746 "select unique_id alert_unique_id, unixepoch(), unique_id alert_unique_id from health_log_%s " \
@@ -818,7 +818,7 @@ void aclk_process_send_alarm_snapshot(char *node_id, char *claim_id, uint64_t sn
818
819 void aclk_mark_alert_cloud_ack(char *uuid_str, uint64_t alerts_ack_sequence_id)
820 {
821 - BUFFER *sql = buffer_create(1024);
821 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
822
823 if (alerts_ack_sequence_id != 0) {
824 buffer_sprintf(
@@ -1027,7 +1027,7 @@ void sql_aclk_alert_clean_dead_entries(RRDHOST *host)
1027 char uuid_str[GUID_LEN + 1];
1028 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
1029
1030 - BUFFER *sql = buffer_create(1024);
1030 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
1031
1032 buffer_sprintf(sql,"delete from aclk_alert_%s where filtered_alert_unique_id not in "
1033 " (select unique_id from health_log_%s); ", uuid_str, uuid_str);
@@ -1053,7 +1053,7 @@ int get_proto_alert_status(RRDHOST *host, struct proto_alert_status *proto_alert
1053 proto_alert_status->alert_updates = wc->alert_updates;
1054 proto_alert_status->alerts_batch_id = wc->alerts_batch_id;
1055
1056 - BUFFER *sql = buffer_create(1024);
1056 + BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
1057 sqlite3_stmt *res = NULL;
1058
1059 buffer_sprintf(sql, "SELECT MIN(sequence_id), MAX(sequence_id), " \
database/sqlite/sqlite_metadata.c
+4 -3
@@ -372,7 +372,7 @@ static BUFFER *sql_store_host_system_info(RRDHOST *host)
372 if (unlikely(!system_info))
373 return NULL;
374
375 - BUFFER *work_buffer = buffer_create(1024);
375 + BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
376
377 struct query_build key_data = {.sql = work_buffer, .count = 0};
378 uuid_unparse_lower(host->host_uuid, key_data.uuid_str);
@@ -887,7 +887,7 @@ static bool metadata_scan_host(RRDHOST *host, uint32_t max_count) {
887
888 bool more_to_do = false;
889 uint32_t scan_count = 1;
890 - BUFFER *work_buffer = buffer_create(1024);
890 + BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
891
892 rrdset_foreach_reentrant(st, host) {
893 if (scan_count == max_count) {
@@ -969,12 +969,13 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused)
969 if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED) || !rrdhost_flag_check(host, RRDHOST_FLAG_METADATA_UPDATE))
970 continue;
971 internal_error(true, "METADATA: Scanning host %s", rrdhost_hostname(host));
972 + rrdhost_flag_clear(host,RRDHOST_FLAG_METADATA_UPDATE);
973
974 if (unlikely(rrdhost_flag_check(host, RRDHOST_FLAG_METADATA_LABELS))) {
975 rrdhost_flag_clear(host, RRDHOST_FLAG_METADATA_LABELS);
976 int rc = exec_statement_with_uuid(SQL_DELETE_HOST_LABELS, &host->host_uuid);
977 if (likely(rc == SQLITE_OK)) {
977 - BUFFER *work_buffer = buffer_create(1024);
978 + BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
979 struct query_build tmp = {.sql = work_buffer, .count = 0};
980 uuid_unparse_lower(host->host_uuid, tmp.uuid_str);
981 rrdlabels_walkthrough_read(host->rrdlabels, host_label_store_to_sql_callback, &tmp);
exporting/graphite/graphite.c
+2 -2
@@ -48,7 +48,7 @@ int init_graphite_instance(struct instance *instance)
48
49 instance->check_response = exporting_discard_response;
50
51 - instance->buffer = (void *)buffer_create(0);
51 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
52 if (!instance->buffer) {
53 error("EXPORTING: cannot create buffer for graphite exporting connector instance %s", instance->config.name);
54 return 1;
@@ -96,7 +96,7 @@ void sanitize_graphite_label_value(char *dst, const char *src, size_t len)
96 int format_host_labels_graphite_plaintext(struct instance *instance, RRDHOST *host)
97 {
98 if (!instance->labels_buffer)
99 - instance->labels_buffer = buffer_create(1024);
99 + instance->labels_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_exporters);
100
101 if (unlikely(!sending_labels_configured(instance)))
102 return 0;
exporting/init_connectors.c
+3 -3
@@ -171,8 +171,8 @@ void simple_connector_init(struct instance *instance)
171 if (connector_specific_data->first_buffer)
172 return;
173
174 - connector_specific_data->header = buffer_create(0);
175 - connector_specific_data->buffer = buffer_create(0);
174 + connector_specific_data->header = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
175 + connector_specific_data->buffer = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
176
177 // create a ring buffer
178 struct simple_connector_buffer *first_buffer = NULL;
@@ -195,7 +195,7 @@ void simple_connector_init(struct instance *instance)
195 connector_specific_data->last_buffer = connector_specific_data->first_buffer;
196
197 if (*instance->config.username || *instance->config.password) {
198 - BUFFER *auth_string = buffer_create(0);
198 + BUFFER *auth_string = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
199
200 buffer_sprintf(auth_string, "%s:%s", instance->config.username, instance->config.password);
201
exporting/json/json.c
+3 -3
@@ -37,7 +37,7 @@ int init_json_instance(struct instance *instance)
37
38 instance->check_response = exporting_discard_response;
39
40 - instance->buffer = (void *)buffer_create(0);
40 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
41 if (!instance->buffer) {
42 error("EXPORTING: cannot create buffer for json exporting connector instance %s", instance->config.name);
43 return 1;
@@ -96,7 +96,7 @@ int init_json_http_instance(struct instance *instance)
96
97 instance->check_response = exporting_discard_response;
98
99 - instance->buffer = (void *)buffer_create(0);
99 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
100
101 simple_connector_init(instance);
102
@@ -119,7 +119,7 @@ int init_json_http_instance(struct instance *instance)
119 int format_host_labels_json_plaintext(struct instance *instance, RRDHOST *host)
120 {
121 if (!instance->labels_buffer)
122 - instance->labels_buffer = buffer_create(1024);
122 + instance->labels_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_exporters);
123
124 if (unlikely(!sending_labels_configured(instance)))
125 return 0;
exporting/mongodb/mongodb.c
+1 -1
@@ -106,7 +106,7 @@ int init_mongodb_instance(struct instance *instance)
106 instance->prepare_header = NULL;
107 instance->check_response = NULL;
108
109 - instance->buffer = (void *)buffer_create(0);
109 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
110 if (!instance->buffer) {
111 error("EXPORTING: cannot create buffer for MongoDB exporting connector instance %s", instance->config.name);
112 return 1;
exporting/opentsdb/opentsdb.c
+4 -4
@@ -45,7 +45,7 @@ int init_opentsdb_telnet_instance(struct instance *instance)
45 instance->prepare_header = NULL;
46 instance->check_response = exporting_discard_response;
47
48 - instance->buffer = (void *)buffer_create(0);
48 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
49 if (!instance->buffer) {
50 error("EXPORTING: cannot create buffer for opentsdb telnet exporting connector instance %s", instance->config.name);
51 return 1;
@@ -102,7 +102,7 @@ int init_opentsdb_http_instance(struct instance *instance)
102 instance->prepare_header = opentsdb_http_prepare_header;
103 instance->check_response = exporting_discard_response;
104
105 - instance->buffer = (void *)buffer_create(0);
105 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
106 if (!instance->buffer) {
107 error("EXPORTING: cannot create buffer for opentsdb HTTP exporting connector instance %s", instance->config.name);
108 return 1;
@@ -150,7 +150,7 @@ void sanitize_opentsdb_label_value(char *dst, const char *src, size_t len)
150
151 int format_host_labels_opentsdb_telnet(struct instance *instance, RRDHOST *host) {
152 if(!instance->labels_buffer)
153 - instance->labels_buffer = buffer_create(1024);
153 + instance->labels_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_exporters);
154
155 if (unlikely(!sending_labels_configured(instance)))
156 return 0;
@@ -283,7 +283,7 @@ void opentsdb_http_prepare_header(struct instance *instance)
283
284 int format_host_labels_opentsdb_http(struct instance *instance, RRDHOST *host) {
285 if (!instance->labels_buffer)
286 - instance->labels_buffer = buffer_create(1024);
286 + instance->labels_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_exporters);
287
288 if (unlikely(!sending_labels_configured(instance)))
289 return 0;
exporting/process_data.c
+7 -7
@@ -77,8 +77,8 @@ NETDATA_DOUBLE exporting_calculate_value_from_stored_data(
77 time_t before = instance->before;
78
79 // find the edges of the rrd database for this chart
80 - time_t first_t = rd->tiers[0]->query_ops->oldest_time_s(rd->tiers[0]->db_metric_handle);
81 - time_t last_t = rd->tiers[0]->query_ops->latest_time_s(rd->tiers[0]->db_metric_handle);
80 + time_t first_t = rd->tiers[0].query_ops->oldest_time_s(rd->tiers[0].db_metric_handle);
81 + time_t last_t = rd->tiers[0].query_ops->latest_time_s(rd->tiers[0].db_metric_handle);
82 time_t update_every = st->update_every;
83 struct storage_engine_query_handle handle;
84
@@ -126,8 +126,8 @@ NETDATA_DOUBLE exporting_calculate_value_from_stored_data(
126 size_t counter = 0;
127 NETDATA_DOUBLE sum = 0;
128
129 - for (rd->tiers[0]->query_ops->init(rd->tiers[0]->db_metric_handle, &handle, after, before, STORAGE_PRIORITY_LOW); !rd->tiers[0]->query_ops->is_finished(&handle);) {
130 - STORAGE_POINT sp = rd->tiers[0]->query_ops->next_metric(&handle);
129 + for (rd->tiers[0].query_ops->init(rd->tiers[0].db_metric_handle, &handle, after, before, STORAGE_PRIORITY_LOW); !rd->tiers[0].query_ops->is_finished(&handle);) {
130 + STORAGE_POINT sp = rd->tiers[0].query_ops->next_metric(&handle);
131 points_read++;
132
133 if (unlikely(storage_point_is_empty(sp))) {
@@ -138,7 +138,7 @@ NETDATA_DOUBLE exporting_calculate_value_from_stored_data(
138 sum += sp.sum;
139 counter += sp.count;
140 }
141 - rd->tiers[0]->query_ops->finalize(&handle);
141 + rd->tiers[0].query_ops->finalize(&handle);
142 global_statistics_exporters_query_completed(points_read);
143
144 if (unlikely(!counter)) {
@@ -397,7 +397,7 @@ int simple_connector_end_batch(struct instance *instance)
397 struct simple_connector_buffer *last_buffer = simple_connector_data->last_buffer;
398
399 if (!last_buffer->buffer) {
400 - last_buffer->buffer = buffer_create(0);
400 + last_buffer->buffer = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
401 }
402
403 if (last_buffer->used) {
@@ -419,7 +419,7 @@ int simple_connector_end_batch(struct instance *instance)
419 if (last_buffer->header)
420 buffer_flush(last_buffer->header);
421 else
422 - last_buffer->header = buffer_create(0);
422 + last_buffer->header = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
423
424 if (instance->prepare_header)
425 instance->prepare_header(instance);
exporting/prometheus/prometheus.c
+1 -1
@@ -317,7 +317,7 @@ void format_host_labels_prometheus(struct instance *instance, RRDHOST *host)
317 return;
318
319 if (!instance->labels_buffer)
320 - instance->labels_buffer = buffer_create(1024);
320 + instance->labels_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_exporters);
321
322 struct format_prometheus_label_callback tmp = {
323 .instance = instance,
exporting/prometheus/remote_write/remote_write.c
+1 -1
@@ -104,7 +104,7 @@ int init_prometheus_remote_write_instance(struct instance *instance)
104 instance->prepare_header = prometheus_remote_write_prepare_header;
105 instance->check_response = process_prometheus_remote_write_response;
106
107 - instance->buffer = (void *)buffer_create(0);
107 + instance->buffer = (void *)buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
108
109 if (uv_mutex_init(&instance->mutex))
110 return 1;
exporting/send_data.c
+1 -1
@@ -64,7 +64,7 @@ void simple_connector_receive_response(int *sock, struct instance *instance)
64 {
65 static BUFFER *response = NULL;
66 if (!response)
67 - response = buffer_create(4096);
67 + response = buffer_create(4096, &netdata_buffers_statistics.buffers_exporters);
68
69 struct stats *stats = &instance->stats;
70 #ifdef ENABLE_HTTPS
exporting/send_internal_metrics.c
+1 -1
@@ -65,7 +65,7 @@ void send_internal_metrics(struct instance *instance)
65
66 if (!stats->initialized) {
67 char id[RRD_ID_LENGTH_MAX + 1];
68 - BUFFER *family = buffer_create(0);
68 + BUFFER *family = buffer_create(0, &netdata_buffers_statistics.buffers_exporters);
69
70 buffer_sprintf(family, "exporting_%s", instance->config.name);
71
health/health.c
+3 -3
@@ -459,8 +459,8 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
459 BUFFER *warn_alarms, *crit_alarms;
460 active_alerts_t *active_alerts = callocz(ACTIVE_ALARMS_LIST_EXAMINE, sizeof(active_alerts_t));
461
462 - warn_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
463 - crit_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
462 + warn_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_health);
463 + crit_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_health);
464
465 foreach_rrdcalc_in_rrdhost_read(host, rc) {
466 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
@@ -517,7 +517,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
517
518 char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
519
520 - BUFFER *wb = buffer_create(8192);
520 + BUFFER *wb = buffer_create(8192, &netdata_buffers_statistics.buffers_health);
521 bool ok = prepare_command(wb,
522 exec,
523 recipient,
health/health_log.c
+5 -3
@@ -73,7 +73,7 @@ inline void health_label_log_save(RRDHOST *host) {
73 health_log_rotate(host);
74
75 if(unlikely(host->health.health_log_fp)) {
76 - BUFFER *wb = buffer_create(1024);
76 + BUFFER *wb = buffer_create(1024, &netdata_buffers_statistics.buffers_health);
77
78 rrdlabels_to_buffer(localhost->rrdlabels, wb, "", "=", "", "\t ", NULL, NULL, NULL, NULL);
79 char *write = (char *) buffer_tostring(wb);
@@ -182,8 +182,10 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
182 size_t line = 0, len = 0;
183 ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
184
185 - DICTIONARY *all_rrdcalcs = dictionary_create(
186 - DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
185 + DICTIONARY *all_rrdcalcs = dictionary_create_advanced(
186 + DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE,
187 + &dictionary_stats_category_rrdhealth);
188 +
189 RRDCALC *rc;
190 foreach_rrdcalc_in_rrdhost_read(host, rc) {
191 dictionary_set(all_rrdcalcs, rrdcalc_name(rc), rc, sizeof(*rc));
libnetdata/arrayalloc/arrayalloc.c
+6 -6
@@ -144,10 +144,10 @@ static void arrayalloc_init(ARAL *ar) {
144
145 #ifdef NETDATA_INTERNAL_CHECKS
146 static inline void arrayalloc_free_validate_internal_check(ARAL *ar, ARAL_FREE *fr) {
147 - if(fr->size < ar->internal.element_size)
147 + if(unlikely(fr->size < ar->internal.element_size))
148 fatal("ARRAYALLOC: free item of size %zu, less than the expected element size %zu", fr->size, ar->internal.element_size);
149
150 - if(fr->size % ar->internal.element_size)
150 + if(unlikely(fr->size % ar->internal.element_size))
151 fatal("ARRAYALLOC: free item of size %zu is not multiple to element size %zu", fr->size, ar->internal.element_size);
152 }
153 #else
@@ -234,13 +234,13 @@ static void arrayalloc_add_page(ARAL *ar TRACE_ALLOCATIONS_FUNCTION_DEFINITION_P
234 arrayalloc_free_validate_internal_check(ar, fr);
235 }
236
237 -static void arrayalloc_lock(ARAL *ar) {
238 - if(!ar->internal.lockless)
237 +static inline void arrayalloc_lock(ARAL *ar) {
238 + if(likely(!ar->internal.lockless))
239 netdata_spinlock_lock(&ar->internal.spinlock);
240 }
241
242 -static void arrayalloc_unlock(ARAL *ar) {
243 - if(!ar->internal.lockless)
242 +static inline void arrayalloc_unlock(ARAL *ar) {
243 + if(likely(!ar->internal.lockless))
244 netdata_spinlock_unlock(&ar->internal.spinlock);
245 }
246
libnetdata/buffer/buffer.c
+34 -26
@@ -442,28 +442,28 @@ void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minute
442 buffer_need_bytes(wb, 36);
443
444 char *b = &wb->buffer[wb->len];
445 - char *p = b;
446 -
447 - *p++ = '0' + year / 1000; year %= 1000;
448 - *p++ = '0' + year / 100; year %= 100;
449 - *p++ = '0' + year / 10;
450 - *p++ = '0' + year % 10;
451 - *p++ = '-';
452 - *p++ = '0' + month / 10;
453 - *p++ = '0' + month % 10;
454 - *p++ = '-';
455 - *p++ = '0' + day / 10;
456 - *p++ = '0' + day % 10;
457 - *p++ = ' ';
458 - *p++ = '0' + hours / 10;
459 - *p++ = '0' + hours % 10;
460 - *p++ = ':';
461 - *p++ = '0' + minutes / 10;
462 - *p++ = '0' + minutes % 10;
463 - *p++ = ':';
464 - *p++ = '0' + seconds / 10;
465 - *p++ = '0' + seconds % 10;
466 - *p = '\0';
445 + char *p = b;
446 +
447 + *p++ = '0' + year / 1000; year %= 1000;
448 + *p++ = '0' + year / 100; year %= 100;
449 + *p++ = '0' + year / 10;
450 + *p++ = '0' + year % 10;
451 + *p++ = '-';
452 + *p++ = '0' + month / 10;
453 + *p++ = '0' + month % 10;
454 + *p++ = '-';
455 + *p++ = '0' + day / 10;
456 + *p++ = '0' + day % 10;
457 + *p++ = ' ';
458 + *p++ = '0' + hours / 10;
459 + *p++ = '0' + hours % 10;
460 + *p++ = ':';
461 + *p++ = '0' + minutes / 10;
462 + *p++ = '0' + minutes % 10;
463 + *p++ = ':';
464 + *p++ = '0' + seconds / 10;
465 + *p++ = '0' + seconds % 10;
466 + *p = '\0';
467
468 wb->len += (size_t)(p - b);
469
@@ -472,7 +472,7 @@ void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minute
472 buffer_overflow_check(wb);
473 }
474
475 -BUFFER *buffer_create(size_t size)
475 +BUFFER *buffer_create(size_t size, size_t *statistics)
476 {
477 BUFFER *b;
478
@@ -483,9 +483,13 @@ BUFFER *buffer_create(size_t size)
483 b->buffer[0] = '\0';
484 b->size = size;
485 b->contenttype = CT_TEXT_PLAIN;
486 + b->statistics = statistics;
487 buffer_overflow_init(b);
488 buffer_overflow_check(b);
489
490 + if(b->statistics)
491 + __atomic_add_fetch(b->statistics, b->size + sizeof(BUFFER) + sizeof(BUFFER_OVERFLOW_EOF) + 2, __ATOMIC_RELAXED);
492 +
493 return(b);
494 }
495
@@ -496,6 +500,9 @@ void buffer_free(BUFFER *b) {
500
501 debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
502
503 + if(b->statistics)
504 + __atomic_sub_fetch(b->statistics, b->size + sizeof(BUFFER) + sizeof(BUFFER_OVERFLOW_EOF) + 2, __ATOMIC_RELAXED);
505 +
506 freez(b->buffer);
507 freez(b);
508 }
@@ -510,9 +517,7 @@ void buffer_increase(BUFFER *b, size_t free_size_required) {
517 size_t minimum = WEB_DATA_LENGTH_INCREASE_STEP;
518 if(minimum > wanted) wanted = minimum;
519
513 - size_t optimal = b->size;
514 - if(b->size > 5*1024*1024) optimal = b->size / 2;
515 -
520 + size_t optimal = (b->size > 5*1024*1024) ? b->size / 2 : b->size;
521 if(optimal > wanted) wanted = optimal;
522
523 debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + wanted);
@@ -520,6 +525,9 @@ void buffer_increase(BUFFER *b, size_t free_size_required) {
525 b->buffer = reallocz(b->buffer, b->size + wanted + sizeof(BUFFER_OVERFLOW_EOF) + 2);
526 b->size += wanted;
527
528 + if(b->statistics)
529 + __atomic_add_fetch(b->statistics, wanted, __ATOMIC_RELAXED);
530 +
531 buffer_overflow_init(b);
532 buffer_overflow_check(b);
533 }
libnetdata/buffer/buffer.h
+2 -1
@@ -15,6 +15,7 @@ typedef struct web_buffer {
15 uint8_t options; // options related to the content
16 time_t date; // the timestamp this content has been generated
17 time_t expires; // the timestamp this content expires
18 + size_t *statistics;
19 } BUFFER;
20
21 // options
@@ -61,7 +62,7 @@ void buffer_rrd_value(BUFFER *wb, NETDATA_DOUBLE value);
62 void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
63 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
64
64 -BUFFER *buffer_create(size_t size);
65 +BUFFER *buffer_create(size_t size, size_t *statistics);
66 void buffer_free(BUFFER *b);
67 void buffer_increase(BUFFER *b, size_t free_size_required);
68
libnetdata/circular_buffer/circular_buffer.c
+22 -8
@@ -1,16 +1,24 @@
1 #include "../libnetdata.h"
2
3 -struct circular_buffer *cbuffer_new(size_t initial, size_t max) {
4 - struct circular_buffer *result = mallocz(sizeof(*result));
5 - result->size = initial;
6 - result->data = mallocz(initial);
7 - result->write = 0;
8 - result->read = 0;
9 - result->max_size = max;
10 - return result;
3 +struct circular_buffer *cbuffer_new(size_t initial, size_t max, size_t *statistics) {
4 + struct circular_buffer *buf = mallocz(sizeof(struct circular_buffer));
5 + buf->size = initial;
6 + buf->data = mallocz(initial);
7 + buf->write = 0;
8 + buf->read = 0;
9 + buf->max_size = max;
10 + buf->statistics = statistics;
11 +
12 + if(buf->statistics)
13 + __atomic_add_fetch(buf->statistics, sizeof(struct circular_buffer) + buf->size, __ATOMIC_RELAXED);
14 +
15 + return buf;
16 }
17
18 void cbuffer_free(struct circular_buffer *buf) {
19 + if(buf && buf->statistics)
20 + __atomic_sub_fetch(buf->statistics, sizeof(struct circular_buffer) + buf->size, __ATOMIC_RELAXED);
21 +
22 freez(buf->data);
23 freez(buf);
24 }
@@ -19,6 +27,8 @@ static int cbuffer_realloc_unsafe(struct circular_buffer *buf) {
27 // Check that we can grow
28 if (buf->size >= buf->max_size)
29 return 1;
30 +
31 + size_t old_size = buf->size;
32 size_t new_size = buf->size * 2;
33 if (new_size > buf->max_size)
34 new_size = buf->max_size;
@@ -43,6 +53,10 @@ static int cbuffer_realloc_unsafe(struct circular_buffer *buf) {
53 freez(buf->data);
54 buf->data = new_data;
55 buf->size = new_size;
56 +
57 + if(buf->statistics)
58 + __atomic_add_fetch(buf->statistics, new_size - old_size, __ATOMIC_RELAXED);
59 +
60 return 0;
61 }
62
libnetdata/circular_buffer/circular_buffer.h
+2 -1
@@ -5,10 +5,11 @@
5
6 struct circular_buffer {
7 size_t size, write, read, max_size;
8 + size_t *statistics;
9 char *data;
10 };
11
11 -struct circular_buffer *cbuffer_new(size_t initial, size_t max);
12 +struct circular_buffer *cbuffer_new(size_t initial, size_t max, size_t *statistics);
13 void cbuffer_free(struct circular_buffer *buf);
14 int cbuffer_add_unsafe(struct circular_buffer *buf, const char *d, size_t d_len);
15 void cbuffer_remove_unsafe(struct circular_buffer *buf, size_t num);
libnetdata/dictionary/dictionary.c
+3 -3
@@ -260,7 +260,7 @@ static inline void pointer_del(DICTIONARY *dict __maybe_unused, DICTIONARY_ITEM
260
261 static inline void DICTIONARY_STATS_PLUS_MEMORY(DICTIONARY *dict, size_t key_size, size_t item_size, size_t value_size) {
262 if(key_size)
263 - __atomic_fetch_add(&dict->stats->memory.indexed, (long)key_size, __ATOMIC_RELAXED);
263 + __atomic_fetch_add(&dict->stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
264
265 if(item_size)
266 __atomic_fetch_add(&dict->stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
@@ -270,7 +270,7 @@ static inline void DICTIONARY_STATS_PLUS_MEMORY(DICTIONARY *dict, size_t key_siz
270 }
271 static inline void DICTIONARY_STATS_MINUS_MEMORY(DICTIONARY *dict, size_t key_size, size_t item_size, size_t value_size) {
272 if(key_size)
273 - __atomic_fetch_sub(&dict->stats->memory.indexed, (long)key_size, __ATOMIC_RELAXED);
273 + __atomic_fetch_sub(&dict->stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
274
275 if(item_size)
276 __atomic_fetch_sub(&dict->stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
@@ -380,7 +380,7 @@ size_t dictionary_referenced_items(DICTIONARY *dict) {
380
381 long int dictionary_stats_for_registry(DICTIONARY *dict) {
382 if(unlikely(!dict)) return 0;
383 - return (dict->stats->memory.indexed + dict->stats->memory.dict);
383 + return (dict->stats->memory.index + dict->stats->memory.dict);
384 }
385 void dictionary_version_increment(DICTIONARY *dict) {
386 __atomic_fetch_add(&dict->version, 1, __ATOMIC_SEQ_CST);
libnetdata/dictionary/dictionary.h
+1 -1
@@ -91,7 +91,7 @@ struct dictionary_stats {
91
92 // memory
93 struct {
94 - long indexed; // bytes of keys indexed (indication of the index size)
94 + long index; // bytes of keys indexed (indication of the index size)
95 long values; // bytes of caller structures
96 long dict; // bytes of the structures dictionary needs
97 } memory;
libnetdata/eval/eval.c
+2 -2
@@ -1126,7 +1126,7 @@ EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, in
1126 return NULL;
1127 }
1128
1129 - BUFFER *out = buffer_create(1024);
1129 + BUFFER *out = buffer_create(1024, NULL);
1130 print_parsed_as_node(out, op, &err);
1131 if(err != EVAL_ERROR_OK) {
1132 error("failed to re-generate expression '%s' with reason: %s", string, expression_strerror(err));
@@ -1141,7 +1141,7 @@ EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, in
1141 exp->parsed_as = strdupz(buffer_tostring(out));
1142 buffer_free(out);
1143
1144 - exp->error_msg = buffer_create(100);
1144 + exp->error_msg = buffer_create(100, NULL);
1145 exp->nodes = (void *)op;
1146
1147 return exp;
libnetdata/json/json.c
+1 -1
@@ -90,7 +90,7 @@ jsmntok_t *json_tokenise(char *js, size_t len, size_t *count)
90 */
91 int json_callback_print(JSON_ENTRY *e)
92 {
93 - BUFFER *wb=buffer_create(300);
93 + BUFFER *wb=buffer_create(300, NULL);
94
95 buffer_sprintf(wb,"%s = ", e->name);
96 char txt[50];
libnetdata/libnetdata.h
+2
@@ -11,6 +11,8 @@ extern "C" {
11 #include <config.h>
12 #endif
13
14 +#define JUDYHS_INDEX_SIZE_ESTIMATE(key_bytes) (((key_bytes) + sizeof(Word_t) - 1) / sizeof(Word_t) * 4)
15 +
16 #if defined(NETDATA_DEV_MODE) && !defined(NETDATA_INTERNAL_CHECKS)
17 #define NETDATA_INTERNAL_CHECKS 1
18 #endif
libnetdata/onewayalloc/onewayalloc.c
+13
@@ -14,6 +14,12 @@ typedef struct owa_page {
14 struct owa_page *last; // the last page on the list - we currently allocate on this
15 } OWA_PAGE;
16
17 +static size_t onewayalloc_total_memory = 0;
18 +
19 +size_t onewayalloc_allocated_memory(void) {
20 + return __atomic_load_n(&onewayalloc_total_memory, __ATOMIC_RELAXED);
21 +}
22 +
23 // allocations need to be aligned to CPU register width
24 // https://en.wikipedia.org/wiki/Data_structure_alignment
25 static inline size_t natural_alignment(size_t size) {
@@ -60,6 +66,7 @@ static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
66 // OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0);
67 // if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);
68 OWA_PAGE *page = (OWA_PAGE *)mallocz(size);
69 + __atomic_add_fetch(&onewayalloc_total_memory, size, __ATOMIC_RELAXED);
70
71 page->size = size;
72 page->offset = natural_alignment(sizeof(OWA_PAGE));
@@ -183,11 +190,17 @@ void onewayalloc_destroy(ONEWAYALLOC *owa) {
190 // head->stats_mallocs_made, head->stats_mallocs_size,
191 // head->stats_pages, head->stats_pages_size);
192
193 + size_t total_size = 0;
194 OWA_PAGE *page = head;
195 while(page) {
196 + total_size += page->size;
197 +
198 OWA_PAGE *p = page;
199 page = page->next;
200 +
201 // munmap(p, p->size);
202 freez(p);
203 }
204 +
205 + __atomic_sub_fetch(&onewayalloc_total_memory, total_size, __ATOMIC_RELAXED);
206 }
libnetdata/onewayalloc/onewayalloc.h
+2
@@ -16,4 +16,6 @@ void onewayalloc_freez(ONEWAYALLOC *owa, const void *ptr);
16
17 void *onewayalloc_doublesize(ONEWAYALLOC *owa, const void *src, size_t oldsize);
18
19 +size_t onewayalloc_allocated_memory(void);
20 +
21 #endif // ONEWAYALLOC_H
libnetdata/string/string.c
+25 -10
@@ -56,14 +56,29 @@ static struct string_hashtable {
56 #define string_stats_atomic_decrement(var) __atomic_sub_fetch(&string_base.var, 1, __ATOMIC_RELAXED)
57
58 void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_t *entries, size_t *references, size_t *memory, size_t *duplications, size_t *releases) {
59 - *inserts = string_base.inserts;
60 - *deletes = string_base.deletes;
61 - *searches = string_base.searches;
62 - *entries = (size_t)string_base.entries;
63 - *references = (size_t)string_base.active_references;
64 - *memory = (size_t)string_base.memory;
65 - *duplications = string_base.duplications;
66 - *releases = string_base.releases;
59 + if(inserts)
60 + *inserts = string_base.inserts;
61 +
62 + if(deletes)
63 + *deletes = string_base.deletes;
64 +
65 + if(searches)
66 + *searches = string_base.searches;
67 +
68 + if(entries)
69 + *entries = (size_t)string_base.entries;
70 +
71 + if(references)
72 + *references = (size_t)string_base.active_references;
73 +
74 + if(memory)
75 + *memory = (size_t)string_base.memory;
76 +
77 + if(duplications)
78 + *duplications = string_base.duplications;
79 +
80 + if(releases)
81 + *releases = string_base.releases;
82 }
83
84 #define string_entry_acquire(se) __atomic_add_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST);
@@ -186,7 +201,7 @@ static inline STRING *string_index_insert(const char *str, size_t length) {
201 *ptr = string;
202 string_base.inserts++;
203 string_base.entries++;
189 - string_base.memory += (long)mem_size;
204 + string_base.memory += (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(length));
205 }
206 else {
207 // the item is already in the index
@@ -240,7 +255,7 @@ static inline void string_index_delete(STRING *string) {
255 size_t mem_size = sizeof(STRING) + string->length;
256 string_base.deletes++;
257 string_base.entries--;
243 - string_base.memory -= (long)mem_size;
258 + string_base.memory -= (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(string->length));
259 freez(string);
260 }
261
libnetdata/worker_utilization/worker_utilization.c
+16 -3
@@ -52,6 +52,7 @@ struct workers_workname { // this is what we add to Ju
52 static struct workers_globals {
53 SPINLOCK spinlock;
54 Pvoid_t worknames_JudyHS;
55 + size_t memory;
56
57 } workers_globals = { // workers globals, the base of all worknames
58 .spinlock = NETDATA_SPINLOCK_INITIALIZER, // a lock for the worknames index
@@ -60,6 +61,14 @@ static struct workers_globals {
61
62 static __thread struct worker *worker = NULL; // the current thread worker
63
64 +size_t workers_allocated_memory(void) {
65 + netdata_spinlock_lock(&workers_globals.spinlock);
66 + size_t memory = workers_globals.memory;
67 + netdata_spinlock_unlock(&workers_globals.spinlock);
68 +
69 + return memory;
70 +}
71 +
72 void worker_register(const char *name) {
73 if(unlikely(worker)) return;
74
@@ -76,9 +85,9 @@ void worker_register(const char *name) {
85 size_t name_size = strlen(name) + 1;
86 netdata_spinlock_lock(&workers_globals.spinlock);
87
79 - Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)name, name_size);
80 - if(!PValue)
81 - PValue = JudyHSIns(&workers_globals.worknames_JudyHS, (void *)name, name_size, PJE0);
88 + workers_globals.memory += sizeof(struct worker) + strlen(worker->tag) + 1 + strlen(worker->workname) + 1;
89 +
90 + Pvoid_t *PValue = JudyHSIns(&workers_globals.worknames_JudyHS, (void *)name, name_size, PJE0);
91
92 struct workers_workname *workname = *PValue;
93 if(!workname) {
@@ -86,6 +95,8 @@ void worker_register(const char *name) {
95 netdata_spinlock_init(&workname->spinlock);
96 workname->base = NULL;
97 *PValue = workname;
98 +
99 + workers_globals.memory += sizeof(struct workers_workname) + JUDYHS_INDEX_SIZE_ESTIMATE(name_size);
100 }
101
102 netdata_spinlock_lock(&workname->spinlock);
@@ -136,8 +147,10 @@ void worker_unregister(void) {
147 if(!workname->base) {
148 JudyHSDel(&workers_globals.worknames_JudyHS, (void *) worker->workname, workname_size, PJE0);
149 freez(workname);
150 + workers_globals.memory -= sizeof(struct workers_workname) + JUDYHS_INDEX_SIZE_ESTIMATE(workname_size);
151 }
152 }
153 + workers_globals.memory -= sizeof(struct worker) + strlen(worker->tag) + 1 + strlen(worker->workname) + 1;
154 netdata_spinlock_unlock(&workers_globals.spinlock);
155
156 for(int i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
libnetdata/worker_utilization/worker_utilization.h
+1
@@ -15,6 +15,7 @@ typedef enum {
15 WORKER_METRIC_INCREMENTAL_TOTAL = 4,
16 } WORKER_METRIC_TYPE;
17
18 +size_t workers_allocated_memory(void);
19 void worker_register(const char *name);
20 void worker_register_job_name(size_t job_id, const char *name);
21 void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type);
ml/Query.h
+4 -4
@@ -8,19 +8,19 @@ namespace ml {
8 class Query {
9 public:
10 Query(RRDDIM *RD) : RD(RD), Initialized(false) {
11 - Ops = RD->tiers[0]->query_ops;
11 + Ops = RD->tiers[0].query_ops;
12 }
13
14 time_t latestTime() {
15 - return Ops->latest_time_s(RD->tiers[0]->db_metric_handle);
15 + return Ops->latest_time_s(RD->tiers[0].db_metric_handle);
16 }
17
18 time_t oldestTime() {
19 - return Ops->oldest_time_s(RD->tiers[0]->db_metric_handle);
19 + return Ops->oldest_time_s(RD->tiers[0].db_metric_handle);
20 }
21
22 void init(time_t AfterT, time_t BeforeT) {
23 - Ops->init(RD->tiers[0]->db_metric_handle, &Handle, AfterT, BeforeT, STORAGE_PRIORITY_BEST_EFFORT);
23 + Ops->init(RD->tiers[0].db_metric_handle, &Handle, AfterT, BeforeT, STORAGE_PRIORITY_BEST_EFFORT);
24 Initialized = true;
25 points_read = 0;
26 }
parser/parser.c
+1 -1
@@ -357,7 +357,7 @@ inline int parser_action(PARSER *parser, char *input)
357
358 #ifdef NETDATA_INTERNAL_CHECKS
359 if(rc == PARSER_RC_ERROR) {
360 - BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX);
360 + BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
361 for(size_t i = 0; i < num_words ;i++) {
362 if(i) buffer_fast_strcat(wb, " ", 1);
363
streaming/receiver.c
+2
@@ -44,6 +44,8 @@ void receiver_state_free(struct receiver_state *rpt) {
44 if(rpt->system_info)
45 rrdhost_system_info_free(rpt->system_info);
46
47 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_receivers, sizeof(*rpt), __ATOMIC_RELAXED);
48 +
49 freez(rpt);
50 }
51
streaming/replication.c
+54 -10
@@ -46,6 +46,12 @@ struct replication_query_statistics replication_get_query_statistics(void) {
46 return ret;
47 }
48
49 +size_t replication_buffers_allocated = 0;
50 +
51 +size_t replication_allocated_buffers(void) {
52 + return __atomic_load_n(&replication_buffers_allocated, __ATOMIC_RELAXED);
53 +}
54 +
55 // ----------------------------------------------------------------------------
56 // sending replication replies
57
@@ -109,6 +115,8 @@ static struct replication_query *replication_query_prepare(
115 ) {
116 size_t dimensions = rrdset_number_of_dimensions(st);
117 struct replication_query *q = callocz(1, sizeof(struct replication_query) + dimensions * sizeof(struct replication_dimension));
118 + __atomic_add_fetch(&replication_buffers_allocated, sizeof(struct replication_query) + dimensions * sizeof(struct replication_dimension), __ATOMIC_RELAXED);
119 +
120 q->dimensions = dimensions;
121 q->st = st;
122
@@ -170,7 +178,7 @@ static struct replication_query *replication_query_prepare(
178 d->rda = dictionary_acquired_item_dup(rd_dfe.dict, rd_dfe.item);
179 d->rd = rd;
180
173 - q->ops->init(rd->tiers[0]->db_metric_handle, &d->handle, q->query.after, q->query.before,
181 + q->ops->init(rd->tiers[0].db_metric_handle, &d->handle, q->query.after, q->query.before,
182 q->query.locked_data_collection ? STORAGE_PRIORITY_HIGH : STORAGE_PRIORITY_LOW);
183 d->enabled = true;
184 d->skip = false;
@@ -231,6 +239,7 @@ static void replication_query_finalize(struct replication_query *q, bool execute
239 netdata_spinlock_unlock(&replication_queries.spinlock);
240 }
241
242 + __atomic_sub_fetch(&replication_buffers_allocated, sizeof(struct replication_query) + dimensions * sizeof(struct replication_dimension), __ATOMIC_RELAXED);
243 freez(q);
244 }
245
@@ -817,6 +826,7 @@ static struct replication_thread {
826 struct {
827 size_t executed; // the number of replication requests executed
828 size_t latest_first_time; // the 'after' timestamp of the last request we executed
829 + size_t memory; // the total memory allocated by replication
830 } atomic; // access should be with atomic operations
831
832 struct {
@@ -849,6 +859,7 @@ static struct replication_thread {
859 .atomic = {
860 .executed = 0,
861 .latest_first_time = 0,
862 + .memory = 0,
863 },
864 .main_thread = {
865 .last_executed = 0,
@@ -857,6 +868,10 @@ static struct replication_thread {
868 },
869 };
870
871 +size_t replication_allocated_memory(void) {
872 + return __atomic_load_n(&replication_globals.atomic.memory, __ATOMIC_RELAXED);
873 +}
874 +
875 #define replication_set_latest_first_time(t) __atomic_store_n(&replication_globals.atomic.latest_first_time, t, __ATOMIC_RELAXED)
876 #define replication_get_latest_first_time() __atomic_load_n(&replication_globals.atomic.latest_first_time, __ATOMIC_RELAXED)
877
@@ -909,6 +924,7 @@ static struct replication_sort_entry *replication_sort_entry_create_unsafe(struc
924 fatal_when_replication_is_not_locked_for_me();
925
926 struct replication_sort_entry *rse = mallocz(sizeof(struct replication_sort_entry));
927 + __atomic_add_fetch(&replication_globals.atomic.memory, sizeof(struct replication_sort_entry), __ATOMIC_RELAXED);
928
929 rrdpush_sender_pending_replication_requests_plus_one(rq->sender);
930
@@ -926,6 +942,7 @@ static struct replication_sort_entry *replication_sort_entry_create_unsafe(struc
942
943 static void replication_sort_entry_destroy(struct replication_sort_entry *rse) {
944 freez(rse);
945 + __atomic_sub_fetch(&replication_globals.atomic.memory, sizeof(struct replication_sort_entry), __ATOMIC_RELAXED);
946 }
947
948 static void replication_sort_entry_add(struct replication_request *rq) {
@@ -959,12 +976,19 @@ static void replication_sort_entry_add(struct replication_request *rq) {
976 Pvoid_t *inner_judy_ptr;
977
978 // find the outer judy entry, using after as key
962 - inner_judy_ptr = JudyLGet(replication_globals.unsafe.queue.JudyL_array, (Word_t) rq->after, PJE0);
963 - if(!inner_judy_ptr)
964 - inner_judy_ptr = JudyLIns(&replication_globals.unsafe.queue.JudyL_array, (Word_t) rq->after, PJE0);
979 + size_t mem_before_outer_judyl = JudyLMemUsed(replication_globals.unsafe.queue.JudyL_array);
980 + inner_judy_ptr = JudyLIns(&replication_globals.unsafe.queue.JudyL_array, (Word_t) rq->after, PJE0);
981 + size_t mem_after_outer_judyl = JudyLMemUsed(replication_globals.unsafe.queue.JudyL_array);
982 + if(unlikely(!inner_judy_ptr || inner_judy_ptr == PJERR))
983 + fatal("REPLICATION: corrupted outer judyL");
984
985 // add it to the inner judy, using unique_id as key
986 + size_t mem_before_inner_judyl = JudyLMemUsed(*inner_judy_ptr);
987 Pvoid_t *item = JudyLIns(inner_judy_ptr, rq->unique_id, PJE0);
988 + size_t mem_after_inner_judyl = JudyLMemUsed(*inner_judy_ptr);
989 + if(unlikely(!item || item == PJERR))
990 + fatal("REPLICATION: corrupted inner judyL");
991 +
992 *item = rse;
993 rq->indexed_in_judy = true;
994 rq->not_indexed_buffer_full = false;
@@ -974,6 +998,8 @@ static void replication_sort_entry_add(struct replication_request *rq) {
998 replication_globals.unsafe.first_time_t = rq->after;
999
1000 replication_recursive_unlock();
1001 +
1002 + __atomic_add_fetch(&replication_globals.atomic.memory, (mem_after_inner_judyl - mem_before_inner_judyl) + (mem_after_outer_judyl - mem_before_outer_judyl), __ATOMIC_RELAXED);
1003 }
1004
1005 static bool replication_sort_entry_unlink_and_free_unsafe(struct replication_sort_entry *rse, Pvoid_t **inner_judy_ppptr, bool preprocessing) {
@@ -989,18 +1015,28 @@ static bool replication_sort_entry_unlink_and_free_unsafe(struct replication_sor
1015 rse->rq->indexed_in_judy = false;
1016 rse->rq->not_indexed_preprocessing = preprocessing;
1017
1018 + size_t memory_saved = 0;
1019 +
1020 // delete it from the inner judy
1021 + size_t mem_before_inner_judyl = JudyLMemUsed(**inner_judy_ppptr);
1022 JudyLDel(*inner_judy_ppptr, rse->rq->unique_id, PJE0);
1023 + size_t mem_after_inner_judyl = JudyLMemUsed(**inner_judy_ppptr);
1024 + memory_saved = mem_before_inner_judyl - mem_after_inner_judyl;
1025
1026 // if no items left, delete it from the outer judy
1027 if(**inner_judy_ppptr == NULL) {
1028 + size_t mem_before_outer_judyl = JudyLMemUsed(replication_globals.unsafe.queue.JudyL_array);
1029 JudyLDel(&replication_globals.unsafe.queue.JudyL_array, rse->rq->after, PJE0);
1030 + size_t mem_after_outer_judyl = JudyLMemUsed(replication_globals.unsafe.queue.JudyL_array);
1031 + memory_saved += mem_before_outer_judyl - mem_after_outer_judyl;
1032 inner_judy_deleted = true;
1033 }
1034
1035 // free memory
1036 replication_sort_entry_destroy(rse);
1037
1038 + __atomic_sub_fetch(&replication_globals.atomic.memory, memory_saved, __ATOMIC_RELAXED);
1039 +
1040 return inner_judy_deleted;
1041 }
1042
@@ -1426,6 +1462,7 @@ static int replication_execute_next_pending_request(void) {
1462 max_requests_ahead = 2;
1463
1464 rqs = callocz(max_requests_ahead, sizeof(struct replication_request));
1465 + __atomic_add_fetch(&replication_buffers_allocated, max_requests_ahead * sizeof(struct replication_request), __ATOMIC_RELAXED);
1466 }
1467
1468 // fill the queue
@@ -1516,6 +1553,7 @@ static void *replication_worker_thread(void *ptr) {
1553
1554 while(service_running(SERVICE_REPLICATION)) {
1555 if(unlikely(replication_execute_next_pending_request() == REQUEST_QUEUE_EMPTY)) {
1556 + sender_thread_buffer_free();
1557 worker_is_busy(WORKER_JOB_WAIT);
1558 worker_is_idle();
1559 sleep_usec(1 * USEC_PER_SEC);
@@ -1534,9 +1572,11 @@ static void replication_main_cleanup(void *ptr) {
1572 for(int i = 0; i < threads ;i++) {
1573 netdata_thread_join(*replication_globals.main_thread.threads_ptrs[i], NULL);
1574 freez(replication_globals.main_thread.threads_ptrs[i]);
1575 + __atomic_sub_fetch(&replication_buffers_allocated, sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1576 }
1577 freez(replication_globals.main_thread.threads_ptrs);
1578 replication_globals.main_thread.threads_ptrs = NULL;
1579 + __atomic_sub_fetch(&replication_buffers_allocated, threads * sizeof(netdata_thread_t *), __ATOMIC_RELAXED);
1580
1581 // custom code
1582 worker_unregister();
@@ -1553,14 +1593,16 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1593 threads = 1;
1594 }
1595
1556 - if(threads > 1) {
1596 + if(--threads) {
1597 replication_globals.main_thread.threads = threads;
1598 replication_globals.main_thread.threads_ptrs = mallocz(threads * sizeof(netdata_thread_t *));
1599 + __atomic_add_fetch(&replication_buffers_allocated, threads * sizeof(netdata_thread_t *), __ATOMIC_RELAXED);
1600
1560 - for(int i = 1; i < threads ;i++) {
1601 + for(int i = 0; i < threads ;i++) {
1602 char tag[NETDATA_THREAD_TAG_MAX + 1];
1562 - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "REPLAY[%d]", i + 1);
1603 + snprintfz(tag, NETDATA_THREAD_TAG_MAX, "REPLAY[%d]", i + 2);
1604 replication_globals.main_thread.threads_ptrs[i] = mallocz(sizeof(netdata_thread_t));
1605 + __atomic_add_fetch(&replication_buffers_allocated, sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1606 netdata_thread_create(replication_globals.main_thread.threads_ptrs[i], tag,
1607 NETDATA_THREAD_OPTION_JOINABLE, replication_worker_thread, NULL);
1608 }
@@ -1649,14 +1691,16 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1691 // the timeout also defines now frequently we will traverse all the pending requests
1692 // when the outbound buffers of all senders is full
1693 usec_t timeout;
1652 - if(slow)
1694 + if(slow) {
1695 // no work to be done, wait for a request to come in
1696 timeout = 1000 * USEC_PER_MS;
1697 + sender_thread_buffer_free();
1698 + }
1699
1700 else if(replication_globals.unsafe.pending > 0) {
1657 - if(replication_globals.unsafe.sender_resets == last_sender_resets) {
1701 + if(replication_globals.unsafe.sender_resets == last_sender_resets)
1702 timeout = 1000 * USEC_PER_MS;
1659 - }
1703 +
1704 else {
1705 // there are pending requests waiting to be executed,
1706 // but none could be executed at this time.
streaming/replication.h
+3
@@ -30,4 +30,7 @@ void replication_sender_delete_pending_requests(struct sender_state *sender);
30 void replication_add_request(struct sender_state *sender, const char *chart_id, time_t after, time_t before, bool start_streaming);
31 void replication_recalculate_buffer_used_ratio_unsafe(struct sender_state *s);
32
33 +size_t replication_allocated_memory(void);
34 +size_t replication_allocated_buffers(void);
35 +
36 #endif /* REPLICATION_H */
streaming/rrdpush.c
+13 -2
@@ -373,6 +373,7 @@ bool rrdset_push_chart_definition_now(RRDSET *st) {
373 BUFFER *wb = sender_start(host->sender);
374 rrdpush_send_chart_definition(wb, st);
375 sender_commit(host->sender, wb);
376 + sender_thread_buffer_free();
377
378 return true;
379 }
@@ -437,6 +438,8 @@ void rrdpush_send_host_labels(RRDHOST *host) {
438 buffer_sprintf(wb, "OVERWRITE %s\n", "labels");
439
440 sender_commit(host->sender, wb);
441 +
442 + sender_thread_buffer_free();
443 }
444
445 void rrdpush_claimed_id(RRDHOST *host)
@@ -454,6 +457,8 @@ void rrdpush_claimed_id(RRDHOST *host)
457
458 rrdhost_aclk_state_unlock(host);
459 sender_commit(host->sender, wb);
460 +
461 + sender_thread_buffer_free();
462 }
463
464 int connect_to_one_of_destinations(
@@ -515,6 +520,8 @@ bool destinations_init_add_one(char *entry, void *data) {
520 struct rrdpush_destinations *d = callocz(1, sizeof(struct rrdpush_destinations));
521 d->destination = string_strdupz(entry);
522
523 + __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_senders, sizeof(struct rrdpush_destinations), __ATOMIC_RELAXED);
524 +
525 DOUBLE_LINKED_LIST_APPEND_UNSAFE(t->list, d, prev, next);
526
527 t->count++;
@@ -545,6 +552,7 @@ void rrdpush_destinations_free(RRDHOST *host) {
552 DOUBLE_LINKED_LIST_REMOVE_UNSAFE(host->destinations, tmp, prev, next);
553 string_freez(tmp->destination);
554 freez(tmp);
555 + __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_senders, sizeof(struct rrdpush_destinations), __ATOMIC_RELAXED);
556 }
557
558 host->destinations = NULL;
@@ -635,6 +643,9 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *url) {
643 rpt->capabilities = STREAM_CAP_INVALID;
644 rpt->hops = 1;
645
646 + __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_receivers, sizeof(*rpt), __ATOMIC_RELAXED);
647 + __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
648 +
649 rpt->system_info = callocz(1, sizeof(struct rrdhost_system_info));
650 rpt->system_info->hops = rpt->hops;
651
@@ -1069,7 +1080,7 @@ static void stream_capabilities_to_string(BUFFER *wb, STREAM_CAPABILITIES caps)
1080 }
1081
1082 void log_receiver_capabilities(struct receiver_state *rpt) {
1072 - BUFFER *wb = buffer_create(100);
1083 + BUFFER *wb = buffer_create(100, NULL);
1084 stream_capabilities_to_string(wb, rpt->capabilities);
1085
1086 info("STREAM %s [receive from [%s]:%s]: established link with negotiated capabilities: %s",
@@ -1079,7 +1090,7 @@ void log_receiver_capabilities(struct receiver_state *rpt) {
1090 }
1091
1092 void log_sender_capabilities(struct sender_state *s) {
1082 - BUFFER *wb = buffer_create(100);
1093 + BUFFER *wb = buffer_create(100, NULL);
1094 stream_capabilities_to_string(wb, s->capabilities);
1095
1096 info("STREAM %s [send to %s]: established link with negotiated capabilities: %s",
streaming/rrdpush.h
+9 -4
@@ -10,7 +10,7 @@
10
11 #define CONNECTED_TO_SIZE 100
12 #define CBUFFER_INITIAL_SIZE (16 * 1024)
13 -#define THREAD_BUFFER_INITIAL_SIZE (CBUFFER_INITIAL_SIZE * 4)
13 +#define THREAD_BUFFER_INITIAL_SIZE (CBUFFER_INITIAL_SIZE / 2)
14
15 // ----------------------------------------------------------------------------
16 // obsolete versions - do not use anymore
@@ -131,8 +131,8 @@ struct decompressor_state {
131 // Metric transmission: collector threads asynchronously fill the buffer, sender thread uses it.
132
133 typedef enum {
134 - SENDER_FLAG_OVERFLOW = (1 << 0), // The buffer has been overflown
135 - SENDER_FLAG_COMPRESSION = (1 << 1), // The stream needs to have and has compression
134 + SENDER_FLAG_OVERFLOW = (1 << 0), // The buffer has been overflown
135 + SENDER_FLAG_COMPRESSION = (1 << 1), // The stream needs to have and has compression
136 } SENDER_FLAGS;
137
138 struct sender_state {
@@ -189,9 +189,13 @@ struct sender_state {
189 struct {
190 size_t buffer_used_percentage; // the current utilization of the sending buffer
191 usec_t last_flush_time_ut; // the last time the sender flushed the sending buffer in USEC
192 + time_t last_buffer_recreate_s; // true when the sender buffer should be re-created
193 } atomic;
194 };
195
196 +#define rrdpush_sender_last_buffer_recreate_get(sender) __atomic_load_n(&(sender)->atomic.last_buffer_recreate_s, __ATOMIC_RELAXED)
197 +#define rrdpush_sender_last_buffer_recreate_set(sender, value) __atomic_store_n(&(sender)->atomic.last_buffer_recreate_s, value, __ATOMIC_RELAXED)
198 +
199 #define rrdpush_sender_replication_buffer_full_set(sender, value) __atomic_store_n(&((sender)->replication.atomic.reached_max), value, __ATOMIC_SEQ_CST)
200 #define rrdpush_sender_replication_buffer_full_get(sender) __atomic_load_n(&((sender)->replication.atomic.reached_max), __ATOMIC_SEQ_CST)
201
@@ -296,7 +300,6 @@ void rrdpush_destinations_free(RRDHOST *host);
300
301 BUFFER *sender_start(struct sender_state *s);
302 void sender_commit(struct sender_state *s, BUFFER *wb);
299 -void sender_cancel(struct sender_state *s);
303 int rrdpush_init();
304 bool rrdpush_receiver_needs_dbengine();
305 int configured_as_parent();
@@ -339,6 +342,8 @@ int32_t stream_capabilities_to_vn(uint32_t caps);
342 void receiver_state_free(struct receiver_state *rpt);
343 bool stop_streaming_receiver(RRDHOST *host, const char *reason);
344
345 +void sender_thread_buffer_free(void);
346 +
347 #include "replication.h"
348
349 #endif //NETDATA_RRDPUSH_H
streaming/sender.c
+65 -39
@@ -36,29 +36,29 @@ extern char *netdata_ssl_ca_file;
36
37 static __thread BUFFER *sender_thread_buffer = NULL;
38 static __thread bool sender_thread_buffer_used = false;
39 -static __thread bool sender_thread_buffer_recreate = false;
39 +static __thread time_t sender_thread_buffer_last_reset_s = 0;
40
41 void sender_thread_buffer_free(void) {
42 buffer_free(sender_thread_buffer);
43 sender_thread_buffer = NULL;
44 + sender_thread_buffer_used = false;
45 }
46
47 // Collector thread starting a transmission
47 -BUFFER *sender_start(struct sender_state *s __maybe_unused) {
48 +BUFFER *sender_start(struct sender_state *s) {
49 if(unlikely(sender_thread_buffer_used))
50 fatal("STREAMING: thread buffer is used multiple times concurrently.");
51
51 - if(unlikely(sender_thread_buffer_recreate)) {
52 - sender_thread_buffer_recreate = false;
53 - if(sender_thread_buffer && sender_thread_buffer->size > THREAD_BUFFER_INITIAL_SIZE) {
52 + if(unlikely(rrdpush_sender_last_buffer_recreate_get(s) > sender_thread_buffer_last_reset_s)) {
53 + if(unlikely(sender_thread_buffer && sender_thread_buffer->size > THREAD_BUFFER_INITIAL_SIZE)) {
54 buffer_free(sender_thread_buffer);
55 sender_thread_buffer = NULL;
56 }
57 }
58
59 - if(!sender_thread_buffer) {
60 - sender_thread_buffer = buffer_create(THREAD_BUFFER_INITIAL_SIZE);
61 - sender_thread_buffer_recreate = false;
59 + if(unlikely(!sender_thread_buffer)) {
60 + sender_thread_buffer = buffer_create(THREAD_BUFFER_INITIAL_SIZE, &netdata_buffers_statistics.buffers_streaming);
61 + sender_thread_buffer_last_reset_s = rrdpush_sender_last_buffer_recreate_get(s);
62 }
63
64 sender_thread_buffer_used = true;
@@ -66,10 +66,6 @@ BUFFER *sender_start(struct sender_state *s __maybe_unused) {
66 return sender_thread_buffer;
67 }
68
69 -void sender_cancel(struct sender_state *s __maybe_unused) {
70 - sender_thread_buffer_used = false;
71 -}
72 -
69 static inline void rrdpush_sender_thread_close_socket(RRDHOST *host);
70
71 #ifdef ENABLE_COMPRESSION
@@ -108,11 +104,11 @@ void sender_commit(struct sender_state *s, BUFFER *wb) {
104
105 netdata_mutex_lock(&s->mutex);
106
111 - if(unlikely(s->host->sender->buffer->max_size < (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE)) {
107 + if(unlikely(s->buffer->max_size < (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE)) {
108 info("STREAM %s [send to %s]: max buffer size of %zu is too small for a data message of size %zu. Increasing the max buffer size to %d times the max data message size.",
113 - rrdhost_hostname(s->host), s->connected_to, s->host->sender->buffer->max_size, buffer_strlen(wb) + 1, SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE);
109 + rrdhost_hostname(s->host), s->connected_to, s->buffer->max_size, buffer_strlen(wb) + 1, SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE);
110
115 - s->host->sender->buffer->max_size = (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE;
111 + s->buffer->max_size = (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE;
112 }
113
114 #ifdef ENABLE_COMPRESSION
@@ -159,17 +155,17 @@ void sender_commit(struct sender_state *s, BUFFER *wb) {
155 }
156 }
157
162 - if(cbuffer_add_unsafe(s->host->sender->buffer, dst, dst_len))
158 + if(cbuffer_add_unsafe(s->buffer, dst, dst_len))
159 s->flags |= SENDER_FLAG_OVERFLOW;
160
161 src = src + size_to_compress;
162 src_len -= size_to_compress;
163 }
164 }
169 - else if(cbuffer_add_unsafe(s->host->sender->buffer, src, src_len))
165 + else if(cbuffer_add_unsafe(s->buffer, src, src_len))
166 s->flags |= SENDER_FLAG_OVERFLOW;
167 #else
172 - if(cbuffer_add_unsafe(s->host->sender->buffer, src, src_len))
168 + if(cbuffer_add_unsafe(s->buffer, src, src_len))
169 s->flags |= SENDER_FLAG_OVERFLOW;
170 #endif
171
@@ -195,6 +191,7 @@ void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, const RRDVAR_ACQU
191 BUFFER *wb = sender_start(host->sender);
192 rrdpush_sender_add_host_variable_to_buffer(wb, rva);
193 sender_commit(host->sender, wb);
194 + sender_thread_buffer_free();
195 }
196 }
197
@@ -223,6 +220,7 @@ static void rrdpush_sender_thread_send_custom_host_variables(RRDHOST *host) {
220 int ret = rrdvar_walkthrough_read(host->rrdvars, rrdpush_sender_thread_custom_host_variables_callback, &tmp);
221 (void)ret;
222 sender_commit(host->sender, wb);
223 + sender_thread_buffer_free();
224
225 debug(D_STREAM, "RRDVAR sent %d VARIABLES", ret);
226 }
@@ -248,6 +246,30 @@ static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) {
246 rrdhost_sender_replicating_charts_zero(host);
247 }
248
249 +static void rrdpush_sender_cbuffer_recreate_timed(struct sender_state *s, time_t now_s, bool have_mutex, bool force) {
250 + static __thread time_t last_reset_time_s = 0;
251 +
252 + if(!force && now_s - last_reset_time_s < 300)
253 + return;
254 +
255 + if(!have_mutex)
256 + netdata_mutex_lock(&s->mutex);
257 +
258 + rrdpush_sender_last_buffer_recreate_set(s, now_s);
259 + last_reset_time_s = now_s;
260 +
261 + if(s->buffer && s->buffer->size > CBUFFER_INITIAL_SIZE) {
262 + size_t max = s->buffer->max_size;
263 + cbuffer_free(s->buffer);
264 + s->buffer = cbuffer_new(CBUFFER_INITIAL_SIZE, max, &netdata_buffers_statistics.cbuffers_streaming);
265 + }
266 +
267 + sender_thread_buffer_free();
268 +
269 + if(!have_mutex)
270 + netdata_mutex_unlock(&s->mutex);
271 +}
272 +
273 static void rrdpush_sender_cbuffer_flush(RRDHOST *host) {
274 rrdpush_sender_set_flush_time(host->sender);
275
@@ -255,6 +277,7 @@ static void rrdpush_sender_cbuffer_flush(RRDHOST *host) {
277
278 // flush the output buffer from any data it may have
279 cbuffer_flush(host->sender->buffer);
280 + rrdpush_sender_cbuffer_recreate_timed(host->sender, now_monotonic_sec(), true, true);
281 replication_recalculate_buffer_used_ratio_unsafe(host->sender);
282
283 netdata_mutex_unlock(&host->sender->mutex);
@@ -781,8 +804,8 @@ static ssize_t attempt_to_send(struct sender_state *s) {
804 debug(D_STREAM, "STREAM: Sending data. Buffer r=%zu w=%zu s=%zu, next chunk=%zu", cb->read, cb->write, cb->size, outstanding);
805
806 #ifdef ENABLE_HTTPS
784 - SSL *conn = s->host->sender->ssl.conn ;
785 - if(conn && s->host->sender->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE)
807 + SSL *conn = s->ssl.conn ;
808 + if(conn && s->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE)
809 ret = netdata_ssl_write(conn, chunk, outstanding);
810 else
811 ret = send(s->rrdpush_sender_socket, chunk, outstanding, MSG_DONTWAIT);
@@ -817,9 +840,9 @@ static ssize_t attempt_read(struct sender_state *s) {
840 ssize_t ret = 0;
841
842 #ifdef ENABLE_HTTPS
820 - if (s->host->sender->ssl.conn && s->host->sender->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE) {
843 + if (s->ssl.conn && s->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE) {
844 size_t desired = sizeof(s->read_buffer) - s->read_len - 1;
822 - ret = netdata_ssl_read(s->host->sender->ssl.conn, s->read_buffer, desired);
845 + ret = netdata_ssl_read(s->ssl.conn, s->read_buffer, desired);
846 if (ret > 0 ) {
847 s->read_len += (int)ret;
848 return ret;
@@ -878,6 +901,7 @@ void stream_execute_function_callback(BUFFER *func_wb, int code, void *data) {
901 pluginsd_function_result_end_to_buffer(wb);
902
903 sender_commit(s, wb);
904 + sender_thread_buffer_free();
905
906 internal_error(true, "STREAM %s [send to %s] FUNCTION transaction %s sending back response (%zu bytes, %llu usec).",
907 rrdhost_hostname(s->host), s->connected_to,
@@ -932,7 +956,7 @@ void execute_commands(struct sender_state *s) {
956 tmp->received_ut = now_realtime_usec();
957 tmp->sender = s;
958 tmp->transaction = string_strdupz(transaction);
935 - BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX + 1);
959 + BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX + 1, &netdata_buffers_statistics.buffers_functions);
960
961 int code = rrd_call_function_async(s->host, wb, timeout, function, stream_execute_function_callback, tmp);
962 if(code != HTTP_RESP_OK) {
@@ -1223,11 +1247,18 @@ void *rrdpush_sender_thread(void *ptr) {
1247
1248 netdata_thread_cleanup_push(rrdpush_sender_thread_cleanup_callback, thread_data);
1249
1250 + size_t iterations = 0;
1251 + time_t now_s = now_monotonic_sec();
1252 while(!rrdhost_sender_should_exit(s)) {
1253 + iterations++;
1254
1255 // The connection attempt blocks (after which we use the socket in nonblocking)
1256 if(unlikely(s->rrdpush_sender_socket == -1)) {
1257 worker_is_busy(WORKER_SENDER_JOB_CONNECT);
1258 +
1259 + now_s = now_monotonic_sec();
1260 + rrdpush_sender_cbuffer_recreate_timed(s, now_s, false, true);
1261 +
1262 rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
1263 s->flags &= ~SENDER_FLAG_OVERFLOW;
1264 s->read_len = 0;
@@ -1240,7 +1271,7 @@ void *rrdpush_sender_thread(void *ptr) {
1271 if(rrdhost_sender_should_exit(s))
1272 break;
1273
1243 - s->last_traffic_seen_t = now_monotonic_sec();
1274 + now_s = s->last_traffic_seen_t = now_monotonic_sec();
1275 rrdpush_claimed_id(s->host);
1276 rrdpush_send_host_labels(s->host);
1277
@@ -1250,8 +1281,11 @@ void *rrdpush_sender_thread(void *ptr) {
1281 continue;
1282 }
1283
1284 + if(iterations % 1000 == 0)
1285 + now_s = now_monotonic_sec();
1286 +
1287 // If the TCP window never opened then something is wrong, restart connection
1254 - if(unlikely(now_monotonic_sec() - s->last_traffic_seen_t > s->timeout &&
1288 + if(unlikely(now_s - s->last_traffic_seen_t > s->timeout &&
1289 !rrdpush_sender_pending_replication_requests(s) &&
1290 !rrdpush_sender_replicating_charts(s)
1291 )) {
@@ -1262,22 +1296,13 @@ void *rrdpush_sender_thread(void *ptr) {
1296 }
1297
1298 netdata_mutex_lock(&s->mutex);
1265 - size_t outstanding = cbuffer_next_unsafe(s->host->sender->buffer, NULL);
1266 - size_t available = cbuffer_available_size_unsafe(s->host->sender->buffer);
1267 - if(unlikely(!outstanding && s->host->sender->buffer->size > CBUFFER_INITIAL_SIZE)) {
1268 - static __thread time_t last_reset_time_t = 0;
1269 - time_t now_t = now_monotonic_sec();
1270 - if(now_t - last_reset_time_t > 600) {
1271 - last_reset_time_t = now_t;
1272 - size_t max = s->host->sender->buffer->max_size;
1273 - cbuffer_free(s->host->sender->buffer);
1274 - s->host->sender->buffer = cbuffer_new(CBUFFER_INITIAL_SIZE, max);
1275 - sender_thread_buffer_recreate = true;
1276 - }
1277 - }
1299 + size_t outstanding = cbuffer_next_unsafe(s->buffer, NULL);
1300 + size_t available = cbuffer_available_size_unsafe(s->buffer);
1301 + if (unlikely(!outstanding))
1302 + rrdpush_sender_cbuffer_recreate_timed(s, now_s, true, false);
1303 netdata_mutex_unlock(&s->mutex);
1304
1280 - worker_set_metric(WORKER_SENDER_JOB_BUFFER_RATIO, (NETDATA_DOUBLE)(s->host->sender->buffer->max_size - available) * 100.0 / (NETDATA_DOUBLE)s->host->sender->buffer->max_size);
1305 + worker_set_metric(WORKER_SENDER_JOB_BUFFER_RATIO, (NETDATA_DOUBLE)(s->buffer->max_size - available) * 100.0 / (NETDATA_DOUBLE)s->buffer->max_size);
1306
1307 if(outstanding)
1308 s->send_attempts++;
@@ -1329,6 +1354,7 @@ void *rrdpush_sender_thread(void *ptr) {
1354 if (poll_rc == 0 || ((poll_rc == -1) && (errno == EAGAIN || errno == EINTR))) {
1355 netdata_thread_testcancel();
1356 debug(D_STREAM, "Spurious wakeup");
1357 + now_s = now_monotonic_sec();
1358 continue;
1359 }
1360
web/api/badges/web_buffer_svg.c
+1 -1
@@ -913,7 +913,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
913 if(!strcmp(name, "chart")) chart = value;
914 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
915 if(!dimensions)
916 - dimensions = buffer_create(100);
916 + dimensions = buffer_create(100, &netdata_buffers_statistics.buffers_api);
917
918 buffer_strcat(dimensions, "|");
919 buffer_strcat(dimensions, value);
web/api/health/health_cmdapi.c
+1 -1
@@ -196,7 +196,7 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
196 w->response.data = wb;
197 buffer_no_cacheable(w->response.data);
198 if (ret == HTTP_RESP_OK && config_changed) {
199 - BUFFER *jsonb = buffer_create(200);
199 + BUFFER *jsonb = buffer_create(200, &netdata_buffers_statistics.buffers_health);
200 health_silencers2json(jsonb);
201 health_silencers2file(jsonb);
202 buffer_free(jsonb);
web/api/queries/query.c
+4 -4
@@ -1550,7 +1550,7 @@ void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s
1550 if(unlikely(tier >= storage_tiers)) return;
1551 if(storage_tiers_backfill[tier] == RRD_BACKFILL_NONE) return;
1552
1553 - struct rrddim_tier *t = rd->tiers[tier];
1553 + struct rrddim_tier *t = &rd->tiers[tier];
1554 if(unlikely(!t)) return;
1555
1556 time_t latest_time_s = t->query_ops->latest_time_s(t->db_metric_handle);
@@ -1567,14 +1567,14 @@ void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s
1567
1568 // for each lower tier
1569 for(int read_tier = (int)tier - 1; read_tier >= 0 ; read_tier--){
1570 - time_t smaller_tier_first_time = rd->tiers[read_tier]->query_ops->oldest_time_s(rd->tiers[read_tier]->db_metric_handle);
1571 - time_t smaller_tier_last_time = rd->tiers[read_tier]->query_ops->latest_time_s(rd->tiers[read_tier]->db_metric_handle);
1570 + time_t smaller_tier_first_time = rd->tiers[read_tier].query_ops->oldest_time_s(rd->tiers[read_tier].db_metric_handle);
1571 + time_t smaller_tier_last_time = rd->tiers[read_tier].query_ops->latest_time_s(rd->tiers[read_tier].db_metric_handle);
1572 if(smaller_tier_last_time <= latest_time_s) continue; // it is as bad as we are
1573
1574 long after_wanted = (latest_time_s < smaller_tier_first_time) ? smaller_tier_first_time : latest_time_s;
1575 long before_wanted = smaller_tier_last_time;
1576
1577 - struct rrddim_tier *tmp = rd->tiers[read_tier];
1577 + struct rrddim_tier *tmp = &rd->tiers[read_tier];
1578 tmp->query_ops->init(tmp->db_metric_handle, &handle, after_wanted, before_wanted, STORAGE_PRIORITY_HIGH);
1579
1580 size_t points_read = 0;
web/api/web_api_v1.c
+4 -4
@@ -312,7 +312,7 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien
312 else if (!strcmp("CLEAR", value)) status = RRDCALC_STATUS_CLEAR;
313 }
314 else if(!strcmp(name, "context") || !strcmp(name, "ctx")) {
315 - if(!contexts) contexts = buffer_create(255);
315 + if(!contexts) contexts = buffer_create(255, &netdata_buffers_statistics.buffers_api);
316 buffer_strcat(contexts, "|");
317 buffer_strcat(contexts, value);
318 }
@@ -460,7 +460,7 @@ static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w
460 else if(!strcmp(name, "chart_label_key")) chart_label_key = value;
461 else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
462 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
463 - if(!dimensions) dimensions = buffer_create(100);
463 + if(!dimensions) dimensions = buffer_create(100, &netdata_buffers_statistics.buffers_api);
464 buffer_strcat(dimensions, "|");
465 buffer_strcat(dimensions, value);
466 }
@@ -521,7 +521,7 @@ static int web_client_api_request_v1_contexts(RRDHOST *host, struct web_client *
521 else if(!strcmp(name, "chart_label_key")) chart_label_key = value;
522 else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
523 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
524 - if(!dimensions) dimensions = buffer_create(100);
524 + if(!dimensions) dimensions = buffer_create(100, &netdata_buffers_statistics.buffers_api);
525 buffer_strcat(dimensions, "|");
526 buffer_strcat(dimensions, value);
527 }
@@ -626,7 +626,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
626 else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
627 else if(!strcmp(name, "chart")) chart = value;
628 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
629 - if(!dimensions) dimensions = buffer_create(100);
629 + if(!dimensions) dimensions = buffer_create(100, &netdata_buffers_statistics.buffers_api);
630 buffer_strcat(dimensions, "|");
631 buffer_strcat(dimensions, value);
632 }
web/server/web_client_cache.c
+5 -3
@@ -65,13 +65,15 @@ static void web_client_free(struct web_client *w) {
65 }
66 #endif
67 freez(w);
68 + __atomic_sub_fetch(&netdata_buffers_statistics.buffers_web, sizeof(struct web_client), __ATOMIC_RELAXED);
69 }
70
71 static struct web_client *web_client_alloc(void) {
72 struct web_client *w = callocz(1, sizeof(struct web_client));
72 - w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
73 - w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
74 - w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
73 + __atomic_add_fetch(&netdata_buffers_statistics.buffers_web, sizeof(struct web_client), __ATOMIC_RELAXED);
74 + w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_web);
75 + w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE, &netdata_buffers_statistics.buffers_web);
76 + w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE, &netdata_buffers_statistics.buffers_web);
77 return w;
78 }
79
web/server/web_server.c
+1 -1
@@ -37,7 +37,7 @@ LISTEN_SOCKETS api_sockets = {
37 };
38
39 void debug_sockets() {
40 - BUFFER *wb = buffer_create(256 * sizeof(char));
40 + BUFFER *wb = buffer_create(256 * sizeof(char), NULL);
41 int i;
42
43 for(i = 0 ; i < (int)api_sockets.opened ; i++) {