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
This commit is contained in:
parent
47fa3d7089
commit
87c0cc2d60
|
@ -383,6 +383,8 @@ set(LIBNETDATA_FILES
|
|||
libnetdata/log/log.h
|
||||
libnetdata/os.c
|
||||
libnetdata/os.h
|
||||
libnetdata/onewayalloc/onewayalloc.c
|
||||
libnetdata/onewayalloc/onewayalloc.h
|
||||
libnetdata/popen/popen.c
|
||||
libnetdata/popen/popen.h
|
||||
libnetdata/procfile/procfile.c
|
||||
|
|
|
@ -158,6 +158,8 @@ LIBNETDATA_FILES = \
|
|||
libnetdata/locks/locks.h \
|
||||
libnetdata/log/log.c \
|
||||
libnetdata/log/log.h \
|
||||
libnetdata/onewayalloc/onewayalloc.c \
|
||||
libnetdata/onewayalloc/onewayalloc.h \
|
||||
libnetdata/popen/popen.c \
|
||||
libnetdata/popen/popen.h \
|
||||
libnetdata/procfile/procfile.c \
|
||||
|
|
|
@ -1758,6 +1758,7 @@ AC_CONFIG_FILES([
|
|||
libnetdata/eval/Makefile
|
||||
libnetdata/locks/Makefile
|
||||
libnetdata/log/Makefile
|
||||
libnetdata/onewayalloc/Makefile
|
||||
libnetdata/popen/Makefile
|
||||
libnetdata/procfile/Makefile
|
||||
libnetdata/simple_pattern/Makefile
|
||||
|
|
|
@ -1732,7 +1732,8 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
|
|||
update_every = REGION_UPDATE_EVERY[current_region];
|
||||
long points = (time_end - time_start) / update_every;
|
||||
for (i = 0 ; i < CHARTS ; ++i) {
|
||||
RRDR *r = rrd2rrdr(st[i], points, time_start + update_every, time_end, RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL, 0);
|
||||
ONEWAYALLOC *owa = onewayalloc_create(0);
|
||||
RRDR *r = rrd2rrdr(owa, st[i], points, time_start + update_every, time_end, RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL, 0);
|
||||
if (!r) {
|
||||
fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", st[i]->name);
|
||||
return ++errors;
|
||||
|
@ -1766,8 +1767,9 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
|
|||
}
|
||||
}
|
||||
}
|
||||
rrdr_free(r);
|
||||
rrdr_free(owa, r);
|
||||
}
|
||||
onewayalloc_destroy(owa);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
@ -1851,7 +1853,8 @@ int test_dbengine(void)
|
|||
long points = (time_end[REGIONS - 1] - time_start[0]) / update_every; // cover all time regions with RRDR
|
||||
long point_offset = (time_start[current_region] - time_start[0]) / update_every;
|
||||
for (i = 0 ; i < CHARTS ; ++i) {
|
||||
RRDR *r = rrd2rrdr(st[i], points, time_start[0] + update_every, time_end[REGIONS - 1], RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL, 0);
|
||||
ONEWAYALLOC *owa = onewayalloc_create(0);
|
||||
RRDR *r = rrd2rrdr(owa, st[i], points, time_start[0] + update_every, time_end[REGIONS - 1], RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL, 0);
|
||||
if (!r) {
|
||||
fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", st[i]->name);
|
||||
++errors;
|
||||
|
@ -1888,8 +1891,9 @@ int test_dbengine(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
rrdr_free(r);
|
||||
rrdr_free(owa, r);
|
||||
}
|
||||
onewayalloc_destroy(owa);
|
||||
}
|
||||
error_out:
|
||||
rrd_wrlock();
|
||||
|
|
|
@ -1446,13 +1446,13 @@ int find_dimension_first_last_t(char *machine_guid, char *chart_id, char *dim_id
|
|||
}
|
||||
|
||||
#ifdef ENABLE_DBENGINE
|
||||
static RRDDIM *create_rrdim_entry(RRDSET *st, char *id, char *name, uuid_t *metric_uuid)
|
||||
static RRDDIM *create_rrdim_entry(ONEWAYALLOC *owa, RRDSET *st, char *id, char *name, uuid_t *metric_uuid)
|
||||
{
|
||||
RRDDIM *rd = callocz(1, sizeof(*rd));
|
||||
RRDDIM *rd = onewayalloc_callocz(owa, 1, sizeof(*rd));
|
||||
rd->rrdset = st;
|
||||
rd->last_stored_value = NAN;
|
||||
rrddim_flag_set(rd, RRDDIM_FLAG_NONE);
|
||||
rd->state = mallocz(sizeof(*rd->state));
|
||||
rd->state = onewayalloc_mallocz(owa, sizeof(*rd->state));
|
||||
rd->rrd_memory_mode = RRD_MEMORY_MODE_DBENGINE;
|
||||
rd->state->query_ops.init = rrdeng_load_metric_init;
|
||||
rd->state->query_ops.next_metric = rrdeng_load_metric_next;
|
||||
|
@ -1460,11 +1460,11 @@ static RRDDIM *create_rrdim_entry(RRDSET *st, char *id, char *name, uuid_t *metr
|
|||
rd->state->query_ops.finalize = rrdeng_load_metric_finalize;
|
||||
rd->state->query_ops.latest_time = rrdeng_metric_latest_time;
|
||||
rd->state->query_ops.oldest_time = rrdeng_metric_oldest_time;
|
||||
rd->state->rrdeng_uuid = mallocz(sizeof(uuid_t));
|
||||
rd->state->rrdeng_uuid = onewayalloc_mallocz(owa, sizeof(uuid_t));
|
||||
uuid_copy(*rd->state->rrdeng_uuid, *metric_uuid);
|
||||
uuid_copy(rd->state->metric_uuid, *metric_uuid);
|
||||
rd->id = strdupz(id);
|
||||
rd->name = strdupz(name);
|
||||
rd->id = onewayalloc_strdupz(owa, id);
|
||||
rd->name = onewayalloc_strdupz(owa, name);
|
||||
return rd;
|
||||
}
|
||||
#endif
|
||||
|
@ -1481,7 +1481,7 @@ static RRDDIM *create_rrdim_entry(RRDSET *st, char *id, char *name, uuid_t *metr
|
|||
"where d.chart_id = c.chart_id and c.host_id = h.host_id and c.host_id = @host_id and c.type||'.'||c.id = @chart " \
|
||||
"order by c.chart_id asc, c.type||'.'||c.id desc;"
|
||||
|
||||
void sql_build_context_param_list(struct context_param **param_list, RRDHOST *host, char *context, char *chart)
|
||||
void sql_build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list, RRDHOST *host, char *context, char *chart)
|
||||
{
|
||||
#ifdef ENABLE_DBENGINE
|
||||
int rc;
|
||||
|
@ -1490,7 +1490,7 @@ void sql_build_context_param_list(struct context_param **param_list, RRDHOST *ho
|
|||
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)->rd = NULL;
|
||||
|
@ -1539,21 +1539,21 @@ void sql_build_context_param_list(struct context_param **param_list, RRDHOST *ho
|
|||
|
||||
if (!st || uuid_compare(*(uuid_t *)sqlite3_column_blob(res, 7), chart_id)) {
|
||||
if (unlikely(st && !st->counter)) {
|
||||
freez(st->context);
|
||||
freez((char *) st->name);
|
||||
freez(st);
|
||||
onewayalloc_freez(owa, st->context);
|
||||
onewayalloc_freez(owa, (char *) st->name);
|
||||
onewayalloc_freez(owa, st);
|
||||
}
|
||||
st = callocz(1, sizeof(*st));
|
||||
st = onewayalloc_callocz(owa, 1, sizeof(*st));
|
||||
char n[RRD_ID_LENGTH_MAX + 1];
|
||||
|
||||
snprintfz(
|
||||
n, RRD_ID_LENGTH_MAX, "%s.%s", (char *)sqlite3_column_text(res, 4),
|
||||
(char *)sqlite3_column_text(res, 3));
|
||||
st->name = strdupz(n);
|
||||
st->name = onewayalloc_strdupz(owa, n);
|
||||
st->update_every = sqlite3_column_int(res, 6);
|
||||
st->counter = 0;
|
||||
if (chart) {
|
||||
st->context = strdupz((char *)sqlite3_column_text(res, 8));
|
||||
st->context = onewayalloc_strdupz(owa, (char *)sqlite3_column_text(res, 8));
|
||||
strncpyz(st->id, chart, RRD_ID_LENGTH_MAX);
|
||||
}
|
||||
uuid_copy(chart_id, *(uuid_t *)sqlite3_column_blob(res, 7));
|
||||
|
@ -1569,7 +1569,7 @@ void sql_build_context_param_list(struct context_param **param_list, RRDHOST *ho
|
|||
st->counter++;
|
||||
st->last_entry_t = MAX(st->last_entry_t, (*param_list)->last_entry_t);
|
||||
|
||||
RRDDIM *rd = create_rrdim_entry(st, (char *)sqlite3_column_text(res, 1), (char *)sqlite3_column_text(res, 2), &rrdeng_uuid);
|
||||
RRDDIM *rd = create_rrdim_entry(owa, st, (char *)sqlite3_column_text(res, 1), (char *)sqlite3_column_text(res, 2), &rrdeng_uuid);
|
||||
if (sqlite3_column_int(res, 9) == 1)
|
||||
rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
|
||||
rd->next = (*param_list)->rd;
|
||||
|
@ -1577,13 +1577,13 @@ void sql_build_context_param_list(struct context_param **param_list, RRDHOST *ho
|
|||
}
|
||||
if (st) {
|
||||
if (!st->counter) {
|
||||
freez(st->context);
|
||||
freez((char *)st->name);
|
||||
freez(st);
|
||||
onewayalloc_freez(owa,st->context);
|
||||
onewayalloc_freez(owa,(char *)st->name);
|
||||
onewayalloc_freez(owa,st);
|
||||
}
|
||||
else
|
||||
if (!st->context && context)
|
||||
st->context = strdupz(context);
|
||||
st->context = onewayalloc_strdupz(owa,context);
|
||||
}
|
||||
|
||||
failed:
|
||||
|
|
|
@ -89,7 +89,7 @@ extern void db_unlock(void);
|
|||
extern void db_lock(void);
|
||||
extern void delete_dimension_uuid(uuid_t *dimension_uuid);
|
||||
extern void sql_store_chart_label(uuid_t *chart_uuid, int source_type, char *label, char *value);
|
||||
extern void sql_build_context_param_list(struct context_param **param_list, RRDHOST *host, char *context, char *chart);
|
||||
extern void sql_build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list, RRDHOST *host, char *context, char *chart);
|
||||
extern void store_claim_id(uuid_t *host_id, uuid_t *claim_id);
|
||||
extern int update_node_id(uuid_t *host_id, uuid_t *node_id);
|
||||
extern int get_node_id(uuid_t *host_id, uuid_t *node_id);
|
||||
|
|
|
@ -17,6 +17,7 @@ SUBDIRS = \
|
|||
health \
|
||||
locks \
|
||||
log \
|
||||
onewayalloc \
|
||||
popen \
|
||||
procfile \
|
||||
simple_pattern \
|
||||
|
|
|
@ -345,6 +345,7 @@ extern char *netdata_configured_host_prefix;
|
|||
#include "json/json.h"
|
||||
#include "health/health.h"
|
||||
#include "string/utf8.h"
|
||||
#include "onewayalloc/onewayalloc.h"
|
||||
|
||||
// BEWARE: Outside of the C code this also exists in alarm-notify.sh
|
||||
#define DEFAULT_CLOUD_BASE_URL "https://app.netdata.cloud"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
dist_noinst_DATA = \
|
||||
README.md \
|
||||
$(NULL)
|
|
@ -0,0 +1,71 @@
|
|||
<!--
|
||||
title: "One Way Allocator"
|
||||
custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/onewayallocator/README.md
|
||||
-->
|
||||
|
||||
# One Way Allocator
|
||||
|
||||
This is a very fast single-threaded-only memory allocator, that minimized system calls
|
||||
when a lot of memory allocations needs to be made to perform a task, which all of them
|
||||
can be freed together when the task finishes.
|
||||
|
||||
It has been designed to be used for netdata context queries.
|
||||
|
||||
For netdata to perform a context query, it builds a virtual chart, a chart that contains
|
||||
all the dimensions of the charts having the same context. This process requires allocating
|
||||
several structures for each of the dimensions to attach them to the virtual chart. All
|
||||
these data can be freed immediately after the query finishes.
|
||||
|
||||
## How it works
|
||||
|
||||
1. The caller calls `ONEWAYALLOC *owa = onewayalloc_create(sizehint)` to create an OWA.
|
||||
Internally this allocates the first memory buffer with size >= `sizehint`.
|
||||
If `sizehint` is zero, it will allocate 1 hardware page (usually 4kb).
|
||||
No need to check for success or failure. As with `mallocz()` in netdata, a `fatal()`
|
||||
will be called if the allocation fails - although this will never fail, since Linux
|
||||
does not really check if there is memory available for `mmap()` calls.
|
||||
|
||||
2. The caller can then perform any number of the following calls to acquire memory:
|
||||
- `onewayalloc_mallocz(owa, size)`, similar to `mallocz()`
|
||||
- `onewayalloc_callocz(owa, nmemb, size)`, similar to `callocz()`
|
||||
- `onewayalloc_strdupz(owa, string)`, similar to `strdupz()`
|
||||
- `onewayalloc_memdupz(owa, ptr, size)`, similar to `mallocz()` and then `memcpy()`
|
||||
|
||||
3. Once the caller has done all the work with the allocated buffers, all memory allocated
|
||||
can be freed with `onewayalloc_destroy(owa)`.
|
||||
|
||||
## How faster it is?
|
||||
|
||||
On modern hardware, for any single query the performance improvement is marginal and not
|
||||
noticeable at all.
|
||||
|
||||
We performed the following tests using the same huge context query (1000 charts,
|
||||
100 dimensions each = 100k dimensions)
|
||||
|
||||
1. using `mallocz()`, 1 caller, 256 queries (sequential)
|
||||
2. using `mallocz()`, 256 callers, 1 query each (parallel)
|
||||
3. using `OWA`, 1 caller, 256 queries (sequential)
|
||||
4. using `OWA`, 256 callers, 1 query each (parallel)
|
||||
|
||||
Netdata was configured to use 24 web threads on the 24 core server we used.
|
||||
|
||||
The results are as follows:
|
||||
|
||||
### sequential test
|
||||
|
||||
branch|transactions|time to complete|transaction rate|average response time|min response time|max response time
|
||||
:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
`malloc()`|256|322.35s|0.79/sec|1.26s|1.01s|1.87s
|
||||
`OWA`|256|310.19s|0.83/sec|1.21s|1.04s|1.63s
|
||||
|
||||
For a single query, the improvement is just marginal and not noticeable at all.
|
||||
|
||||
### parallel test
|
||||
|
||||
branch|transactions|time to complete|transaction rate|average response time|min response time|max response time
|
||||
:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
`malloc()`|256|84.72s|3.02/sec|68.43s|50.20s|84.71s
|
||||
`OWA`|256|39.35s|6.51/sec|34.48s|20.55s|39.34s
|
||||
|
||||
For parallel workload, like the one executed by netdata.cloud, `OWA` provides a 54% overall speed improvement (more than double the overall
|
||||
user-experienced speed, including the data query itself).
|
|
@ -0,0 +1,173 @@
|
|||
#include "onewayalloc.h"
|
||||
|
||||
static size_t OWA_NATURAL_PAGE_SIZE = 0;
|
||||
static size_t OWA_NATURAL_ALIGNMENT = sizeof(int*);
|
||||
|
||||
typedef struct owa_page {
|
||||
size_t stats_pages;
|
||||
size_t stats_pages_size;
|
||||
size_t stats_mallocs_made;
|
||||
size_t stats_mallocs_size;
|
||||
size_t size; // the total size of the page
|
||||
size_t offset; // the first free byte of the page
|
||||
struct owa_page *next; // the next page on the list
|
||||
struct owa_page *last; // the last page on the list - we currently allocate on this
|
||||
} OWA_PAGE;
|
||||
|
||||
// allocations need to be aligned to CPU register width
|
||||
// https://en.wikipedia.org/wiki/Data_structure_alignment
|
||||
static inline size_t natural_alignment(size_t size) {
|
||||
if(unlikely(size % OWA_NATURAL_ALIGNMENT))
|
||||
size = size + OWA_NATURAL_ALIGNMENT - (size % OWA_NATURAL_ALIGNMENT);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Create an OWA
|
||||
// Once it is created, the called may call the onewayalloc_mallocz()
|
||||
// any number of times, for any amount of memory.
|
||||
|
||||
static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
|
||||
if(unlikely(!OWA_NATURAL_PAGE_SIZE))
|
||||
OWA_NATURAL_PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
// our default page size
|
||||
size_t size = OWA_NATURAL_PAGE_SIZE;
|
||||
|
||||
// make sure the new page will fit both the requested size
|
||||
// and the OWA_PAGE structure at its beginning
|
||||
size_hint += sizeof(OWA_PAGE);
|
||||
|
||||
// prefer the user size if it is bigger than our size
|
||||
if(size_hint > size) size = size_hint;
|
||||
|
||||
// try to allocate half of the total we have allocated already
|
||||
if(likely(head)) {
|
||||
size_t optimal_size = head->stats_pages_size / 2;
|
||||
if(optimal_size > size) size = optimal_size;
|
||||
}
|
||||
|
||||
// Make sure our allocations are always a multiple of the hardware page size
|
||||
if(size % OWA_NATURAL_PAGE_SIZE) size = size + OWA_NATURAL_PAGE_SIZE - (size % OWA_NATURAL_PAGE_SIZE);
|
||||
|
||||
OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0);
|
||||
if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);
|
||||
|
||||
page->size = size;
|
||||
page->offset = natural_alignment(sizeof(OWA_PAGE));
|
||||
page->next = page->last = NULL;
|
||||
|
||||
if(unlikely(!head)) {
|
||||
// this is the first time we are called
|
||||
head = page;
|
||||
head->stats_pages = 0;
|
||||
head->stats_pages_size = 0;
|
||||
head->stats_mallocs_made = 0;
|
||||
head->stats_mallocs_size = 0;
|
||||
}
|
||||
else {
|
||||
// link this page into our existing linked list
|
||||
head->last->next = page;
|
||||
}
|
||||
|
||||
head->last = page;
|
||||
head->stats_pages++;
|
||||
head->stats_pages_size += size;
|
||||
|
||||
return (ONEWAYALLOC *)page;
|
||||
}
|
||||
|
||||
ONEWAYALLOC *onewayalloc_create(size_t size_hint) {
|
||||
return onewayalloc_create_internal(NULL, size_hint);
|
||||
}
|
||||
|
||||
void *onewayalloc_mallocz(ONEWAYALLOC *owa, size_t size) {
|
||||
OWA_PAGE *head = (OWA_PAGE *)owa;
|
||||
OWA_PAGE *page = head->last;
|
||||
|
||||
// update stats
|
||||
head->stats_mallocs_made++;
|
||||
head->stats_mallocs_size += size;
|
||||
|
||||
// make sure the size is aligned
|
||||
size = natural_alignment(size);
|
||||
|
||||
if(unlikely(page->size - page->offset < size)) {
|
||||
// we don't have enough space to fit the data
|
||||
// let's get another page
|
||||
page = onewayalloc_create_internal(head, (size > page->size)?size:page->size);
|
||||
}
|
||||
|
||||
char *mem = (char *)page;
|
||||
mem = &mem[page->offset];
|
||||
page->offset += size;
|
||||
|
||||
return (void *)mem;
|
||||
}
|
||||
|
||||
void *onewayalloc_callocz(ONEWAYALLOC *owa, size_t nmemb, size_t size) {
|
||||
size_t total = nmemb * size;
|
||||
void *mem = onewayalloc_mallocz(owa, total);
|
||||
memset(mem, 0, total);
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *onewayalloc_strdupz(ONEWAYALLOC *owa, const char *s) {
|
||||
size_t size = strlen(s) + 1;
|
||||
char *d = onewayalloc_mallocz((OWA_PAGE *)owa, size);
|
||||
memcpy(d, s, size);
|
||||
return d;
|
||||
}
|
||||
|
||||
void *onewayalloc_memdupz(ONEWAYALLOC *owa, const void *src, size_t size) {
|
||||
void *mem = onewayalloc_mallocz((OWA_PAGE *)owa, size);
|
||||
// memcpy() is way faster than strcpy() since it does not check for '\0'
|
||||
memcpy(mem, src, size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void onewayalloc_freez(ONEWAYALLOC *owa __maybe_unused, const void *ptr __maybe_unused) {
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
// allow the caller to call us for a mallocz() allocation
|
||||
// so try to find it in our memory and if it is not there
|
||||
// log an error
|
||||
|
||||
OWA_PAGE *head = (OWA_PAGE *)owa;
|
||||
OWA_PAGE *page;
|
||||
size_t seeking = (size_t)ptr;
|
||||
|
||||
for(page = head; page ;page = page->next) {
|
||||
size_t start = (size_t)page;
|
||||
size_t end = start + page->size;
|
||||
|
||||
if(seeking >= start && seeking <= end) {
|
||||
// found it - it is ours
|
||||
// just return to let the caller think we actually did something
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found - it is not ours
|
||||
// let's free it with the system allocator
|
||||
error("ONEWAYALLOC: request to free address 0x%p that is not allocated by this OWA", ptr);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void onewayalloc_destroy(ONEWAYALLOC *owa) {
|
||||
if(!owa) return;
|
||||
|
||||
OWA_PAGE *head = (OWA_PAGE *)owa;
|
||||
|
||||
//info("OWA: %zu allocations of %zu total bytes, in %zu pages of %zu total bytes",
|
||||
// head->stats_mallocs_made, head->stats_mallocs_size,
|
||||
// head->stats_pages, head->stats_pages_size);
|
||||
|
||||
OWA_PAGE *page = head;
|
||||
while(page) {
|
||||
OWA_PAGE *p = page;
|
||||
page = page->next;
|
||||
munmap(p, p->size);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef ONEWAYALLOC_H
|
||||
#define ONEWAYALLOC_H 1
|
||||
|
||||
#include "../libnetdata.h"
|
||||
|
||||
typedef void ONEWAYALLOC;
|
||||
|
||||
extern ONEWAYALLOC *onewayalloc_create(size_t size_hint);
|
||||
extern void onewayalloc_destroy(ONEWAYALLOC *owa);
|
||||
|
||||
extern void *onewayalloc_mallocz(ONEWAYALLOC *owa, size_t size);
|
||||
extern void *onewayalloc_callocz(ONEWAYALLOC *owa, size_t nmemb, size_t size);
|
||||
extern char *onewayalloc_strdupz(ONEWAYALLOC *owa, const char *s);
|
||||
extern void *onewayalloc_memdupz(ONEWAYALLOC *owa, const void *src, size_t size);
|
||||
extern void onewayalloc_freez(ONEWAYALLOC *owa, const void *ptr);
|
||||
|
||||
#endif // ONEWAYALLOC_H
|
|
@ -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;
|
||||
|
||||
RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions, NULL, timeout);
|
||||
ONEWAYALLOC *owa = onewayalloc_create(0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue