r19728 - gnucash/trunk/src - Bug #630770 - Crash when connection lost using db
Geert Janssens
gjanssens at code.gnucash.org
Fri Oct 29 04:39:29 EDT 2010
Author: gjanssens
Date: 2010-10-29 04:39:29 -0400 (Fri, 29 Oct 2010)
New Revision: 19728
Trac: http://svn.gnucash.org/trac/changeset/19728
Modified:
gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c
gnucash/trunk/src/backend/sql/gnc-backend-sql.c
gnucash/trunk/src/engine/Split.c
Log:
Bug #630770 - Crash when connection lost using db
Modified: gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c
===================================================================
--- gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c 2010-10-29 08:32:07 UTC (rev 19727)
+++ gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c 2010-10-29 08:39:29 UTC (rev 19728)
@@ -161,6 +161,7 @@
dbi_conn conn;
/*@ observer @*/
provider_functions_t* provider;
+ gboolean conn_ok; // Used by the error handler routines to flag if the connection is ok to use
gint last_error; // Code of the last error that occurred. This is set in the error callback function
gint error_repeat; // Used in case of transient errors. After such error, another attempt at the
// original call is allowed. error_repeat tracks the number of attempts and can
@@ -193,6 +194,27 @@
gnc_dbi_set_error( dbi_conn, ERR_BACKEND_NO_ERR, 0, FALSE );
}
+/* Check if the dbi connection is valid. If not attempt to re-establish it
+ * Returns TRUE is there is a valid connection in the end or FALSE otherwise
+ */
+static gboolean
+gnc_dbi_verify_conn( GncDbiSqlConnection* dbi_conn )
+{
+ if ( dbi_conn->conn_ok )
+ return TRUE;
+
+ /* We attempt to connect only once here. The error function will automatically
+ * re-attempt up until DBI_MAX_CONN_ATTEMPTS time to connect if this call fails.
+ * After all these attempts, conn_ok will indicate if there is a valid connection
+ * or not.
+ */
+ gnc_dbi_init_error( dbi_conn );
+ dbi_conn->conn_ok = TRUE;
+ (void)dbi_conn_connect( dbi_conn->conn );
+
+ return dbi_conn->conn_ok;
+}
+
/* ================================================================= */
static void
@@ -330,16 +352,24 @@
}
else if ( err_num == 2006 ) // Server has gone away
{
- if (dbi_conn->error_repeat > DBI_MAX_CONN_ATTEMPTS )
+ PINFO( "DBI error: %s - Reconnecting...\n", msg );
+ gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE );
+ dbi_conn->conn_ok = TRUE;
+ (void)dbi_conn_connect( conn );
+ }
+ else if ( err_num == 2003 ) // Unable to connect
+ {
+ if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS )
{
- PERR( "DBI error: %s - Failed to reconnect after %d attempts.\n", msg, DBI_MAX_CONN_ATTEMPTS );
+ PERR( "DBI error: %s - Giving up after %d consecutive attempts.\n", msg, DBI_MAX_CONN_ATTEMPTS );
gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE );
+ dbi_conn->conn_ok = FALSE;
}
else
{
PINFO( "DBI error: %s - Reconnecting...\n", msg );
- gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE );
-
+ gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE );
+ dbi_conn->conn_ok = TRUE;
(void)dbi_conn_connect( conn );
}
}
@@ -571,6 +601,30 @@
be->exists = FALSE;
gnc_dbi_set_error( dbi_conn, ERR_BACKEND_NO_SUCH_DB, 0, FALSE );
}
+ else if ( g_strrstr( msg, "server closed the connection unexpectedly" ) ) // Connection lost
+ {
+ PINFO( "DBI error: %s - Reconnecting...\n", msg );
+ gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE );
+ dbi_conn->conn_ok = TRUE;
+ (void)dbi_conn_connect( conn );
+ }
+ else if ( g_str_has_prefix( msg, "connection pointer is NULL" ) ||
+ g_str_has_prefix(msg, "could not connect to server" ) ) // No connection
+ {
+ if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS )
+ {
+ PERR( "DBI error: %s - Giving up after %d consecutive attempts.\n", msg, DBI_MAX_CONN_ATTEMPTS );
+ gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE );
+ dbi_conn->conn_ok = FALSE;
+ }
+ else
+ {
+ PINFO( "DBI error: %s - Reconnecting...\n", msg );
+ gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE );
+ dbi_conn->conn_ok = TRUE;
+ (void)dbi_conn_connect( conn );
+ }
+ }
else
{
PERR( "DBI error: %s\n", msg );
@@ -1575,9 +1629,17 @@
GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
dbi_result result;
gint status;
+ gboolean success = FALSE;
DEBUG( "BEGIN\n" );
+ if ( !gnc_dbi_verify_conn (dbi_conn) )
+ {
+ PERR( "gnc_dbi_verify_conn() failed\n" );
+ qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
+ return FALSE;
+ }
+
do
{
gnc_dbi_init_error( dbi_conn );
@@ -1585,14 +1647,20 @@
}
while ( dbi_conn->retry );
+ success = ( result != NULL );
status = dbi_result_free( result );
if ( status < 0 )
{
PERR( "Error in dbi_result_free() result\n" );
qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
}
+ if ( !success )
+ {
+ PERR( "BEGIN transaction failed()\n" );
+ qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
+ }
- return TRUE;
+ return success;
}
static gboolean
@@ -1601,17 +1669,25 @@
GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
dbi_result result;
gint status;
+ gboolean success = FALSE;
DEBUG( "ROLLBACK\n" );
result = dbi_conn_queryf( dbi_conn->conn, "ROLLBACK" );
+ success = ( result != NULL );
+
status = dbi_result_free( result );
if ( status < 0 )
{
PERR( "Error in dbi_result_free() result\n" );
qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
}
+ if ( !success )
+ {
+ PERR( "Error in conn_rollback_transaction()\n" );
+ qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
+ }
- return TRUE;
+ return success;
}
static gboolean
@@ -1620,17 +1696,25 @@
GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
dbi_result result;
gint status;
+ gboolean success = FALSE;
DEBUG( "COMMIT\n" );
result = dbi_conn_queryf( dbi_conn->conn, "COMMIT" );
+ success = ( result != NULL );
+
status = dbi_result_free( result );
if ( status < 0 )
{
PERR( "Error in dbi_result_free() result\n" );
qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
}
+ if ( !success )
+ {
+ PERR( "Error in conn_commit_transaction()\n" );
+ qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
+ }
- return TRUE;
+ return success;
}
static /*@ null @*/ gchar*
@@ -2171,6 +2255,7 @@
dbi_conn->qbe = qbe;
dbi_conn->conn = conn;
dbi_conn->provider = provider;
+ dbi_conn->conn_ok = TRUE;
gnc_dbi_init_error(dbi_conn);
Modified: gnucash/trunk/src/backend/sql/gnc-backend-sql.c
===================================================================
--- gnucash/trunk/src/backend/sql/gnc-backend-sql.c 2010-10-29 08:32:07 UTC (rev 19727)
+++ gnucash/trunk/src/backend/sql/gnc-backend-sql.c 2010-10-29 08:39:29 UTC (rev 19728)
@@ -494,13 +494,16 @@
be->obj_total += gnc_book_count_transactions( book );
be->operations_done = 0;
- (void)gnc_sql_connection_begin_transaction( be->conn );
+ is_ok = gnc_sql_connection_begin_transaction( be->conn );
// FIXME: should write the set of commodities that are used
//write_commodities( be, book );
- is_ok = gnc_sql_save_book( be, QOF_INSTANCE(book) );
if ( is_ok )
{
+ is_ok = gnc_sql_save_book( be, QOF_INSTANCE(book) );
+ }
+ if ( is_ok )
+ {
is_ok = write_accounts( be );
}
if ( is_ok )
@@ -519,9 +522,12 @@
{
qof_object_foreach_backend( GNC_SQL_BACKEND, write_cb, be );
}
- if ( is_ok )
+ if ( is_ok )
{
- (void)gnc_sql_connection_commit_transaction( be->conn );
+ is_ok = gnc_sql_connection_commit_transaction( be->conn );
+ }
+ if ( is_ok )
+ {
be->is_pristine_db = FALSE;
// Mark the book as clean
@@ -529,7 +535,7 @@
}
else
{
- gnc_sql_connection_rollback_transaction( be->conn );
+ is_ok = gnc_sql_connection_rollback_transaction( be->conn );
}
LEAVE( "book=%p", book );
}
@@ -623,7 +629,12 @@
return;
}
- (void)gnc_sql_connection_begin_transaction( be->conn );
+ if ( !gnc_sql_connection_begin_transaction( be->conn ) )
+ {
+ PERR( "gnc_sql_commit_edit(): begin_transaction failed\n" );
+ LEAVE( "Rolled back - database transaction begin error" );
+ return;
+ }
be_data.is_known = FALSE;
be_data.be = be;
Modified: gnucash/trunk/src/engine/Split.c
===================================================================
--- gnucash/trunk/src/engine/Split.c 2010-10-29 08:32:07 UTC (rev 19727)
+++ gnucash/trunk/src/engine/Split.c 2010-10-29 08:39:29 UTC (rev 19728)
@@ -778,8 +778,9 @@
original and new transactions, for the _next_ begin/commit cycle. */
s->orig_acc = s->acc;
s->orig_parent = s->parent;
- qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, NULL,
- (void (*) (QofInstance *)) xaccFreeSplit);
+ if (!qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, NULL,
+ (void (*) (QofInstance *)) xaccFreeSplit))
+ return;
if (acc)
{
More information about the gnucash-changes
mailing list