/****************************************************************************** * * * Function: calculate_checksums * * * * Purpose: calculate checksums of configuration data * * * * Parameters: * * * * Return value: SUCCESS - calculated successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t recordid) { const char *__function_name = "calculate_checksums"; char *sql = NULL; size_t sql_alloc = 2 * ZBX_KIBIBYTE, sql_offset = 0; int t, f, res = SUCCEED; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); sql = zbx_malloc(sql, sql_alloc); zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from node_cksum" " where nodeid=%d" " and cksumtype=%d", nodeid, NODE_CKSUM_TYPE_NEW); if (NULL != tablename) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and tablename='%s'", tablename); if (0 != recordid) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and recordid=" ZBX_FS_UI64, recordid); if (ZBX_DB_OK > DBexecute("%s", sql)) res = FAIL; for (t = 0; NULL != tables[t].table; t++) { if (0 == (tables[t].flags & ZBX_SYNC)) continue; if (NULL != tablename && 0 != strcmp(tablename, tables[t].table)) continue; sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)" " select %d,'%s',%s,%d,", nodeid, tables[t].table, tables[t].recid, NODE_CKSUM_TYPE_NEW); #ifdef HAVE_MYSQL zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "concat_ws(',',"); #endif for (f = 0; NULL != tables[t].fields[f].name; f++) { const ZBX_FIELD *field = &tables[t].fields[f]; if (0 == (field->flags & ZBX_SYNC)) continue; if (field->flags & ZBX_NOTNULL) { switch (field->type) { case ZBX_TYPE_ID: case ZBX_TYPE_INT: case ZBX_TYPE_UINT: zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, field->name); break; case ZBX_TYPE_FLOAT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "md5(cast(%s as char))", field->name); break; default: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "md5(%s)", field->name); break; } } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "case when %s is null then 'NULL'", field->name); switch (field->type) { case ZBX_TYPE_ID: case ZBX_TYPE_INT: case ZBX_TYPE_UINT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else cast(%s as char) end", field->name); break; case ZBX_TYPE_FLOAT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else md5(cast(%s as char)) end", field->name); break; default: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else md5(%s) end", field->name); break; } } #ifdef HAVE_MYSQL zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ','); #else zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "||','||"); #endif } /* remove last delimiter */ if (f > 0) { #ifdef HAVE_MYSQL sql_offset--; zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')'); #else sql_offset -= 7; #endif } zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " from %s", tables[t].table); if (0 != recordid) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=" ZBX_FS_UI64, tables[t].recid, recordid); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where 1=1" DB_NODE, DBnode(tables[t].recid, nodeid)); } if (ZBX_DB_OK > DBexecute("%s", sql)) { res = FAIL; break; } } zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res)); return res; }
/****************************************************************************** * * * Function : process_hstory_table_data: * * * * Purpose: process new history data * * * * Parameters: * * * * Return value: * * * * Author: Aleksander Vladishev * * * * Comments: * * * ******************************************************************************/ void process_history_table_data(ZBX_TABLE *table, int master_nodeid, int nodeid) { DB_RESULT result; DB_ROW row; char *data = NULL, *tmp = NULL; int data_allocated = 1024*1024, tmp_allocated = 4096, tmp_offset, data_offset, f, fld, len; int data_found = 0; zbx_uint64_t lastid; int lastclock = 0, clock; zabbix_log( LOG_LEVEL_DEBUG, "In process_history_table_data()"); DBbegin(); if ((table->flags & ZBX_HISTORY) && FAIL == get_history_lastid(master_nodeid, nodeid, table, &lastid)) return; if ((table->flags & ZBX_HISTORY_TRENDS) && FAIL == get_trends_lastid(master_nodeid, nodeid, table, &lastid, &lastclock)) return; data = zbx_malloc(data, data_allocated); tmp = zbx_malloc(tmp, tmp_allocated); data_offset = 0; zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "History%c%d%c%d%c%s", ZBX_DM_DELIMITER, CONFIG_NODEID, ZBX_DM_DELIMITER, nodeid, ZBX_DM_DELIMITER, table->table); /* Do not send history for current node if CONFIG_NODE_NOHISTORY is set */ /* if ((CONFIG_NODE_NOHISTORY != 0) && (CONFIG_NODEID == nodeid)) goto exit;*/ tmp_offset = 0; if (table->flags & ZBX_HISTORY_SYNC) { zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "select %s,", table->recid); } else { /* ZBX_HISTORY, ZBX_HISTORY_TRENDS */ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16, "select "); } for (f = 0; table->fields[f].name != 0; f++) { if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s,", table->fields[f].name); } tmp_offset--; if (table->flags & ZBX_HISTORY_SYNC) { zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where nodeid=%d order by %s", table->table, nodeid, table->recid); } else if (table->flags & ZBX_HISTORY_TRENDS) { clock = time(NULL) - 600; /* -10min */ clock -= clock % 3600; zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where" " (itemid>"ZBX_FS_UI64" or (itemid="ZBX_FS_UI64" and clock>%d)) and clock<%d" DB_NODE " order by itemid,clock", table->table, lastid, lastid, lastclock, clock, DBnode("itemid", nodeid)); } else { /* ZBX_HISTORY */ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where %s>"ZBX_FS_UI64 DB_NODE " order by %s", table->table, table->recid, lastid, DBnode(table->recid, nodeid), table->recid); } result = DBselectN(tmp, 10000); while (NULL != (row = DBfetch(result))) { if (table->flags & ZBX_HISTORY_SYNC) { ZBX_STR2UINT64(lastid, row[0]); fld = 1; } else fld = 0; zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n"); for (f = 0; table->fields[f].name != 0; f++) { if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; if (table->fields[f].type == ZBX_TYPE_INT || table->fields[f].type == ZBX_TYPE_UINT || table->fields[f].type == ZBX_TYPE_ID || table->fields[f].type == ZBX_TYPE_FLOAT) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c", row[fld], ZBX_DM_DELIMITER); } else { /* ZBX_TYPE_CHAR ZBX_TYPE_BLOB ZBX_TYPE_TEXT */ len = (int)strlen(row[fld]); len = zbx_binary2hex((u_char *)row[fld], len, &tmp, &tmp_allocated); zbx_snprintf_alloc(&data, &data_allocated, &data_offset, len + 8, "%s%c", tmp, ZBX_DM_DELIMITER); } fld++; } data_offset--; data_found = 1; } DBfree_result(result); data[data_offset] = '\0'; if (1 == data_found && SUCCEED == send_to_node(table->table, master_nodeid, nodeid, data)) { if (table->flags & ZBX_HISTORY_SYNC) { DBexecute("delete from %s where nodeid=%d and %s<="ZBX_FS_UI64, table->table, nodeid, table->recid, lastid); } } DBcommit(); zbx_free(tmp); zbx_free(data); }
/****************************************************************************** * * * Function: send_history_last_id * * * * Purpose: send list of last historical tables IDs * * * * Parameters: sock - opened socket of node-node connection * * record * * * * Return value: SUCCEED - sent successfully * * FAIL - an error occurred * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ int send_history_last_id(zbx_sock_t *sock, const char *data) { DB_RESULT result; DB_ROW row; const char *r; const ZBX_TABLE *table; size_t buffer_offset; int sender_nodeid = (-1), nodeid = (-1), res; zabbix_log(LOG_LEVEL_DEBUG, "In send_history_last_id()"); buffer_alloc = 320; buffer = zbx_malloc(buffer, buffer_alloc); r = data; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* constant 'ZBX_GET_HISTORY_LAST_ID' */ if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* sender_nodeid */ sender_nodeid = atoi(buffer); if (NULL == r) goto error; if (FAIL == is_direct_slave_node(sender_nodeid)) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received data from node %d that is not a direct slave node [%s]", CONFIG_NODEID, sender_nodeid, data); goto fail; } zbx_get_next_field(&r, &buffer, &buffer_alloc, '\n'); /* nodeid */ nodeid = atoi(buffer); if (NULL == r) goto error; if (FAIL == is_slave_node(CONFIG_NODEID, nodeid)) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received data for unknown slave node %d [%s]", CONFIG_NODEID, nodeid, data); goto fail; } zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* table name */ if (NULL == (table = DBget_table(buffer))) goto error; if (0 == (table->flags & ZBX_HISTORY)) goto error; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* field name */ if (0 != strcmp(buffer, table->recid)) goto error; buffer_offset= 0; zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, "select max(%s)" " from %s" " where 1=1" DB_NODE, table->recid, table->table, DBnode(table->recid, nodeid)); buffer_offset= 0; result = DBselect("%s", buffer); if (NULL != (row = DBfetch(result))) zbx_strcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, SUCCEED == DBis_null(row[0]) ? "0" : row[0]); DBfree_result(result); if (buffer_offset == 0) goto error; alarm(CONFIG_TIMEOUT); res = send_data_to_node(sender_nodeid, sock, buffer); alarm(0); zbx_free(buffer); return res; error: zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", CONFIG_NODEID, sender_nodeid, nodeid, data); fail: buffer_offset= 0; zbx_strcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, "FAIL"); alarm(CONFIG_TIMEOUT); res = send_data_to_node(sender_nodeid, sock, buffer); alarm(0); zbx_free(buffer); return FAIL; }