diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2022-05-03 00:31:19 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-03 00:31:19 +0300 |
commit | 87c0cc2d6049c46f38b9c866668a0a24a3e962c0 (patch) | |
tree | 066c18bc90894e89ce46dc0b2e104c61018e830c /web | |
parent | 47fa3d708902fb001b2e88e4145d2a451549cd8e (diff) |
One way allocator to double the speed of parallel context queries (#12787)
* one way allocator to speed up context queries
* fixed a bug while expanding memory pages
* reworked for clarity and finally fixed the bug of allocating memory beyond the page size
* further optimize allocation step to minimize the number of allocations made
* implement strdup with memcpy instead of strcpy
* added documentation
* prevent an uninitialized use of owa
* added callocz() interface
* integrate onewayalloc everywhere - apart sql queries
* one way allocator is now used in context queries using archived charts in sql
* align on the size of pointers
* forgotten freez()
* removed not needed memcpys
* give unique names to global variables to avoid conflicts with system definitions
Diffstat (limited to 'web')
-rw-r--r-- | web/api/formatters/rrd2json.c | 75 | ||||
-rw-r--r-- | web/api/formatters/rrd2json.h | 9 | ||||
-rw-r--r-- | web/api/queries/query.c | 25 | ||||
-rw-r--r-- | web/api/queries/rrdr.c | 24 | ||||
-rw-r--r-- | web/api/queries/rrdr.h | 5 | ||||
-rw-r--r-- | web/api/web_api_v1.c | 18 |
6 files changed, 85 insertions, 71 deletions
diff --git a/web/api/formatters/rrd2json.c b/web/api/formatters/rrd2json.c index 1a8b07c7c8..9ac54f7589 100644 --- a/web/api/formatters/rrd2json.c +++ b/web/api/formatters/rrd2json.c @@ -2,27 +2,27 @@ #include "web/api/web_api_v1.h" -static inline void free_single_rrdrim(RRDDIM *temp_rd, int archive_mode) +static inline void free_single_rrdrim(ONEWAYALLOC *owa, RRDDIM *temp_rd, int archive_mode) { if (unlikely(!temp_rd)) return; - freez((char *)temp_rd->id); - freez((char *)temp_rd->name); + onewayalloc_freez(owa, (char *)temp_rd->id); if (unlikely(archive_mode)) { temp_rd->rrdset->counter--; if (!temp_rd->rrdset->counter) { - freez((char *)temp_rd->rrdset->name); - freez(temp_rd->rrdset->context); - freez(temp_rd->rrdset); + onewayalloc_freez(owa, (char *)temp_rd->rrdset->name); + onewayalloc_freez(owa, temp_rd->rrdset->context); + onewayalloc_freez(owa, temp_rd->rrdset); } } - freez(temp_rd->state); - freez(temp_rd); + + onewayalloc_freez(owa, temp_rd->state); + onewayalloc_freez(owa, temp_rd); } -static inline void free_rrddim_list(RRDDIM *temp_rd, int archive_mode) +static inline void free_rrddim_list(ONEWAYALLOC *owa, RRDDIM *temp_rd, int archive_mode) { if (unlikely(!temp_rd)) return; @@ -30,22 +30,22 @@ static inline void free_rrddim_list(RRDDIM *temp_rd, int archive_mode) RRDDIM *t; while (temp_rd) { t = temp_rd->next; - free_single_rrdrim(temp_rd, archive_mode); + free_single_rrdrim(owa, temp_rd, archive_mode); temp_rd = t; } } -void free_context_param_list(struct context_param **param_list) +void free_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list) { if (unlikely(!param_list || !*param_list)) return; - free_rrddim_list(((*param_list)->rd), (*param_list)->flags & CONTEXT_FLAGS_ARCHIVE); - freez((*param_list)); + free_rrddim_list(owa, ((*param_list)->rd), (*param_list)->flags & CONTEXT_FLAGS_ARCHIVE); + onewayalloc_freez(owa, (*param_list)); *param_list = NULL; } -void rebuild_context_param_list(struct context_param *context_param_list, time_t after_requested) +void rebuild_context_param_list(ONEWAYALLOC *owa, struct context_param *context_param_list, time_t after_requested) { RRDDIM *temp_rd = context_param_list->rd; RRDDIM *new_rd_list = NULL, *t; @@ -59,19 +59,19 @@ void rebuild_context_param_list(struct context_param *context_param_list, time_t temp_rd->next = new_rd_list; new_rd_list = temp_rd; } else - free_single_rrdrim(temp_rd, is_archived); + free_single_rrdrim(owa, temp_rd, is_archived); temp_rd = t; } context_param_list->rd = new_rd_list; }; -void build_context_param_list(struct context_param **param_list, RRDSET *st) +void build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list, RRDSET *st) { if (unlikely(!param_list || !st)) return; if (unlikely(!(*param_list))) { - *param_list = mallocz(sizeof(struct context_param)); + *param_list = onewayalloc_mallocz(owa, sizeof(struct context_param)); (*param_list)->first_entry_t = LONG_MAX; (*param_list)->last_entry_t = 0; (*param_list)->flags = CONTEXT_FLAGS_CONTEXT; @@ -86,14 +86,10 @@ void build_context_param_list(struct context_param **param_list, RRDSET *st) (*param_list)->last_entry_t = MAX((*param_list)->last_entry_t, rrdset_last_entry_t_nolock(st)); rrddim_foreach_read(rd1, st) { - RRDDIM *rd = mallocz(rd1->memsize); - memcpy(rd, rd1, rd1->memsize); - rd->id = strdupz(rd1->id); - rd->name = strdupz(rd1->name); - rd->state = mallocz(sizeof(*rd->state)); - memcpy(rd->state, rd1->state, sizeof(*rd->state)); - memcpy(&rd->state->collect_ops, &rd1->state->collect_ops, sizeof(struct rrddim_collect_ops)); - memcpy(&rd->state->query_ops, &rd1->state->query_ops, sizeof(struct rrddim_query_ops)); + RRDDIM *rd = onewayalloc_memdupz(owa, rd1, rd1->memsize); + rd->id = onewayalloc_strdupz(owa, rd1->id); + rd->name = onewayalloc_strdupz(owa, rd1->name); + rd->state = onewayalloc_memdupz(owa, rd1->state, sizeof(*rd->state)); rd->next = (*param_list)->rd; (*param_list)->rd = rd; } @@ -169,22 +165,27 @@ int rrdset2value_api_v1( , int *value_is_null , int timeout ) { + int ret = HTTP_RESP_INTERNAL_SERVER_ERROR; + + ONEWAYALLOC *owa = onewayalloc_create(0); - RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions, NULL, timeout); + RRDR *r = rrd2rrdr(owa, st, points, after, before, group_method, group_time, options, dimensions, NULL, timeout); if(!r) { if(value_is_null) *value_is_null = 1; - return HTTP_RESP_INTERNAL_SERVER_ERROR; + ret = HTTP_RESP_INTERNAL_SERVER_ERROR; + goto cleanup; } if(rrdr_rows(r) == 0) { - rrdr_free(r); + rrdr_free(owa, r); if(db_after) *db_after = 0; if(db_before) *db_before = 0; if(value_is_null) *value_is_null = 1; - return HTTP_RESP_BAD_REQUEST; + ret = HTTP_RESP_BAD_REQUEST; + goto cleanup; } if(wb) { @@ -199,13 +200,17 @@ int rrdset2value_api_v1( long i = (!(options & RRDR_OPTION_REVERSED))?rrdr_rows(r) - 1:0; *n = rrdr2value(r, i, options, value_is_null, NULL); + ret = HTTP_RESP_OK; - rrdr_free(r); - return HTTP_RESP_OK; +cleanup: + if(r) rrdr_free(owa, r); + onewayalloc_destroy(owa); + return ret; } int rrdset2anything_api_v1( - RRDSET *st + ONEWAYALLOC *owa + , RRDSET *st , BUFFER *wb , BUFFER *dimensions , uint32_t format @@ -225,14 +230,14 @@ int rrdset2anything_api_v1( if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) st->last_accessed_time = now_realtime_sec(); - RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL, context_param_list, timeout); + RRDR *r = rrd2rrdr(owa, st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL, context_param_list, timeout); if(!r) { buffer_strcat(wb, "Cannot generate output with these parameters on this chart."); return HTTP_RESP_INTERNAL_SERVER_ERROR; } if (r->result_options & RRDR_RESULT_OPTION_CANCEL) { - rrdr_free(r); + rrdr_free(owa, r); return HTTP_RESP_BACKEND_FETCH_FAILED; } @@ -411,6 +416,6 @@ int rrdset2anything_api_v1( break; } - rrdr_free(r); + rrdr_free(owa, r); return HTTP_RESP_OK; } diff --git a/web/api/formatters/rrd2json.h b/web/api/formatters/rrd2json.h index af809c54f9..a3fe50cbbb 100644 --- a/web/api/formatters/rrd2json.h +++ b/web/api/formatters/rrd2json.h @@ -54,7 +54,8 @@ extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb); extern void rrdr_buffer_print_format(BUFFER *wb, uint32_t format); extern int rrdset2anything_api_v1( - RRDSET *st + ONEWAYALLOC *owa + , RRDSET *st , BUFFER *wb , BUFFER *dimensions , uint32_t format @@ -88,8 +89,8 @@ extern int rrdset2value_api_v1( , int timeout ); -extern void build_context_param_list(struct context_param **param_list, RRDSET *st); -extern void rebuild_context_param_list(struct context_param *context_param_list, time_t after_requested); -extern void free_context_param_list(struct context_param **param_list); +extern void build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list, RRDSET *st); +extern void rebuild_context_param_list(ONEWAYALLOC *owa, struct context_param *context_param_list, time_t after_requested); +extern void free_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list); #endif /* NETDATA_RRD2JSON_H */ diff --git a/web/api/queries/query.c b/web/api/queries/query.c index c55a970609..9308d10bf5 100644 --- a/web/api/queries/query.c +++ b/web/api/queries/query.c @@ -831,7 +831,8 @@ static int rrdr_convert_before_after_to_absolute( } static RRDR *rrd2rrdr_fixedstep( - RRDSET *st + ONEWAYALLOC *owa + , RRDSET *st , long points_requested , long long after_requested , long long before_requested @@ -855,7 +856,7 @@ static RRDR *rrd2rrdr_fixedstep( RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL; if(duration <= 0 || available_points <= 0) - return rrdr_create(st, 1, context_param_list); + return rrdr_create(owa, st, 1, context_param_list); // check the number of wanted points in the result if(unlikely(points_requested < 0)) points_requested = -points_requested; @@ -1013,7 +1014,7 @@ static RRDR *rrd2rrdr_fixedstep( // initialize our result set // this also locks the chart for us - RRDR *r = rrdr_create(st, points_wanted, context_param_list); + RRDR *r = rrdr_create(owa, st, points_wanted, context_param_list); if(unlikely(!r)) { #ifdef NETDATA_INTERNAL_CHECKS error("INTERNAL CHECK: Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted); @@ -1216,7 +1217,8 @@ static RRDR *rrd2rrdr_fixedstep( #ifdef ENABLE_DBENGINE static RRDR *rrd2rrdr_variablestep( - RRDSET *st + ONEWAYALLOC *owa + , RRDSET *st , long points_requested , long long after_requested , long long before_requested @@ -1242,7 +1244,7 @@ static RRDR *rrd2rrdr_variablestep( if(duration <= 0 || available_points <= 0) { freez(region_info_array); - return rrdr_create(st, 1, context_param_list); + return rrdr_create(owa, st, 1, context_param_list); } // check the number of wanted points in the result @@ -1401,7 +1403,7 @@ static RRDR *rrd2rrdr_variablestep( // initialize our result set // this also locks the chart for us - RRDR *r = rrdr_create(st, points_wanted, context_param_list); + RRDR *r = rrdr_create(owa, st, points_wanted, context_param_list); if(unlikely(!r)) { #ifdef NETDATA_INTERNAL_CHECKS error("INTERNAL CHECK: Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted); @@ -1608,7 +1610,8 @@ static RRDR *rrd2rrdr_variablestep( #endif //#ifdef ENABLE_DBENGINE RRDR *rrd2rrdr( - RRDSET *st + ONEWAYALLOC *owa + , RRDSET *st , long points_requested , long long after_requested , long long before_requested @@ -1644,7 +1647,7 @@ RRDR *rrd2rrdr( first_entry_t = after_requested; if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) { - rebuild_context_param_list(context_param_list, after_requested); + rebuild_context_param_list(owa, context_param_list, after_requested); st = context_param_list->rd ? context_param_list->rd->rrdset : NULL; if (unlikely(!st)) return NULL; @@ -1669,7 +1672,7 @@ RRDR *rrd2rrdr( } freez(region_info_array); } - return rrd2rrdr_fixedstep(st, points_requested, after_requested, before_requested, group_method, + return rrd2rrdr_fixedstep(owa, st, points_requested, after_requested, before_requested, group_method, resampling_time_requested, options, dimensions, rrd_update_every, first_entry_t, last_entry_t, absolute_period_requested, context_param_list, timeout); } else { @@ -1680,13 +1683,13 @@ RRDR *rrd2rrdr( rrd_update_every, first_entry_t, last_entry_t, options); } - return rrd2rrdr_variablestep(st, points_requested, after_requested, before_requested, group_method, + return rrd2rrdr_variablestep(owa, st, points_requested, after_requested, before_requested, group_method, resampling_time_requested, options, dimensions, rrd_update_every, first_entry_t, last_entry_t, absolute_period_requested, region_info_array, context_param_list, timeout); } } #endif - return rrd2rrdr_fixedstep(st, points_requested, after_requested, before_requested, group_method, + return rrd2rrdr_fixedstep(owa, st, points_requested, after_requested, before_requested, group_method, resampling_time_requested, options, dimensions, rrd_update_every, first_entry_t, last_entry_t, absolute_period_requested, context_param_list, timeout); } diff --git a/web/api/queries/rrdr.c b/web/api/queries/rrdr.c index b64868222d..03b71db558 100644 --- a/web/api/queries/rrdr.c +++ b/web/api/queries/rrdr.c @@ -83,7 +83,7 @@ inline static void rrdr_unlock_rrdset(RRDR *r) { } } -inline void rrdr_free(RRDR *r) +inline void rrdr_free(ONEWAYALLOC *owa, RRDR *r) { if(unlikely(!r)) { error("NULL value given!"); @@ -91,21 +91,21 @@ inline void rrdr_free(RRDR *r) } rrdr_unlock_rrdset(r); - freez(r->t); - freez(r->v); - freez(r->o); - freez(r->od); - freez(r); + onewayalloc_freez(owa, r->t); + onewayalloc_freez(owa, r->v); + onewayalloc_freez(owa, r->o); + onewayalloc_freez(owa, r->od); + onewayalloc_freez(owa, r); } -RRDR *rrdr_create(struct rrdset *st, long n, struct context_param *context_param_list) +RRDR *rrdr_create(ONEWAYALLOC *owa, struct rrdset *st, long n, struct context_param *context_param_list) { if (unlikely(!st)) { error("NULL value given!"); return NULL; } - RRDR *r = callocz(1, sizeof(RRDR)); + RRDR *r = onewayalloc_callocz(owa, 1, sizeof(RRDR)); r->st = st; if (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) { @@ -126,10 +126,10 @@ RRDR *rrdr_create(struct rrdset *st, long n, struct context_param *context_param r->n = n; - r->t = callocz((size_t)n, sizeof(time_t)); - r->v = mallocz(n * r->d * sizeof(calculated_number)); - r->o = mallocz(n * r->d * sizeof(RRDR_VALUE_FLAGS)); - r->od = mallocz(r->d * sizeof(RRDR_DIMENSION_FLAGS)); + r->t = onewayalloc_callocz(owa, (size_t)n, sizeof(time_t)); + r->v = onewayalloc_mallocz(owa, n * r->d * sizeof(calculated_number)); + r->o = onewayalloc_mallocz(owa, n * r->d * sizeof(RRDR_VALUE_FLAGS)); + r->od = onewayalloc_mallocz(owa, r->d * sizeof(RRDR_DIMENSION_FLAGS)); // set the hidden flag on hidden dimensions int c; diff --git a/web/api/queries/rrdr.h b/web/api/queries/rrdr.h index bd94e56e2b..00125ddf57 100644 --- a/web/api/queries/rrdr.h +++ b/web/api/queries/rrdr.h @@ -102,13 +102,14 @@ typedef struct rrdresult { #define rrdr_rows(r) ((r)->rows) #include "database/rrd.h" -extern void rrdr_free(RRDR *r); -extern RRDR *rrdr_create(struct rrdset *st, long n, struct context_param *context_param_list); +extern void rrdr_free(ONEWAYALLOC *owa, RRDR *r); +extern RRDR *rrdr_create(ONEWAYALLOC *owa, struct rrdset *st, long n, struct context_param *context_param_list); #include "../web_api_v1.h" #include "web/api/queries/query.h" extern RRDR *rrd2rrdr( + ONEWAYALLOC *owa, RRDSET *st, long points_requested, long long after_requested, long long before_requested, RRDR_GROUPING group_method, long resampling_time_requested, RRDR_OPTIONS options, const char *dimensions, struct context_param *context_param_list, int timeout); diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 8cf89d38d5..54c5e52808 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -512,6 +512,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c fix_google_param(outFileName); RRDSET *st = NULL; + ONEWAYALLOC *owa = onewayalloc_create(0); if((!chart || !*chart) && (!context)) { buffer_sprintf(w->response.data, "No chart id is given at the request."); @@ -519,8 +520,10 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c } struct context_param *context_param_list = NULL; + if (context && !chart) { RRDSET *st1; + uint32_t context_hash = simple_hash(context); rrdhost_rdlock(host); @@ -532,14 +535,14 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)) && (!chart_labels_filter || rrdset_matches_label_keys(st1, chart_labels_filter, words, hash_key_list, &word_count, MAX_CHART_LABELS_FILTER))) - build_context_param_list(&context_param_list, st1); + build_context_param_list(owa, &context_param_list, st1); } rrdhost_unlock(host); if (likely(context_param_list && context_param_list->rd)) // Just set the first one st = context_param_list->rd->rrdset; else { if (!chart_label_key && !chart_labels_filter) - sql_build_context_param_list(&context_param_list, host, context, NULL); + sql_build_context_param_list(owa, &context_param_list, host, context, NULL); } } else { @@ -549,14 +552,14 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c if (likely(st)) st->last_accessed_time = now_realtime_sec(); else - sql_build_context_param_list(&context_param_list, host, NULL, chart); + sql_build_context_param_list(owa, &context_param_list, host, NULL, chart); } if (!st) { if (likely(context_param_list && context_param_list->rd && context_param_list->rd->rrdset)) st = context_param_list->rd->rrdset; else { - free_context_param_list(&context_param_list); + free_context_param_list(owa, &context_param_list); context_param_list = NULL; } } @@ -630,12 +633,12 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c buffer_strcat(w->response.data, "("); } - ret = rrdset2anything_api_v1(st, w->response.data, dimensions, format, + ret = rrdset2anything_api_v1(owa, st, w->response.data, dimensions, format, points, after, before, group, group_time, options, &last_timestamp_in_data, context_param_list, chart_label_key, max_anomaly_rates, timeout); - free_context_param_list(&context_param_list); + free_context_param_list(owa, &context_param_list); if(format == DATASOURCE_DATATABLE_JSONP) { if(google_timestamp < last_timestamp_in_data) @@ -652,7 +655,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c else if(format == DATASOURCE_JSONP) buffer_strcat(w->response.data, ");"); - cleanup: +cleanup: + onewayalloc_destroy(owa); buffer_free(dimensions); return ret; } |