[libgda] Added the GDA_CONNECTION_OPTIONS_THREAD_ISOLATED connection option
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Added the GDA_CONNECTION_OPTIONS_THREAD_ISOLATED connection option
- Date: Tue, 1 Jun 2010 16:57:40 +0000 (UTC)
commit 7498a4239f27522af89fca6dcacfa3e44e0da438
Author: Vivien Malerba <malerba gnome-db org>
Date: Tue Jun 1 18:39:13 2010 +0200
Added the GDA_CONNECTION_OPTIONS_THREAD_ISOLATED connection option
doc/C/tmpl/gda-connection.sgml | 2 +
libgda/gda-connection.c | 25 ++++++---
libgda/gda-connection.h | 63 ++++++++++++++++++++++--
libgda/sqlite/gda-sqlite-provider.c | 11 +++--
libgda/sqlite/virtual/gda-virtual-connection.c | 7 ++-
libgda/thread-wrapper/gda-thread-provider.c | 21 ++++++--
providers/mysql/gda-mysql-provider.c | 2 +
providers/postgres/gda-postgres-provider.c | 2 +
tests/multi-threading/check_threaded_cnc.c | 4 +-
9 files changed, 111 insertions(+), 26 deletions(-)
---
diff --git a/doc/C/tmpl/gda-connection.sgml b/doc/C/tmpl/gda-connection.sgml
index 6acd755..8e411cd 100644
--- a/doc/C/tmpl/gda-connection.sgml
+++ b/doc/C/tmpl/gda-connection.sgml
@@ -172,6 +172,7 @@ A connection to a database
@GDA_CONNECTION_OPTIONS_READ_ONLY:
@GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE:
@GDA_CONNECTION_OPTIONS_THREAD_SAFE:
+ GDA_CONNECTION_OPTIONS_THREAD_ISOLATED:
<!-- ##### ENUM GdaConnectionError ##### -->
<para>
@@ -626,6 +627,7 @@ A connection to a database
@GDA_CONNECTION_FEATURE_USERS:
@GDA_CONNECTION_FEATURE_VIEWS:
@GDA_CONNECTION_FEATURE_XA_TRANSACTIONS:
+ GDA_CONNECTION_FEATURE_MULTI_THREADING:
@GDA_CONNECTION_FEATURE_LAST:
<!-- ##### FUNCTION gda_connection_supports_feature ##### -->
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 3c29ae1..b6c7106 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -877,7 +877,8 @@ gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
g_return_val_if_fail (dsn && *dsn, NULL);
- if ((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) && !g_thread_supported ()) {
+ if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) || (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE)) &&
+ !g_thread_supported ()) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
"%s", _("Multi threading is not supported or enabled"));
return NULL;
@@ -923,10 +924,14 @@ gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
pinfo = gda_config_get_provider_info (dsn_info->provider);
if (pinfo) {
- if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE)
+ prov = gda_config_get_provider (dsn_info->provider, error);
+ if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
+ !gda_server_provider_supports_feature (prov, NULL,
+ GDA_CONNECTION_FEATURE_MULTI_THREADING)) ||
+ (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
+ options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
prov = _gda_connection_get_internal_thread_provider ();
- else
- prov = gda_config_get_provider (dsn_info->provider, error);
+ }
}
else
g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
@@ -1022,7 +1027,8 @@ gda_connection_open_from_string (const gchar *provider_name, const gchar *cnc_st
g_return_val_if_fail (cnc_string && *cnc_string, NULL);
- if ((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) && !g_thread_supported ()) {
+ if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) || (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE)) &&
+ !g_thread_supported ()) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
"%s", _("Multi threading is not supported or enabled"));
return NULL;
@@ -1068,15 +1074,18 @@ gda_connection_open_from_string (const gchar *provider_name, const gchar *cnc_st
pinfo = gda_config_get_provider_info (provider_name ? provider_name : real_provider);
if (pinfo) {
- if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) {
+ prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
+ if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
+ !gda_server_provider_supports_feature (prov, NULL,
+ GDA_CONNECTION_FEATURE_MULTI_THREADING)) ||
+ (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
gchar *tmp;
tmp = g_strdup_printf ("%s;PROVIDER_NAME=%s", real_cnc, pinfo->id);
g_free (real_cnc);
real_cnc = tmp;
+ options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
prov = _gda_connection_get_internal_thread_provider ();
}
- else
- prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
}
else
g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
diff --git a/libgda/gda-connection.h b/libgda/gda-connection.h
index 1a74338..dfe9946 100644
--- a/libgda/gda-connection.h
+++ b/libgda/gda-connection.h
@@ -1,5 +1,5 @@
/* GDA library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+ * Copyright (C) 1998 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Michael Lausch <michael lausch at>
@@ -77,6 +77,7 @@ struct _GdaConnectionClass {
void (*dsn_changed) (GdaConnection *obj);
void (*transaction_status_changed)(GdaConnection *obj);
+ /*< private >*/
/* Padding for future expansion */
void (*_gda_reserved1) (void);
void (*_gda_reserved2) (void);
@@ -89,10 +90,13 @@ struct _GdaConnectionClass {
* @GDA_CONNECTION_OPTIONS_NONE: no specific aspect
* @GDA_CONNECTION_OPTIONS_READ_ONLY: this flag specifies that the connection to open should be in a read-only mode
* (this policy is not correctly enforced at the moment)
- * @GDA_CONNECTION_OPTIONS_THREAD_SAFE: this flag specifies that the connection to open will be used
- * by several threads at once so it has to be thread safe
* @GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE: this flag specifies that SQL identifiers submitted as input
* to Libgda have to keep their case sensitivity.
+ * @GDA_CONNECTION_OPTIONS_THREAD_SAFE: this flag specifies that the connection to open will be used
+ * by several threads at once so it has to be thread safe
+ * @GDA_CONNECTION_OPTIONS_THREAD_ISOLATED: this flag specifies that the connection to open will be used
+ * by several threads at once and requests that the real connection be used
+ * only in a sub thread created specifically for it
*
*
* Specifies some aspects of a connection when opening it.
@@ -109,14 +113,55 @@ struct _GdaConnectionClass {
* <listitem><para>Libgda will not apply this rule when parsing SQL code, the SQL code being parsed
* has to be conform to the database it will be used with</para></listitem>
* </itemizedlist>
+ *
+ * Additional information about the GDA_CONNECTION_OPTIONS_THREAD_SAFE and GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flags:
+ * The GDA_CONNECTION_OPTIONS_THREAD_SAFE flag specifies that it has to be able to use the returned connection object from
+ * several threads at once (locking is ensured by the #GdaConnection itself). Depending on the database provider's
+ * implementation and on the native libraries it uses, the "normal" connection object might not respect this requirement,
+ * and in this case a specific thread is started and used as the unique thread which will manipulate the actual connection,
+ * while a "wrapper connection" is actually returned and used by the caller (that wrapper connection passes method calls
+ * from the calling thread to the actual connection's specific thread, and gets the results back).
+ *
+ * The GDA_CONNECTION_OPTIONS_THREAD_ISOLATED forces using a specific thread and a "wrapper connection" even if the
+ * "normal" connection would itself be thread safe; this is usefull for example to be sure the asynchronous API can
+ * always be used (see gda_connection_async_statement_execute()).
+ *
+ * Having a specific thread and a "wrapper connection" definitely has an impact on the performances (because it involves
+ * messages passing between threads for every method call), so using the
+ * GDA_CONNECTION_OPTIONS_THREAD_SAFE or GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flags should be carefully considered.
*/
typedef enum {
- GDA_CONNECTION_OPTIONS_NONE = 0,
+ GDA_CONNECTION_OPTIONS_NONE = 0,
GDA_CONNECTION_OPTIONS_READ_ONLY = 1 << 0,
GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE = 1 << 1,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE = 1 << 2
+ GDA_CONNECTION_OPTIONS_THREAD_SAFE = 1 << 2,
+ GDA_CONNECTION_OPTIONS_THREAD_ISOLATED = 1 << 3
} GdaConnectionOptions;
+
+/**
+ * GdaConnectionFeature
+ * @GDA_CONNECTION_FEATURE_AGGREGATES: test for aggregates support
+ * @GDA_CONNECTION_FEATURE_BLOBS: test for BLOBS (binary large objects) support
+ * @GDA_CONNECTION_FEATURE_INDEXES: test for indexes support
+ * @GDA_CONNECTION_FEATURE_INHERITANCE: test for tables inheritance support
+ * @GDA_CONNECTION_FEATURE_NAMESPACES: test for namespaces support
+ * @GDA_CONNECTION_FEATURE_PROCEDURES: test for functions support
+ * @GDA_CONNECTION_FEATURE_SEQUENCES: test for sequences support
+ * @GDA_CONNECTION_FEATURE_SQL: test for SQL language (even specific to the database) support
+ * @GDA_CONNECTION_FEATURE_TRANSACTIONS: test for transactions support
+ * @GDA_CONNECTION_FEATURE_SAVEPOINTS: test for savepoints within transactions support
+ * @GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE: test if savepoints can be removed
+ * @GDA_CONNECTION_FEATURE_TRIGGERS: test for triggers support
+ * @GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR: test for updatable cursors support
+ * @GDA_CONNECTION_FEATURE_USERS: test for users support
+ * @GDA_CONNECTION_FEATURE_VIEWS: test for views support
+ * @GDA_CONNECTION_FEATURE_XA_TRANSACTIONS: test for distributed transactions support
+ * @GDA_CONNECTION_FEATURE_MULTI_THREADING: test for native multi-threading support
+ *
+ * Used in gda_connection_supports_feature() and gda_server_provider_supports_feature() to test if a connection
+ * or a database provider supports some specific feature.
+ */
typedef enum {
GDA_CONNECTION_FEATURE_AGGREGATES,
GDA_CONNECTION_FEATURE_BLOBS,
@@ -134,10 +179,18 @@ typedef enum {
GDA_CONNECTION_FEATURE_USERS,
GDA_CONNECTION_FEATURE_VIEWS,
GDA_CONNECTION_FEATURE_XA_TRANSACTIONS,
+
+ GDA_CONNECTION_FEATURE_MULTI_THREADING,
GDA_CONNECTION_FEATURE_LAST
} GdaConnectionFeature;
+
+/**
+ * GdaConnectionSchema
+ *
+ * Deprecated: 4.2: This was a leftover from the pre 4.0 area
+ */
typedef enum {
GDA_CONNECTION_SCHEMA_AGGREGATES,
GDA_CONNECTION_SCHEMA_DATABASES,
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index cd767a9..3e96e09 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -764,9 +764,10 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
}
}
- /* Note: we don't need to set the thread owner because as stating with SQLite version 3.6.0
- * connections and prepared statement can be shared by threads */
- g_object_set (G_OBJECT (cnc), "thread-owner", NULL, NULL);
+ if (sqlite3_threadsafe ())
+ g_object_set (G_OBJECT (cnc), "thread-owner", NULL, NULL);
+ else
+ g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL);
g_static_rec_mutex_unlock (&cnc_mutex);
return TRUE;
@@ -844,7 +845,7 @@ gda_sqlite_provider_supports_operation (GdaServerProvider *provider, GdaConnecti
case GDA_SERVER_OPERATION_CREATE_VIEW:
case GDA_SERVER_OPERATION_DROP_VIEW:
- return TRUE;
+ return TRUE;
default:
return FALSE;
}
@@ -1194,6 +1195,8 @@ gda_sqlite_provider_supports (GdaServerProvider *provider,
case GDA_CONNECTION_FEATURE_VIEWS :
case GDA_CONNECTION_FEATURE_PROCEDURES :
return TRUE;
+ case GDA_CONNECTION_FEATURE_MULTI_THREADING:
+ return sqlite3_threadsafe () ? TRUE : FALSE;
default:
return FALSE;
}
diff --git a/libgda/sqlite/virtual/gda-virtual-connection.c b/libgda/sqlite/virtual/gda-virtual-connection.c
index 5124636..fab51be 100644
--- a/libgda/sqlite/virtual/gda-virtual-connection.c
+++ b/libgda/sqlite/virtual/gda-virtual-connection.c
@@ -161,7 +161,7 @@ gda_virtual_connection_open (GdaVirtualProvider *virtual_provider, GError **erro
* @error: a place to store errors, or %NULL
*
* Creates and opens a new virtual connection using the @virtual_provider provider. If @options
- * contains the %GDA_CONNECTION_OPTIONS_THREAD_SAFE flag, then the returned connection will be
+ * contains the %GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flag, then the returned connection will be
* a thread wrapped connection, and the actual (wrapped) virtual connection can be obtained through
* the "gda-virtual-connection" user property (use g_object_get_data() to get it).
*
@@ -177,7 +177,8 @@ gda_virtual_connection_open_extended (GdaVirtualProvider *virtual_provider, GdaC
cnc = PROV_CLASS (virtual_provider)->create_connection ((GdaServerProvider*) virtual_provider);
if (cnc) {
g_object_set (G_OBJECT (cnc), "provider", virtual_provider,
- "options", options & (~GDA_CONNECTION_OPTIONS_THREAD_SAFE), NULL);
+ "options",
+ options & (~ (GDA_CONNECTION_OPTIONS_THREAD_ISOLATED | GDA_CONNECTION_OPTIONS_THREAD_SAFE)), NULL);
if (!gda_connection_open (cnc, error)) {
g_object_unref (cnc);
cnc = NULL;
@@ -188,7 +189,7 @@ gda_virtual_connection_open_extended (GdaVirtualProvider *virtual_provider, GdaC
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR, "%s",
_("Internal error: virtual provider does not implement the create_operation() virtual method"));
- if (cnc && (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE)) {
+ if (cnc && (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
GdaConnection *wcnc;
wcnc = _gda_thread_provider_handle_virtual_connection (GDA_THREAD_PROVIDER (_gda_connection_get_internal_thread_provider ()),
cnc);
diff --git a/libgda/thread-wrapper/gda-thread-provider.c b/libgda/thread-wrapper/gda-thread-provider.c
index a54fe64..e09c3ea 100644
--- a/libgda/thread-wrapper/gda-thread-provider.c
+++ b/libgda/thread-wrapper/gda-thread-provider.c
@@ -443,7 +443,7 @@ gda_thread_provider_open_connection (GdaServerProvider *provider, GdaConnection
guint jid;
g_assert (data);
data->auth_string = auth_string;
- data->options = options & (~GDA_CONNECTION_OPTIONS_THREAD_SAFE);
+ data->options = options & (~(GDA_CONNECTION_OPTIONS_THREAD_ISOLATED | GDA_CONNECTION_OPTIONS_THREAD_SAFE));
jid = gda_thread_wrapper_execute (wr, (GdaThreadWrapperFunc) sub_thread_open_connection, data, NULL, NULL);
sub_cnc = gda_thread_wrapper_fetch_result (wr, TRUE, jid, &error);
@@ -2059,6 +2059,17 @@ gda_thread_provider_identifier_quote (GdaServerProvider *provider, GdaConnection
return res;
}
+static gpointer
+sub_thread_unref_connection (GdaConnection *cnc, GError **error)
+{
+ /* WARNING: function executed in sub thread! */
+ g_object_unref (cnc);
+#ifdef GDA_DEBUG_NO
+ g_print ("/%s()\n", __FUNCTION__);
+#endif
+ return NULL;
+}
+
/*
* Free connection's specific data
*/
@@ -2076,9 +2087,11 @@ gda_thread_free_cnc_data (ThreadConnectionData *cdata)
}
/* unref cdata->sub_connection in sub thread */
- gda_thread_wrapper_execute_void (cdata->wrapper,
- (GdaThreadWrapperVoidFunc) g_object_unref,
- cdata->sub_connection, NULL, NULL);
+ guint jid;
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperVoidFunc) sub_thread_unref_connection,
+ cdata->sub_connection, NULL, NULL);
+ gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
g_object_unref (cdata->wrapper);
/* free async data */
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index d85a231..8975d62 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -1234,6 +1234,8 @@ gda_mysql_provider_supports_feature (GdaServerProvider *provider,
switch (feature) {
case GDA_CONNECTION_FEATURE_SQL :
return TRUE;
+ case GDA_CONNECTION_FEATURE_MULTI_THREADING:
+ return mysql_thread_safe () ? TRUE : FALSE;
default:
return FALSE;
}
diff --git a/providers/postgres/gda-postgres-provider.c b/providers/postgres/gda-postgres-provider.c
index 9c0ce6c..1966a9f 100644
--- a/providers/postgres/gda-postgres-provider.c
+++ b/providers/postgres/gda-postgres-provider.c
@@ -1263,6 +1263,8 @@ gda_postgres_provider_supports_feature (GdaServerProvider *provider, GdaConnecti
}
else
return TRUE;
+ case GDA_CONNECTION_FEATURE_MULTI_THREADING:
+ return PQisthreadsafe () ? TRUE : FALSE;
default:
break;
}
diff --git a/tests/multi-threading/check_threaded_cnc.c b/tests/multi-threading/check_threaded_cnc.c
index dacf061..5988012 100644
--- a/tests/multi-threading/check_threaded_cnc.c
+++ b/tests/multi-threading/check_threaded_cnc.c
@@ -52,7 +52,7 @@ main (int argc, char** argv)
return 1;
}
tcnc = gda_connection_open_from_string ("SQlite", "DB_DIR=.;DB_NAME=testdb", NULL,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE, &error);
+ GDA_CONNECTION_OPTIONS_THREAD_ISOLATED, &error);
if (!tcnc) {
g_print ("ERROR opening connection in thread safe mode: %s\n",
error && error->message ? error->message : "No detail");
@@ -452,7 +452,7 @@ test_meta_store (GdaConnection *cnc)
g_print ("=== Starting test where threaded connection is used internally by a meta store\n");
tcnc = gda_connection_open_from_string ("SQlite", "DB_DIR=.;DB_NAME=storedb", NULL,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE, &error);
+ GDA_CONNECTION_OPTIONS_THREAD_ISOLATED, &error);
if (!tcnc) {
g_print ("ERROR opening connection in thread safe mode: %s\n",
error && error->message ? error->message : "No detail");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]