[libgda] GdaConnection now uses a circular array to store (and reuse) GdaConnectionEvent objects



commit e7b3c71f229bfd79692329bbaec23c17744c2323
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sat Jul 10 15:06:28 2010 +0200

    GdaConnection now uses a circular array to store (and reuse) GdaConnectionEvent objects

 libgda/gda-connection-private.h     |    1 +
 libgda/gda-connection.c             |  166 +++++++++++++++++++++++++++--------
 libgda/sqlite/gda-sqlite-provider.c |   28 +++---
 3 files changed, 146 insertions(+), 49 deletions(-)
---
diff --git a/libgda/gda-connection-private.h b/libgda/gda-connection-private.h
index f849f10..b1fc088 100644
--- a/libgda/gda-connection-private.h
+++ b/libgda/gda-connection-private.h
@@ -37,6 +37,7 @@ gpointer gda_connection_internal_get_provider_data (GdaConnection *cnc);
 /*
  * Connection's events
  */
+GdaConnectionEvent  *gda_connection_point_available_event(GdaConnection *cnc, GdaConnectionEventType type);
 void                 gda_connection_add_event            (GdaConnection *cnc, GdaConnectionEvent *event);
 GdaConnectionEvent  *gda_connection_add_event_string     (GdaConnection *cnc, const gchar *str, ...);
 void                 gda_connection_clear_events_list    (GdaConnection *cnc);
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index d0bbf09..0b6b1ee 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -53,6 +53,7 @@
 #include <unistd.h>
 
 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
+#define EVENTS_ARRAY_SIZE 5
 
 struct _GdaConnectionPrivate {
 	GdaServerProvider    *provider_obj;
@@ -66,8 +67,11 @@ struct _GdaConnectionPrivate {
 
 	GdaMetaStore         *meta_store;
 
-	gboolean              auto_clear_events_list; /* TRUE if events_list is cleared before any statement execution */
-	GList                *events_list; /* last event is stored as the first node */
+	GdaConnectionEvent  **events_array; /* circular array */
+	gint                  events_array_size;
+	gboolean              events_array_full;
+	gint                  events_array_next;
+	GList                *events_list; /* for API compat */
 
 	GdaTransactionStatus *trans_status;
 	GHashTable           *prepared_stmts;
@@ -398,8 +402,10 @@ gda_connection_init (GdaConnection *cnc, GdaConnectionClass *klass)
 	cnc->priv->cnc_string = NULL;
 	cnc->priv->auth_string = NULL;
 	cnc->priv->is_open = FALSE;
-	cnc->priv->auto_clear_events_list = TRUE;
-	cnc->priv->events_list = NULL;
+	cnc->priv->events_array_size = EVENTS_ARRAY_SIZE;
+	cnc->priv->events_array = g_new0 (GdaConnectionEvent*, EVENTS_ARRAY_SIZE);
+	cnc->priv->events_array_full = FALSE;
+	cnc->priv->events_array_next = 0;
 	cnc->priv->trans_status = NULL; /* no transaction yet */
 	cnc->priv->prepared_stmts = NULL;
 
@@ -440,11 +446,22 @@ gda_connection_dispose (GObject *object)
 	}
 
 	if (cnc->priv->events_list) {
-		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
 		g_list_free (cnc->priv->events_list);
 		cnc->priv->events_list = NULL;
 	}
 
+	if (cnc->priv->events_array) {
+		gint i;
+		for (i = 0; i < cnc->priv->events_array_size ; i++) {
+			GdaConnectionEvent *ev;
+			ev = cnc->priv->events_array [i];
+			if (ev)
+				g_object_unref (ev);
+		}
+		g_free (cnc->priv->events_array);
+		cnc->priv->events_array = NULL;
+	}
+
 	if (cnc->priv->trans_status) {
 		g_object_unref (cnc->priv->trans_status);
 		cnc->priv->trans_status = NULL;
@@ -1676,6 +1693,52 @@ gda_connection_get_authentication (GdaConnection *cnc)
 }
 
 /**
+ * gda_connection_point_available_event
+ * @cnc: a #GdaConnection object
+ * @type: a #GdaConnectionEventType
+ *
+ * Use this method to get a pointer to the next available connection event which can then be customized
+ * and taken into account using gda_connection_add_event().
+ *
+ * Returns: (transfer none): a pointer to the next available connection event, or %NULL if event should
+ * be ignored
+ */
+GdaConnectionEvent *
+gda_connection_point_available_event (GdaConnection *cnc, GdaConnectionEventType type)
+{
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+
+	GdaConnectionEvent *eev;
+	eev = cnc->priv->events_array [cnc->priv->events_array_next];
+	if (!eev) {
+		eev = gda_connection_event_new (type);
+		cnc->priv->events_array [cnc->priv->events_array_next] = eev;
+	}
+	else
+		gda_connection_event_set_event_type (eev, type);
+		
+	return eev;
+}
+
+#ifdef GDA_DEBUG_NO
+static void
+dump_events_array (GdaConnection *cnc)
+{
+	gint i;
+	g_print ("=== Array dump for %p ===\n", cnc);
+	for (i = 0; i < cnc->priv->events_array_size; i++) {
+		g_print ("   [%d] => %p\n", i, cnc->priv->events_array [i]);
+	}
+
+	const GList *list;
+	for (list = gda_connection_get_events (cnc); list; list = list->next) {
+		GdaConnectionEvent *ev = GDA_CONNECTION_EVENT (list->data);
+		g_print ("    => %p\n", ev);
+	}
+}
+#endif
+
+/**
  * gda_connection_add_event:
  * @cnc: a #GdaConnection object.
  * @event: (transfer full): is stored internally, so you don't need to unref it.
@@ -1699,7 +1762,27 @@ gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event)
 
 	gda_mutex_lock (cnc->priv->mutex);
 
-	cnc->priv->events_list = g_list_prepend (cnc->priv->events_list, event);
+	/* clear external list of events */
+	if (cnc->priv->events_list) {
+		g_list_free (cnc->priv->events_list);
+		cnc->priv->events_list = NULL;
+	}
+
+	/* add event */
+	GdaConnectionEvent *eev;
+	eev = cnc->priv->events_array [cnc->priv->events_array_next];
+	if (eev != event) {
+		if (eev)
+			g_object_unref (eev);
+		cnc->priv->events_array [cnc->priv->events_array_next] = event;
+	}
+
+	/* handle indexes */
+	cnc->priv->events_array_next ++;
+	if (cnc->priv->events_array_next == cnc->priv->events_array_size) {
+		cnc->priv->events_array_next = 0;
+		cnc->priv->events_array_full = TRUE;
+	}
 
 	if (debug_level > 0) {
 		const gchar *str = NULL;
@@ -1727,6 +1810,10 @@ gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event)
 
 	if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR)
 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[ERROR], 0, event);
+
+#ifdef GDA_DEBUG_NO
+	dump_events_array (cnc);
+#endif
 	gda_mutex_unlock (cnc->priv->mutex);
 }
 
@@ -1758,7 +1845,7 @@ gda_connection_add_event_string (GdaConnection *cnc, const gchar *str, ...)
 	vsprintf (sz, str, args);
 	va_end (args);
 	
-	error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+	error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 	gda_connection_event_set_description (error, sz);
 	gda_connection_event_set_code (error, -1);
 	gda_connection_event_set_source (error, gda_connection_get_provider_name (cnc));
@@ -1769,19 +1856,6 @@ gda_connection_add_event_string (GdaConnection *cnc, const gchar *str, ...)
 	return error;
 }
 
-/*
- * Must be called while @cnc is locked.
- */
-static void
-_clear_events_list (GdaConnection *cnc)
-{
-	for (; cnc->priv->events_list; ) {
-		g_object_unref ((GObject*) cnc->priv->events_list->data);
-		cnc->priv->events_list = g_list_delete_link (cnc->priv->events_list,
-							     cnc->priv->events_list);
-	}
-}
-
 /**
  * gda_connection_clear_events_list:
  * @cnc: a #GdaConnection object.
@@ -1794,7 +1868,8 @@ gda_connection_clear_events_list (GdaConnection *cnc)
 {
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 	gda_connection_lock ((GdaLockable*) cnc);
-	_clear_events_list (cnc);
+	cnc->priv->events_array_full = FALSE;
+	cnc->priv->events_array_next = 0;
 	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
@@ -1837,15 +1912,12 @@ gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type
 gboolean
 gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error)
 {
-	gboolean auto_clear_events, retval;
+	gboolean retval;
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
 	g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
 
-	auto_clear_events = cnc->priv->auto_clear_events_list;
-	cnc->priv->auto_clear_events_list = FALSE;
 	retval = gda_server_provider_perform_operation (cnc->priv->provider_obj, cnc, op, error);
-	cnc->priv->auto_clear_events_list = auto_clear_events;
 	return retval;
 }
 
@@ -1892,13 +1964,10 @@ gda_connection_batch_execute (GdaConnection *cnc, GdaBatch *batch, GdaSet *param
 			      GdaStatementModelUsage model_usage, GError **error)
 {
 	GSList *retlist = NULL, *stmt_list;
-	gboolean auto_clear_events;
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (GDA_IS_BATCH (batch), NULL);
 
 	gda_connection_lock ((GdaLockable*) cnc);
-	auto_clear_events = cnc->priv->auto_clear_events_list;
-	cnc->priv->auto_clear_events_list = FALSE;
 	for (stmt_list = (GSList*) gda_batch_get_statements (batch); stmt_list; stmt_list = stmt_list->next) {
 		GObject *obj;
 		obj = gda_connection_statement_execute (cnc, GDA_STATEMENT (stmt_list->data), params,
@@ -1907,7 +1976,6 @@ gda_connection_batch_execute (GdaConnection *cnc, GdaBatch *batch, GdaSet *param
 			break;
 		retlist = g_slist_prepend (retlist, obj);
 	}
-	cnc->priv->auto_clear_events_list = auto_clear_events;
 	gda_connection_unlock ((GdaLockable*) cnc);
 	
 	return g_slist_reverse (retlist);
@@ -2421,8 +2489,6 @@ gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaS
 	gda_connection_lock ((GdaLockable*) cnc);
 	if (last_inserted_row) 
 		*last_inserted_row = NULL;
-	if (cnc->priv->auto_clear_events_list)
-		_clear_events_list (cnc);
 
 	if (!cnc->priv->is_open) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
@@ -2692,8 +2758,6 @@ gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement
 
 	g_object_ref ((GObject*) cnc);
 	gda_connection_lock ((GdaLockable*) cnc);
-	if (cnc->priv->auto_clear_events_list)
-		_clear_events_list (cnc);
 
 	if (!cnc->priv->is_open) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
@@ -2764,8 +2828,6 @@ gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *
 
 	g_object_ref ((GObject*) cnc);
 	gda_connection_lock ((GdaLockable*) cnc);
-	if (cnc->priv->auto_clear_events_list)
-		_clear_events_list (cnc);
 	
 	if (!cnc->priv->is_open) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
@@ -4610,6 +4672,40 @@ gda_connection_get_events (GdaConnection *cnc)
 {
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 
+	if (cnc->priv->events_list)
+		return cnc->priv->events_list;
+	
+	GList *list = NULL;
+	if (cnc->priv->events_array_full) {
+		gint i;
+		for (i = cnc->priv->events_array_next + 1; ; i++) {
+			if (i == cnc->priv->events_array_size)
+				i = 0;
+			if (i == cnc->priv->events_array_next)
+				break;
+			GdaConnectionEvent *ev;
+			ev = cnc->priv->events_array [i];
+			cnc->priv->events_array [i] = NULL;
+			g_assert (ev);
+			list = g_list_prepend (list, ev);
+		}
+	}
+	else {
+		gint i;
+		for (i = 0; i < cnc->priv->events_array_next; i++) {
+			GdaConnectionEvent *ev;
+			ev = cnc->priv->events_array [i];
+			g_assert (ev);
+			list = g_list_prepend (list, ev);
+			cnc->priv->events_array [i] = NULL;
+		}
+	}
+	cnc->priv->events_list = g_list_reverse (list);
+
+	/* reset events */
+	cnc->priv->events_array_full = FALSE;
+	cnc->priv->events_array_next = 0;
+
 	return cnc->priv->events_list;
 }
 
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index c45e642..58b3fd8 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -2236,7 +2236,7 @@ fill_blob_data (GdaConnection *cnc, GdaSet *params,
 
 	if (cstr) {
 		GdaConnectionEvent *event;
-		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 		gda_connection_event_set_description (event, cstr);
 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 			     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", cstr);
@@ -2244,7 +2244,7 @@ fill_blob_data (GdaConnection *cnc, GdaSet *params,
 	}
 	if (lerror) {
 		GdaConnectionEvent *event;
-		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 		gda_connection_event_set_description (event, lerror->message ? lerror->message : _("No detail"));
 		g_propagate_error (error, lerror);
 		return event;
@@ -2345,7 +2345,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		const char *errmsg;
 
 		errmsg = _("Empty statement");
-		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 		gda_connection_event_set_description (event, errmsg);
 		gda_connection_add_event (cnc, event);
 		gda_connection_del_prepared_statement (cnc, stmt);
@@ -2363,7 +2363,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		const char *errmsg;
 
 		errmsg = SQLITE3_CALL (sqlite3_errmsg) (cdata->connection);
-		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 		gda_connection_event_set_description (event, errmsg);
 		gda_connection_add_event (cnc, event);
 		gda_connection_del_prepared_statement (cnc, stmt);
@@ -2385,7 +2385,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		GdaHolder *h = NULL;		
 
 		if (!params) {
-			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 			gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
 			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 				     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
@@ -2405,7 +2405,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			if (! allow_noparam) {
 				gchar *str;
 				str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 				gda_connection_event_set_description (event, str);
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
@@ -2424,7 +2424,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			if (! allow_noparam) {
 				gchar *str;
 				str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 				gda_connection_event_set_description (event, str);
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
@@ -2486,7 +2486,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 				str = _("BLOB is too big");
 
 			if (str) {
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 				gda_connection_event_set_description (event, str);
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 					     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
@@ -2497,7 +2497,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			GError *lerror = NULL;
 			pb = make_pending_blob (stmt, h, &lerror);
 			if (!pb) {
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 				gda_connection_event_set_description (event, 
 				   lerror && lerror->message ? lerror->message : _("No detail"));
 								      
@@ -2509,7 +2509,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 
 			if (SQLITE3_CALL (sqlite3_bind_zeroblob) (ps->sqlite_stmt, i, (int) blob_len) !=
 			    SQLITE_OK) {
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 				gda_connection_event_set_description (event, 
 				   lerror && lerror->message ? lerror->message : _("No detail"));
 								      
@@ -2567,7 +2567,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			gchar *str;
 			str = g_strdup_printf (_("Non handled data type '%s'"), 
 					       g_type_name (G_VALUE_TYPE (value)));
-			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
 			gda_connection_event_set_description (event, str);
 			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 				     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
@@ -2585,7 +2585,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 	}
 	
 	/* add a connection event */
-	event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+	event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
         gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
         gda_connection_add_event (cnc, event);
 	
@@ -2623,7 +2623,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
                 if (status != SQLITE_DONE) {
                         if (SQLITE3_CALL (sqlite3_errcode) (handle) != SQLITE_OK) {
 				const char *errmsg = SQLITE3_CALL (sqlite3_errmsg) (handle);
-                                event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+                                event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
                                 gda_connection_event_set_description (event, errmsg);
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 					     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s", errmsg);
@@ -2691,7 +2691,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			}
 
 			if (str) {
-                                event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+                                event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE);
                                 gda_connection_event_set_description (event, str);
                                 g_free (str);
                                 gda_connection_add_event (cnc, event);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]