int db_do_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, const int _un, int (*val2str) (const db_con_t*, const db_val_t*, char*, int*), int (*submit_query)(const db_con_t* _h, const str* _c)) { int off, ret; if (!_h || !_uk || !_uv || !_un || !val2str || !submit_query) { LM_ERR("invalid parameter value\n"); goto err_exit; } ret = snprintf(sql_buf, SQL_BUF_LEN, "update %.*s set ", CON_TABLE(_h)->len, CON_TABLE(_h)->s); if (ret < 0 || ret >= SQL_BUF_LEN) goto error; off = ret; ret = db_print_set(_h, sql_buf + off, SQL_BUF_LEN - off, _uk, _uv, _un, val2str); if (ret < 0) goto err_exit; off += ret; if (_n) { ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, " where "); if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error; off += ret; ret = db_print_where(_h, sql_buf + off, SQL_BUF_LEN - off, _k, _o, _v, _n, val2str); if (ret < 0) goto err_exit; off += ret; } if (off + 1 > SQL_BUF_LEN) goto error; sql_buf[off] = '\0'; sql_str.s = sql_buf; sql_str.len = off; if (submit_query(_h, &sql_str) < 0) { LM_ERR("error while submitting query\n"); CON_OR_RESET(_h); return -2; } CON_OR_RESET(_h); return 0; error: LM_ERR("error while preparing update operation\n"); err_exit: CON_OR_RESET(_h); return -1; }
int update_db_state(int state) { db_key_t node_id_key = &id_col; db_val_t node_id_val; db_key_t update_key; db_val_t update_val; VAL_TYPE(&node_id_val) = DB_INT; VAL_NULL(&node_id_val) = 0; VAL_INT(&node_id_val) = current_id; update_key = &state_col; CON_OR_RESET(db_hdl); if (dr_dbf.use_table(db_hdl, &db_table) < 0) { LM_ERR("cannot select table: \"%.*s\"\n", db_table.len, db_table.s); return -1; } VAL_TYPE(&update_val) = DB_INT; VAL_NULL(&update_val) = 0; VAL_INT(&update_val) = state; if (dr_dbf.update(db_hdl, &node_id_key, 0, &node_id_val, &update_key, &update_val, 1, 1) < 0) return -1; return 0; }
/* loads data from the db */ table_entry_t* load_info(db_func_t *dr_dbf, db_con_t* db_hdl, str *db_table) { int int_vals[7]; char *str_vals[2]; int no_of_results; int i, n; int no_rows = 5; int db_cols = 10; unsigned long last_attempt; static db_key_t clusterer_machine_id_key = &machine_id_col; static db_val_t clusterer_machine_id_value = { .type = DB_INT, .nul = 0, }; VAL_INT(&clusterer_machine_id_value) = server_id; /* the columns from the db table */ db_key_t columns[10]; /* result from a db query */ db_res_t* res; /* a row from the db table */ db_row_t* row; /* the processed result */ table_entry_t *data; res = 0; data = 0; columns[0] = &cluster_id_col; columns[1] = &machine_id_col; columns[2] = &state_col; columns[3] = &description_col; columns[4] = &url_col; columns[5] = &id_col; columns[6] = &last_attempt_col; columns[7] = &failed_attempts_col; columns[8] = &no_tries_col; columns[9] = &duration_col; CON_OR_RESET(db_hdl); /* checking if the table version is up to date*/ if (db_check_table_version(dr_dbf, db_hdl, db_table, 1/*version*/) != 0) goto error; /* read data */ if (dr_dbf->use_table(db_hdl, db_table) < 0) { LM_ERR("cannot select table \"%.*s\"\n", db_table->len, db_table->s); goto error; } LM_DBG("DB query - retrieve the clusters list" "in which the specified server runs\n"); /* first we see in which clusters the specified server runs*/ if (dr_dbf->query(db_hdl, &clusterer_machine_id_key, &op_eq, &clusterer_machine_id_value, columns, 1, 1, 0, &res) < 0) { LM_ERR("DB query failed - cannot retrieve the clusters list in which" " the specified server runs\n"); goto error; } LM_DBG("%d rows found in %.*s\n", RES_ROW_N(res), db_table->len, db_table->s); if (RES_ROW_N(res) == 0) { LM_WARN("No machines found in cluster %d\n", server_id); return 0; } clusterer_cluster_id_key = pkg_realloc(clusterer_cluster_id_key, RES_ROW_N(res) * sizeof(db_key_t)); if (!clusterer_cluster_id_key) { LM_ERR("no more pkg memory\n"); goto error; } for (i = 0; i < RES_ROW_N(res); i++) clusterer_cluster_id_key[i] = &cluster_id_col; clusterer_cluster_id_value = pkg_realloc(clusterer_cluster_id_value, RES_ROW_N(res) * sizeof(db_val_t)); if (!clusterer_cluster_id_value) { LM_ERR("no more pkg memory\n"); goto error; } for (i = 0; i < RES_ROW_N(res); i++) { VAL_TYPE(clusterer_cluster_id_value + i) = DB_INT; VAL_NULL(clusterer_cluster_id_value + i) = 0; } for (i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; check_val(cluster_id_col, ROW_VALUES(row), DB_INT, 1, 0); VAL_INT(clusterer_cluster_id_value + i) = VAL_INT(ROW_VALUES(row)); } no_of_results = RES_ROW_N(res); dr_dbf->free_result(db_hdl, res); res = 0; LM_DBG("DB query - retrieve valid connections\n"); /* fetch is the best strategy */ CON_USE_OR_OP(db_hdl); if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) { if (dr_dbf->query(db_hdl, clusterer_cluster_id_key, 0, clusterer_cluster_id_value, columns, no_of_results, db_cols, 0, 0) < 0) { LM_ERR("DB query failed - retrieve valid connections \n"); goto error; } no_rows = estimate_available_rows(4 + 4 + 4 + 64 + 4 + 45 + 4 + 8 + 4 + 4, db_cols); if (no_rows == 0) no_rows = 5; if (dr_dbf->fetch_result(db_hdl, &res, no_rows) < 0) { LM_ERR("Error fetching rows\n"); goto error; } } else { if (dr_dbf->query(db_hdl, clusterer_cluster_id_key, 0, clusterer_cluster_id_value, columns, no_of_results, db_cols, 0, &res) < 0) { LM_ERR("DB query failed - retrieve valid connections\n"); goto error; } } LM_DBG("%d rows found in %.*s\n", RES_ROW_N(res), db_table->len, db_table->s); n = 0; do { for (i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; /* CLUSTER ID column */ check_val(cluster_id_col, ROW_VALUES(row), DB_INT, 1, 0); int_vals[INT_VALS_CLUSTER_ID_COL] = VAL_INT(ROW_VALUES(row)); /* MACHINE ID column */ check_val(machine_id_col, ROW_VALUES(row) + 1, DB_INT, 1, 0); int_vals[INT_VALS_MACHINE_ID_COL] = VAL_INT(ROW_VALUES(row) + 1); /* STATE column */ check_val(state_col, ROW_VALUES(row) + 2, DB_INT, 1, 0); int_vals[INT_VALS_STATE_COL] = VAL_INT(ROW_VALUES(row) + 2); /* DESCRIPTION column */ check_val(description_col, ROW_VALUES(row) + 3, DB_STRING, 0, 0); str_vals[STR_VALS_DESCRIPTION_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 3); /* URL column */ check_val(url_col, ROW_VALUES(row) + 4, DB_STRING, 1, 1); str_vals[STR_VALS_URL_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 4); /* CLUSTERER_ID column */ check_val(id_col, ROW_VALUES(row) + 5, DB_INT, 1, 0); int_vals[INT_VALS_CLUSTERER_ID_COL] = VAL_INT(ROW_VALUES(row) + 5); /* LAST_ATTEMPT column */ check_val(last_attempt_col, ROW_VALUES(row) + 6, DB_BIGINT, 1, 0); last_attempt = VAL_BIGINT(ROW_VALUES(row) + 6); /* FAILED_ATTEMPTS column */ check_val(failed_attempts_col, ROW_VALUES(row) + 7, DB_INT, 1, 0); int_vals[INT_VALS_FAILED_ATTEMPTS_COL] = VAL_INT(ROW_VALUES(row) + 7); /* NO_TRIES column */ check_val(no_tries_col, ROW_VALUES(row) + 8, DB_INT, 1, 0); int_vals[INT_VALS_NO_TRIES_COL] = VAL_INT(ROW_VALUES(row) + 8); /* DURATION column */ check_val(duration_col, ROW_VALUES(row) + 9, DB_INT, 1, 0); int_vals[INT_VALS_DURATION_COL] = VAL_INT(ROW_VALUES(row) + 9); /* store data */ if (add_info(&data, int_vals, last_attempt, str_vals) < 0) { LM_DBG("error while adding info to shm\n"); goto error; } LM_DBG("machine id %d\n", int_vals[0]); LM_DBG("cluster id %d\n", int_vals[1]); LM_DBG("state %d\n", int_vals[2]); LM_DBG("clusterer_id %d\n", int_vals[3]); LM_DBG("description %s\n", str_vals[0]); LM_DBG("url %s\n", str_vals[1]); n++; } if (n == 1) LM_WARN("The server is the only one in the cluster\n"); if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) { if (dr_dbf->fetch_result(db_hdl, &res, no_rows) < 0) { LM_ERR("fetching rows (1)\n"); goto error; } } else { break; } } while (RES_ROW_N(res) > 0); LM_DBG("%d records found in %.*s\n", n, db_table->len, db_table->s); dr_dbf->free_result(db_hdl, res); res = 0; return data; error: if (res) dr_dbf->free_result(db_hdl, res); if (data) free_data(data); data = NULL; return 0; } /* deallocates data */ void free_data(table_entry_t *data) { table_entry_t *tmp_entry; table_entry_info_t *info; table_entry_info_t *tmp_info; table_entry_value_t *value; table_entry_value_t *tmp_value; struct module_timestamp *timestamp; struct module_timestamp *tmp_timestamp; while (data != NULL) { tmp_entry = data; data = data->next; info = tmp_entry->info; while (info != NULL) { value = info->value; while (value != NULL) { if (value->path.s) shm_free(value->path.s); if (value->description.s) shm_free(value->description.s); timestamp = value->in_timestamps; while (timestamp != NULL) { tmp_timestamp = timestamp; timestamp = timestamp->next; shm_free(tmp_timestamp); } tmp_value = value; value = value->next; shm_free(tmp_value); } tmp_info = info; info = info->next; shm_free(tmp_info); } shm_free(tmp_entry); } }
/* synchronize backend with the db */ static void update_db_handler(unsigned int ticks, void* param) { /* data */ table_entry_t *head_table; table_entry_value_t *value; table_entry_info_t *info; /* columns to be compared ( clusterer_id_col ) */ db_key_t key_cmp; /* with values */ db_val_t val_cmp; /* columns to be set */ db_key_t key_set[3]; /* with values */ db_val_t val_set[3]; int i; CON_OR_RESET(db_hdl); /* table to use*/ if (dr_dbf.use_table(db_hdl, &db_table) < 0) { LM_ERR("cannot select table \"%.*s\"\n", db_table.len, db_table.s); return; } val_cmp.type = DB_INT; val_cmp.nul = 0; for (i = 0; i < 2; ++i) { val_set[i].type = DB_INT; val_set[i].nul = 0; } val_set[2].type = DB_BIGINT; val_set[2].nul = 0; key_cmp = &id_col; key_set[0] = &state_col; key_set[1] = &no_tries_col; key_set[2] = &last_attempt_col; lock_start_write(ref_lock); head_table = *tdata; /* iterating through backend storage to find all data that * must be synchronized with the db */ while (head_table != NULL) { info = head_table->info; while (info != NULL) { value = info->value; while (value != NULL) { if (value->dirty_bit == 1) { LM_DBG("setting row with primary key %d the status %d\n", value->id, value->state); val_cmp.val.int_val = value->id; val_set[0].val.int_val = value->state; val_set[1].val.int_val = value->no_tries; val_set[2].val.int_val = value->last_attempt; /* updating */ if (dr_dbf.update(db_hdl, &key_cmp, &op_eq, &val_cmp, key_set, val_set, 1, 3) < 0) { LM_ERR("DB update failed\n"); } else { /* only if the query is successful the data is synchronized */ value->dirty_bit = 0; } } value = value->next; } info = info->next; } head_table = head_table->next; } lock_stop_write(ref_lock); }
int db_do_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op, const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc, const db_key_t _o, db_res_t** _r, int (*val2str) (const db_con_t*, const db_val_t*, char*, int* _len), int (*submit_query)(const db_con_t*, const str*), int (*store_result)(const db_con_t* _h, db_res_t** _r)) { int off, ret; if (!_h || !val2str || !submit_query || (_r && !store_result)) { LM_ERR("invalid parameter value\n"); goto err_exit; } if (!_c) { ret = snprintf(sql_buf, SQL_BUF_LEN, "select * from %.*s ", CON_TABLE(_h)->len, CON_TABLE(_h)->s); if (ret < 0 || ret >= SQL_BUF_LEN) goto error; off = ret; } else { ret = snprintf(sql_buf, SQL_BUF_LEN, "select "); if (ret < 0 || ret >= SQL_BUF_LEN) goto error; off = ret; ret = db_print_columns(sql_buf + off, SQL_BUF_LEN - off, _c, _nc); if (ret < 0) goto err_exit; off += ret; ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, "from %.*s ", CON_TABLE(_h)->len, CON_TABLE(_h)->s); if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error; off += ret; } if (_n) { ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, "where "); if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error; off += ret; ret = db_print_where(_h, sql_buf + off, SQL_BUF_LEN - off, _k, _op, _v, _n, val2str); if (ret < 0) goto err_exit; off += ret; } if (_o) { ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, " order by %.*s", _o->len, _o->s); if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error; off += ret; } /* * Null-terminate the string for the postgres driver. Its query function * don't support a length parameter, so they need this for the correct * function of strlen. This zero is not included in the 'str' length. * We need to check the length here, otherwise we could overwrite the buffer * boundaries if off is equal to SQL_BUF_LEN. */ if (off + 1 >= SQL_BUF_LEN) goto error; sql_buf[off + 1] = '\0'; sql_str.s = sql_buf; sql_str.len = off; if (submit_query(_h, &sql_str) < 0) { LM_ERR("error while submitting query - [%.*s]\n",sql_str.len,sql_str.s); goto err_exit; } if(_r) { int tmp = store_result(_h, _r); if (tmp < 0) { LM_ERR("error while storing result for query [%.*s]\n",sql_str.len,sql_str.s); CON_OR_RESET(_h); return tmp; } } CON_OR_RESET(_h); return 0; error: LM_ERR("error while preparing query\n"); err_exit: CON_OR_RESET(_h); return -1; }
/* loads info from the db */ int load_db_info(db_func_t *dr_dbf, db_con_t* db_hdl, str *db_table, cluster_info_t **cl_list) { int int_vals[NO_DB_INT_VALS]; char *str_vals[NO_DB_STR_VALS]; int no_clusters; int i; int rc; node_info_t *new_info = NULL; db_key_t columns[NO_DB_COLS]; /* the columns from the db table */ db_res_t *res = NULL; db_row_t *row; static db_key_t clusterer_node_id_key = &node_id_col; static db_val_t clusterer_node_id_value = { .type = DB_INT, .nul = 0, }; *cl_list = NULL; columns[0] = &id_col; columns[1] = &cluster_id_col; columns[2] = &node_id_col; columns[3] = &url_col; columns[4] = &state_col; columns[5] = &no_ping_retries_col; columns[6] = &priority_col; columns[7] = &sip_addr_col; columns[8] = &flags_col; columns[9] = &description_col; CON_OR_RESET(db_hdl); if (db_check_table_version(dr_dbf, db_hdl, db_table, CLUSTERER_TABLE_VERSION)) goto error; if (dr_dbf->use_table(db_hdl, db_table) < 0) { LM_ERR("cannot select table: \"%.*s\"\n", db_table->len, db_table->s); goto error; } LM_DBG("DB query - retrieve the list of clusters" " in which the local node runs\n"); VAL_INT(&clusterer_node_id_value) = current_id; /* first we see in which clusters the local node runs*/ if (dr_dbf->query(db_hdl, &clusterer_node_id_key, &op_eq, &clusterer_node_id_value, columns+1, 1, 1, 0, &res) < 0) { LM_ERR("DB query failed - cannot retrieve the list of clusters in which" " the local node runs\n"); goto error; } LM_DBG("%d rows found in %.*s\n", RES_ROW_N(res), db_table->len, db_table->s); if (RES_ROW_N(res) > MAX_NO_CLUSTERS) { LM_ERR("Defined: %d clusters for local node, maximum number of clusters " "supported(%d) exceeded\n", RES_ROW_N(res), MAX_NO_CLUSTERS); goto error; } if (RES_ROW_N(res) == 0) { LM_WARN("No nodes found in cluster\n"); return 1; } clusterer_cluster_id_key = pkg_realloc(clusterer_cluster_id_key, RES_ROW_N(res) * sizeof(db_key_t)); if (!clusterer_cluster_id_key) { LM_ERR("no more pkg memory\n"); goto error; } for (i = 0; i < RES_ROW_N(res); i++) clusterer_cluster_id_key[i] = &cluster_id_col; clusterer_cluster_id_value = pkg_realloc(clusterer_cluster_id_value, RES_ROW_N(res) * sizeof(db_val_t)); if (!clusterer_cluster_id_value) { LM_ERR("no more pkg memory\n"); goto error; } for (i = 0; i < RES_ROW_N(res); i++) { VAL_TYPE(clusterer_cluster_id_value + i) = DB_INT; VAL_NULL(clusterer_cluster_id_value + i) = 0; } for (i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; check_val(cluster_id_col, ROW_VALUES(row), DB_INT, 1, 0); VAL_INT(clusterer_cluster_id_value + i) = VAL_INT(ROW_VALUES(row)); } no_clusters = RES_ROW_N(res); dr_dbf->free_result(db_hdl, res); res = NULL; LM_DBG("DB query - retrieve nodes info\n"); CON_USE_OR_OP(db_hdl); if (dr_dbf->query(db_hdl, clusterer_cluster_id_key, 0, clusterer_cluster_id_value, columns, no_clusters, NO_DB_COLS, 0, &res) < 0) { LM_ERR("DB query failed - retrieve valid connections\n"); goto error; } LM_DBG("%d rows found in %.*s\n", RES_ROW_N(res), db_table->len, db_table->s); if (RES_ROW_N(res) > MAX_NO_NODES) { LM_ERR("Defined: %d nodes in local node's clusters, maximum number of nodes " "supported(%d) exceeded\n", RES_ROW_N(res), MAX_NO_NODES); goto error; } for (i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; check_val(id_col, ROW_VALUES(row), DB_INT, 1, 0); int_vals[INT_VALS_ID_COL] = VAL_INT(ROW_VALUES(row)); check_val(cluster_id_col, ROW_VALUES(row) + 1, DB_INT, 1, 0); int_vals[INT_VALS_CLUSTER_ID_COL] = VAL_INT(ROW_VALUES(row) + 1); check_val(node_id_col, ROW_VALUES(row) + 2, DB_INT, 1, 0); int_vals[INT_VALS_NODE_ID_COL] = VAL_INT(ROW_VALUES(row) + 2); check_val(url_col, ROW_VALUES(row) + 3, DB_STRING, 1, 1); str_vals[STR_VALS_URL_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 3); check_val(state_col, ROW_VALUES(row) + 4, DB_INT, 1, 0); int_vals[INT_VALS_STATE_COL] = VAL_INT(ROW_VALUES(row) + 4); check_val(no_ping_retries_col, ROW_VALUES(row) + 5, DB_INT, 1, 0); int_vals[INT_VALS_NO_PING_RETRIES_COL] = VAL_INT(ROW_VALUES(row) + 5); check_val(priority_col, ROW_VALUES(row) + 6, DB_INT, 1, 0); int_vals[INT_VALS_PRIORITY_COL] = VAL_INT(ROW_VALUES(row) + 6); check_val(sip_addr_col, ROW_VALUES(row) + 7, DB_STRING, 0, 0); str_vals[STR_VALS_SIP_ADDR_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 7); check_val(flags_col, ROW_VALUES(row) + 8, DB_STRING, 0, 0); str_vals[STR_VALS_FLAGS_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 8); check_val(description_col, ROW_VALUES(row) + 9, DB_STRING, 0, 0); str_vals[STR_VALS_DESCRIPTION_COL] = (char*) VAL_STRING(ROW_VALUES(row) + 9); /* add info to backing list */ if ((rc = add_node_info(&new_info, cl_list, int_vals, str_vals)) != 0) { LM_ERR("Unable to add node info to backing list\n"); if (rc < 0) return -1; else return 2; } } /* warn if no seed node is defined in a cluster */ check_seed_flag(cl_list); if (RES_ROW_N(res) == 1) LM_INFO("The local node is the only one in the cluster\n"); dr_dbf->free_result(db_hdl, res); return 0; error: if (res) dr_dbf->free_result(db_hdl, res); if (*cl_list) free_info(*cl_list); *cl_list = NULL; return -1; } int provision_neighbor(modparam_t type, void *val) { int int_vals[NO_DB_INT_VALS]; char *str_vals[NO_DB_STR_VALS]; str prov_str; node_info_t *new_info; if (db_mode) { LM_INFO("Running in db mode, provisioning from the script is ignored\n"); return 0; } prov_str.s = (char*)val; prov_str.len = strlen(prov_str.s); if (parse_param_node_info(&prov_str, int_vals, str_vals) < 0) { LM_ERR("Unable to define a neighbor node\n"); return -1; } if (int_vals[INT_VALS_CLUSTER_ID_COL] == -1 || int_vals[INT_VALS_NODE_ID_COL] == -1 || str_vals[STR_VALS_URL_COL] == NULL) { LM_ERR("At least the cluster id, node id and url are required for a neighbor node\n"); return -1; } int_vals[INT_VALS_STATE_COL] = 1; if (int_vals[INT_VALS_NO_PING_RETRIES_COL] == -1) int_vals[INT_VALS_NO_PING_RETRIES_COL] = DEFAULT_NO_PING_RETRIES; if (int_vals[INT_VALS_PRIORITY_COL] == -1) int_vals[INT_VALS_PRIORITY_COL] = DEFAULT_NO_PING_RETRIES; str_vals[STR_VALS_DESCRIPTION_COL] = NULL; int_vals[INT_VALS_ID_COL] = -1; if (cluster_list == NULL) { cluster_list = shm_malloc(sizeof *cluster_list); if (!cluster_list) { LM_CRIT("No more shm memory\n"); return -1; } *cluster_list = NULL; } if (add_node_info(&new_info, cluster_list, int_vals, str_vals) < 0) { LM_ERR("Unable to add node info to backing list\n"); return -1; } return 0; }