]> granicus.if.org Git - ejabberd/commitdiff
* src/odbc/ejabberd_odbc.erl: Print meaningful error message when
authorEvgeniy Khramtsov <xramtsov@gmail.com>
Mon, 29 Dec 2008 04:21:27 +0000 (04:21 +0000)
committerEvgeniy Khramtsov <xramtsov@gmail.com>
Mon, 29 Dec 2008 04:21:27 +0000 (04:21 +0000)
an SQL transaction exceeds number of restarts. Also rollbacks
this transaction to prevent deadlocks.

SVN Revision: 1761

ChangeLog
src/odbc/ejabberd_odbc.erl

index baee8cf50051b48fffb7d94514110f03e698687d..ed9ef0f4d66faaed4c0a78d8de6e764efd3952f3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-12-29  Evgeniy Khramtsov <ekhramtsov@process-one.net>
+
+       * src/odbc/ejabberd_odbc.erl: Print meaningful error message when
+       an SQL transaction exceeds number of restarts. Also rollbacks
+       this transaction to prevent deadlocks.
+
 2008-12-28  Mickael Remond  <mremond@process-one.net>
 
        * src/ejabberd_c2s.erl: We should allow use of bare resource in from by
index c675c61c07394f1414a5a79289154b0e44ce676b..3a75b8a6e4d08124351ff77e1afa0abb05e36c57 100644 (file)
@@ -55,6 +55,8 @@
 -define(PGSQL_PORT, 5432).
 -define(MYSQL_PORT, 3306).
 
+-define(TRANSACTION_TIMEOUT, 60000).
+-define(KEEPALIVE_TIMEOUT, 60000).
 -define(KEEPALIVE_QUERY, "SELECT 1;").
 
 %%%----------------------------------------------------------------------
@@ -68,7 +70,7 @@ start_link(Host, StartInterval) ->
 
 sql_query(Host, Query) ->
     gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
-                   {sql_query, Query}, 60000).
+                   {sql_query, Query}, ?TRANSACTION_TIMEOUT).
 
 %% SQL transaction based on a list of queries
 %% This function automatically
@@ -83,7 +85,7 @@ sql_transaction(Host, Queries) when is_list(Queries) ->
 %% SQL transaction, based on a erlang anonymous function (F = fun)
 sql_transaction(Host, F) ->
     gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
-                   {sql_transaction, F}, 60000).
+                   {sql_transaction, F}, ?TRANSACTION_TIMEOUT).
 
 %% This function is intended to be used from inside an sql_transaction:
 sql_query_t(Query) ->
@@ -93,12 +95,12 @@ sql_query_t(Query) ->
        {error, "No SQL-driver information available."} ->
            % workaround for odbc bug
            {updated, 0};
-       {error, _} = Err ->
-           exit(Err);
+       {error, Reason} ->
+           throw({aborted, Reason});
        Rs when is_list(Rs) ->
            case lists:keysearch(error, 1, Rs) of
-               {value, Err} ->
-                   exit(Err);
+               {value, {error, Reason}} ->
+                   throw({aborted, Reason});
                _ ->
                    QRes
            end;
@@ -177,7 +179,7 @@ handle_call({sql_query, Query}, _From, State) ->
            {reply, Reply, State}
     end;
 handle_call({sql_transaction, F}, _From, State) ->
-    case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS) of
+    case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, "") of
        % error returned by MySQL driver
        {error, "query timed out"} ->
            {stop, timeout, State};
@@ -247,14 +249,22 @@ sql_query_internal(State, Query) ->
            mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self()))
     end.
 
-execute_transaction(_State, _F, 0) ->
+execute_transaction(State, _F, 0, Reason) ->
+    ?ERROR_MSG("SQL transaction restarts exceeded~n"
+              "** Restarts: ~p~n"
+              "** Last abort reason: ~p~n"
+              "** Stacktrace: ~p~n"
+              "** When State == ~p",
+              [?MAX_TRANSACTION_RESTARTS, Reason,
+               erlang:get_stacktrace(), State]),
+    sql_query_internal(State, "rollback;"),
     {aborted, restarts_exceeded};
-execute_transaction(State, F, NRestarts) ->
+execute_transaction(State, F, NRestarts, _Reason) ->
     put(?STATE_KEY, State),
     sql_query_internal(State, "begin;"),
     case catch F() of
-       aborted ->
-           execute_transaction(State, F, NRestarts - 1);
+       {aborted, Reason} ->
+           execute_transaction(State, F, NRestarts - 1, Reason);
        {'EXIT', Reason} ->
            sql_query_internal(State, "rollback;"),
            {aborted, Reason};
@@ -360,7 +370,7 @@ mysql_item_to_odbc(Columns, Recs) ->
 
 % perform a harmless query on all opened connexions to avoid connexion close.
 keep_alive(PID) ->
-    gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, 60000).
+    gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, ?KEEPALIVE_TIMEOUT).
 
 % log function used by MySQL driver
 log(Level, Format, Args) ->