netdata/database/rrdcalc.c

757 lines
24 KiB
C

// SPDX-License-Identifier: GPL-3.0-or-later
#define NETDATA_HEALTH_INTERNALS
#include "rrd.h"
// ----------------------------------------------------------------------------
// RRDCALC management
inline const char *rrdcalc_status2string(RRDCALC_STATUS status) {
switch(status) {
case RRDCALC_STATUS_REMOVED:
return "REMOVED";
case RRDCALC_STATUS_UNDEFINED:
return "UNDEFINED";
case RRDCALC_STATUS_UNINITIALIZED:
return "UNINITIALIZED";
case RRDCALC_STATUS_CLEAR:
return "CLEAR";
case RRDCALC_STATUS_RAISED:
return "RAISED";
case RRDCALC_STATUS_WARNING:
return "WARNING";
case RRDCALC_STATUS_CRITICAL:
return "CRITICAL";
default:
error("Unknown alarm status %d", status);
return "UNKNOWN";
}
}
static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
RRDHOST *host = st->rrdhost;
debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
rc->last_status_change = now_realtime_sec();
rc->rrdset = st;
rc->rrdset_next = st->alarms;
rc->rrdset_prev = NULL;
if(rc->rrdset_next)
rc->rrdset_next->rrdset_prev = rc;
st->alarms = rc;
if(rc->update_every < rc->rrdset->update_every) {
error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
rc->update_every = rc->rrdset->update_every;
}
if(!isnan(rc->green) && isnan(st->green)) {
debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from " NETDATA_DOUBLE_FORMAT_AUTO
" to " NETDATA_DOUBLE_FORMAT_AUTO ".", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
st->green = rc->green;
}
if(!isnan(rc->red) && isnan(st->red)) {
debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from " NETDATA_DOUBLE_FORMAT_AUTO " to " NETDATA_DOUBLE_FORMAT_AUTO
".", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
st->red = rc->red;
}
rc->local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_LOCAL_VAR, &rc->value);
rc->family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_FAMILY_VAR, &rc->value);
char fullname[RRDVAR_MAX_LENGTH + 1];
snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
rc->hostid = rrdvar_create_and_index("host", &host->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTID_VAR, &rc->value);
snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
rc->hostname = rrdvar_create_and_index("host", &host->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTNAME_VAR, &rc->value);
if(rc->hostid && !rc->hostname)
rc->hostid->options |= RRDVAR_OPTION_RRDCALC_HOST_CHARTNAME_VAR;
if(!rc->units) rc->units = strdupz(st->units);
time_t now = now_realtime_sec();
ALARM_ENTRY *ae = health_create_alarm_entry(
host,
rc->id,
rc->next_event_id++,
rc->config_hash_id,
now,
rc->name,
rc->rrdset->id,
rc->rrdset->family,
rc->classification,
rc->component,
rc->type,
rc->exec,
rc->recipient,
now - rc->last_status_change,
rc->old_value,
rc->value,
rc->status,
RRDCALC_STATUS_UNINITIALIZED,
rc->source,
rc->units,
rc->info,
0,
0);
health_alarm_log(host, ae);
}
static int rrdcalc_is_matching_rrdset(RRDCALC *rc, RRDSET *st) {
if((rc->hash_chart != st->hash || strcmp(rc->chart, st->id) != 0) &&
(rc->hash_chart != st->hash_name || strcmp(rc->chart, st->name) != 0))
return 0;
if (rc->module_pattern && !simple_pattern_matches(rc->module_pattern, st->module_name))
return 0;
if (rc->plugin_pattern && !simple_pattern_matches(rc->plugin_pattern, st->plugin_name))
return 0;
if (st->rrdhost->host_labels && rc->host_labels_pattern && !rrdlabels_match_simple_pattern_parsed(st->rrdhost->host_labels, rc->host_labels_pattern, '='))
return 0;
return 1;
}
// this has to be called while the RRDHOST is locked
inline void rrdsetcalc_link_matching(RRDSET *st) {
RRDHOST *host = st->rrdhost;
// debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
RRDCALC *rc;
for(rc = host->alarms; rc ; rc = rc->next) {
if(unlikely(rc->rrdset))
continue;
if(unlikely(rrdcalc_is_matching_rrdset(rc, st)))
rrdsetcalc_link(st, rc);
}
}
// this has to be called while the RRDHOST is locked
inline void rrdsetcalc_unlink(RRDCALC *rc) {
RRDSET *st = rc->rrdset;
if(!st) {
debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
return;
}
RRDHOST *host = st->rrdhost;
time_t now = now_realtime_sec();
ALARM_ENTRY *ae = health_create_alarm_entry(
host,
rc->id,
rc->next_event_id++,
rc->config_hash_id,
now,
rc->name,
rc->rrdset->id,
rc->rrdset->family,
rc->classification,
rc->component,
rc->type,
rc->exec,
rc->recipient,
now - rc->last_status_change,
rc->old_value,
rc->value,
rc->status,
RRDCALC_STATUS_REMOVED,
rc->source,
rc->units,
rc->info,
0,
0);
health_alarm_log(host, ae);
debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
// unlink it
if(rc->rrdset_prev)
rc->rrdset_prev->rrdset_next = rc->rrdset_next;
if(rc->rrdset_next)
rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
if(st->alarms == rc)
st->alarms = rc->rrdset_next;
rc->rrdset_prev = rc->rrdset_next = NULL;
rrdvar_free(host, &st->rrdvar_root_index, rc->local);
rc->local = NULL;
rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rc->family);
rc->family = NULL;
rrdvar_free(host, &host->rrdvar_root_index, rc->hostid);
rc->hostid = NULL;
rrdvar_free(host, &host->rrdvar_root_index, rc->hostname);
rc->hostname = NULL;
rc->rrdset = NULL;
// RRDCALC will remain in RRDHOST
// so that if the matching chart is found in the future
// it will be applied automatically
}
RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
RRDCALC *rc;
uint32_t hash = simple_hash(name);
for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
return rc;
}
return NULL;
}
inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
RRDCALC *rc;
if(unlikely(!chart)) {
error("attempt to find RRDCALC '%s' without giving a chart name", name);
return 1;
}
if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
if(unlikely(!hash_name)) hash_name = simple_hash(name);
// make sure it does not already exist
for(rc = host->alarms; rc ; rc = rc->next) {
if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
info("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
return 1;
}
}
return 0;
}
inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
if(chart && name) {
uint32_t hash_chart = simple_hash(chart);
uint32_t hash_name = simple_hash(name);
// re-use old IDs, by looking them up in the alarm log
ALARM_ENTRY *ae;
for(ae = host->health_log.alarms; ae ;ae = ae->next) {
if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
return ae->alarm_id;
}
}
}
if (unlikely(!host->health_log.next_alarm_id))
host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
return host->health_log.next_alarm_id++;
}
/**
* Alarm name with dimension
*
* Change the name of the current alarm appending a new diagram.
*
* @param name the alarm name
* @param namelen is the length of the previous vector.
* @param dim the dimension of the chart.
* @param dimlen is the length of the previous vector.
*
* @return It returns the new name on success and the old otherwise
*/
char *alarm_name_with_dim(char *name, size_t namelen, const char *dim, size_t dimlen) {
char *newname,*move;
newname = mallocz(namelen + dimlen + 2);
move = newname;
memcpy(move, name, namelen);
move += namelen;
*move++ = '_';
memcpy(move, dim, dimlen);
move += dimlen;
*move = '\0';
return newname;
}
/**
* Remove pipe comma
*
* Remove the pipes and commas converting to space.
*
* @param str the string to change.
*/
void dimension_remove_pipe_comma(char *str) {
while(*str) {
if(*str == '|' || *str == ',') *str = ' ';
str++;
}
}
inline void rrdcalc_add_to_host(RRDHOST *host, RRDCALC *rc) {
rrdhost_check_rdlock(host);
if(rc->calculation) {
rc->calculation->status = &rc->status;
rc->calculation->myself = &rc->value;
rc->calculation->after = &rc->db_after;
rc->calculation->before = &rc->db_before;
rc->calculation->rrdcalc = rc;
}
if(rc->warning) {
rc->warning->status = &rc->status;
rc->warning->myself = &rc->value;
rc->warning->after = &rc->db_after;
rc->warning->before = &rc->db_before;
rc->warning->rrdcalc = rc;
}
if(rc->critical) {
rc->critical->status = &rc->status;
rc->critical->myself = &rc->value;
rc->critical->after = &rc->db_after;
rc->critical->before = &rc->db_before;
rc->critical->rrdcalc = rc;
}
if(!rc->foreachdim) {
// link it to the host alarms list
if(likely(host->alarms)) {
// append it
RRDCALC *t;
for(t = host->alarms; t && t->next ; t = t->next) ;
t->next = rc;
}
else {
host->alarms = rc;
}
// link it to its chart
RRDSET *st;
rrdset_foreach_read(st, host) {
if(rrdcalc_is_matching_rrdset(rc, st)) {
rrdsetcalc_link(st, rc);
break;
}
}
} else {
//link it case there is a foreach
if(likely(host->alarms_with_foreach)) {
// append it
RRDCALC *t;
for(t = host->alarms_with_foreach; t && t->next ; t = t->next) ;
t->next = rc;
}
else {
host->alarms_with_foreach = rc;
}
//I am not linking this alarm direct to the host here, this will be done when the children is created
}
}
inline RRDCALC *rrdcalc_create_from_template(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
if(rrdcalc_exists(host, chart, rt->name, 0, 0))
return NULL;
RRDCALC *rc = callocz(1, sizeof(RRDCALC));
rc->next_event_id = 1;
rc->name = strdupz(rt->name);
rc->hash = simple_hash(rc->name);
rc->chart = strdupz(chart);
rc->hash_chart = simple_hash(rc->chart);
uuid_copy(rc->config_hash_id, rt->config_hash_id);
rc->id = rrdcalc_get_unique_id(host, rc->chart, rc->name, &rc->next_event_id);
if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
if(rt->foreachdim) {
rc->foreachdim = strdupz(rt->foreachdim);
rc->spdim = health_pattern_from_foreach(rc->foreachdim);
}
rc->foreachcounter = rt->foreachcounter;
rc->green = rt->green;
rc->red = rt->red;
rc->value = NAN;
rc->old_value = NAN;
rc->delay_up_duration = rt->delay_up_duration;
rc->delay_down_duration = rt->delay_down_duration;
rc->delay_max_duration = rt->delay_max_duration;
rc->delay_multiplier = rt->delay_multiplier;
rc->last_repeat = 0;
rc->times_repeat = 0;
rc->warn_repeat_every = rt->warn_repeat_every;
rc->crit_repeat_every = rt->crit_repeat_every;
rc->group = rt->group;
rc->after = rt->after;
rc->before = rt->before;
rc->update_every = rt->update_every;
rc->options = rt->options;
if(rt->exec) rc->exec = strdupz(rt->exec);
if(rt->recipient) rc->recipient = strdupz(rt->recipient);
if(rt->source) rc->source = strdupz(rt->source);
if(rt->units) rc->units = strdupz(rt->units);
if(rt->info) rc->info = strdupz(rt->info);
if (rt->classification) rc->classification = strdupz(rt->classification);
if (rt->component) rc->component = strdupz(rt->component);
if (rt->type) rc->type = strdupz(rt->type);
if(rt->calculation) {
rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
if(!rc->calculation)
error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
}
if(rt->warning) {
rc->warning = expression_parse(rt->warning->source, NULL, NULL);
if(!rc->warning)
error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
}
if(rt->critical) {
rc->critical = expression_parse(rt->critical->source, NULL, NULL);
if(!rc->critical)
error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
}
debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green " NETDATA_DOUBLE_FORMAT_AUTO
", red " NETDATA_DOUBLE_FORMAT_AUTO
", lookup: group %d, after %d, before %d, options %u, dimensions '%s', for each dimension '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f, warn_repeat_every %u, crit_repeat_every %u",
(rc->chart)?rc->chart:"NOCHART",
rc->name,
(rc->exec)?rc->exec:"DEFAULT",
(rc->recipient)?rc->recipient:"DEFAULT",
rc->green,
rc->red,
(int)rc->group,
rc->after,
rc->before,
rc->options,
(rc->dimensions)?rc->dimensions:"NONE",
(rc->foreachdim)?rc->foreachdim:"NONE",
rc->update_every,
(rc->calculation)?rc->calculation->parsed_as:"NONE",
(rc->warning)?rc->warning->parsed_as:"NONE",
(rc->critical)?rc->critical->parsed_as:"NONE",
rc->source,
rc->delay_up_duration,
rc->delay_down_duration,
rc->delay_max_duration,
rc->delay_multiplier,
rc->warn_repeat_every,
rc->crit_repeat_every
);
rrdcalc_add_to_host(host, rc);
if(!rt->foreachdim) {
RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_health_log,(avl_t *)rc);
if (rdcmp != rc) {
error("Cannot insert the alarm index ID %s",rc->name);
}
}
return rc;
}
/**
* Create from RRDCALC
*
* Create a new alarm using another alarm as template.
*
* @param rc is the alarm that will be used as source
* @param host is the host structure.
* @param name is the newest chart name.
* @param dimension is the current dimension
* @param foreachdim the whole list of dimension
*
* @return it returns the new alarm changed.
*/
inline RRDCALC *rrdcalc_create_from_rrdcalc(RRDCALC *rc, RRDHOST *host, const char *name, const char *dimension) {
RRDCALC *newrc = callocz(1, sizeof(RRDCALC));
newrc->next_event_id = 1;
newrc->id = rrdcalc_get_unique_id(host, rc->chart, name, &rc->next_event_id);
newrc->name = (char *)name;
newrc->hash = simple_hash(newrc->name);
newrc->chart = strdupz(rc->chart);
newrc->hash_chart = simple_hash(rc->chart);
uuid_copy(newrc->config_hash_id, *((uuid_t *) &rc->config_hash_id));
newrc->dimensions = strdupz(dimension);
newrc->foreachdim = NULL;
rc->foreachcounter++;
newrc->foreachcounter = rc->foreachcounter;
newrc->green = rc->green;
newrc->red = rc->red;
newrc->value = NAN;
newrc->old_value = NAN;
newrc->delay_up_duration = rc->delay_up_duration;
newrc->delay_down_duration = rc->delay_down_duration;
newrc->delay_max_duration = rc->delay_max_duration;
newrc->delay_multiplier = rc->delay_multiplier;
newrc->last_repeat = 0;
newrc->times_repeat = 0;
newrc->warn_repeat_every = rc->warn_repeat_every;
newrc->crit_repeat_every = rc->crit_repeat_every;
newrc->group = rc->group;
newrc->after = rc->after;
newrc->before = rc->before;
newrc->update_every = rc->update_every;
newrc->options = rc->options;
if(rc->exec) newrc->exec = strdupz(rc->exec);
if(rc->recipient) newrc->recipient = strdupz(rc->recipient);
if(rc->source) newrc->source = strdupz(rc->source);
if(rc->units) newrc->units = strdupz(rc->units);
if(rc->info) newrc->info = strdupz(rc->info);
if (rc->classification) newrc->classification = strdupz(rc->classification);
if (rc->component) newrc->component = strdupz(rc->component);
if (rc->type) newrc->type = strdupz(rc->type);
if(rc->calculation) {
newrc->calculation = expression_parse(rc->calculation->source, NULL, NULL);
if(!newrc->calculation)
error("Health alarm '%s.%s': failed to parse calculation expression '%s'", rc->chart, rc->name, rc->calculation->source);
}
if(rc->warning) {
newrc->warning = expression_parse(rc->warning->source, NULL, NULL);
if(!newrc->warning)
error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", rc->chart, rc->name, rc->warning->source);
}
if(rc->critical) {
newrc->critical = expression_parse(rc->critical->source, NULL, NULL);
if(!newrc->critical)
error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", rc->chart, rc->name, rc->critical->source);
}
return newrc;
}
void rrdcalc_free(RRDCALC *rc) {
if(unlikely(!rc)) return;
expression_free(rc->calculation);
expression_free(rc->warning);
expression_free(rc->critical);
freez(rc->name);
freez(rc->chart);
freez(rc->family);
freez(rc->dimensions);
freez(rc->foreachdim);
freez(rc->exec);
freez(rc->recipient);
freez(rc->source);
freez(rc->units);
freez(rc->info);
freez(rc->classification);
freez(rc->component);
freez(rc->type);
simple_pattern_free(rc->spdim);
freez(rc->host_labels);
simple_pattern_free(rc->host_labels_pattern);
freez(rc->module_match);
simple_pattern_free(rc->module_pattern);
freez(rc->plugin_match);
simple_pattern_free(rc->plugin_pattern);
freez(rc);
}
void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc) {
if(unlikely(!rc)) return;
debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
// unlink it from RRDSET
if(rc->rrdset) rrdsetcalc_unlink(rc);
// unlink it from RRDHOST
if(unlikely(rc == host->alarms))
host->alarms = rc->next;
else {
RRDCALC *t;
for(t = host->alarms; t && t->next != rc; t = t->next) ;
if(t) {
t->next = rc->next;
rc->next = NULL;
}
else
error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
}
RRDCALC *rdcmp = (RRDCALC *) avl_search_lock(&(host)->alarms_idx_health_log, (avl_t *)rc);
if (rdcmp) {
rdcmp = (RRDCALC *) avl_remove_lock(&(host)->alarms_idx_health_log, (avl_t *)rc);
if (!rdcmp) {
error("Cannot remove the health alarm index from health_log");
}
}
rdcmp = (RRDCALC *) avl_search_lock(&(host)->alarms_idx_name, (avl_t *)rc);
if (rdcmp) {
rdcmp = (RRDCALC *) avl_remove_lock(&(host)->alarms_idx_name, (avl_t *)rc);
if (!rdcmp) {
error("Cannot remove the health alarm index from idx_name");
}
}
rrdcalc_free(rc);
}
void rrdcalc_foreach_unlink_and_free(RRDHOST *host, RRDCALC *rc) {
if(unlikely(rc == host->alarms_with_foreach))
host->alarms_with_foreach = rc->next;
else {
RRDCALC *t;
for(t = host->alarms_with_foreach; t && t->next != rc; t = t->next) ;
if(t) {
t->next = rc->next;
rc->next = NULL;
}
else
error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
}
rrdcalc_free(rc);
}
static void rrdcalc_labels_unlink_alarm_loop(RRDHOST *host, RRDCALC *alarms) {
for(RRDCALC *rc = alarms ; rc ; rc = rc->next ) {
if (!rc->host_labels) continue;
if(!rrdlabels_match_simple_pattern_parsed(host->host_labels, rc->host_labels_pattern, '=')) {
info("Health configuration for alarm '%s' cannot be applied, because the host %s does not have the label(s) '%s'",
rc->name,
host->hostname,
rc->host_labels);
if(host->alarms == alarms)
rrdcalc_unlink_and_free(host, rc);
else
rrdcalc_foreach_unlink_and_free(host, rc);
}
}
}
void rrdcalc_labels_unlink_alarm_from_host(RRDHOST *host) {
rrdcalc_labels_unlink_alarm_loop(host, host->alarms);
rrdcalc_labels_unlink_alarm_loop(host, host->alarms_with_foreach);
}
void rrdcalc_labels_unlink() {
rrd_rdlock();
RRDHOST *host;
rrdhost_foreach_read(host) {
if (unlikely(!host->health_enabled))
continue;
if (host->host_labels) {
rrdhost_wrlock(host);
rrdcalc_labels_unlink_alarm_from_host(host);
rrdhost_unlock(host);
}
}
rrd_unlock();
}
// ----------------------------------------------------------------------------
// Alarm
/**
* Alarm is repeating
*
* Is this alarm repeating ?
*
* @param host The structure that has the binary tree
* @param alarm_id the id of the alarm to search
*
* @return It returns 1 case it is repeating and 0 otherwise
*/
int alarm_isrepeating(RRDHOST *host, uint32_t alarm_id) {
RRDCALC findme;
findme.id = alarm_id;
RRDCALC *rc = (RRDCALC *)avl_search_lock(&host->alarms_idx_health_log, (avl_t *)&findme);
if (!rc) {
return 0;
}
return rrdcalc_isrepeating(rc);
}
/**
* Entry is repeating
*
* Check whether the id of alarm entry is yet present in the host structure
*
* @param host The structure that has the binary tree
* @param ae the alarm entry
*
* @return It returns 1 case it is repeating and 0 otherwise
*/
int alarm_entry_isrepeating(RRDHOST *host, ALARM_ENTRY *ae) {
return alarm_isrepeating(host, ae->alarm_id);
}
/**
* Max last repeat
*
* Check the maximum last_repeat for the alarms associated a host
*
* @param host The structure that has the binary tree
*
* @return It returns 1 case it is repeating and 0 otherwise
*/
RRDCALC *alarm_max_last_repeat(RRDHOST *host, char *alarm_name,uint32_t hash) {
RRDCALC findme;
findme.name = alarm_name;
findme.hash = hash;
RRDCALC *rc = (RRDCALC *)avl_search_lock(&host->alarms_idx_name, (avl_t *)&findme);
return rc;
}