/****************************************************************************** * * * Function: DMcolect_table_data * * * * Purpose: obtain configuration changes to required node * * * * Return value: SUCCESS - processed successfully * * FAIL - an error occurred * * * * Author: Alexander Vladishev * * * * Comments: the changes are collected into data parameter * * * ******************************************************************************/ static void DMcollect_table_data(int nodeid, unsigned char dest_nodetype, const ZBX_TABLE *table, char **data, size_t *data_alloc, size_t *data_offset) { #define ZBX_REC_UPDATED '1' #define ZBX_REC_DELETED '2' const char *__function_name = "DMcolect_table_data"; DB_RESULT result; DB_RESULT result2; DB_ROW row; DB_ROW row2; const char *s; char *hex = NULL, *sql = NULL, sync[128], *curr_cksum, *d_curr_cksum, *prev_cksum, *d_prev_cksum; size_t sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0, hex_alloc = ZBX_KIBIBYTE, rowlen; int f, j; zabbix_log(LOG_LEVEL_DEBUG, "In %s() table:'%s'", __function_name, table->table); hex = zbx_malloc(hex, hex_alloc); sql = zbx_malloc(sql, sql_alloc); result = DBselect( /* new records */ "select curr.recordid,prev.cksum,curr.cksum,curr.sync" " from node_cksum curr" " left join node_cksum prev" " on prev.nodeid=curr.nodeid" " and prev.tablename=curr.tablename" " and prev.recordid=curr.recordid" " and prev.cksumtype=%d" " where curr.nodeid=%d" " and curr.tablename='%s'" " and curr.cksumtype=%d" " and prev.tablename is null" " union all " /* updated records */ "select curr.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum curr,node_cksum prev" " where curr.nodeid=prev.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.nodeid=%d" " and curr.tablename='%s'" " and curr.cksumtype=%d" " and prev.cksumtype=%d" " union all " /* deleted records */ "select prev.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum prev" " left join node_cksum curr" " on curr.nodeid=prev.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.cksumtype=%d" " where prev.nodeid=%d" " and prev.tablename='%s'" " and prev.cksumtype=%d" " and curr.tablename is null", NODE_CKSUM_TYPE_OLD, nodeid, table->table, NODE_CKSUM_TYPE_NEW, nodeid, table->table, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, NODE_CKSUM_TYPE_NEW, nodeid, table->table, NODE_CKSUM_TYPE_OLD); while (NULL != (row = DBfetch(result))) { memset(sync, ' ', sizeof(sync)); memcpy(sync, row[3], strlen(row[3])); s = sync; /* special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[2])) { if (ZBX_REC_DELETED != s[dest_nodetype]) { zbx_snprintf_alloc(data, data_alloc, data_offset, "\n%s%c%s%c%d", table->table, ZBX_DM_DELIMITER, row[0], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_DELETE); } continue; } prev_cksum = (SUCCEED == DBis_null(row[1]) ? NULL : row[1]); curr_cksum = row[2]; f = 0; sql_offset = 0; zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select "); do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d_prev_cksum = NULL; if (NULL != prev_cksum && NULL != (d_prev_cksum = strchr(prev_cksum, ','))) *d_prev_cksum = '\0'; d_curr_cksum = NULL; if (NULL != curr_cksum && NULL != (d_curr_cksum = strchr(curr_cksum, ','))) *d_curr_cksum = '\0'; if (NULL == prev_cksum || NULL == curr_cksum || ZBX_REC_UPDATED != s[dest_nodetype] || 0 != strcmp(prev_cksum, curr_cksum)) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s,", table->fields[f].name); if (table->fields[f].type == ZBX_TYPE_BLOB) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "length(%s),", table->fields[f].name); } } /* "host_inventory" table has more than 64 fields */ /* remaining fields are processed as one */ if (126 > s - sync) s += 2; f++; if (d_prev_cksum != NULL) { *d_prev_cksum = ','; prev_cksum = d_prev_cksum + 1; } else prev_cksum = NULL; if (d_curr_cksum != NULL) { *d_curr_cksum = ','; curr_cksum = d_curr_cksum + 1; } else curr_cksum = NULL; } while (NULL != d_prev_cksum || NULL != d_curr_cksum); if (sql[sql_offset - 1] != ',') continue; sql_offset--; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " from %s where %s=%s", table->table, table->recid, row[0]); result2 = DBselect("%s", sql); if (NULL == (row2 = DBfetch(result2))) goto out; zbx_snprintf_alloc(data, data_alloc, data_offset, "\n%s%c%s%c%d", table->table, ZBX_DM_DELIMITER, row[0], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_UPDATE); prev_cksum = DBis_null(row[1]) == SUCCEED ? NULL : row[1]; curr_cksum = row[2]; s = sync; f = 0; j = 0; do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d_prev_cksum = NULL; if (NULL != prev_cksum && NULL != (d_prev_cksum = strchr(prev_cksum, ','))) *d_prev_cksum = '\0'; d_curr_cksum = NULL; if (NULL != curr_cksum && NULL != (d_curr_cksum = strchr(curr_cksum, ','))) *d_curr_cksum = '\0'; if (NULL == prev_cksum || NULL == curr_cksum || ZBX_REC_UPDATED != s[dest_nodetype] || 0 != strcmp(prev_cksum, curr_cksum)) { /* fieldname, type */ zbx_snprintf_alloc(data, data_alloc, data_offset, "%c%s%c%d%c", ZBX_DM_DELIMITER, table->fields[f].name, ZBX_DM_DELIMITER, table->fields[f].type, ZBX_DM_DELIMITER); /* value */ if (SUCCEED == DBis_null(row2[j])) { zbx_strcpy_alloc(data, data_alloc, data_offset, "NULL"); } else if (ZBX_TYPE_INT == table->fields[f].type || ZBX_TYPE_UINT == table->fields[f].type || ZBX_TYPE_ID == table->fields[f].type || ZBX_TYPE_FLOAT == table->fields[f].type) { zbx_strcpy_alloc(data, data_alloc, data_offset, row2[j]); } else { if (table->fields[f].type == ZBX_TYPE_BLOB) rowlen = (size_t)atoi(row2[j + 1]); else rowlen = strlen(row2[j]); zbx_binary2hex((u_char *)row2[j], rowlen, &hex, &hex_alloc); zbx_strcpy_alloc(data, data_alloc, data_offset, hex); } if (table->fields[f].type == ZBX_TYPE_BLOB) j += 2; else j++; } /* "host_inventory" table has more than 64 fields */ /* remaining fields are processed as one */ if (126 > s - sync) s += 2; f++; if (d_prev_cksum != NULL) { *d_prev_cksum = ','; prev_cksum = d_prev_cksum + 1; } else prev_cksum = NULL; if (d_curr_cksum != NULL) { *d_curr_cksum = ','; curr_cksum = d_curr_cksum + 1; } else curr_cksum = NULL; } while (NULL != d_prev_cksum || NULL != d_curr_cksum); out: DBfree_result(result2); } DBfree_result(result); zbx_free(hex); zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * 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: get_config_data * * * * Purpose: obtain configuration changes to required node * * * * Parameters: * * * * Return value: SUCCESS - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ char *get_config_data(int nodeid, int dest_nodetype) { const char *__function_name = "get_config_data"; DB_RESULT result; DB_RESULT result2; DB_ROW row; DB_ROW row2; const ZBX_TABLE *table; char *data = NULL, *hex = NULL, *sql = NULL, c[2], sync[129], *s, *r[2], *d[2]; int data_offset = 0, sql_offset = 0; int data_allocated = 1024, hex_allocated = 1024, sql_allocated = 8192; int f, j, rowlen; zabbix_log(LOG_LEVEL_DEBUG, "In %s() node:%d dest_nodetype:%s", __function_name, nodeid, (dest_nodetype == ZBX_NODE_MASTER) ? "MASTER" : "SLAVE"); data = zbx_malloc(data, data_allocated); hex = zbx_malloc(hex, hex_allocated); sql = zbx_malloc(sql, sql_allocated); c[0] = '1'; /* for new and updated records */ c[1] = '2'; /* for deleted records */ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 16, "Data%c%d%c%d", ZBX_DM_DELIMITER, CONFIG_NODEID, ZBX_DM_DELIMITER, nodeid); /* Find updated records */ result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum curr, node_cksum prev " "where curr.nodeid=%d and prev.nodeid=curr.nodeid and " "curr.tablename=prev.tablename and curr.recordid=prev.recordid and " "curr.cksumtype=%d and prev.cksumtype=%d " "union all " /* Find new records */ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,curr.sync " "from node_cksum curr left join node_cksum prev " "on prev.nodeid=curr.nodeid and prev.tablename=curr.tablename and " "prev.recordid=curr.recordid and prev.cksumtype=%d " "where curr.nodeid=%d and curr.cksumtype=%d and prev.tablename is null " "union all " /* Find deleted records */ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum prev left join node_cksum curr " "on curr.nodeid=prev.nodeid and curr.tablename=prev.tablename and " "curr.recordid=prev.recordid and curr.cksumtype=%d " "where prev.nodeid=%d and prev.cksumtype=%d and curr.tablename is null", nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, NODE_CKSUM_TYPE_OLD, nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_NEW, nodeid, NODE_CKSUM_TYPE_OLD); while (NULL != (row = DBfetch(result))) { /* Found table */ if (NULL == (table = DBget_table(row[0]))) { zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", row[0]); continue; } if (FAIL == DBis_null(row[4])) zbx_strlcpy(sync, row[4], sizeof(sync)); else memset(sync, ' ', sizeof(sync)); s = sync; /* Special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[3])) { if ((dest_nodetype == ZBX_NODE_SLAVE && s[0] != c[1]) || (dest_nodetype == ZBX_NODE_MASTER && s[1] != c[1])) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n%s%c%s%c%d", row[0], ZBX_DM_DELIMITER, row[1], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_DELETE); } continue; } r[0] = (SUCCEED == DBis_null(row[2]) ? NULL : row[2]); r[1] = row[3]; f = 0; sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "select "); do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (NULL == r[0] || NULL == r[1] || (ZBX_NODE_SLAVE == dest_nodetype && s[0] != c[0]) || (ZBX_NODE_MASTER == dest_nodetype && s[1] != c[0]) || 0 != strcmp(r[0], r[1])) { zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "%s,", table->fields[f].name); if (table->fields[f].type == ZBX_TYPE_BLOB) { zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "length(%s),", table->fields[f].name); } } s += 2; f++; if (d[0] != NULL) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (d[1] != NULL) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (NULL != d[0] || NULL != d[1]); if (sql[sql_offset-1] != ',') continue; sql_offset--; zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, " from %s where %s=%s", row[0], table->recid, row[1]); result2 = DBselect("%s", sql); if (NULL == (row2 = DBfetch(result2))) goto out; zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n%s%c%s%c%d", row[0], ZBX_DM_DELIMITER, row[1], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_UPDATE); r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; r[1] = row[3]; s = sync; f = 0; j = 0; do { while ((table->fields[f].flags & ZBX_SYNC) == 0) f++; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c[0]) || (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c[0]) || strcmp(r[0], r[1]) != 0) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%c%s%c%d%c", ZBX_DM_DELIMITER, table->fields[f].name, ZBX_DM_DELIMITER, table->fields[f].type, ZBX_DM_DELIMITER); /* Fieldname, type, value */ if (SUCCEED == DBis_null(row2[j])) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 5, "NULL"); } else 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", row2[j]); } else { if (ZBX_TYPE_BLOB == table->fields[f].type) rowlen = atoi(row2[j + 1]); else rowlen = strlen(row2[j]); zbx_binary2hex((u_char *)row2[j], rowlen, &hex, &hex_allocated); zbx_snprintf_alloc(&data, &data_allocated, &data_offset, strlen(hex) + 128, "%s", hex); } if (ZBX_TYPE_BLOB == table->fields[f].type) j += 2; else j++; } s += 2; f++; if (NULL != d[0]) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (NULL != d[1]) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (NULL != d[0] || NULL != d[1]); out: DBfree_result(result2); } DBfree_result(result); zbx_free(hex); zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); return data; }