From: Florian Forster Date: Mon, 5 Apr 2010 12:04:18 +0000 (+0200) Subject: Merge branch 'schmurfy/re_invert' X-Git-Tag: collectd-4.10.0~29 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=7477d555a1dab3bee2db3eff26f2b2e5e5334956;hp=c412b6b2436f8ba18a35344dd851488922649dcc;p=collectd.git Merge branch 'schmurfy/re_invert' --- diff --git a/configure.in b/configure.in index 11935835..db0b083c 100644 --- a/configure.in +++ b/configure.in @@ -3789,7 +3789,7 @@ AC_DEFUN( enable_plugin="yes" force="yes" else - enable_plugin="no" + enable_plugin="no (disabled on command line)" fi; fi ], [ diff --git a/src/apache.c b/src/apache.c index 39849e6e..3d6d957c 100644 --- a/src/apache.c +++ b/src/apache.c @@ -313,7 +313,8 @@ static int config_add (oconfig_item_t *ci) (st->host != NULL) ? st->host : hostname_g, (st->name != NULL) ? st->name : "default"), - status = plugin_register_complex_read (callback_name, + status = plugin_register_complex_read (/* group = */ NULL, + /* name = */ callback_name, /* callback = */ apache_read_host, /* interval = */ NULL, /* user_data = */ &ud); diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index c2dfaf3d..e3af2e26 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2988,6 +2988,7 @@ L. + Interval 300 Service "service_name" Query backend # predefined Query rt36_tickets @@ -3051,7 +3052,8 @@ The username used to connect to the database. =item I -The interval collectd is using (as specified by the B option). +The interval with which this database is queried (as specified by the database +specific or global B options). =back @@ -3189,6 +3191,11 @@ for details. =over 4 +=item B I + +Specify the interval with which the database should be queried. The default is +to use the global B setting. + =item B I Specify the hostname or IP of the PostgreSQL server to connect to. If the diff --git a/src/csv.c b/src/csv.c index 0b34687d..96c1e3e7 100644 --- a/src/csv.c +++ b/src/csv.c @@ -299,7 +299,7 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl, fprintf (use_stdio == 1 ? stdout : stderr, "PUTVAL %s interval=%i %s\n", - filename, interval_g, values); + filename, vl->interval, values); return (0); } diff --git a/src/curl_json.c b/src/curl_json.c index 53e8abda..03ef6a34 100644 --- a/src/curl_json.c +++ b/src/curl_json.c @@ -673,7 +673,7 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */ ssnprintf (cb_name, sizeof (cb_name), "curl_json-%s-%s", db->instance, db->url); - plugin_register_complex_read (cb_name, cj_read, + plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read, /* interval = */ NULL, &ud); } else diff --git a/src/curl_xml.c b/src/curl_xml.c index 240be662..c10955cb 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -870,7 +870,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ ssnprintf (cb_name, sizeof (cb_name), "curl_xml-%s-%s", db->instance, db->url); - plugin_register_complex_read (cb_name, cx_read, + plugin_register_complex_read (/* group = */ NULL, cb_name, cx_read, /* interval = */ NULL, &ud); } else diff --git a/src/dbi.c b/src/dbi.c index ce4cd02f..77f393f5 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -46,6 +46,7 @@ struct cdbi_database_s /* {{{ */ cdbi_driver_option_t *driver_options; size_t driver_options_num; + udb_query_preparation_area_t **q_prep_areas; udb_query_t **queries; size_t queries_num; @@ -162,6 +163,11 @@ static void cdbi_database_free (cdbi_database_t *db) /* {{{ */ } sfree (db->driver_options); + if (db->q_prep_areas) + for (i = 0; i < db->queries_num; ++i) + udb_query_delete_preparation_area (db->q_prep_areas[i]); + free (db->q_prep_areas); + sfree (db); } /* }}} void cdbi_database_free */ @@ -328,6 +334,34 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */ break; } /* while (status == 0) */ + while ((status == 0) && (db->queries_num > 0)) + { + db->q_prep_areas = (udb_query_preparation_area_t **) calloc ( + db->queries_num, sizeof (*db->q_prep_areas)); + + if (db->q_prep_areas == NULL) + { + WARNING ("dbi plugin: malloc failed"); + status = -1; + break; + } + + for (i = 0; i < db->queries_num; ++i) + { + db->q_prep_areas[i] + = udb_query_allocate_preparation_area (db->queries[i]); + + if (db->q_prep_areas[i] == NULL) + { + WARNING ("dbi plugin: udb_query_allocate_preparation_area failed"); + status = -1; + break; + } + } + + break; + } + /* If all went well, add this database to the global list of databases. */ if (status == 0) { @@ -422,7 +456,7 @@ static int cdbi_init (void) /* {{{ */ } /* }}} int cdbi_init */ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ - udb_query_t *q) + udb_query_t *q, udb_query_preparation_area_t *prep_area) { const char *statement; dbi_result res; @@ -530,8 +564,9 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ sstrncpy (column_names[i], column_name, DATA_MAX_NAME_LEN); } /* }}} for (i = 0; i < column_num; i++) */ - udb_query_prepare_result (q, hostname_g, /* plugin = */ "dbi", db->name, - column_names, column_num); + udb_query_prepare_result (q, prep_area, hostname_g, + /* plugin = */ "dbi", db->name, + column_names, column_num, /* interval = */ -1); /* 0 = error; 1 = success; */ status = dbi_result_first_row (res); /* {{{ */ @@ -543,7 +578,7 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ "return any rows?", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); - udb_query_finish_result (q); + udb_query_finish_result (q, prep_area); BAIL_OUT (-1); } /* }}} */ @@ -572,7 +607,7 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ * to dispatch the row to the daemon. */ if (status == 0) /* {{{ */ { - status = udb_query_handle_result (q, column_values); + status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " @@ -598,7 +633,7 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ } /* }}} while (42) */ /* Tell the db query interface that we're done with this query. */ - udb_query_finish_result (q); + udb_query_finish_result (q, prep_area); /* Clean up and return `status = 0' (success) */ BAIL_OUT (0); @@ -741,7 +776,8 @@ static int cdbi_read_database (cdbi_database_t *db) /* {{{ */ && (udb_query_check_version (db->queries[i], db_version) == 0)) continue; - status = cdbi_read_database_query (db, db->queries[i]); + status = cdbi_read_database_query (db, + db->queries[i], db->q_prep_areas[i]); if (status == 0) success++; } diff --git a/src/java.c b/src/java.c index 87b189fa..528ec9c4 100644 --- a/src/java.c +++ b/src/java.c @@ -1419,7 +1419,7 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */ ud.data = (void *) cbi; ud.free_func = cjni_callback_info_destroy; - plugin_register_complex_read (cbi->name, cjni_read, + plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read, /* interval = */ NULL, &ud); (*jvm_env)->DeleteLocalRef (jvm_env, o_read); diff --git a/src/mysql.c b/src/mysql.c index 30f5504a..c7b796b1 100644 --- a/src/mysql.c +++ b/src/mysql.c @@ -342,7 +342,8 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */ else sstrncpy (cb_name, "mysql", sizeof (cb_name)); - plugin_register_complex_read (cb_name, mysql_read, + plugin_register_complex_read (/* group = */ NULL, cb_name, + mysql_read, /* interval = */ NULL, &ud); } else diff --git a/src/netapp.c b/src/netapp.c index fc653582..317b0fe4 100644 --- a/src/netapp.c +++ b/src/netapp.c @@ -2559,7 +2559,7 @@ static int cna_config (oconfig_item_t *ci) { /* {{{ */ ud.data = host; ud.free_func = (void (*) (void *)) free_host_config; - plugin_register_complex_read (cb_name, + plugin_register_complex_read (/* group = */ NULL, cb_name, /* callback = */ cna_read, /* interval = */ (host->interval > 0) ? &interval : NULL, /* user data = */ &ud); diff --git a/src/onewire.c b/src/onewire.c index cae0d63d..462458c7 100644 --- a/src/onewire.c +++ b/src/onewire.c @@ -310,7 +310,7 @@ static int cow_init (void) if (ow_interval > 0) cb_interval.tv_sec = (time_t) ow_interval; - plugin_register_complex_read ("onewire", cow_read, + plugin_register_complex_read (/* group = */ NULL, "onewire", cow_read, &cb_interval, /* user data = */ NULL); plugin_register_shutdown ("onewire", cow_shutdown); diff --git a/src/oracle.c b/src/oracle.c index 7a8ccc6b..3fe21254 100644 --- a/src/oracle.c +++ b/src/oracle.c @@ -62,6 +62,7 @@ struct o_database_s char *username; char *password; + udb_query_preparation_area_t **q_prep_areas; udb_query_t **queries; size_t queries_num; @@ -121,6 +122,8 @@ static void o_report_error (const char *where, /* {{{ */ static void o_database_free (o_database_t *db) /* {{{ */ { + size_t i; + if (db == NULL) return; @@ -130,6 +133,11 @@ static void o_database_free (o_database_t *db) /* {{{ */ sfree (db->password); sfree (db->queries); + if (db->q_prep_areas != NULL) + for (i = 0; i < db->queries_num; ++i) + udb_query_delete_preparation_area (db->q_prep_areas[i]); + free (db->q_prep_areas); + sfree (db); } /* }}} void o_database_free */ @@ -256,6 +264,34 @@ static int o_config_add_database (oconfig_item_t *ci) /* {{{ */ break; } /* while (status == 0) */ + while ((status == 0) && (db->queries_num > 0)) + { + db->q_prep_areas = (udb_query_preparation_area_t **) calloc ( + db->queries_num, sizeof (*db->q_prep_areas)); + + if (db->q_prep_areas == NULL) + { + WARNING ("oracle plugin: malloc failed"); + status = -1; + break; + } + + for (i = 0; i < db->queries_num; ++i) + { + db->q_prep_areas[i] + = udb_query_allocate_preparation_area (db->queries[i]); + + if (db->q_prep_areas[i] == NULL) + { + WARNING ("oracle plugin: udb_query_allocate_preparation_area failed"); + status = -1; + break; + } + } + + break; + } + /* If all went well, add this query to the list of queries within the * database structure. */ if (status == 0) @@ -349,7 +385,7 @@ static int o_init (void) /* {{{ */ } /* }}} int o_init */ static int o_read_database_query (o_database_t *db, /* {{{ */ - udb_query_t *q) + udb_query_t *q, udb_query_preparation_area_t *prep_area) { char **column_names; char **column_values; @@ -548,8 +584,9 @@ static int o_read_database_query (o_database_t *db, /* {{{ */ } /* for (j = 1; j <= param_counter; j++) */ /* }}} End of the ``define'' stuff. */ - status = udb_query_prepare_result (q, hostname_g, /* plugin = */ "oracle", - db->name, column_names, column_num); + status = udb_query_prepare_result (q, prep_area, hostname_g, + /* plugin = */ "oracle", db->name, column_names, column_num, + /* interval = */ -1); if (status != 0) { ERROR ("oracle plugin: o_read_database_query (%s, %s): " @@ -576,7 +613,7 @@ static int o_read_database_query (o_database_t *db, /* {{{ */ break; } - status = udb_query_handle_result (q, column_values); + status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { WARNING ("oracle plugin: o_read_database_query (%s, %s): " @@ -661,7 +698,7 @@ static int o_read_database (o_database_t *db) /* {{{ */ db->connect_id, db->oci_service_context); for (i = 0; i < db->queries_num; i++) - o_read_database_query (db, db->queries[i]); + o_read_database_query (db, db->queries[i], db->q_prep_areas[i]); return (0); } /* }}} int o_read_database */ diff --git a/src/plugin.c b/src/plugin.c index 1eed532c..a134446b 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -59,6 +59,7 @@ struct read_func_s #define rf_callback rf_super.cf_callback #define rf_udata rf_super.cf_udata callback_func_t rf_super; + char rf_group[DATA_MAX_NAME_LEN]; char rf_name[DATA_MAX_NAME_LEN]; int rf_type; struct timespec rf_interval; @@ -772,6 +773,7 @@ int plugin_register_read (const char *name, rf->rf_callback = (void *) callback; rf->rf_udata.data = NULL; rf->rf_udata.free_func = NULL; + rf->rf_group[0] = '\0'; sstrncpy (rf->rf_name, name, sizeof (rf->rf_name)); rf->rf_type = RF_SIMPLE; rf->rf_interval.tv_sec = 0; @@ -781,7 +783,7 @@ int plugin_register_read (const char *name, return (plugin_insert_read (rf)); } /* int plugin_register_read */ -int plugin_register_complex_read (const char *name, +int plugin_register_complex_read (const char *group, const char *name, plugin_read_cb callback, const struct timespec *interval, user_data_t *user_data) @@ -797,6 +799,10 @@ int plugin_register_complex_read (const char *name, memset (rf, 0, sizeof (read_func_t)); rf->rf_callback = (void *) callback; + if (group != NULL) + sstrncpy (rf->rf_group, group, sizeof (rf->rf_group)); + else + rf->rf_group[0] = '\0'; sstrncpy (rf->rf_name, name, sizeof (rf->rf_name)); rf->rf_type = RF_COMPLEX; if (interval != NULL) @@ -948,6 +954,67 @@ int plugin_unregister_read (const char *name) /* {{{ */ return (0); } /* }}} int plugin_unregister_read */ +static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */ +{ + read_func_t *rf = e->value; + char *group = ud; + + return strcmp (rf->rf_group, (const char *)group); +} /* }}} int compare_read_func_group */ + +int plugin_unregister_read_group (const char *group) /* {{{ */ +{ + llentry_t *le; + read_func_t *rf; + + int found = 0; + + if (group == NULL) + return (-ENOENT); + + pthread_mutex_lock (&read_lock); + + if (read_list == NULL) + { + pthread_mutex_unlock (&read_lock); + return (-ENOENT); + } + + while (42) + { + le = llist_search_custom (read_list, + compare_read_func_group, (void *)group); + + if (le == NULL) + break; + + ++found; + + llist_remove (read_list, le); + + rf = le->value; + assert (rf != NULL); + rf->rf_type = RF_REMOVE; + + llentry_destroy (le); + + DEBUG ("plugin_unregister_read_group: " + "Marked `%s' (group `%s') for removal.", + rf->rf_name, group); + } + + pthread_mutex_unlock (&read_lock); + + if (found == 0) + { + WARNING ("plugin_unregister_read_group: No such " + "group of read function: %s", group); + return (-ENOENT); + } + + return (0); +} /* }}} int plugin_unregister_read_group */ + int plugin_unregister_write (const char *name) { return (plugin_unregister (list_write, name)); diff --git a/src/plugin.h b/src/plugin.h index 868f44ab..8b9449ee 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -264,7 +264,7 @@ int plugin_register_init (const char *name, plugin_init_cb callback); int plugin_register_read (const char *name, int (*callback) (void)); -int plugin_register_complex_read (const char *name, +int plugin_register_complex_read (const char *group, const char *name, plugin_read_cb callback, const struct timespec *interval, user_data_t *user_data); @@ -284,6 +284,7 @@ int plugin_unregister_config (const char *name); int plugin_unregister_complex_config (const char *name); int plugin_unregister_init (const char *name); int plugin_unregister_read (const char *name); +int plugin_unregister_read_group (const char *group); int plugin_unregister_write (const char *name); int plugin_unregister_flush (const char *name); int plugin_unregister_shutdown (const char *name); diff --git a/src/postgresql.c b/src/postgresql.c index e6527b95..dd53cb4f 100644 --- a/src/postgresql.c +++ b/src/postgresql.c @@ -2,19 +2,30 @@ * collectd - src/postgresql.c * Copyright (C) 2008, 2009 Sebastian Harl * Copyright (C) 2009 Florian Forster + * All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; only version 2 of the License is applicable. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. * * Authors: * Sebastian Harl @@ -102,9 +113,12 @@ typedef struct { int max_params_num; /* user configuration */ + udb_query_preparation_area_t **q_prep_areas; udb_query_t **queries; size_t queries_num; + int interval; + char *host; char *port; char *database; @@ -132,22 +146,16 @@ static int def_queries_num = STATIC_ARRAY_SIZE (def_queries); static udb_query_t **queries = NULL; static size_t queries_num = 0; -static c_psql_database_t *databases = NULL; -static int databases_num = 0; - static c_psql_database_t *c_psql_database_new (const char *name) { c_psql_database_t *db; - ++databases_num; - if (NULL == (databases = (c_psql_database_t *)realloc (databases, - databases_num * sizeof (*databases)))) { + db = (c_psql_database_t *)malloc (sizeof (*db)); + if (NULL == db) { log_err ("Out of memory."); - exit (5); + return NULL; } - db = databases + (databases_num - 1); - db->conn = NULL; C_COMPLAIN_INIT (&db->conn_complaint); @@ -157,9 +165,12 @@ static c_psql_database_t *c_psql_database_new (const char *name) db->max_params_num = 0; + db->q_prep_areas = NULL; db->queries = NULL; db->queries_num = 0; + db->interval = 0; + db->database = sstrdup (name); db->host = NULL; db->port = NULL; @@ -174,11 +185,20 @@ static c_psql_database_t *c_psql_database_new (const char *name) return db; } /* c_psql_database_new */ -static void c_psql_database_delete (c_psql_database_t *db) +static void c_psql_database_delete (void *data) { + size_t i; + + c_psql_database_t *db = data; + PQfinish (db->conn); db->conn = NULL; + if (db->q_prep_areas) + for (i = 0; i < db->queries_num; ++i) + udb_query_delete_preparation_area (db->q_prep_areas[i]); + free (db->q_prep_areas); + sfree (db->queries); db->queries_num = 0; @@ -196,8 +216,49 @@ static void c_psql_database_delete (c_psql_database_t *db) return; } /* c_psql_database_delete */ +static int c_psql_connect (c_psql_database_t *db) +{ + char conninfo[4096]; + char *buf = conninfo; + int buf_len = sizeof (conninfo); + int status; + + if (! db) + return -1; + + status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database); + if (0 < status) { + buf += status; + buf_len -= status; + } + + C_PSQL_PAR_APPEND (buf, buf_len, "host", db->host); + C_PSQL_PAR_APPEND (buf, buf_len, "port", db->port); + C_PSQL_PAR_APPEND (buf, buf_len, "user", db->user); + C_PSQL_PAR_APPEND (buf, buf_len, "password", db->password); + C_PSQL_PAR_APPEND (buf, buf_len, "sslmode", db->sslmode); + C_PSQL_PAR_APPEND (buf, buf_len, "krbsrvname", db->krbsrvname); + C_PSQL_PAR_APPEND (buf, buf_len, "service", db->service); + + db->conn = PQconnectdb (conninfo); + db->proto_version = PQprotocolVersion (db->conn); + return 0; +} /* c_psql_connect */ + static int c_psql_check_connection (c_psql_database_t *db) { + _Bool init = 0; + + if (! db->conn) { + init = 1; + + /* trigger c_release() */ + if (0 == db->conn_complaint.interval) + db->conn_complaint.interval = 1; + + c_psql_connect (db); + } + /* "ping" */ PQclear (PQexec (db->conn, "SELECT 42;")); @@ -216,15 +277,30 @@ static int c_psql_check_connection (c_psql_database_t *db) } db->proto_version = PQprotocolVersion (db->conn); - if (3 > db->proto_version) - log_warn ("Protocol version %d does not support parameters.", - db->proto_version); } db->server_version = PQserverVersion (db->conn); - c_release (LOG_INFO, &db->conn_complaint, - "Successfully reconnected to database %s", PQdb (db->conn)); + if (c_would_release (&db->conn_complaint)) { + char *server_host; + int server_version; + + server_host = PQhost (db->conn); + server_version = PQserverVersion (db->conn); + + c_do_release (LOG_INFO, &db->conn_complaint, + "Successfully %sconnected to database %s (user %s) " + "at server %s%s%s (server version: %d.%d.%d, " + "protocol version: %d, pid: %d)", init ? "" : "re", + PQdb (db->conn), PQuser (db->conn), + C_PSQL_SOCKET3 (server_host, PQport (db->conn)), + C_PSQL_SERVER_VERSION3 (server_version), + db->proto_version, PQbackendPID (db->conn)); + + if (3 > db->proto_version) + log_warn ("Protocol version %d does not support parameters.", + db->proto_version); + } return 0; } /* c_psql_check_connection */ @@ -259,7 +335,8 @@ static PGresult *c_psql_exec_query_params (c_psql_database_t *db, params[i] = db->user; break; case C_PSQL_PARAM_INTERVAL: - ssnprintf (interval, sizeof (interval), "%i", interval_g); + ssnprintf (interval, sizeof (interval), "%i", + db->interval > 0 ? db->interval : interval_g); params[i] = interval; break; default: @@ -273,7 +350,8 @@ static PGresult *c_psql_exec_query_params (c_psql_database_t *db, NULL, NULL, /* return text data */ 0); } /* c_psql_exec_query_params */ -static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q) +static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q, + udb_query_preparation_area_t *prep_area) { PGresult *res; @@ -356,8 +434,8 @@ static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q) else host = db->host; - status = udb_query_prepare_result (q, host, "postgresql", - db->database, column_names, (size_t) column_num); + status = udb_query_prepare_result (q, prep_area, host, "postgresql", + db->database, column_names, (size_t) column_num, db->interval); if (0 != status) { log_err ("udb_query_prepare_result failed with status %i.", status); @@ -380,46 +458,52 @@ static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q) if (col < column_num) continue; - status = udb_query_handle_result (q, column_values); + status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { log_err ("udb_query_handle_result failed with status %i.", status); } } /* for (row = 0; row < rows_num; ++row) */ + udb_query_finish_result (q, prep_area); + BAIL_OUT (0); #undef BAIL_OUT } /* c_psql_exec_query */ -static int c_psql_read (void) +static int c_psql_read (user_data_t *ud) { + c_psql_database_t *db; + int success = 0; int i; - for (i = 0; i < databases_num; ++i) { - c_psql_database_t *db = databases + i; + if ((ud == NULL) || (ud->data == NULL)) { + log_err ("c_psql_read: Invalid user data."); + return -1; + } - int j; + db = ud->data; - assert (NULL != db->database); + assert (NULL != db->database); - if (0 != c_psql_check_connection (db)) - continue; + if (0 != c_psql_check_connection (db)) + return -1; - for (j = 0; j < db->queries_num; ++j) - { - udb_query_t *q; + for (i = 0; i < db->queries_num; ++i) + { + udb_query_preparation_area_t *prep_area; + udb_query_t *q; - q = db->queries[j]; + prep_area = db->q_prep_areas[i]; + q = db->queries[i]; - if ((0 != db->server_version) + if ((0 != db->server_version) && (udb_query_check_version (q, db->server_version) <= 0)) - continue; - - c_psql_exec_query (db, q); - } + continue; - ++success; + if (0 == c_psql_exec_query (db, q, prep_area)) + success = 1; } if (! success) @@ -429,19 +513,7 @@ static int c_psql_read (void) static int c_psql_shutdown (void) { - int i; - - if ((NULL == databases) || (0 == databases_num)) - return 0; - - plugin_unregister_read ("postgresql"); - plugin_unregister_shutdown ("postgresql"); - - for (i = 0; i < databases_num; ++i) - c_psql_database_delete (databases + i); - - sfree (databases); - databases_num = 0; + plugin_unregister_read_group ("postgresql"); udb_query_free (queries, queries_num); queries = NULL; @@ -450,70 +522,6 @@ static int c_psql_shutdown (void) return 0; } /* c_psql_shutdown */ -static int c_psql_init (void) -{ - int i; - - if ((NULL == databases) || (0 == databases_num)) - return 0; - - for (i = 0; i < databases_num; ++i) { - c_psql_database_t *db = databases + i; - - char conninfo[4096]; - char *buf = conninfo; - int buf_len = sizeof (conninfo); - int status; - - char *server_host; - int server_version; - - /* this will happen during reinitialization */ - if (NULL != db->conn) { - c_psql_check_connection (db); - continue; - } - - status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database); - if (0 < status) { - buf += status; - buf_len -= status; - } - - C_PSQL_PAR_APPEND (buf, buf_len, "host", db->host); - C_PSQL_PAR_APPEND (buf, buf_len, "port", db->port); - C_PSQL_PAR_APPEND (buf, buf_len, "user", db->user); - C_PSQL_PAR_APPEND (buf, buf_len, "password", db->password); - C_PSQL_PAR_APPEND (buf, buf_len, "sslmode", db->sslmode); - C_PSQL_PAR_APPEND (buf, buf_len, "krbsrvname", db->krbsrvname); - C_PSQL_PAR_APPEND (buf, buf_len, "service", db->service); - - db->conn = PQconnectdb (conninfo); - if (0 != c_psql_check_connection (db)) - continue; - - db->proto_version = PQprotocolVersion (db->conn); - - server_host = PQhost (db->conn); - server_version = PQserverVersion (db->conn); - log_info ("Successfully connected to database %s (user %s) " - "at server %s%s%s (server version: %d.%d.%d, " - "protocol version: %d, pid: %d)", - PQdb (db->conn), PQuser (db->conn), - C_PSQL_SOCKET3 (server_host, PQport (db->conn)), - C_PSQL_SERVER_VERSION3 (server_version), - db->proto_version, PQbackendPID (db->conn)); - - if (3 > db->proto_version) - log_warn ("Protocol version %d does not support parameters.", - db->proto_version); - } - - plugin_register_read ("postgresql", c_psql_read); - plugin_register_shutdown ("postgresql", c_psql_shutdown); - return 0; -} /* c_psql_init */ - static int config_set_s (char *name, char **var, const oconfig_item_t *ci) { if ((0 != ci->children_num) || (1 != ci->values_num) @@ -527,6 +535,28 @@ static int config_set_s (char *name, char **var, const oconfig_item_t *ci) return 0; } /* config_set_s */ +static int config_set_i (char *name, int *var, + const oconfig_item_t *ci, int min) +{ + int value; + + if ((0 != ci->children_num) || (1 != ci->values_num) + || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) { + log_err ("%s expects a single number argument.", name); + return 1; + } + + value = (int)ci->values[0].value.number; + + if (value < min) { + log_err ("%s expects a number greater or equal to %i.", name, min); + return 1; + } + + *var = value; + return 0; +} /* config_set_s */ + static int config_query_param_add (udb_query_t *q, oconfig_item_t *ci) { c_psql_user_data_t *data; @@ -587,6 +617,10 @@ static int c_psql_config_database (oconfig_item_t *ci) { c_psql_database_t *db; + char cb_name[DATA_MAX_NAME_LEN]; + struct timespec cb_interval; + user_data_t ud; + int i; if ((1 != ci->values_num) @@ -595,7 +629,11 @@ static int c_psql_config_database (oconfig_item_t *ci) return 1; } + memset (&ud, 0, sizeof (ud)); + db = c_psql_database_new (ci->values[0].value.string); + if (db == NULL) + return -1; for (i = 0; i < ci->children_num; ++i) { oconfig_item_t *c = ci->children + i; @@ -617,25 +655,58 @@ static int c_psql_config_database (oconfig_item_t *ci) else if (0 == strcasecmp (c->key, "Query")) udb_query_pick_from_list (c, queries, queries_num, &db->queries, &db->queries_num); + else if (0 == strcasecmp (c->key, "Interval")) + config_set_i ("Interval", &db->interval, c, /* min = */ 1); else log_warn ("Ignoring unknown config key \"%s\".", c->key); } /* If no `Query' options were given, add the default queries.. */ - if (db->queries_num == 0) - { + if (db->queries_num == 0) { for (i = 0; i < def_queries_num; i++) udb_query_pick_from_list_by_name (def_queries[i], queries, queries_num, &db->queries, &db->queries_num); } + if (db->queries_num > 0) { + db->q_prep_areas = (udb_query_preparation_area_t **) calloc ( + db->queries_num, sizeof (*db->q_prep_areas)); + + if (db->q_prep_areas == NULL) { + log_err ("Out of memory."); + c_psql_database_delete (db); + return -1; + } + } + for (i = 0; (size_t)i < db->queries_num; ++i) { c_psql_user_data_t *data; data = udb_query_get_user_data (db->queries[i]); if ((data != NULL) && (data->params_num > db->max_params_num)) db->max_params_num = data->params_num; + + db->q_prep_areas[i] + = udb_query_allocate_preparation_area (db->queries[i]); + + if (db->q_prep_areas[i] == NULL) { + log_err ("Out of memory."); + c_psql_database_delete (db); + return -1; + } } + + ud.data = db; + ud.free_func = c_psql_database_delete; + + ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->database); + + memset (&cb_interval, 0, sizeof (cb_interval)); + if (db->interval > 0) + cb_interval.tv_sec = (time_t)db->interval; + + plugin_register_complex_read ("postgresql", cb_name, c_psql_read, + /* interval = */ &cb_interval, &ud); return 0; } /* c_psql_config_database */ @@ -679,7 +750,7 @@ static int c_psql_config (oconfig_item_t *ci) void module_register (void) { plugin_register_complex_config ("postgresql", c_psql_config); - plugin_register_init ("postgresql", c_psql_init); + plugin_register_shutdown ("postgresql", c_psql_shutdown); } /* module_register */ /* vim: set sw=4 ts=4 tw=78 noexpandtab : */ diff --git a/src/python.c b/src/python.c index 5664b0c6..2f4f01e1 100644 --- a/src/python.c +++ b/src/python.c @@ -568,7 +568,8 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd user_data->data = c; ts.tv_sec = interval; ts.tv_nsec = (interval - ts.tv_sec) * 1000000000; - plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data); + plugin_register_complex_read(/* group = */ NULL, buf, + cpy_read_callback, &ts, user_data); return cpy_string_to_unicode_or_bytes(buf); } diff --git a/src/routeros.c b/src/routeros.c index 2512613c..a020692e 100644 --- a/src/routeros.c +++ b/src/routeros.c @@ -408,8 +408,8 @@ static int cr_config_router (oconfig_item_t *ci) /* {{{ */ user_data.data = router_data; user_data.free_func = (void *) cr_free_data; if (status == 0) - status = plugin_register_complex_read (read_name, cr_read, - /* interval = */ NULL, &user_data); + status = plugin_register_complex_read (/* group = */ NULL, read_name, + cr_read, /* interval = */ NULL, &user_data); if (status != 0) cr_free_data (router_data); diff --git a/src/snmp.c b/src/snmp.c index 00df3779..24707611 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -655,8 +655,9 @@ static int csnmp_config_add_host (oconfig_item_t *ci) if (hd->interval != 0) cb_interval.tv_sec = (time_t) hd->interval; - status = plugin_register_complex_read (cb_name, csnmp_read_host, - /* interval = */ &cb_interval, /* user_data = */ &cb_data); + status = plugin_register_complex_read (/* group = */ NULL, cb_name, + csnmp_read_host, /* interval = */ &cb_interval, + /* user_data = */ &cb_data); if (status != 0) { ERROR ("snmp plugin: Registering complex read function failed."); diff --git a/src/target_scale.c b/src/target_scale.c index 6b261c7c..29fecdfd 100644 --- a/src/target_scale.c +++ b/src/target_scale.c @@ -302,11 +302,15 @@ static int ts_config_set_double (double *ret, oconfig_item_t *ci) /* {{{ */ static int ts_destroy (void **user_data) /* {{{ */ { + ts_data_t **data; + if (user_data == NULL) return (-EINVAL); - free (*user_data); - *user_data = NULL; + data = (ts_data_t **) user_data; + + free (*data); + *data = NULL; return (0); } /* }}} int ts_destroy */ diff --git a/src/utils_db_query.c b/src/utils_db_query.c index 5f892a40..7d594d81 100644 --- a/src/utils_db_query.c +++ b/src/utils_db_query.c @@ -39,13 +39,6 @@ struct udb_result_s char **values; size_t values_num; - /* Preparation area */ - const data_set_t *ds; - size_t *instances_pos; - size_t *values_pos; - char **instances_buffer; - char **values_buffer; - /* Legacy data */ int legacy_mode; size_t legacy_position; @@ -69,13 +62,31 @@ struct udb_query_s /* {{{ */ unsigned int min_version; unsigned int max_version; - /* Preparation area */ + udb_result_t *results; +}; /* }}} */ + +struct udb_result_preparation_area_s /* {{{ */ +{ + const data_set_t *ds; + size_t *instances_pos; + size_t *values_pos; + char **instances_buffer; + char **values_buffer; + + struct udb_result_preparation_area_s *next; +}; /* }}} */ +typedef struct udb_result_preparation_area_s udb_result_preparation_area_t; + +struct udb_query_preparation_area_s /* {{{ */ +{ size_t column_num; char *host; char *plugin; char *db_name; - udb_result_t *results; + int interval; + + udb_result_preparation_area_t *result_prep_areas; }; /* }}} */ /* @@ -182,43 +193,49 @@ static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */ /* * Legacy result private functions */ -static void udb_legacy_result_finish_result (udb_result_t *r) /* {{{ */ +static void udb_legacy_result_finish_result (const udb_result_t const *r, /* {{{ */ + udb_result_preparation_area_t *prep_area) { - if (r == NULL) + if ((r == NULL) || (prep_area)) return; assert (r->legacy_mode == 1); - r->ds = NULL; + prep_area->ds = NULL; } /* }}} void udb_legacy_result_finish_result */ static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */ - udb_query_t *q, char **column_values) + udb_query_preparation_area_t *q_area, + udb_result_preparation_area_t *r_area, + const udb_query_t const *q, char **column_values) { value_list_t vl = VALUE_LIST_INIT; value_t value; char *value_str; assert (r->legacy_mode == 1); - assert (r->ds != NULL); - assert (r->ds->ds_num == 1); + assert (r_area->ds != NULL); + assert (r_area->ds->ds_num == 1); vl.values = &value; vl.values_len = 1; value_str = column_values[r->legacy_position]; - if (0 != parse_value (value_str, &vl.values[0], r->ds->ds[0].type)) + if (0 != parse_value (value_str, &vl.values[0], r_area->ds->ds[0].type)) { ERROR ("db query utils: udb_legacy_result_handle_result: " "Parsing `%s' as %s failed.", value_str, - DS_TYPE_TO_STRING (r->ds->ds[0].type)); + DS_TYPE_TO_STRING (r_area->ds->ds[0].type)); errno = EINVAL; return (-1); } - sstrncpy (vl.host, q->host, sizeof (vl.host)); - sstrncpy (vl.plugin, q->plugin, sizeof (vl.plugin)); - sstrncpy (vl.plugin_instance, q->db_name, sizeof (vl.type_instance)); + if (q_area->interval > 0) + vl.interval = q_area->interval; + + sstrncpy (vl.host, q_area->host, sizeof (vl.host)); + sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance)); sstrncpy (vl.type, r->type, sizeof (vl.type)); if (r->instance_prefix != NULL) @@ -230,7 +247,8 @@ static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */ return (0); } /* }}} int udb_legacy_result_handle_result */ -static int udb_legacy_result_prepare_result (udb_result_t *r, /* {{{ */ +static int udb_legacy_result_prepare_result (const udb_result_t const *r, /* {{{ */ + udb_result_preparation_area_t *prep_area, char **column_names, size_t column_num) { if (r == NULL) @@ -239,7 +257,7 @@ static int udb_legacy_result_prepare_result (udb_result_t *r, /* {{{ */ assert (r->legacy_mode == 1); /* Make sure previous preparations are cleaned up. */ - udb_legacy_result_finish_result (r); + udb_legacy_result_finish_result (r, prep_area); if (r->legacy_position >= column_num) { @@ -250,8 +268,8 @@ static int udb_legacy_result_prepare_result (udb_result_t *r, /* {{{ */ } /* Read `ds' and check number of values {{{ */ - r->ds = plugin_get_ds (r->type); - if (r->ds == NULL) + prep_area->ds = plugin_get_ds (r->type); + if (prep_area->ds == NULL) { ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not " "known by the daemon. See types.db(5) for details.", @@ -259,13 +277,13 @@ static int udb_legacy_result_prepare_result (udb_result_t *r, /* {{{ */ return (-1); } - if (r->ds->ds_num != 1) + if (prep_area->ds->ds_num != 1) { ERROR ("db query utils: udb_result_prepare_result: The type `%s' " "requires exactly %i values, but the legacy configuration " "requires exactly one!", r->type, - r->ds->ds_num); + prep_area->ds->ds_num); return (-1); } /* }}} */ @@ -342,40 +360,45 @@ static int udb_legacy_result_create (const char *query_name, /* {{{ */ /* * Result private functions */ -static int udb_result_submit (udb_result_t *r, udb_query_t *q) /* {{{ */ +static int udb_result_submit (udb_result_t *r, /* {{{ */ + udb_result_preparation_area_t *r_area, + const udb_query_t const *q, udb_query_preparation_area_t *q_area) { value_list_t vl = VALUE_LIST_INIT; size_t i; assert (r != NULL); assert (r->legacy_mode == 0); - assert (r->ds != NULL); - assert (((size_t) r->ds->ds_num) == r->values_num); + assert (r_area->ds != NULL); + assert (((size_t) r_area->ds->ds_num) == r->values_num); - vl.values = (value_t *) calloc (r->ds->ds_num, sizeof (value_t)); + vl.values = (value_t *) calloc (r_area->ds->ds_num, sizeof (value_t)); if (vl.values == NULL) { ERROR ("db query utils: malloc failed."); return (-1); } - vl.values_len = r->ds->ds_num; + vl.values_len = r_area->ds->ds_num; for (i = 0; i < r->values_num; i++) { - char *value_str = r->values_buffer[i]; + char *value_str = r_area->values_buffer[i]; - if (0 != parse_value (value_str, &vl.values[i], r->ds->ds[i].type)) + if (0 != parse_value (value_str, &vl.values[i], r_area->ds->ds[i].type)) { ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.", - value_str, DS_TYPE_TO_STRING (r->ds->ds[i].type)); + value_str, DS_TYPE_TO_STRING (r_area->ds->ds[i].type)); errno = EINVAL; return (-1); } } - sstrncpy (vl.host, q->host, sizeof (vl.host)); - sstrncpy (vl.plugin, q->plugin, sizeof (vl.plugin)); - sstrncpy (vl.plugin_instance, q->db_name, sizeof (vl.type_instance)); + if (q_area->interval > 0) + vl.interval = q_area->interval; + + sstrncpy (vl.host, q_area->host, sizeof (vl.host)); + sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance)); sstrncpy (vl.type, r->type, sizeof (vl.type)); /* Set vl.type_instance {{{ */ @@ -392,13 +415,14 @@ static int udb_result_submit (udb_result_t *r, udb_query_t *q) /* {{{ */ if (r->instance_prefix == NULL) { strjoin (vl.type_instance, sizeof (vl.type_instance), - r->instances_buffer, r->instances_num, "-"); + r_area->instances_buffer, r->instances_num, "-"); } else { char tmp[DATA_MAX_NAME_LEN]; - strjoin (tmp, sizeof (tmp), r->instances_buffer, r->instances_num, "-"); + strjoin (tmp, sizeof (tmp), r_area->instances_buffer, + r->instances_num, "-"); tmp[sizeof (tmp) - 1] = 0; snprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s", @@ -414,74 +438,82 @@ static int udb_result_submit (udb_result_t *r, udb_query_t *q) /* {{{ */ return (0); } /* }}} void udb_result_submit */ -static void udb_result_finish_result (udb_result_t *r) /* {{{ */ +static void udb_result_finish_result (const udb_result_t const *r, /* {{{ */ + udb_result_preparation_area_t *prep_area) { - if (r == NULL) + if ((r == NULL) || (prep_area == NULL)) return; if (r->legacy_mode == 1) { - udb_legacy_result_finish_result (r); + udb_legacy_result_finish_result (r, prep_area); return; } assert (r->legacy_mode == 0); - r->ds = NULL; - sfree (r->instances_pos); - sfree (r->values_pos); - sfree (r->instances_buffer); - sfree (r->values_buffer); + prep_area->ds = NULL; + sfree (prep_area->instances_pos); + sfree (prep_area->values_pos); + sfree (prep_area->instances_buffer); + sfree (prep_area->values_buffer); } /* }}} void udb_result_finish_result */ static int udb_result_handle_result (udb_result_t *r, /* {{{ */ - udb_query_t *q, char **column_values) + udb_query_preparation_area_t *q_area, + udb_result_preparation_area_t *r_area, + const udb_query_t const *q, char **column_values) { size_t i; + assert (r && q_area && r_area); + if (r->legacy_mode == 1) - return (udb_legacy_result_handle_result (r, q, column_values)); + return (udb_legacy_result_handle_result (r, q_area, r_area, + q, column_values)); assert (r->legacy_mode == 0); for (i = 0; i < r->instances_num; i++) - r->instances_buffer[i] = column_values[r->instances_pos[i]]; + r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]]; for (i = 0; i < r->values_num; i++) - r->values_buffer[i] = column_values[r->values_pos[i]]; + r_area->values_buffer[i] = column_values[r_area->values_pos[i]]; - return udb_result_submit (r, q); + return udb_result_submit (r, r_area, q, q_area); } /* }}} int udb_result_handle_result */ -static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ +static int udb_result_prepare_result (const udb_result_t const *r, /* {{{ */ + udb_result_preparation_area_t *prep_area, char **column_names, size_t column_num) { size_t i; - if (r == NULL) + if ((r == NULL) || (prep_area == NULL)) return (-EINVAL); if (r->legacy_mode == 1) - return (udb_legacy_result_prepare_result (r, column_names, column_num)); + return (udb_legacy_result_prepare_result (r, prep_area, + column_names, column_num)); assert (r->legacy_mode == 0); #define BAIL_OUT(status) \ - r->ds = NULL; \ - sfree (r->instances_pos); \ - sfree (r->values_pos); \ - sfree (r->instances_buffer); \ - sfree (r->values_buffer); \ + prep_area->ds = NULL; \ + sfree (prep_area->instances_pos); \ + sfree (prep_area->values_pos); \ + sfree (prep_area->instances_buffer); \ + sfree (prep_area->values_buffer); \ return (status) /* Make sure previous preparations are cleaned up. */ - udb_result_finish_result (r); - r->instances_pos = NULL; - r->values_pos = NULL; + udb_result_finish_result (r, prep_area); + prep_area->instances_pos = NULL; + prep_area->values_pos = NULL; /* Read `ds' and check number of values {{{ */ - r->ds = plugin_get_ds (r->type); - if (r->ds == NULL) + prep_area->ds = plugin_get_ds (r->type); + if (prep_area->ds == NULL) { ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not " "known by the daemon. See types.db(5) for details.", @@ -489,12 +521,12 @@ static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ BAIL_OUT (-1); } - if (((size_t) r->ds->ds_num) != r->values_num) + if (((size_t) prep_area->ds->ds_num) != r->values_num) { ERROR ("db query utils: udb_result_prepare_result: The type `%s' " "requires exactly %i value%s, but the configuration specifies %zu.", r->type, - r->ds->ds_num, (r->ds->ds_num == 1) ? "" : "s", + prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s", r->values_num); BAIL_OUT (-1); } @@ -504,30 +536,34 @@ static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ * r->values_buffer {{{ */ if (r->instances_num > 0) { - r->instances_pos = (size_t *) calloc (r->instances_num, sizeof (size_t)); - if (r->instances_pos == NULL) + prep_area->instances_pos + = (size_t *) calloc (r->instances_num, sizeof (size_t)); + if (prep_area->instances_pos == NULL) { ERROR ("db query utils: udb_result_prepare_result: malloc failed."); BAIL_OUT (-ENOMEM); } - r->instances_buffer = (char **) calloc (r->instances_num, sizeof (char *)); - if (r->instances_buffer == NULL) + prep_area->instances_buffer + = (char **) calloc (r->instances_num, sizeof (char *)); + if (prep_area->instances_buffer == NULL) { ERROR ("db query utils: udb_result_prepare_result: malloc failed."); BAIL_OUT (-ENOMEM); } } /* if (r->instances_num > 0) */ - r->values_pos = (size_t *) calloc (r->values_num, sizeof (size_t)); - if (r->values_pos == NULL) + prep_area->values_pos + = (size_t *) calloc (r->values_num, sizeof (size_t)); + if (prep_area->values_pos == NULL) { ERROR ("db query utils: udb_result_prepare_result: malloc failed."); BAIL_OUT (-ENOMEM); } - r->values_buffer = (char **) calloc (r->values_num, sizeof (char *)); - if (r->values_buffer == NULL) + prep_area->values_buffer + = (char **) calloc (r->values_num, sizeof (char *)); + if (prep_area->values_buffer == NULL) { ERROR ("db query utils: udb_result_prepare_result: malloc failed."); BAIL_OUT (-ENOMEM); @@ -543,7 +579,7 @@ static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ { if (strcasecmp (r->instances[i], column_names[j]) == 0) { - r->instances_pos[i] = j; + prep_area->instances_pos[i] = j; break; } } @@ -566,7 +602,7 @@ static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ { if (strcasecmp (r->values[i], column_names[j]) == 0) { - r->values_pos[i] = j; + prep_area->values_pos[i] = j; break; } } @@ -1029,33 +1065,45 @@ int udb_query_check_version (udb_query_t *q, unsigned int version) /* {{{ */ return (1); } /* }}} int udb_query_check_version */ -void udb_query_finish_result (udb_query_t *q) /* {{{ */ +void udb_query_finish_result (const udb_query_t const *q, /* {{{ */ + udb_query_preparation_area_t *prep_area) { + udb_result_preparation_area_t *r_area; udb_result_t *r; - if (q == NULL) + if ((q == NULL) || (prep_area == NULL)) return; - q->column_num = 0; - sfree (q->host); - sfree (q->plugin); - sfree (q->db_name); + prep_area->column_num = 0; + sfree (prep_area->host); + sfree (prep_area->plugin); + sfree (prep_area->db_name); - for (r = q->results; r != NULL; r = r->next) - udb_result_finish_result (r); + prep_area->interval = -1; + + for (r = q->results, r_area = prep_area->result_prep_areas; + r != NULL; r = r->next, r_area = r_area->next) + { + /* this may happen during error conditions of the caller */ + if (r_area == NULL) + break; + udb_result_finish_result (r, r_area); + } } /* }}} void udb_query_finish_result */ -int udb_query_handle_result (udb_query_t *q, char **column_values) /* {{{ */ +int udb_query_handle_result (const udb_query_t const *q, /* {{{ */ + udb_query_preparation_area_t *prep_area, char **column_values) { + udb_result_preparation_area_t *r_area; udb_result_t *r; int success; int status; - if (q == NULL) + if ((q == NULL) || (prep_area == NULL)) return (-EINVAL); - if ((q->column_num < 1) || (q->host == NULL) || (q->plugin == NULL) - || (q->db_name == NULL)) + if ((prep_area->column_num < 1) || (prep_area->host == NULL) + || (prep_area->plugin == NULL) || (prep_area->db_name == NULL)) { ERROR ("db query utils: Query `%s': Query is not prepared; " "can't handle result.", q->name); @@ -1067,19 +1115,21 @@ int udb_query_handle_result (udb_query_t *q, char **column_values) /* {{{ */ { size_t i; - for (i = 0; i < q->column_num; i++) + for (i = 0; i < prep_area->column_num; i++) { DEBUG ("db query utils: udb_query_handle_result (%s, %s): " "column[%zu] = %s;", - q->db_name, q->name, i, column_values[i]); + prep_area->db_name, q->name, i, column_values[i]); } } while (0); #endif /* }}} */ success = 0; - for (r = q->results; r != NULL; r = r->next) + for (r = q->results, r_area = prep_area->result_prep_areas; + r != NULL; r = r->next, r_area = r_area->next) { - status = udb_result_handle_result (r, q, column_values); + status = udb_result_handle_result (r, prep_area, r_area, + q, column_values); if (status == 0) success++; } @@ -1087,34 +1137,39 @@ int udb_query_handle_result (udb_query_t *q, char **column_values) /* {{{ */ if (success == 0) { ERROR ("db query utils: udb_query_handle_result (%s, %s): " - "All results failed.", q->db_name, q->name); + "All results failed.", prep_area->db_name, q->name); return (-1); } return (0); } /* }}} int udb_query_handle_result */ -int udb_query_prepare_result (udb_query_t *q, /* {{{ */ +int udb_query_prepare_result (const udb_query_t const *q, /* {{{ */ + udb_query_preparation_area_t *prep_area, const char *host, const char *plugin, const char *db_name, - char **column_names, size_t column_num) + char **column_names, size_t column_num, int interval) { + udb_result_preparation_area_t *r_area; udb_result_t *r; int status; - if (q == NULL) + if ((q == NULL) || (prep_area == NULL)) return (-EINVAL); - udb_query_finish_result (q); + udb_query_finish_result (q, prep_area); + + prep_area->column_num = column_num; + prep_area->host = strdup (host); + prep_area->plugin = strdup (plugin); + prep_area->db_name = strdup (db_name); - q->column_num = column_num; - q->host = strdup (host); - q->plugin = strdup (plugin); - q->db_name = strdup (db_name); + prep_area->interval = interval; - if ((q->host == NULL) || (q->plugin == NULL) || (q->db_name == NULL)) + if ((prep_area->host == NULL) || (prep_area->plugin == NULL) + || (prep_area->db_name == NULL)) { ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name); - udb_query_finish_result (q); + udb_query_finish_result (q, prep_area); return (-ENOMEM); } @@ -1132,12 +1187,21 @@ int udb_query_prepare_result (udb_query_t *q, /* {{{ */ } while (0); #endif - for (r = q->results; r != NULL; r = r->next) + for (r = q->results, r_area = prep_area->result_prep_areas; + r != NULL; r = r->next, r_area = r_area->next) { - status = udb_result_prepare_result (r, column_names, column_num); + if (! r_area) + { + ERROR ("db query utils: Query `%s': Invalid number of result " + "preparation areas.", q->name); + udb_query_finish_result (q, prep_area); + return (-EINVAL); + } + + status = udb_result_prepare_result (r, r_area, column_names, column_num); if (status != 0) { - udb_query_finish_result (q); + udb_query_finish_result (q, prep_area); return (status); } } @@ -1145,4 +1209,72 @@ int udb_query_prepare_result (udb_query_t *q, /* {{{ */ return (0); } /* }}} int udb_query_prepare_result */ +udb_query_preparation_area_t * +udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */ +{ + udb_query_preparation_area_t *q_area; + udb_result_preparation_area_t **next_r_area; + udb_result_t *r; + + q_area = (udb_query_preparation_area_t *)malloc (sizeof (*q_area)); + if (q_area == NULL) + return NULL; + + memset (q_area, 0, sizeof (*q_area)); + + next_r_area = &q_area->result_prep_areas; + for (r = q->results; r != NULL; r = r->next) + { + udb_result_preparation_area_t *r_area; + + r_area = (udb_result_preparation_area_t *)malloc (sizeof (*r_area)); + if (r_area == NULL) + { + for (r_area = q_area->result_prep_areas; + r_area != NULL; r_area = r_area->next) + { + free (r_area); + } + free (q_area); + return NULL; + } + + memset (r_area, 0, sizeof (*r_area)); + + *next_r_area = r_area; + next_r_area = &r_area->next; + } + + return (q_area); +} /* }}} udb_query_preparation_area_t *udb_query_allocate_preparation_area */ + +void +udb_query_delete_preparation_area (udb_query_preparation_area_t *q_area) /* {{{ */ +{ + udb_result_preparation_area_t *r_area; + + if (q_area == NULL) + return; + + r_area = q_area->result_prep_areas; + while (r_area != NULL) + { + udb_result_preparation_area_t *area = r_area; + + r_area = r_area->next; + + sfree (area->instances_pos); + sfree (area->values_pos); + sfree (area->instances_buffer); + sfree (area->values_buffer); + free (area); + } + + sfree (q_area->host); + sfree (q_area->plugin); + sfree (q_area->db_name); + + free (q_area); +} /* }}} void udb_query_delete_preparation_area */ + /* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/src/utils_db_query.h b/src/utils_db_query.h index 6703e924..fa2b2885 100644 --- a/src/utils_db_query.h +++ b/src/utils_db_query.h @@ -30,6 +30,9 @@ struct udb_query_s; typedef struct udb_query_s udb_query_t; +struct udb_query_preparation_area_s; +typedef struct udb_query_preparation_area_s udb_query_preparation_area_t; + typedef int (*udb_query_create_callback_t) (udb_query_t *q, oconfig_item_t *ci); @@ -62,11 +65,19 @@ void *udb_query_get_user_data (udb_query_t *q); */ int udb_query_check_version (udb_query_t *q, unsigned int version); -int udb_query_prepare_result (udb_query_t *q, +int udb_query_prepare_result (const udb_query_t const *q, + udb_query_preparation_area_t *prep_area, const char *host, const char *plugin, const char *db_name, - char **column_names, size_t column_num); -int udb_query_handle_result (udb_query_t *q, char **column_values); -void udb_query_finish_result (udb_query_t *q); + char **column_names, size_t column_num, int interval); +int udb_query_handle_result (const udb_query_t const *q, + udb_query_preparation_area_t *prep_area, char **column_values); +void udb_query_finish_result (const udb_query_t const *q, + udb_query_preparation_area_t *prep_area); + +udb_query_preparation_area_t * +udb_query_allocate_preparation_area (udb_query_t *q); +void +udb_query_delete_preparation_area (udb_query_preparation_area_t *q_area); #endif /* UTILS_DB_QUERY_H */ /* vim: set sw=2 sts=2 et : */ diff --git a/src/utils_llist.c b/src/utils_llist.c index bf5f7e49..6a0c6f06 100644 --- a/src/utils_llist.c +++ b/src/utils_llist.c @@ -139,17 +139,36 @@ int llist_size (llist_t *l) return (l ? l->size : 0); } +static int llist_strcmp (llentry_t *e, void *ud) +{ + if ((e == NULL) || (ud == NULL)) + return (-1); + return (strcmp (e->key, (const char *)ud)); +} + llentry_t *llist_search (llist_t *l, const char *key) { + return (llist_search_custom (l, llist_strcmp, (void *)key)); +} + +llentry_t *llist_search_custom (llist_t *l, + int (*compare) (llentry_t *, void *), void *user_data) +{ llentry_t *e; if (l == NULL) return (NULL); - for (e = l->head; e != NULL; e = e->next) - if (strcmp (key, e->key) == 0) + e = l->head; + while (e != NULL) { + llentry_t *next = e->next; + + if (compare (e, user_data) == 0) break; + e = next; + } + return (e); } diff --git a/src/utils_llist.h b/src/utils_llist.h index c3753d83..19d8d947 100644 --- a/src/utils_llist.h +++ b/src/utils_llist.h @@ -54,6 +54,8 @@ void llist_remove (llist_t *l, llentry_t *e); int llist_size (llist_t *l); llentry_t *llist_search (llist_t *l, const char *key); +llentry_t *llist_search_custom (llist_t *l, + int (*compare) (llentry_t *, void *), void *user_data); llentry_t *llist_head (llist_t *l); llentry_t *llist_tail (llist_t *l);