utils_db_query: Introduced the query & result preparation areas.
authorSebastian Harl <sh@tokkee.org>
Tue, 30 Mar 2010 19:27:55 +0000 (21:27 +0200)
committerSebastian Harl <sh@tokkee.org>
Tue, 30 Mar 2010 19:27:55 +0000 (21:27 +0200)
These objects are used to store the temporary data needed during execution of
a query, which was previously stored in the query object itself. This allows
the query object to be used read-only, making it possible to use it from
multiple threads in parallel.

The dbi, oracle and postgresql plugins have been updated to use that
(mandatory) new feature.

src/dbi.c
src/oracle.c
src/postgresql.c
src/utils_db_query.c
src/utils_db_query.h

index ce4cd02..5dad197 100644 (file)
--- 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,7 +564,8 @@ 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,
+  udb_query_prepare_result (q, prep_area, hostname_g,
+      /* plugin = */ "dbi", db->name,
       column_names, column_num);
 
   /* 0 = error; 1 = success; */
@@ -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++;
   }
index 7a8ccc6..7ab5a0c 100644 (file)
@@ -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,8 @@ 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);
   if (status != 0)
   {
     ERROR ("oracle plugin: o_read_database_query (%s, %s): "
@@ -576,7 +612,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 +697,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 */
index 9e91659..431f8e3 100644 (file)
@@ -102,6 +102,7 @@ typedef struct {
        int max_params_num;
 
        /* user configuration */
+       udb_query_preparation_area_t **q_prep_areas;
        udb_query_t    **queries;
        size_t           queries_num;
 
@@ -141,7 +142,7 @@ static c_psql_database_t *c_psql_database_new (const char *name)
        db = (c_psql_database_t *)malloc (sizeof (*db));
        if (NULL == db) {
                log_err ("Out of memory.");
-               exit (5);
+               return NULL;
        }
 
        db->conn = NULL;
@@ -153,6 +154,7 @@ 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;
 
@@ -174,11 +176,18 @@ static c_psql_database_t *c_psql_database_new (const char *name)
 
 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;
 
@@ -330,7 +339,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;
 
@@ -413,7 +423,7 @@ 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",
+       status = udb_query_prepare_result (q, prep_area, host, "postgresql",
                        db->database, column_names, (size_t) column_num);
        if (0 != status) {
                log_err ("udb_query_prepare_result failed with status %i.",
@@ -437,13 +447,15 @@ 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 */
@@ -467,15 +479,17 @@ static int c_psql_read (user_data_t *ud)
 
        for (i = 0; i < db->queries_num; ++i)
        {
+               udb_query_preparation_area_t *prep_area;
                udb_query_t *q;
 
+               prep_area = db->q_prep_areas[i];
                q = db->queries[i];
 
                if ((0 != db->server_version)
                                && (udb_query_check_version (q, db->server_version) <= 0))
                        continue;
 
-               c_psql_exec_query (db, q);
+               c_psql_exec_query (db, q, prep_area);
        }
        return 0;
 } /* c_psql_read */
@@ -601,6 +615,8 @@ static int c_psql_config_database (oconfig_item_t *ci)
        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;
@@ -629,19 +645,38 @@ static int c_psql_config_database (oconfig_item_t *ci)
        }
 
        /* 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;
index 5f892a4..13cdf9e 100644 (file)
@@ -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,29 @@ 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;
+  udb_result_preparation_area_t *result_prep_areas;
 }; /* }}} */
 
 /*
@@ -182,43 +191,46 @@ 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));
+  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 +242,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 +252,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 +263,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 +272,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 +355,42 @@ 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));
+  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 +407,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 +430,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 +513,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 +528,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 +571,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 +594,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 +1057,43 @@ 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);
+  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 +1105,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 +1127,37 @@ 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)
 {
+  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);
 
-  q->column_num = column_num;
-  q->host = strdup (host);
-  q->plugin = strdup (plugin);
-  q->db_name = strdup (db_name);
+  prep_area->column_num = column_num;
+  prep_area->host = strdup (host);
+  prep_area->plugin = strdup (plugin);
+  prep_area->db_name = strdup (db_name);
 
-  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 +1175,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 +1197,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 : */
index 6703e92..da235f7 100644 (file)
@@ -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);
+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 : */