Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
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);
	}
}
Exemplo n.º 4
0
/* 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);

}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
/* 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;
}