mirror of
https://github.com/netdata/netdata.git
synced 2025-05-06 02:00:18 +00:00
Add message queue statistics (#5115)
* Add IPC message queue charts * Add obsolete flag for dimensions * Delete obsolete dimensions from memory * Remove files for obsolete dimensions, filter requests * Make empty charts obsolete * Minimize obsolete dimension checks * Limit the number of dimensions in memory * Remove obsolete dimensions on netdata exit * Update documentation * Move flag to the end * Fix typo * Fix typo
This commit is contained in:
parent
cbe45897de
commit
2f6f8155db
14 changed files with 431 additions and 167 deletions
backends/prometheus
collectors
daemon/config
database
streaming
web/api
|
@ -291,7 +291,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
|
|||
// for each dimension
|
||||
RRDDIM *rd;
|
||||
rrddim_foreach_read(rd, st) {
|
||||
if(rd->collections_counter) {
|
||||
if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
|
||||
char dimension[PROMETHEUS_ELEMENT_MAX + 1];
|
||||
char *suffix = "";
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
#define NETDATA_CHART_PRIO_SYSTEM_ENTROPY 1000
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_UPTIME 1000
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES 990 // freebsd only
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1000 // freebsd only
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE 1100 // freebsd only
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1000
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE 1100
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES 1000
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS 1000
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SEGS 1000 // freebsd only
|
||||
|
|
|
@ -233,7 +233,7 @@ the template is:
|
|||
|
||||
the template is:
|
||||
|
||||
> DIMENSION id [name [algorithm [multiplier [divisor [hidden]]]]]
|
||||
> DIMENSION id [name [algorithm [multiplier [divisor [options]]]]]
|
||||
|
||||
where:
|
||||
|
||||
|
@ -283,10 +283,9 @@ the template is:
|
|||
an integer value to divide the collected value,
|
||||
if empty or missing, `1` is used
|
||||
|
||||
- `hidden`
|
||||
- `options`
|
||||
|
||||
giving the keyword `hidden` will make this dimension hidden,
|
||||
it will take part in the calculations but will not be presented in the chart
|
||||
a space separated list of options, enclosed in quotes. Options supported: `obsolete` to mark a dimension as obsolete (netdata will delete it after some time) and `hidden` to make this dimension hidden, it will take part in the calculations but will not be presented in the chart.
|
||||
|
||||
|
||||
#### VARIABLE
|
||||
|
|
|
@ -394,10 +394,17 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
|
|||
rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
|
||||
rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
|
||||
if(options && *options) {
|
||||
if(strstr(options, "obsolete") != NULL)
|
||||
rrddim_is_obsolete(st, rd);
|
||||
else
|
||||
rrddim_isnot_obsolete(st, rd);
|
||||
if(strstr(options, "hidden") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
|
||||
if(strstr(options, "noreset") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
|
||||
if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
|
||||
}
|
||||
else {
|
||||
rrddim_isnot_obsolete(st, rd);
|
||||
}
|
||||
}
|
||||
else if(likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) {
|
||||
char *name = words[1];
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
- `/proc/loadavg` (system load and total processes running)
|
||||
- `/proc/sys/kernel/random/entropy_avail` (random numbers pool availability - used in cryptography)
|
||||
- `/sys/class/power_supply` (power supply properties)
|
||||
- `ipc` (IPC semaphores and message queues)
|
||||
- `ksm` Kernel Same-Page Merging performance (several files under `/sys/kernel/mm/ksm`).
|
||||
- `netdata` (internal netdata resources utilization)
|
||||
|
||||
|
@ -343,4 +344,18 @@ corresponding `min` or `empty` attribute, then Netdata will still provide
|
|||
the corresponding `min` or `empty`, which will then always read as zero.
|
||||
This way, alerts which match on these will still work.
|
||||
|
||||
## IPC
|
||||
|
||||
This module monitors the number of semaphores, semaphore arrays, number of messages in message queues, and amount of memory used by message queues. As far as the message queue charts are dynamic, sane limits are applied for the number of dimensions per chart (the limit is configurable).
|
||||
|
||||
#### configuration
|
||||
|
||||
```
|
||||
[plugin:proc:ipc]
|
||||
# semaphore totals = yes
|
||||
# message queues = yes
|
||||
# msg filename to monitor = /proc/sysvipc/msg
|
||||
# max dimensions in memory allowed = 50
|
||||
```
|
||||
|
||||
[]()
|
||||
|
|
|
@ -53,6 +53,18 @@ union semun {
|
|||
};
|
||||
#endif
|
||||
|
||||
struct message_queue {
|
||||
unsigned long long id;
|
||||
int found;
|
||||
|
||||
RRDDIM *rd_messages;
|
||||
RRDDIM *rd_bytes;
|
||||
unsigned long long messages;
|
||||
unsigned long long bytes;
|
||||
|
||||
struct message_queue * next;
|
||||
};
|
||||
|
||||
static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
|
||||
static procfile *ff = NULL;
|
||||
static int error_shown = 0;
|
||||
|
@ -162,31 +174,96 @@ static inline int ipc_sem_get_status(struct ipc_status *st) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ipc_msq_get_info(char *msg_filename, struct message_queue **message_queue_root) {
|
||||
static procfile *ff;
|
||||
struct message_queue *msq;
|
||||
|
||||
if(unlikely(!ff)) {
|
||||
ff = procfile_open(config_get("plugin:proc:ipc", "msg filename to monitor", msg_filename), " \t:", PROCFILE_FLAG_DEFAULT);
|
||||
if(unlikely(!ff)) return 1;
|
||||
}
|
||||
|
||||
ff = procfile_readall(ff);
|
||||
if(unlikely(!ff)) return 1;
|
||||
|
||||
size_t lines = procfile_lines(ff);
|
||||
size_t words = 0;
|
||||
|
||||
if(unlikely(lines < 2)) {
|
||||
error("Cannot read %s. Expected 2 or more lines, read %zu.", ff->filename, lines);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// loop through all lines except the first and the last ones
|
||||
size_t l;
|
||||
for(l = 1; l < lines - 1; l++) {
|
||||
words = procfile_linewords(ff, l);
|
||||
if(unlikely(words < 2)) continue;
|
||||
if(unlikely(words < 14)) {
|
||||
error("Cannot read %s line. Expected 14 params, read %zu.", ff->filename, words);
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the id in the linked list or create a new stucture
|
||||
int found = 0;
|
||||
|
||||
unsigned long long id = str2ull(procfile_lineword(ff, l, 1));
|
||||
for(msq = *message_queue_root; msq ; msq = msq->next) {
|
||||
if(unlikely(id == msq->id)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(unlikely(!found)) {
|
||||
msq = callocz(1, sizeof(struct message_queue));
|
||||
msq->next = *message_queue_root;
|
||||
*message_queue_root = msq;
|
||||
msq->id = id;
|
||||
}
|
||||
|
||||
msq->messages = str2ull(procfile_lineword(ff, l, 4));
|
||||
msq->bytes = str2ull(procfile_lineword(ff, l, 3));
|
||||
msq->found = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_ipc(int update_every, usec_t dt) {
|
||||
(void)dt;
|
||||
|
||||
static int initialized = 0, read_limits_next = -1;
|
||||
static int do_sem = -1, do_msg = -1;
|
||||
static int read_limits_next = -1;
|
||||
static struct ipc_limits limits;
|
||||
static struct ipc_status status;
|
||||
static RRDVAR *arrays_max = NULL, *semaphores_max = NULL;
|
||||
static RRDSET *st_semaphores = NULL, *st_arrays = NULL;
|
||||
static RRDDIM *rd_semaphores = NULL, *rd_arrays = NULL;
|
||||
static char *msg_filename = NULL;
|
||||
static struct message_queue *message_queue_root = NULL;
|
||||
static long long dimensions_limit;
|
||||
|
||||
if(unlikely(!initialized)) {
|
||||
initialized = 1;
|
||||
if(unlikely(do_sem == -1)) {
|
||||
do_sem = config_get_boolean("plugin:proc:ipc", "semaphore totals", CONFIG_BOOLEAN_YES);
|
||||
do_msg = config_get_boolean("plugin:proc:ipc", "message queues", CONFIG_BOOLEAN_YES);
|
||||
|
||||
char filename[FILENAME_MAX + 1];
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sysvipc/msg");
|
||||
msg_filename = config_get("plugin:proc:ipc", "msg filename to monitor", filename);
|
||||
|
||||
dimensions_limit = config_get_number("plugin:proc:ipc", "max dimensions in memory allowed", 50);
|
||||
|
||||
// make sure it works
|
||||
if(ipc_sem_get_limits(&limits) == -1) {
|
||||
error("unable to fetch semaphore limits");
|
||||
return 1;
|
||||
do_sem = CONFIG_BOOLEAN_NO;
|
||||
}
|
||||
|
||||
// make sure it works
|
||||
if(ipc_sem_get_status(&status) == -1) {
|
||||
else if(ipc_sem_get_status(&status) == -1) {
|
||||
error("unable to fetch semaphore statistics");
|
||||
return 1;
|
||||
do_sem = CONFIG_BOOLEAN_NO;
|
||||
}
|
||||
|
||||
else {
|
||||
// create the charts
|
||||
if(unlikely(!st_semaphores)) {
|
||||
st_semaphores = rrdset_create_localhost(
|
||||
|
@ -229,6 +306,18 @@ int do_ipc(int update_every, usec_t dt) {
|
|||
arrays_max = rrdvar_custom_host_variable_create(localhost, "ipc_semaphores_arrays_max");
|
||||
}
|
||||
|
||||
struct stat stbuf;
|
||||
if (stat(msg_filename, &stbuf)) {
|
||||
do_msg = CONFIG_BOOLEAN_NO;
|
||||
}
|
||||
|
||||
if(unlikely(do_sem == CONFIG_BOOLEAN_NO && do_msg == CONFIG_BOOLEAN_NO)) {
|
||||
error("ipc module disabled");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(likely(do_sem != CONFIG_BOOLEAN_NO)) {
|
||||
if(unlikely(read_limits_next < 0)) {
|
||||
if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
|
||||
error("Unable to fetch semaphore limits.");
|
||||
|
@ -258,6 +347,118 @@ int do_ipc(int update_every, usec_t dt) {
|
|||
if(st_arrays->counter_done) rrdset_next(st_arrays);
|
||||
rrddim_set_by_pointer(st_arrays, rd_arrays, status.semusz);
|
||||
rrdset_done(st_arrays);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
if(likely(do_msg != CONFIG_BOOLEAN_NO)) {
|
||||
static RRDSET *st_msq_messages = NULL, *st_msq_bytes = NULL;
|
||||
|
||||
int ret = ipc_msq_get_info(msg_filename, &message_queue_root);
|
||||
|
||||
if(!ret && message_queue_root) {
|
||||
if(unlikely(!st_msq_messages))
|
||||
st_msq_messages = rrdset_create_localhost(
|
||||
"system"
|
||||
, "message_queue_messages"
|
||||
, NULL
|
||||
, "ipc message queues"
|
||||
, NULL
|
||||
, "IPC Message Queue Number of Messages"
|
||||
, "messages"
|
||||
, PLUGIN_PROC_NAME
|
||||
, "ipc"
|
||||
, NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES
|
||||
, update_every
|
||||
, RRDSET_TYPE_STACKED
|
||||
);
|
||||
else
|
||||
rrdset_next(st_msq_messages);
|
||||
|
||||
if(unlikely(!st_msq_bytes))
|
||||
st_msq_bytes = rrdset_create_localhost(
|
||||
"system"
|
||||
, "message_queue_bytes"
|
||||
, NULL
|
||||
, "ipc message queues"
|
||||
, NULL
|
||||
, "IPC Message Queue Used Bytes"
|
||||
, "bytes"
|
||||
, PLUGIN_PROC_NAME
|
||||
, "ipc"
|
||||
, NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE
|
||||
, update_every
|
||||
, RRDSET_TYPE_STACKED
|
||||
);
|
||||
else
|
||||
rrdset_next(st_msq_bytes);
|
||||
|
||||
struct message_queue *msq = message_queue_root, *msq_prev = NULL;
|
||||
while(likely(msq)){
|
||||
if(likely(msq->found)) {
|
||||
if(unlikely(!msq->rd_messages || !msq->rd_bytes)) {
|
||||
char id[RRD_ID_LENGTH_MAX + 1];
|
||||
snprintfz(id, RRD_ID_LENGTH_MAX, "%llu", msq->id);
|
||||
if(likely(!msq->rd_messages)) msq->rd_messages = rrddim_add(st_msq_messages, id, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
if(likely(!msq->rd_bytes)) msq->rd_bytes = rrddim_add(st_msq_bytes, id, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
}
|
||||
|
||||
rrddim_set_by_pointer(st_msq_messages, msq->rd_messages, msq->messages);
|
||||
rrddim_set_by_pointer(st_msq_bytes, msq->rd_bytes, msq->bytes);
|
||||
|
||||
msq->found = 0;
|
||||
}
|
||||
else {
|
||||
rrddim_is_obsolete(st_msq_messages, msq->rd_messages);
|
||||
rrddim_is_obsolete(st_msq_bytes, msq->rd_bytes);
|
||||
|
||||
// remove message queue from the linked list
|
||||
if(!msq_prev)
|
||||
message_queue_root = msq->next;
|
||||
else
|
||||
msq_prev->next = msq->next;
|
||||
freez(msq);
|
||||
msq = NULL;
|
||||
}
|
||||
if(likely(msq)) {
|
||||
msq_prev = msq;
|
||||
msq = msq->next;
|
||||
}
|
||||
else if(!msq_prev)
|
||||
msq = message_queue_root;
|
||||
else
|
||||
msq = msq_prev->next;
|
||||
}
|
||||
|
||||
rrdset_done(st_msq_messages);
|
||||
rrdset_done(st_msq_bytes);
|
||||
|
||||
long long dimensions_num = 0;
|
||||
RRDDIM *rd;
|
||||
rrdset_rdlock(st_msq_messages);
|
||||
rrddim_foreach_read(rd, st_msq_messages) dimensions_num++;
|
||||
rrdset_unlock(st_msq_messages);
|
||||
|
||||
if(unlikely(dimensions_num > dimensions_limit)) {
|
||||
info("Message queue statistics has been disabled");
|
||||
info("There are %lld dimensions in memory but limit was set to %lld", dimensions_num, dimensions_limit);
|
||||
rrdset_is_obsolete(st_msq_messages);
|
||||
rrdset_is_obsolete(st_msq_bytes);
|
||||
st_msq_messages = NULL;
|
||||
st_msq_bytes = NULL;
|
||||
do_msg = CONFIG_BOOLEAN_NO;
|
||||
}
|
||||
else if(unlikely(!message_queue_root)) {
|
||||
info("Making chart %s (%s) obsolete since it does not have any dimensions", st_msq_messages->name, st_msq_messages->id);
|
||||
rrdset_is_obsolete(st_msq_messages);
|
||||
st_msq_messages = NULL;
|
||||
|
||||
info("Making chart %s (%s) obsolete since it does not have any dimensions", st_msq_bytes->name, st_msq_bytes->id);
|
||||
rrdset_is_obsolete(st_msq_bytes);
|
||||
st_msq_bytes = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -69,10 +69,10 @@ errors flood protection period | `1200` | UNUSED - Length of period (in sec) dur
|
|||
errors to trigger flood protection | `200` | UNUSED - Number of errors written to the log in `errors flood protection period` sec before flood protection is activated.
|
||||
run as user | `netdata` | The user netdata will run as.
|
||||
pthread stack size | auto-detected |
|
||||
cleanup obsolete charts after seconds | `3600` | See [monitoring ephemeral containers](../../collectors/cgroups.plugin/#monitoring-ephemeral-containers)
|
||||
cleanup obsolete charts after seconds | `3600` | See [monitoring ephemeral containers](../../collectors/cgroups.plugin/#monitoring-ephemeral-containers), also sets the timeout for cleaning up obsolete dimensions
|
||||
gap when lost iterations above | `1` |
|
||||
cleanup orphan hosts after seconds | `3600` | How long to wait until automatically removing from the DB a remote netdata host (slave) that is no longer sending data.
|
||||
delete obsolete charts files | `yes` | See [monitoring ephemeral containers](../../collectors/cgroups.plugin/#monitoring-ephemeral-containers)
|
||||
delete obsolete charts files | `yes` | See [monitoring ephemeral containers](../../collectors/cgroups.plugin/#monitoring-ephemeral-containers), also affects the deletion of files for obsolete dimensions
|
||||
delete orphan hosts files | `yes` | Set to `no` to disable non-responsive host removal.
|
||||
|
||||
### [web] section options
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct alarm_entry ALARM_ENTRY;
|
|||
extern int default_rrd_update_every;
|
||||
extern int default_rrd_history_entries;
|
||||
extern int gap_when_lost_iterations_above;
|
||||
extern time_t rrdset_free_obsolete_time;
|
||||
|
||||
#define RRD_ID_LENGTH_MAX 200
|
||||
|
||||
|
@ -123,7 +124,8 @@ typedef struct rrdfamily RRDFAMILY;
|
|||
typedef enum rrddim_flags {
|
||||
RRDDIM_FLAG_NONE = 0,
|
||||
RRDDIM_FLAG_HIDDEN = (1 << 0), // this dimension will not be offered to callers
|
||||
RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS = (1 << 1) // do not offer RESET or OVERFLOW info to callers
|
||||
RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS = (1 << 1), // do not offer RESET or OVERFLOW info to callers
|
||||
RRDDIM_FLAG_OBSOLETE = (1 << 2) // this is marked by the collector/module as obsolete
|
||||
} RRDDIM_FLAGS;
|
||||
|
||||
#ifdef HAVE_C___ATOMIC
|
||||
|
@ -257,6 +259,7 @@ typedef enum rrdset_flags {
|
|||
RRDSET_FLAG_HOMEGENEOUS_CHECK = 1 << 11, // if set, the chart should be checked to determine if the dimensions as homogeneous
|
||||
RRDSET_FLAG_HIDDEN = 1 << 12, // if set, do not show this chart on the dashboard, but use it for backends
|
||||
RRDSET_FLAG_SYNC_CLOCK = 1 << 13, // if set, microseconds on next data collection will be ignored (the chart will be synced to now)
|
||||
RRDSET_FLAG_OBSOLETE_DIMENSIONS = 1 << 14 // this is marked by the collector/module when a chart has obsolete dimensions
|
||||
} RRDSET_FLAGS;
|
||||
|
||||
#ifdef HAVE_C___ATOMIC
|
||||
|
@ -846,6 +849,9 @@ extern RRDDIM *rrddim_find(RRDSET *st, const char *id);
|
|||
extern int rrddim_hide(RRDSET *st, const char *id);
|
||||
extern int rrddim_unhide(RRDSET *st, const char *id);
|
||||
|
||||
extern void rrddim_is_obsolete(RRDSET *st, RRDDIM *rd);
|
||||
extern void rrddim_isnot_obsolete(RRDSET *st, RRDDIM *rd);
|
||||
|
||||
extern collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
|
||||
extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
|
||||
|
||||
|
@ -879,6 +885,7 @@ extern void rrdset_free(RRDSET *st);
|
|||
extern void rrdset_reset(RRDSET *st);
|
||||
extern void rrdset_save(RRDSET *st);
|
||||
extern void rrdset_delete(RRDSET *st);
|
||||
extern void rrdset_delete_obsolete_dimensions(RRDSET *st);
|
||||
|
||||
extern void rrdhost_cleanup_obsolete_charts(RRDHOST *host);
|
||||
|
||||
|
|
|
@ -368,6 +368,18 @@ int rrddim_unhide(RRDSET *st, const char *id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline void rrddim_is_obsolete(RRDSET *st, RRDDIM *rd) {
|
||||
debug(D_RRD_CALLS, "rrddim_is_obsolete() for chart %s, dimension %s", st->name, rd->name);
|
||||
|
||||
rrddim_flag_set(rd, RRDDIM_FLAG_OBSOLETE);
|
||||
rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS);
|
||||
}
|
||||
|
||||
inline void rrddim_isnot_obsolete(RRDSET *st, RRDDIM *rd) {
|
||||
debug(D_RRD_CALLS, "rrddim_isnot_obsolete() for chart %s, dimension %s", st->name, rd->name);
|
||||
|
||||
rrddim_flag_clear(rd, RRDDIM_FLAG_OBSOLETE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RRDDIM - collect values for a dimension
|
||||
|
|
|
@ -665,6 +665,8 @@ void rrdhost_cleanup_charts(RRDHOST *host) {
|
|||
|
||||
if(rrdhost_delete_obsolete_charts && rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))
|
||||
rrdset_delete(st);
|
||||
else if(rrdhost_delete_obsolete_charts && rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS))
|
||||
rrdset_delete_obsolete_dimensions(st);
|
||||
else
|
||||
rrdset_save(st);
|
||||
|
||||
|
|
|
@ -417,6 +417,24 @@ void rrdset_delete(RRDSET *st) {
|
|||
recursively_delete_dir(st->cache_dir, "left-over chart");
|
||||
}
|
||||
|
||||
void rrdset_delete_obsolete_dimensions(RRDSET *st) {
|
||||
RRDDIM *rd;
|
||||
|
||||
rrdset_check_rdlock(st);
|
||||
|
||||
info("Deleting dimensions of chart '%s' ('%s') from disk...", st->id, st->name);
|
||||
|
||||
rrddim_foreach_read(rd, st) {
|
||||
if(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
|
||||
if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || rd->rrd_memory_mode == RRD_MEMORY_MODE_MAP)) {
|
||||
info("Deleting dimension file '%s'.", rd->cache_filename);
|
||||
if(unlikely(unlink(rd->cache_filename) == -1))
|
||||
error("Cannot delete dimension file '%s'", rd->cache_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RRDSET - create a chart
|
||||
|
||||
|
@ -1303,6 +1321,11 @@ void rrdset_done(RRDSET *st) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE))) {
|
||||
error("Dimension %s in chart '%s' has the OBSOLETE flag set, but it is collected.", rd->name, st->id);
|
||||
rrddim_isnot_obsolete(st, rd);
|
||||
}
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
rrdset_debug(st, "%s: START "
|
||||
" last_collected_value = " COLLECTED_NUMBER_FORMAT
|
||||
|
@ -1582,37 +1605,37 @@ void rrdset_done(RRDSET *st) {
|
|||
// ALL DONE ABOUT THE DATA UPDATE
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
// find if there are any obsolete dimensions (not updated recently)
|
||||
if(unlikely(rrd_delete_unupdated_dimensions)) {
|
||||
// find if there are any obsolete dimensions
|
||||
time_t now = now_realtime_sec();
|
||||
|
||||
for( rd = st->dimensions; likely(rd) ; rd = rd->next )
|
||||
if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
|
||||
if(unlikely(rrddim_flag_check(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS))) {
|
||||
rrddim_foreach_read(rd, st)
|
||||
if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)))
|
||||
break;
|
||||
|
||||
if(unlikely(rd)) {
|
||||
RRDDIM *last;
|
||||
// there is dimension to free
|
||||
// there is a dimension to free
|
||||
// upgrade our read lock to a write lock
|
||||
rrdset_unlock(st);
|
||||
rrdset_wrlock(st);
|
||||
|
||||
for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
|
||||
// remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
|
||||
|
||||
if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
|
||||
if(unlikely(rd->last_collected_time.tv_sec + rrdset_free_obsolete_time < now)) {
|
||||
info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
|
||||
|
||||
if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || rd->rrd_memory_mode == RRD_MEMORY_MODE_MAP)) {
|
||||
info("Deleting dimension file '%s'.", rd->cache_filename);
|
||||
if(unlikely(unlink(rd->cache_filename) == -1))
|
||||
error("Cannot delete dimension file '%s'", rd->cache_filename);
|
||||
}
|
||||
|
||||
if(unlikely(!last)) {
|
||||
st->dimensions = rd->next;
|
||||
rd->next = NULL;
|
||||
rrddim_free(st, rd);
|
||||
rd = st->dimensions;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
last->next = rd->next;
|
||||
rd->next = NULL;
|
||||
rrddim_free(st, rd);
|
||||
rd = last->next;
|
||||
continue;
|
||||
|
@ -1622,14 +1645,11 @@ void rrdset_done(RRDSET *st) {
|
|||
last = rd;
|
||||
rd = rd->next;
|
||||
}
|
||||
|
||||
if(unlikely(!st->dimensions)) {
|
||||
info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
|
||||
st->enabled = 0;
|
||||
}
|
||||
else {
|
||||
rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
rrdset_unlock(st);
|
||||
|
||||
|
|
|
@ -188,12 +188,13 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
|
|||
rrddim_foreach_read(rd, st) {
|
||||
buffer_sprintf(
|
||||
host->rrdpush_sender_buffer
|
||||
, "DIMENSION \"%s\" \"%s\" \"%s\" " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " \"%s %s\"\n"
|
||||
, "DIMENSION \"%s\" \"%s\" \"%s\" " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " \"%s %s %s\"\n"
|
||||
, rd->id
|
||||
, rd->name
|
||||
, rrd_algorithm_name(rd->algorithm)
|
||||
, rd->multiplier
|
||||
, rd->divisor
|
||||
, rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)?"obsolete":""
|
||||
, rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":""
|
||||
, rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":""
|
||||
);
|
||||
|
|
|
@ -39,7 +39,7 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
|
|||
// for each dimension
|
||||
RRDDIM *rd;
|
||||
rrddim_foreach_read(rd, st) {
|
||||
if(rd->collections_counter) {
|
||||
if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
|
||||
char dimension[SHELL_ELEMENT_MAX + 1];
|
||||
shell_name_copy(dimension, rd->name?rd->name:rd->id, SHELL_ELEMENT_MAX);
|
||||
|
||||
|
@ -126,7 +126,7 @@ void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
|
|||
// for each dimension
|
||||
RRDDIM *rd;
|
||||
rrddim_foreach_read(rd, st) {
|
||||
if(rd->collections_counter) {
|
||||
if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
|
||||
|
||||
buffer_sprintf(wb, "%s\n"
|
||||
"\t\t\t\"%s\": {\n"
|
||||
|
|
|
@ -51,7 +51,7 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
|
|||
size_t dimensions = 0;
|
||||
RRDDIM *rd;
|
||||
rrddim_foreach_read(rd, st) {
|
||||
if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) continue;
|
||||
if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN) || rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) continue;
|
||||
|
||||
memory += rd->memsize;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue