[Asterisk-cvs] asterisk-addons res_config_mysql.c,1.5,1.6
markster at lists.digium.com
markster at lists.digium.com
Wed Jan 26 20:53:21 CST 2005
Update of /usr/cvsroot/asterisk-addons
In directory mongoose.digium.com:/tmp/cvs-serv7142
Modified Files:
res_config_mysql.c
Log Message:
Fix mysql config stuff (bug #3433)
Index: res_config_mysql.c
===================================================================
RCS file: /usr/cvsroot/asterisk-addons/res_config_mysql.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- res_config_mysql.c 22 Jan 2005 21:09:56 -0000 1.5
+++ res_config_mysql.c 27 Jan 2005 02:55:26 -0000 1.6
@@ -1,29 +1,33 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
- * Copyright (C) 1999-2004, Digium, Inc.
+ * Copyright (C) 1999-2005, Digium, Inc.
*
* Mark Spencer <markster at digium.com> - Asterisk Author
* Matthew Boehm <mboehm at cytelcom.com> - MySQL RealTime Driver Author
*
* res_config_mysql.c <mysql plugin for RealTime configuration engine >
*
- * v1.4 - (12-02-04) - Added realtime_multi_mysql function
- * This function will return an ast_config with categories,
- * unlike standard realtime_mysql which only returns
- * a linked list of ast_variables
+ * v1.5.1 - (01-26-05) - Added better(?) locking stuff
*
- * v1.3 - (12-01-04) - Added support other operators
- * Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
+ * v1.5 - (01-26-05) - Brought up to date with new config.h changes (bug #3406)
+ * - Added in extra locking provided by georg (bug #3248)
*
- * v1.2 - (11-DD-04) - Added reload. Updated load and unload.
- * Code beautification (doc/CODING-GUIDELINES)
+ * v1.4 - (12-02-04) - Added realtime_multi_mysql function
+ * This function will return an ast_config with categories,
+ * unlike standard realtime_mysql which only returns
+ * a linked list of ast_variables
+ *
+ * v1.3 - (12-01-04) - Added support other operators
+ * Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
+ *
+ * v1.2 - (11-DD-04) - Added reload. Updated load and unload.
+ * Code beautification (doc/CODING-GUIDELINES)
*/
#include <asterisk/channel.h>
#include <asterisk/logger.h>
#include <asterisk/config.h>
-#include <asterisk/config_pvt.h>
#include <asterisk/module.h>
#include <asterisk/lock.h>
#include <asterisk/options.h>
@@ -36,7 +40,6 @@
#include <errmsg.h>
static char *res_config_mysql_desc = "MySQL RealTime Configuration Driver";
-static struct ast_config_reg reg_mysql;
AST_MUTEX_DEFINE_STATIC(mysql_lock);
#define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
@@ -122,36 +125,30 @@
return NULL;
}
- /* Toss up here. Each has its pros and cons. Gonna use store result cause most people will be running database
- either locally or on same network. And since the tables are small text based, shouldn't be that big of a problem
- unless you're retrieving a few million rows.
- mysql_store_result: Will copy all the rows returned by the query to local memory. This save network time,
- but could possibly use up lots of memory if the result set is large.
- mysql_use_result: Will keep the result set on the server and will retrieve each row at a time from server.
- Reduces local memory usage, but increases network traffic for large sets. Also, the server
- could go down part way thru our retrieval process and we wouldn't get all the rows. */
-
- result = mysql_store_result(&mysql);
- numFields = mysql_num_fields(result);
- fields = mysql_fetch_fields(result);
+ if((result = mysql_store_result(&mysql))) {
+ numFields = mysql_num_fields(result);
+ fields = mysql_fetch_fields(result);
- while((row = mysql_fetch_row(result))) {
- for(i = 0; i < numFields; i++) {
- stringp = row[i];
- while(stringp) {
- chunk = strsep(&stringp, ";");
- if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
- if(prev) {
- prev->next = ast_new_variable(fields[i].name, chunk);
- if (prev->next) {
- prev = prev->next;
+ while((row = mysql_fetch_row(result))) {
+ for(i = 0; i < numFields; i++) {
+ stringp = row[i];
+ while(stringp) {
+ chunk = strsep(&stringp, ";");
+ if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
+ if(prev) {
+ prev->next = ast_variable_new(fields[i].name, chunk);
+ if (prev->next) {
+ prev = prev->next;
+ }
+ } else {
+ prev = var = ast_variable_new(fields[i].name, chunk);
}
- } else {
- prev = var = ast_new_variable(fields[i].name, chunk);
}
}
}
}
+ } else {
+ ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
}
ast_mutex_unlock(&mysql_lock);
@@ -168,13 +165,12 @@
int numFields, i;
char sql[256];
const char *initfield = NULL;
- char *title = NULL;
char *stringp;
char *chunk;
char *op;
const char *newparam, *newval;
struct ast_realloca ra;
- struct ast_variable *var=NULL, *prev=NULL;
+ struct ast_variable *var=NULL;
struct ast_config *cfg = NULL;
struct ast_category *cat = NULL;
@@ -185,6 +181,13 @@
memset(&ra, 0, sizeof(ra));
+ cfg = ast_config_new();
+ if (!cfg) {
+ /* If I can't alloc memory at this point, why bother doing anything else? */
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ return NULL;
+ }
+
/* Get the first parameter and first value in our list of passed paramater/value pairs */
newparam = va_arg(ap, const char *);
newval = va_arg(ap, const char *);
@@ -233,50 +236,29 @@
return NULL;
}
- result = mysql_store_result(&mysql);
- numFields = mysql_num_fields(result);
- fields = mysql_fetch_fields(result);
+ if((result = mysql_store_result(&mysql))) {
+ numFields = mysql_num_fields(result);
+ fields = mysql_fetch_fields(result);
- while ((row = mysql_fetch_row(result))) {
- var = NULL;
- prev = NULL;
- title = NULL;
- for(i = 0; i < numFields; i++) {
- stringp = row[i];
- while(stringp) {
- chunk = strsep(&stringp, ";");
- if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
- if (initfield && !strcmp(initfield, fields[i].name) && !title) {
- title = ast_restrdupa(&ra, chunk);
- }
- if (prev) {
- prev->next = ast_new_variable(fields[i].name, chunk);
- if (prev->next) {
- prev = prev->next;
+ while((row = mysql_fetch_row(result))) {
+ var = NULL;
+ for(i = 0; i < numFields; i++) {
+ stringp = row[i];
+ while(stringp) {
+ chunk = strsep(&stringp, ";");
+ if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
+ if(initfield && !strcmp(initfield, fields[i].name)) {
+ ast_category_rename(cat, chunk);
}
- } else {
- prev = var = ast_new_variable(fields[i].name, chunk);
+ var = ast_variable_new(fields[i].name, chunk);
+ ast_variable_append(cat, var);
}
}
}
+ ast_category_append(cfg, cat);
}
- if(var) {
- cat = ast_new_category(title ? title : "");
- if(cat) {
- cat->root = var;
- if(!cfg) {
- cfg = ast_new_config();
- }
- if(cfg) {
- ast_category_append(cfg, cat);
- } else {
- ast_category_destroy(cat);
- }
- } else {
- ast_log(LOG_WARNING, "Out of memory!\n");
- ast_destroy_realtime(var);
- }
- }
+ } else {
+ ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
}
ast_mutex_unlock(&mysql_lock);
@@ -344,7 +326,7 @@
return -1;
}
-static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *new_config_s, struct ast_category **new_cat_p, struct ast_variable **new_v_p, int recur)
+static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg)
{
MYSQL_RES *result;
MYSQL_ROW row;
@@ -367,18 +349,6 @@
snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
- if(new_config_s) {
- new = new_config_s;
- cat_started++;
- } else {
- new = ast_new_config();
- }
-
- if(!new) {
- ast_log(LOG_WARNING, "MySQL RealTime: Cannot create new config. Out of memory!\n");
- return NULL;
- }
-
ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
/* We now have our complete statement; Lets connect to the server and execute it. */
@@ -399,65 +369,50 @@
num_rows = mysql_num_rows(result);
ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
- cat_started = 0;
-
- cur_cat = *new_cat_p;
- cur_v = *new_v_p;
-
- if(cur_cat) {
- cat_started = 1;
- }
-
- if(cur_v) {
- var_started = 1;
- }
-
/* There might exist a better way to access the column names other than counting,
but I believe that would require another loop that we don't need. */
while((row = mysql_fetch_row(result))) {
- if(!strcmp(row[1], "#include") && recur < MAX_INCLUDE_LEVEL) {
- config_mysql(database, table, row[2], new, &cur_cat, &cur_v, recur + 1);
- } else {
- if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
- strncpy(last, row[0], sizeof(last) - 1);
- last_cat_metric = atoi(row[3]);
- new_cat = (struct ast_category *) ast_new_category(row[0]);
-
- if(!cat_started) {
- cat_started++;
- new->root = new_cat;
- cur_cat = new->root;
- } else {
- cur_cat->next = new_cat;
- cur_cat = cur_cat->next;
- }
- var_started = 0;
+ if(!strcmp(row[1], "#include")) {
+ if (!ast_config_internal_load(row[2], cfg)) {
+ mysql_free_result(result);
+ ast_mutex_unlock(&mysql_lock);
+ return NULL;
}
+ continue;
+ }
- new_v = ast_new_variable(row[1], row[2]);
-
- if (!var_started) {
- var_started++;
- cur_cat->root = new_v;
- cur_v = cur_cat->root;
- } else {
- cur_v->next = new_v;
- cur_v = cur_v->next;
+ if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
+ cur_cat = ast_category_new(row[0]);
+ if (!cur_cat) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ break;
}
+ strcpy(last, row[0]);
+ last_cat_metric = atoi(row[3]);
+ ast_category_append(cfg, cur_cat);
}
+ new_v = ast_variable_new(row[1], row[2]);
+ ast_variable_append(cur_cat, new_v);
}
- mysql_free_result(result);
- ast_mutex_unlock(&mysql_lock);
} else {
ast_log(LOG_WARNING, "MySQL RealTime: Could not find config '%s' in database.\n", file);
- mysql_free_result(result);
- ast_mutex_unlock(&mysql_lock);
}
- return new;
+ mysql_free_result(result);
+ ast_mutex_unlock(&mysql_lock);
+
+ return cfg;
}
+static struct ast_config_engine mysql_engine = {
+ .name = "mysql",
+ .load_func = config_mysql,
+ .realtime_func = realtime_mysql,
+ .realtime_multi_func = realtime_multi_mysql,
+ .update_func = update_mysql
+};
+
int load_module (void)
{
parse_config();
@@ -467,56 +422,54 @@
ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
}
- memset(®_mysql, 0, sizeof(struct ast_config_reg));
- strncpy(reg_mysql.name, "mysql", sizeof(reg_mysql.name) - 1);
-
- reg_mysql.static_func = config_mysql;
- reg_mysql.realtime_func = realtime_mysql;
- reg_mysql.update_func = update_mysql;
- reg_mysql.realtime_multi_func = realtime_multi_mysql;
-
- ast_cust_config_register(®_mysql);
- ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime driver loaded.\n");
+ ast_config_engine_register(&mysql_engine);
+ if(option_verbose) {
+ ast_verbose("MySQL RealTime driver loaded.\n");
+ }
ast_cli_register(&cli_realtime_mysql_status);
+
return 0;
}
int unload_module (void)
{
+ /* Aquire control before doing anything to the module itself. */
+ ast_mutex_lock(&mysql_lock);
+
mysql_close(&mysql);
ast_cli_unregister(&cli_realtime_mysql_status);
- ast_cust_config_deregister(®_mysql);
- ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime unloaded.\n");
-
- if(ast_mutex_lock(&mysql_lock)) {
- ast_mutex_unlock(&mysql_lock);
+ ast_config_engine_deregister(&mysql_engine);
+ if(option_verbose) {
+ ast_verbose("MySQL RealTime unloaded.\n");
}
STANDARD_HANGUP_LOCALUSERS;
+ /* Unlock so something else can destroy the lock. */
+ ast_mutex_unlock(&mysql_lock);
+
return 0;
}
int reload (void)
{
- if(ast_mutex_lock(&mysql_lock)) {
- ast_log(LOG_WARNING, "MySQL RealTime: Couldn't reload. Use count %i.\n", usecount());
- return 1;
- }
+ /* Aquire control before doing anything to the module itself. */
+ ast_mutex_lock(&mysql_lock);
- ast_mutex_unlock(&mysql_lock);
mysql_close(&mysql);
-
connected = 0;
-
parse_config();
+ /* Need to unlock so that mysql_reconnect can regain the lock. */
+ ast_mutex_unlock(&mysql_lock);
+
if(!mysql_reconnect()) {
ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
}
ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
+
return 0;
}
@@ -525,7 +478,7 @@
struct ast_config *config;
char *s;
- config = ast_load(RES_CONFIG_MYSQL_CONF);
+ config = ast_config_load(RES_CONFIG_MYSQL_CONF);
if(config) {
if(!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
@@ -570,7 +523,7 @@
strncpy(dbsock, s, sizeof(dbsock) - 1);
}
}
- ast_destroy(config);
+ ast_config_destroy(config);
if(dbhost) {
ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
@@ -591,10 +544,9 @@
int usecount (void)
{
- /* Try and get a lock. If unsuccessful, than that means a query is currently being run.
- Lets be nice and don't interrupt the query. */
- if(ast_mutex_lock(&mysql_lock)) {
- ast_log(LOG_DEBUG, "MySQL RealTime: Usecount 1. Query in progress.\n");
+ /* Try and get a lock. If unsuccessful, than that means another thread is using the mysql object. */
+ if(ast_mutex_trylock(&mysql_lock)) {
+ ast_log(LOG_DEBUG, "MySQL RealTime: Module usage count is 1.\n");
return 1;
}
ast_mutex_unlock(&mysql_lock);
More information about the svn-commits
mailing list