/****************************************************************************** * * * Function: process_deleted_records * * * * Purpose: * * * * Parameters: * * * * Return value: * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static void process_deleted_records(int nodeid, char *data, int sender_nodetype) { const char *__function_name = "process_deleted_records"; char *r, *lf; const ZBX_TABLE *table = NULL; zbx_uint64_t recid, *ids = NULL; int ids_alloc = 0, ids_num = 0; char *sql = NULL; size_t sql_alloc = 4 * ZBX_KIBIBYTE, sql_offset = 0; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); sql = zbx_malloc(sql, sql_alloc); DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); for (r = data; '\0' != *r;) { if (NULL != (lf = strchr(r, '\n'))) *lf = '\0'; zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (NULL == table || 0 != strcmp(table->table, buf)) { make_delete_sql(&sql, &sql_alloc, &sql_offset, table, ids, &ids_num); if (NULL == (table = DBget_table(buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find table [%s]", __function_name, buf); goto next; } } zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); ZBX_STR2UINT64(recid, buf); if ('2' == *r) /* NODE_CONFIGLOG_OP_DELETE */ uint64_array_add(&ids, &ids_alloc, &ids_num, recid, 64); next: if (lf != NULL) { *lf++ = '\n'; r = lf; } else break; } make_delete_sql(&sql, &sql_alloc, &sql_offset, table, ids, &ids_num); DBend_multiple_update(&sql, &sql_alloc, &sql_offset); if (sql_offset > 16) /* In ORACLE always present begin..end; */ DBexecute("%s", sql); zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: process_record_event * * * * Purpose: process record update * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * ******************************************************************************/ static int process_record_event(int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record) { const char *r; int f, source = 0, object = 0, value = 0, acknowledged = 0; unsigned char value_changed = 0; zbx_uint64_t eventid = 0, objectid = 0; zbx_timespec_t ts; zabbix_log(LOG_LEVEL_DEBUG, "In process_record_event()"); ts.sec = 0; ts.ns = 0; r = record; for (f = 0; NULL != table->fields[f].name; f++) { if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); if (0 == strcmp(table->fields[f].name, "eventid")) ZBX_STR2UINT64(eventid, buffer); else if (0 == strcmp(table->fields[f].name, "source")) source = atoi(buffer); else if (0 == strcmp(table->fields[f].name, "object")) object = atoi(buffer); else if (0 == strcmp(table->fields[f].name, "objectid")) ZBX_STR2UINT64(objectid, buffer); else if (0 == strcmp(table->fields[f].name, "clock")) ts.sec = atoi(buffer); else if (0 == strcmp(table->fields[f].name, "ns")) ts.ns = atoi(buffer); else if (0 == strcmp(table->fields[f].name, "value")) value = atoi(buffer); else if (0 == strcmp(table->fields[f].name, "value_changed")) value_changed = (unsigned char)atoi(buffer); else if (0 == strcmp(table->fields[f].name, "acknowledged")) acknowledged = atoi(buffer); } return process_event(eventid, source, object, objectid, &ts, value, value_changed, acknowledged, 0); error: zabbix_log(LOG_LEVEL_ERR, "NODE %d: received invalid record from node %d for node %d [%s]", CONFIG_NODEID, sender_nodeid, nodeid, record); return FAIL; }
/****************************************************************************** * * * Function: process_record * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occured * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int process_record(int nodeid, const char *record, int sender_nodetype) { char fieldname[ZBX_FIELDNAME_LEN_MAX]; zbx_uint64_t recid; int op, res = SUCCEED; int valuetype; char *value_esc; const ZBX_TABLE *table; DB_RESULT result; DB_ROW row; const char *r; char *buffer = NULL, *tmp = NULL, *fields_update = NULL, *fields = NULL, *values = NULL; int buffer_allocated = 16*1024, buffer_len, fieldname_len; int tmp_allocated = 16*1024, tmp_offset = 0; int fields_update_allocated = 16*1024, fields_update_offset = 0; int fields_allocated = 4*1024, fields_offset = 0; int values_allocated = 16*1024, values_offset = 0; zabbix_log( LOG_LEVEL_DEBUG, "In process_record [%s]", record); r = record; buffer = zbx_malloc(buffer, buffer_allocated); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); if (NULL == (table = DBget_table(buffer))) { zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", buffer); res = FAIL; goto out; } zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); ZBX_STR2UINT64(recid, buffer); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); op = atoi(buffer); if (op == NODE_CONFIGLOG_OP_DELETE) { DBexecute("delete from %s where %s=" ZBX_FS_UI64, table->table, table->recid, recid); goto out; } tmp = zbx_malloc(tmp, tmp_allocated); fields_update = zbx_malloc(fields_update, fields_update_allocated); fields = zbx_malloc(fields, fields_allocated); values = zbx_malloc(values, values_allocated); zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", table->recid); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, ZBX_FS_UI64",", recid); while (NULL != r) { fieldname_len = zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); zbx_strlcpy(fieldname, buffer, sizeof(fieldname)); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); valuetype=atoi(buffer); buffer_len = zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); if (op == NODE_CONFIGLOG_OP_UPDATE) { if (0 == strcmp(buffer, "NULL")) { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + 8, "%s=NULL,", fieldname); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 8, "NULL,"); } else { if (valuetype == ZBX_TYPE_INT || valuetype == ZBX_TYPE_UINT || valuetype == ZBX_TYPE_ID || valuetype == ZBX_TYPE_FLOAT) { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 4, "%s=%s,", fieldname, buffer); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 4, "%s,", buffer); } else if (valuetype == ZBX_TYPE_BLOB) { if (*buffer == '\0') { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + 8, "%s='',", fieldname); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 8, "'',"); } else { #if defined(HAVE_POSTGRESQL) buffer_len = zbx_hex2binary(buffer); buffer_len = zbx_pg_escape_bytea((u_char *)buffer, buffer_len, &tmp, &tmp_allocated); zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s='%s',", fieldname, tmp); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "'%s',", tmp); #else zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s=0x%s,", fieldname, buffer); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "0x%s,", buffer); #endif } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string(buffer); buffer_len = strlen(value_esc); zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s='%s',", fieldname, value_esc); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "'%s',", value_esc); zbx_free(value_esc) } } zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, fieldname_len + 4, "%s,", fieldname); } else { zabbix_log( LOG_LEVEL_WARNING, "Unknown record operation [%d]", op); res = FAIL; goto out; } }
/****************************************************************************** * * * 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; }
/****************************************************************************** * * * Function: node_history * * * * Purpose: process new history received from a slave node * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int node_history(char *data, size_t datalen) { const char *r; char *newline = NULL; char *pos; int sender_nodeid = 0, nodeid = 0, firstline = 1, events = 0, history = 0, acknowledges = 0; const ZBX_TABLE *table_sync = NULL, *table = NULL; int res = SUCCEED; char *sql1 = NULL, *sql2 = NULL, *sql3 = NULL; size_t sql1_alloc, sql2_alloc, sql3_alloc; size_t sql1_offset, sql2_offset, sql3_offset; zbx_vector_uint64_t ack_eventids; assert(data); zabbix_log(LOG_LEVEL_DEBUG, "In node_history()"); buffer_alloc = 4 * ZBX_KIBIBYTE; sql1_alloc = 32 * ZBX_KIBIBYTE; sql2_alloc = 32 * ZBX_KIBIBYTE; sql3_alloc = 32 * ZBX_KIBIBYTE; tmp_alloc = 4 * ZBX_KIBIBYTE; buffer = zbx_malloc(buffer, buffer_alloc); sql1 = zbx_malloc(sql1, sql1_alloc); sql2 = zbx_malloc(sql2, sql2_alloc); sql3 = zbx_malloc(sql3, sql3_alloc); tmp = zbx_malloc(tmp, tmp_alloc); zbx_vector_uint64_create(&ack_eventids); DBbegin(); for (r = data; *r != '\0' && res == SUCCEED;) { if (NULL != (newline = strchr(r, '\n'))) *newline = '\0'; if (1 == firstline) { zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* constant 'History' */ zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* sender_nodeid */ sender_nodeid=atoi(buffer); zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* nodeid */ nodeid=atoi(buffer); zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); /* tablename */ 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", CONFIG_NODEID, sender_nodeid); res = FAIL; } if (FAIL == is_slave_node(CONFIG_NODEID, nodeid)) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received history for unknown slave node %d", CONFIG_NODEID, nodeid); res = FAIL; } table = DBget_table(buffer); if (NULL != table && 0 == (table->flags & (ZBX_HISTORY | ZBX_HISTORY_SYNC))) table = NULL; if (NULL != table && 0 != (table->flags & ZBX_HISTORY_SYNC)) { table_sync = table; if (NULL != (pos = strstr(buffer, "_sync"))) { *pos = '\0'; table = DBget_table(buffer); } } if (NULL == table) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Invalid received data: unknown tablename \"%s\"", CONFIG_NODEID, buffer); res = FAIL; } else { if (0 == strcmp(table->table, "events")) events = 1; if (0 == strncmp(table->table, "history", 7)) history = 1; if (0 == strcmp(table->table, "acknowledges")) acknowledges = 1; } if (NULL != newline) { zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received %s from node %d for node %d datalen " ZBX_FS_SIZE_T, CONFIG_NODEID, buffer, sender_nodeid, nodeid, (zbx_fs_size_t)datalen); } firstline = 0; sql1_offset = 0; sql2_offset = 0; sql3_offset = 0; } else if (NULL != table) { if (events) { res = process_record_event(sender_nodeid, nodeid, table, r); } else { res = process_record(&sql1, &sql1_alloc, &sql1_offset, sender_nodeid, nodeid, table, r, newline ? 0 : 1, acknowledges, &ack_eventids); if (SUCCEED == res && 0 != history) { res = process_items(&sql2, &sql2_alloc, &sql2_offset, sender_nodeid, nodeid, table, r, newline ? 0 : 1); } if (SUCCEED == res && NULL != table_sync && 0 != CONFIG_MASTER_NODEID) { res = process_record(&sql3, &sql3_alloc, &sql3_offset, sender_nodeid, nodeid, table_sync, r, newline ? 0 : 1, 0, NULL); } } } if (newline != NULL) { *newline = '\n'; r = newline + 1; } else break; } if (SUCCEED == res) DBcommit(); else DBrollback(); zbx_vector_uint64_destroy(&ack_eventids); zbx_free(tmp); zbx_free(sql1); zbx_free(sql2); zbx_free(sql3); zbx_free(buffer); return res; }
/****************************************************************************** * * * Function: update_items * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: * * * * Comments: * * * ******************************************************************************/ static int process_items(char **sql, size_t *sql_alloc, size_t *sql_offset, int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, int lastrecord) { const char *r; int f, res = FAIL; zbx_uint64_t itemid = 0; char *value_esc; int clock, value_type = -1; double value_double; zbx_uint64_t value_uint64; zabbix_log(LOG_LEVEL_DEBUG, "In process_items()"); if (*sql_offset == 0) DBbegin_multiple_update(sql, sql_alloc, sql_offset); zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update items set prevvalue=lastvalue"); for (r = record, f = 0; table->fields[f].name != 0; f++) { if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); if (0 == strcmp(table->fields[f].name, "itemid")) ZBX_STR2UINT64(itemid, buffer); 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) { if (0 == strcmp(table->fields[f].name, "clock")) { zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastclock=%s", buffer); clock = atoi(buffer); } else if (0 == strcmp(table->fields[f].name, "value")) { zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastvalue=%s", buffer); value_type = table->fields[f].type; if (value_type == ZBX_TYPE_FLOAT) value_double = atof(buffer); else if (value_type == ZBX_TYPE_UINT) ZBX_STR2UINT64(value_uint64, buffer); } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { if (0 == strcmp(table->fields[f].name, "value")) { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string_len(buffer, ITEM_LASTVALUE_LEN); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastvalue='%s'", value_esc); zbx_free(value_esc); } } } if (value_type == ZBX_TYPE_FLOAT) DBadd_trend(itemid, value_double, clock); else if (value_type == ZBX_TYPE_UINT) DBadd_trend_uint(itemid, value_uint64, clock); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where itemid=" ZBX_FS_UI64 ";\n", itemid); if (lastrecord || *sql_offset > ZBX_MAX_SQL_SIZE) { DBend_multiple_update(sql, sql_alloc, sql_offset); if (DBexecute("%s", *sql) >= ZBX_DB_OK) res = SUCCEED; *sql_offset = 0; } else res = SUCCEED; 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, record); return FAIL; }
/****************************************************************************** * * * Function: process_record * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int process_record(char **sql, size_t *sql_alloc, size_t *sql_offset, int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, int lastrecord, int acknowledges, zbx_vector_uint64_t *ack_eventids) { const char *r; int f, res = FAIL; char *value_esc; zabbix_log(LOG_LEVEL_DEBUG, "In process_record()"); if (0 == *sql_offset) { DBbegin_multiple_update(sql, sql_alloc, sql_offset); #ifdef HAVE_MULTIROW_INSERT begin_history_sql(sql, sql_alloc, sql_offset, table); #endif } #if !defined(HAVE_MULTIROW_INSERT) begin_history_sql(sql, sql_alloc, sql_offset, table); #endif zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '('); if (0 != (table->flags & ZBX_HISTORY_SYNC)) zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%d,", nodeid); for (r = record, f = 0; table->fields[f].name != 0; f++) { if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); if (0 != acknowledges && 0 == strcmp(table->fields[f].name, "eventid")) { zbx_uint64_t eventid; ZBX_STR2UINT64(eventid, buffer); zbx_vector_uint64_append(ack_eventids, eventid); } 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(sql, sql_alloc, sql_offset, "%s,", buffer); } else if (table->fields[f].type == ZBX_TYPE_BLOB) { if ('\0' == *buffer) zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "'',"); else { #ifdef HAVE_POSTGRESQL size_t len; len = zbx_hex2binary(buffer); zbx_pg_escape_bytea((u_char *)buffer, len, &tmp, &tmp_alloc); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "'%s',", tmp); #else zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "0x%s,", buffer); #endif } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string(buffer); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "'%s',", value_esc); zbx_free(value_esc); } } (*sql_offset)--; #ifdef HAVE_MULTIROW_INSERT zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "),"); #else zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ");\n"); #endif if (0 != lastrecord || *sql_offset > ZBX_MAX_SQL_SIZE) { #ifdef HAVE_MULTIROW_INSERT (*sql_offset)--; zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ";\n"); #endif DBend_multiple_update(sql, sql_alloc, sql_offset); if (ZBX_DB_OK <= DBexecute("%s", *sql)) res = SUCCEED; *sql_offset = 0; if (SUCCEED == res && 0 != lastrecord && 0 != acknowledges && 0 != ack_eventids->values_num) { zbx_vector_uint64_sort(ack_eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); zbx_vector_uint64_uniq(ack_eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update events" " set acknowledged=1" " where"); DBadd_condition_alloc(sql, sql_alloc, sql_offset, "eventid", ack_eventids->values, ack_eventids->values_num); if (ZBX_DB_OK > DBexecute("%s", *sql)) res = FAIL; *sql_offset = 0; } } else res = SUCCEED; 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, record); return FAIL; }
/****************************************************************************** * * * Function: node_sync * * * * Purpose: process configuration changes received from a node * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int node_sync(char *data, int *sender_nodeid, int *nodeid) { const char *r; char *lf; int datalen, res = SUCCEED; unsigned char sender_nodetype; datalen = strlen(data); zabbix_log(LOG_LEVEL_DEBUG, "In node_sync() len:%d", datalen); tmp = zbx_malloc(tmp, tmp_alloc); if (NULL != (lf = strchr(data, '\n'))) *lf = '\0'; r = data; zbx_get_next_field(&r, &tmp, &tmp_alloc, ZBX_DM_DELIMITER); /* Data */ zbx_get_next_field(&r, &tmp, &tmp_alloc, ZBX_DM_DELIMITER); *sender_nodeid = atoi(tmp); sender_nodetype = (*sender_nodeid == CONFIG_MASTER_NODEID) ? ZBX_NODE_MASTER : ZBX_NODE_SLAVE; zbx_get_next_field(&r, &tmp, &tmp_alloc, ZBX_DM_DELIMITER); *nodeid = atoi(tmp); if (0 != *sender_nodeid && 0 != *nodeid) { if (CONFIG_MASTER_NODEID != *sender_nodeid && FAIL == is_direct_slave_node(*sender_nodeid)) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received configuration changes from unknown node %d", CONFIG_NODEID, *sender_nodeid); res = FAIL; goto quit; } if (CONFIG_MASTER_NODEID != *sender_nodeid && CONFIG_NODEID == *nodeid) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received configuration changes for this node from a non-master node %d", CONFIG_NODEID, *sender_nodeid); res = FAIL; goto quit; } if (CONFIG_NODEID != *nodeid && FAIL == is_slave_node(CONFIG_NODEID, *nodeid)) { zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received configuration changes for unknown node %d", CONFIG_NODEID, *nodeid); res = FAIL; goto quit; } zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received configuration changes from %s node %d for node %d datalen %d", CONFIG_NODEID, zbx_nodetype_string(sender_nodetype), *sender_nodeid, *nodeid, datalen); DBexecute("delete from node_cksum where nodeid=%d and cksumtype=%d", *nodeid, NODE_CKSUM_TYPE_NEW); if (lf != NULL) { *lf++ = '\n'; data = lf; buf = zbx_malloc(buf, buf_alloc); process_updated_records(*nodeid, data); process_deleted_records(*nodeid, data); process_checksum(*nodeid, data, sender_nodetype); zbx_free(buf); } } quit: zbx_free(tmp); return res; }
/****************************************************************************** * * * Function: process_checksum * * * * Author: Alexander Vladishev * * * ******************************************************************************/ static void process_checksum(int nodeid, char *data, unsigned char sender_nodetype) { const char *__function_name = "process_checksum"; char *r, *lf; size_t tmp_offset; const ZBX_TABLE *table = NULL; zbx_uint64_t recid; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); for (r = data; '\0' != *r;) { if (NULL != (lf = strchr(r, '\n'))) *lf = '\0'; zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* table name */ if (NULL == table || 0 != strcmp(table->table, buf)) { if (NULL == (table = DBget_table(buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find table [%s]", __function_name, buf); goto next; } } zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* record id */ ZBX_STR2UINT64(recid, buf); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* operation type */ if ('0' == *buf) /* NODE_CONFIGLOG_OP_UPDATE */ { *tmp = '\0'; tmp_offset = 0; while (NULL != r) { /* field name */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (0 != tmp_offset) zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ','); zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, buf); /* field type */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* value */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); } if (SUCCEED == calculate_checksums(nodeid, table->table, recid)) update_checksums(nodeid, sender_nodetype, SUCCEED, table->table, recid, tmp); } next: if (NULL != lf) { *lf++ = '\n'; r = lf; } else break; } zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: process_deleted_records * * * * Purpose: * * * * Parameters: * * * * Return value: * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static void process_deleted_records(int nodeid, char *data) { const char *__function_name = "process_deleted_records"; typedef struct { const ZBX_TABLE *table; zbx_vector_uint64_t recids; void *next; } zbx_records_t; char *r, *lf; zbx_uint64_t recid; char *sql = NULL; size_t sql_alloc = 4 * ZBX_KIBIBYTE, sql_offset = 0; zbx_records_t *first = NULL, *rec; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); for (r = data; '\0' != *r;) { if (NULL != (lf = strchr(r, '\n'))) *lf = '\0'; zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* table name */ if (NULL == first || 0 != strcmp(first->table->table, buf)) { rec = zbx_malloc(NULL, sizeof(zbx_records_t)); if (NULL == (rec->table = DBget_table(buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find table [%s]", __function_name, buf); zbx_free(rec); goto next; } zbx_vector_uint64_create(&rec->recids); rec->next = first; first = rec; } zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* record id */ ZBX_STR2UINT64(recid, buf); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); /* operation type */ if ('2' == *buf) /* deleted record */ zbx_vector_uint64_append(&rec->recids, recid); next: if (lf != NULL) { *lf++ = '\n'; r = lf; } else break; } sql = zbx_malloc(sql, sql_alloc); DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); for (rec = first; NULL != rec; rec = rec->next) { if (0 == rec->recids.values_num) continue; zbx_vector_uint64_sort(&rec->recids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from %s where", rec->table->table); DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, rec->table->recid, rec->recids.values, rec->recids.values_num); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); } DBend_multiple_update(&sql, &sql_alloc, &sql_offset); if (sql_offset > 16) /* in ORACLE always present begin..end; */ DBexecute("%s", sql); zbx_free(sql); while (NULL != first) { rec = first; first = rec->next; zbx_vector_uint64_destroy(&rec->recids); zbx_free(rec); } zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: process_updated_records * * * * Purpose: * * * * Parameters: * * * * Return value: * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static void process_updated_records(int nodeid, char *data) { const char *__function_name = "process_updated_records"; char *r, *lf, *value_esc; int op, dnum; const ZBX_TABLE *table = NULL; const ZBX_FIELD *field = NULL; zbx_uint64_t recid; char *dsql = NULL, *isql = NULL, *ifld = NULL, *ival = NULL, *usql = NULL, *ufld = NULL; size_t dsql_alloc = 4 * ZBX_KIBIBYTE, dsql_offset = 0, dtmp_offset = 0, isql_alloc = 4 * ZBX_KIBIBYTE, isql_offset = 0, ifld_alloc = 4 * ZBX_KIBIBYTE, ifld_offset = 0, ival_alloc = 4 * ZBX_KIBIBYTE, ival_offset = 0, usql_alloc = 4 * ZBX_KIBIBYTE, usql_offset = 0, ufld_alloc = 4 * ZBX_KIBIBYTE, ufld_offset = 0; DB_RESULT result; DB_ROW row; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); dsql = zbx_malloc(dsql, dsql_alloc); isql = zbx_malloc(isql, isql_alloc); ifld = zbx_malloc(ifld, ifld_alloc); ival = zbx_malloc(ival, ival_alloc); usql = zbx_malloc(usql, usql_alloc); ufld = zbx_malloc(ufld, ufld_alloc); #ifdef HAVE_ORACLE DBbegin_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBbegin_multiple_update(&isql, &isql_alloc, &isql_offset); DBbegin_multiple_update(&usql, &usql_alloc, &usql_offset); #endif for (r = data; '\0' != *r;) { if (NULL != (lf = strchr(r, '\n'))) *lf = '\0'; /* table name */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (NULL == table || 0 != strcmp(table->table, buf)) { if (NULL == (table = DBget_table(buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find table [%s]", __function_name, buf); goto next; } } /* record id */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); ZBX_STR2UINT64(recid, buf); if (NULL == r) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): invalid record", __function_name); goto next; } if ('0' == *r) /* NODE_CONFIGLOG_OP_UPDATE */ { result = DBselect("select 0 from %s where %s=" ZBX_FS_UI64, table->table, table->recid, recid); if (NULL == (row = DBfetch(result))) op = NODE_CONFIGLOG_OP_ADD; else op = NODE_CONFIGLOG_OP_UPDATE; DBfree_result(result); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); ifld_offset = 0; ival_offset = 0; ufld_offset = 0; dtmp_offset = dsql_offset; dnum = 0; if (op == NODE_CONFIGLOG_OP_ADD && NULL != table->uniq) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "delete from %s where ", table->table); } while (NULL != r) { /* field name */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (NULL == (field = DBget_field(table, buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find field [%s.%s]", __function_name, table->table, buf); goto next; } if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s=", buf); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ifld, &ifld_alloc, &ifld_offset, "%s,", buf); /* value type (ignored) */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (0 == strcmp(buf, "NULL")) { if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_strcpy_alloc(&ufld, &ufld_alloc, &ufld_offset, "NULL,"); else /* NODE_CONFIGLOG_OP_ADD */ zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "NULL,"); continue; } switch (field->type) { case ZBX_TYPE_ID: /* if the field relates the same table * for example: host.proxy_hostid relates with host.hostid */ if (NODE_CONFIGLOG_OP_ADD == op && NULL != field->fk_table && 0 == strcmp(table->table, field->fk_table)) { zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s=%s,", field->name, buf); zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "NULL,"); break; } case ZBX_TYPE_INT: case ZBX_TYPE_UINT: case ZBX_TYPE_FLOAT: if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s,", buf); else /* NODE_CONFIGLOG_OP_ADD */ { zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "%s,", buf); if (NULL != table->uniq && SUCCEED == str_in_list(table->uniq, field->name, ',')) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "%s=%s and ", field->name, buf); dnum++; } } break; case ZBX_TYPE_BLOB: if ('\0' == *buf) { if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_strcpy_alloc(&ufld, &ufld_alloc, &ufld_offset, "'',"); else /* NODE_CONFIGLOG_OP_ADD */ zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "'',"); } else { #if defined(HAVE_POSTGRESQL) size_t len; len = zbx_hex2binary(buf); DBbytea_escape((u_char *)buf, len, &tmp, &tmp_alloc); if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "'%s',", tmp); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "'%s',", tmp); #else if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "0x%s,", buf); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "0x%s,", buf); #endif } break; default: /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ zbx_hex2binary(buf); value_esc = DBdyn_escape_string(buf); if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "'%s',", value_esc); else /* NODE_CONFIGLOG_OP_ADD */ { zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "'%s',", value_esc); if (NULL != table->uniq && SUCCEED == str_in_list(table->uniq, field->name, ',')) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "%s='%s' and ", field->name, value_esc); dnum++; } } zbx_free(value_esc); } } if (dsql_offset != dtmp_offset) { if (dnum != num_param(table->uniq)) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): missing required fields [%s][%s]", __function_name, table->table, table->uniq); dsql_offset = dtmp_offset; goto next; } dsql_offset -= 5; zbx_strcpy_alloc(&dsql, &dsql_alloc, &dsql_offset, ";\n"); } if (0 != ifld_offset) { ifld[--ifld_offset] = '\0'; ival[--ival_offset] = '\0'; zbx_snprintf_alloc(&isql, &isql_alloc, &isql_offset, "insert into %s (%s,%s) values (" ZBX_FS_UI64 ",%s);\n", table->table, table->recid, ifld, recid, ival); } if (0 != ufld_offset) { ufld[--ufld_offset] = '\0'; zbx_snprintf_alloc(&usql, &usql_alloc, &usql_offset, "update %s set %s where %s=" ZBX_FS_UI64 ";\n", table->table, ufld, table->recid, recid); } if (dsql_offset > ZBX_MAX_SQL_SIZE || isql_offset > ZBX_MAX_SQL_SIZE || usql_offset > ZBX_MAX_SQL_SIZE) { DBend_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBend_multiple_update(&isql, &isql_alloc, &isql_offset); DBend_multiple_update(&usql, &usql_alloc, &usql_offset); if (dsql_offset > 16) DBexecute("%s", dsql); if (isql_offset > 16) DBexecute("%s", isql); if (usql_offset > 16) DBexecute("%s", usql); dsql_offset = 0; isql_offset = 0; usql_offset = 0; #ifdef HAVE_ORACLE DBbegin_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBbegin_multiple_update(&isql, &isql_alloc, &isql_offset); DBbegin_multiple_update(&usql, &usql_alloc, &usql_offset); #endif } } next: if (lf != NULL) { *lf++ = '\n'; r = lf; } else break; } DBend_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBend_multiple_update(&isql, &isql_alloc, &isql_offset); DBend_multiple_update(&usql, &usql_alloc, &usql_offset); if (dsql_offset > 16) DBexecute("%s", dsql); if (isql_offset > 16) DBexecute("%s", isql); if (usql_offset > 16) DBexecute("%s", usql); zbx_free(ufld); zbx_free(usql); zbx_free(ival); zbx_free(ifld); zbx_free(isql); zbx_free(dsql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }