/********************************************************************************* * * * Function: db_read_values_by_time * * * * Purpose: reads item history data from database * * * * Parameters: itemid - [IN] the itemid * * value_type - [IN] the value type (see ITEM_VALUE_TYPE_* defs) * * values - [OUT] the item history data values * * seconds - [IN] the time period to read * * end_timestamp - [IN] the value timestamp to start reading with * * * * Return value: SUCCEED - the history data were read successfully * * FAIL - otherwise * * * * Comments: This function reads all values with timestamps in range: * * end_timestamp - seconds < <value timestamp> <= end_timestamp * * * *********************************************************************************/ static int db_read_values_by_time(zbx_uint64_t itemid, int value_type, zbx_vector_history_record_t *values, int seconds, int end_timestamp) { char *sql = NULL; size_t sql_alloc = 0, sql_offset = 0; DB_RESULT result; DB_ROW row; zbx_vc_history_table_t *table = &vc_history_tables[value_type]; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select clock,ns,%s" " from %s" " where itemid=" ZBX_FS_UI64, table->fields, table->name, itemid); if (1 == seconds) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock=%d", end_timestamp); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock>%d and clock<=%d", end_timestamp - seconds, end_timestamp); } result = DBselect("%s", sql); zbx_free(sql); if (NULL == result) goto out; while (NULL != (row = DBfetch(result))) { zbx_history_record_t value; value.timestamp.sec = atoi(row[0]); value.timestamp.ns = atoi(row[1]); table->rtov(&value.value, row + 2); zbx_vector_history_record_append_ptr(values, &value); } DBfree_result(result); out: return SUCCEED; }
/************************************************************************************ * * * Function: db_read_values_by_time_and_count * * * * Purpose: reads item history data from database * * * * Parameters: itemid - [IN] the itemid * * value_type - [IN] the value type (see ITEM_VALUE_TYPE_* defs) * * values - [OUT] the item history data values * * seconds - [IN] the time period to read * * count - [IN] the number of values to read * * end_timestamp - [IN] the value timestamp to start reading with * * * * Return value: SUCCEED - the history data were read successfully * * FAIL - otherwise * * * * Comments: this function reads <count> values from <seconds> period before * * <count_timestamp> (including) plus all values in range: * * count_timestamp < <value timestamp> <= read_timestamp * * * ************************************************************************************/ static int db_read_values_by_time_and_count(zbx_uint64_t itemid, int value_type, zbx_vector_history_record_t *values, int seconds, int count, int end_timestamp) { int ret = FAIL; char *sql = NULL; size_t sql_alloc = 0, sql_offset; DB_RESULT result; DB_ROW row; zbx_vc_history_table_t *table = &vc_history_tables[value_type]; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select clock,ns,%s" " from %s" " where itemid=" ZBX_FS_UI64, table->fields, table->name, itemid); if (1 == seconds) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock=%d", end_timestamp); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock>%d and clock<=%d order by clock desc", end_timestamp - seconds, end_timestamp); } result = DBselectN(sql, count); zbx_free(sql); if (NULL == result) goto out; while (NULL != (row = DBfetch(result)) && 0 < count--) { zbx_history_record_t value; value.timestamp.sec = atoi(row[0]); value.timestamp.ns = atoi(row[1]); table->rtov(&value.value, row + 2); zbx_vector_history_record_append_ptr(values, &value); } DBfree_result(result); if (0 < count) { /* no more data in the specified time period, return success */ ret = SUCCEED; goto out; } /* Drop data from the last second and read the whole second again */ /* to ensure that data is cached by seconds. */ /* Because the initial select has limit option (DBselectN()) we have */ /* to perform another select to read the last second data. */ end_timestamp = values->values[values->values_num - 1].timestamp.sec; while (0 < values->values_num && values->values[values->values_num - 1].timestamp.sec == end_timestamp) { values->values_num--; zbx_history_record_clear(&values->values[values->values_num], value_type); } ret = db_read_values_by_time(itemid, value_type, values, 1, end_timestamp); out: zbx_free(sql); return ret; }
/************************************************************************************ * * * Function: db_read_values_by_count * * * * Purpose: reads item history data from database * * * * Parameters: itemid - [IN] the itemid * * value_type - [IN] the value type (see ITEM_VALUE_TYPE_* defs) * * values - [OUT] the item history data values * * count - [IN] the number of values to read * * end_timestamp - [IN] the value timestamp to start reading with * * * * Return value: SUCCEED - the history data were read successfully * * FAIL - otherwise * * * * Comments: this function reads <count> values before <count_timestamp> (including)* * plus all values in range: * * count_timestamp < <value timestamp> <= read_timestamp * * * * To speed up the reading time with huge data loads, data is read by * * smaller time segments (hours, day, week, month) and the next (larger) * * time segment is read only if the requested number of values (<count>) * * is not yet retrieved. * * * ************************************************************************************/ static int db_read_values_by_count(zbx_uint64_t itemid, int value_type, zbx_vector_history_record_t *values, int count, int end_timestamp) { char *sql = NULL; size_t sql_alloc = 0, sql_offset; int clock_to, clock_from, step = 0, ret = FAIL; DB_RESULT result; DB_ROW row; zbx_vc_history_table_t *table = &vc_history_tables[value_type]; const int periods[] = {SEC_PER_HOUR, SEC_PER_DAY, SEC_PER_WEEK, SEC_PER_MONTH, 0, -1}; clock_to = end_timestamp; while (-1 != periods[step] && 0 < count) { if (0 > (clock_from = clock_to - periods[step])) { clock_from = clock_to; step = 4; } sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select clock,ns,%s" " from %s" " where itemid=" ZBX_FS_UI64 " and clock<=%d", table->fields, table->name, itemid, clock_to); if (clock_from != clock_to) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock>%d", clock_from); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by clock desc"); result = DBselectN(sql, count); if (NULL == result) goto out; while (NULL != (row = DBfetch(result))) { zbx_history_record_t value; value.timestamp.sec = atoi(row[0]); value.timestamp.ns = atoi(row[1]); table->rtov(&value.value, row + 2); zbx_vector_history_record_append_ptr(values, &value); count--; } DBfree_result(result); clock_to -= periods[step]; step++; } if (0 < count) { /* no more data in database, return success */ ret = SUCCEED; goto out; } /* drop data from the last second and read the whole second again */ /* to ensure that data is cached by seconds */ end_timestamp = values->values[values->values_num - 1].timestamp.sec; while (0 < values->values_num && values->values[values->values_num - 1].timestamp.sec == end_timestamp) { values->values_num--; zbx_history_record_clear(&values->values[values->values_num], value_type); } ret = db_read_values_by_time(itemid, value_type, values, 1, end_timestamp); out: zbx_free(sql); return ret; }
/****************************************************************************** * * * Function: evaluate_aggregate * * * * Parameters: item - [IN] aggregated item * * grp_func - [IN] one of ZBX_GRP_FUNC_* * * groups - [IN] list of comma-separated host groups * * itemkey - [IN] item key to aggregate * * item_func - [IN] one of ZBX_VALUE_FUNC_* * * param - [IN] item_func parameter (optional) * * * * Return value: SUCCEED - aggregate item evaluated successfully * * FAIL - otherwise * * * ******************************************************************************/ static int evaluate_aggregate(DC_ITEM *item, AGENT_RESULT *res, int grp_func, const char *groups, const char *itemkey, int item_func, const char *param) { const char *__function_name = "evaluate_aggregate"; zbx_vector_uint64_t itemids; history_value_t value, item_result; zbx_history_record_t group_value; int ret = FAIL, now, *errcodes = NULL, i, count; DC_ITEM *items = NULL; zbx_vector_history_record_t values, group_values; unsigned int seconds; zabbix_log(LOG_LEVEL_DEBUG, "In %s() grp_func:%d groups:'%s' itemkey:'%s' item_func:%d param:'%s'", __function_name, grp_func, groups, itemkey, item_func, ZBX_NULL2STR(param)); now = time(NULL); zbx_vector_uint64_create(&itemids); aggregate_get_items(&itemids, groups, itemkey); if (0 == itemids.values_num) { SET_MSG_RESULT(res, zbx_dsprintf(NULL, "No items for key \"%s\" in group(s) \"%s\".", itemkey, groups)); goto clean1; } memset(&value, 0, sizeof(value)); zbx_history_record_vector_create(&group_values); items = zbx_malloc(items, sizeof(DC_ITEM) * itemids.values_num); errcodes = zbx_malloc(errcodes, sizeof(int) * itemids.values_num); DCconfig_get_items_by_itemids(items, itemids.values, errcodes, itemids.values_num); if (ZBX_VALUE_FUNC_LAST == item_func) { count = 1; seconds = 0; } else { if (FAIL == is_uint_suffix(param, &seconds)) { SET_MSG_RESULT(res, zbx_strdup(NULL, "Invalid fourth parameter.")); goto clean2; } count = 0; } for (i = 0; i < itemids.values_num; i++) { if (SUCCEED != errcodes[i]) continue; if (ITEM_STATUS_ACTIVE != items[i].status) continue; if (HOST_STATUS_MONITORED != items[i].host.status) continue; if (ITEM_VALUE_TYPE_FLOAT != items[i].value_type && ITEM_VALUE_TYPE_UINT64 != items[i].value_type) continue; zbx_history_record_vector_create(&values); if (SUCCEED == zbx_vc_get_value_range(items[i].itemid, items[i].value_type, &values, seconds, count, now) && 0 < values.values_num) { evaluate_history_func(&values, items[i].value_type, item_func, &item_result); if (item->value_type == items[i].value_type) group_value.value = item_result; else { if (ITEM_VALUE_TYPE_UINT64 == item->value_type) group_value.value.ui64 = (zbx_uint64_t)item_result.dbl; else group_value.value.dbl = (double)item_result.ui64; } zbx_vector_history_record_append_ptr(&group_values, &group_value); } zbx_history_record_vector_destroy(&values, items[i].value_type); } if (0 == group_values.values_num) { SET_MSG_RESULT(res, zbx_dsprintf(NULL, "No values for key \"%s\" in group(s) \"%s\"", itemkey, groups)); goto clean2; } evaluate_history_func(&group_values, item->value_type, grp_func, &value); if (ITEM_VALUE_TYPE_FLOAT == item->value_type) SET_DBL_RESULT(res, value.dbl); else SET_UI64_RESULT(res, value.ui64); ret = SUCCEED; clean2: DCconfig_clean_items(items, errcodes, itemids.values_num); zbx_free(errcodes); zbx_free(items); zbx_history_record_vector_destroy(&group_values, item->value_type); clean1: zbx_vector_uint64_destroy(&itemids); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }