aboutsummaryrefslogtreecommitdiffstats
path: root/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/cosTransactions/src/CosTransactions_Terminator_impl.erl')
-rw-r--r--lib/cosTransactions/src/CosTransactions_Terminator_impl.erl362
1 files changed, 362 insertions, 0 deletions
diff --git a/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl b/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
new file mode 100644
index 0000000000..768e63950c
--- /dev/null
+++ b/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
@@ -0,0 +1,362 @@
+%%--------------------------------------------------------------------
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% File : CosTransactions_Terminator_impl.erl
+%% Purpose : Support operations to commit or roll-back a transaction.
+%%----------------------------------------------------------------------
+
+-module('CosTransactions_Terminator_impl').
+
+%%--------------- INCLUDES -----------------------------------
+-include_lib("orber/include/corba.hrl").
+%% Local
+-include_lib("ETraP_Common.hrl").
+-include_lib("CosTransactions.hrl").
+
+%%--------------- IMPORTS-------------------------------------
+-import(etrap_logmgr, [log_safe/2, get_next/2]).
+
+%%--------------- EXPORTS-------------------------------------
+%%-compile(export_all).
+-export([commit/3, rollback/2]).
+-export([init/1, terminate/2]).
+-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
+
+%%--------------- LOCAL DATA ---------------------------------
+%-record(terminator, {reg_resources, rollback_only, regname, coordinator}).
+
+%%------------------------------------------------------------
+%% function : init, terminate
+%% Arguments:
+%% Returns :
+%% Effect : Functions demanded by the module ic. Used to initiate
+%% and terminate a gen_server.
+%%------------------------------------------------------------
+
+init(State) ->
+ process_flag(trap_exit,true),
+ case catch start_object(State) of
+ {'EXIT', Reason} ->
+ %% Happens when, for example, we encounter an
+ %% error when reading from the log file.
+ {stop, Reason};
+ Other ->
+ Other
+ end.
+
+start_object(State) ->
+ case catch file:read_file_info(?tr_get_terminator(State)) of
+ {error, enoent} ->
+ %% File does not exist. It's the first time. No restart.
+ ?debug_print("Terminator:init(~p)~n", [?tr_get_terminator(State)]),
+ etrap_logmgr:start(?tr_get_terminator(State)),
+ {ok, State, ?tr_get_timeout(State)};
+ {error, Reason} -> % File exist but error occurred.
+ ?tr_error_msg("CosTransactions_Terminator( ~p ) Cannot open log file: ~p~n",
+ [?tr_get_terminator(State), Reason]),
+ {stop, {error, "unable_to_open_log"}};
+ _ -> % File exists, perform restart.
+ etrap_logmgr:start(?tr_get_terminator(State)),
+ ?debug_print("RESTART Terminator:init(~p)~n",
+ [?tr_get_terminator(State)]),
+ do_restart(State, get_next(?tr_get_terminator(State), start), init)
+ end.
+
+
+terminate(Reason, State) ->
+ ?debug_print("STOP ~p ~p~n", [?tr_get_terminator(State), Reason]),
+ case Reason of
+ normal ->
+ %% normal termination. Transaction completed.
+ log_safe(?tr_get_terminator(State), done),
+ etrap_logmgr:stop(?tr_get_terminator(State)),
+ file:delete(?tr_get_terminator(State)),
+ ok;
+ _ ->
+ ok
+ end.
+
+%%------------------------------------------------------------
+%% function : handle_call, handle_cast, handle_info, code_change
+%% Arguments:
+%% Returns :
+%% Effect : Functions demanded by the module ic.
+%%------------------------------------------------------------
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+handle_call(_,_, State) ->
+ {noreply, State}.
+
+
+handle_cast(_, State) ->
+ {noreply, State}.
+
+
+handle_info(Info, State) ->
+ ?debug_print("Terminator:handle_info(~p)~n", [Info]),
+ Pid = self(),
+ case Info of
+ timeout ->
+ ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n",
+ [?tr_get_terminator(State)]),
+ {stop, normal, State};
+ {suicide, Pid} ->
+ {stop, normal, State};
+ _->
+ {noreply, State}
+ end.
+
+%%------------------------------------------------------------
+%% function : commit
+%% Arguments: Self - its own object reference.
+%% State - Gen-Server State
+%% Heuristics - boolean; report heuristic decisions?
+%% Returns : ok - equal to void
+%% Effect :
+%% Exception: HeuristicMixed - Highest priority
+%% HeuristicHazard - Lowest priority
+%%------------------------------------------------------------
+
+commit(_Self, State, _Heuristics) when ?tr_is_retransmit(State) ->
+ ?debug_print("Terminator:commit() recalled.~n", []),
+ {stop, normal, ?tr_get_reportH(State), State};
+commit(Self, State, Heuristics) ->
+ ?debug_print("Terminator:commit() called.~n", []),
+ NewState = ?tr_set_reportH(State, Heuristics),
+ log_safe(?tr_get_terminator(NewState), {init_commit, NewState}),
+ transmit(Self, NewState, Heuristics).
+
+
+transmit(Self, State, Heuristics) ->
+ case catch 'ETraP_Common':try_timeout(?tr_get_alarm(State)) of
+ false ->
+% catch 'ETraP_Server':before_completion(?tr_get_etrap(State)),
+ case catch 'CosTransactions_Resource':prepare(?tr_get_etrap(State)) of
+ 'VoteCommit' ->
+ evaluate_answer(Self, State, Heuristics,
+ 'ETraP_Common':try_timeout(?tr_get_alarm(State)));
+ 'VoteRollback' ->
+ {stop, normal,
+ {'EXCEPTION',
+ #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State};
+ 'VoteReadOnly' ->
+ {stop, normal, ok, State};
+ {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed'),
+ Heuristics==true->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+ {stop, normal, {'EXCEPTION', E}, State};
+ {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard'),
+ Heuristics==true->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+ {stop, normal, {'EXCEPTION', E}, State};
+ {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed') ->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+ {stop, normal,
+ {'EXCEPTION',#'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State};
+ {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard') ->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+ {stop, normal,
+ {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State};
+ Other ->
+ ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n",
+ [?tr_get_etrap(State), Other]),
+ {stop, normal,
+ {'EXCEPTION',
+ #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State}
+ end;
+ _ ->
+ %% Timeout, rollback.
+ log_safe(?tr_get_terminator(State), rolled_back),
+ catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal,
+ {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State}
+ end.
+
+evaluate_answer(Self, State, Heuristics, false) ->
+ evaluate_answer(Self, State, Heuristics, commit);
+evaluate_answer(Self, State, Heuristics, true) ->
+ evaluate_answer(Self, State, Heuristics, rollback);
+evaluate_answer(_Self, State, Heuristics, Vote) ->
+ case catch 'ETraP_Common':send_stubborn('ETraP_Server', Vote,
+ ?tr_get_etrap(State),
+ ?tr_get_maxR(State),
+ ?tr_get_maxW(State)) of
+ ok ->
+ ?eval_debug_fun({_Self, commit_ok1}, State),
+ log_safe(?tr_get_terminator(State), committed),
+ ?eval_debug_fun({_Self, commit_ok2}, State),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusCommitted'),
+ {stop, normal, ok, State};
+ {'EXCEPTION', E} when Heuristics == true andalso
+ is_record(E,'CosTransactions_HeuristicMixed') ->
+ log_safe(?tr_get_terminator(State), {heuristic, State, E}),
+ ?eval_debug_fun({_Self, commit_heuristic1}, State),
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, {'EXCEPTION', E}, State};
+ {'EXCEPTION', E} when Heuristics == true andalso
+ is_record(E, 'CosTransactions_HeuristicHazard') ->
+ log_safe(?tr_get_terminator(State), {heuristic, State, E}),
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, {'EXCEPTION', E}, State};
+ {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
+ log_safe(?tr_get_terminator(State), rolled_back),
+ {stop, normal, {'EXCEPTION', ?tr_hazard}, State};
+ {'EXCEPTION', E} when is_record(E, 'TRANSACTION_ROLLEDBACK') ->
+ log_safe(?tr_get_terminator(State), rolled_back),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, {'EXCEPTION', E}, State};
+ {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicCommit') ->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, ok, State};
+ {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicRollback') ->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusCommitted'),
+ {stop, normal,
+ {'EXCEPTION',
+ #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ State};
+ _Other when Heuristics == true ->
+ log_safe(?tr_get_terminator(State), rolled_back),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, {'EXCEPTION', ?tr_hazard}, State};
+ _Other ->
+ log_safe(?tr_get_terminator(State), rolled_back),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ {stop, normal, ok, State}
+ end.
+
+%%-----------------------------------------------------------%
+%% function : rollback
+%% Arguments: Self - its own object reference.
+%% State - Gen-Server State
+%% Returns : ok - equal to void
+%% Effect :
+%%------------------------------------------------------------
+
+rollback(_Self, State) ->
+ ?debug_print("Terminator:rollback() called.~n", []),
+ log_safe(?tr_get_terminator(State), rolled_back),
+ catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
+ {stop, normal, ok, State}.
+
+%%-----------------------------------------------------------%
+%% function : do_restart
+%% Arguments: State - server context
+%% Returns :
+%% Effect :
+%%------------------------------------------------------------
+
+%% No data in file. Commit never initiated so we rollback (presumed rollback.
+do_restart(State, eof, init) ->
+ log_safe(?tr_get_terminator(State), rolled_back),
+ catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), 'StatusRolledBack'),
+ self() ! {suicide, self()},
+ {ok, State};
+
+do_restart(State, {error, Reason}, _) ->
+ ?tr_error_msg("CosTransactions_Terminator (~p) failed. Cannot read log file: ~p~n",
+ [?tr_get_terminator(State), Reason]),
+ {stop, Reason};
+do_restart(State, eof, Phase) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [Phase]),
+ case Phase of
+ committed ->
+ {ok, ?tr_set_reportH(State, ok)};
+ rolled_back ->
+ self() ! {suicide, self()},
+ {ok, State};
+ init_commit ->
+ case catch corba_object:non_existent(?tr_get_etrap(State)) of
+ true ->
+ self() ! {suicide, self()},
+ {ok, State};
+ _->
+ case transmit(false, State, ?tr_get_reportH(State)) of
+ {stop, normal, ok, NewState} ->
+ {ok, NewState};
+ {stop, normal,
+ {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
+ NewState} ->
+ self() ! {suicide, self()},
+ {ok, NewState};
+ {stop, normal, {'EXCEPTION', Exc}, NewState} ->
+ if
+ ?tr_dont_reportH(State) ->
+ self() ! {suicide, self()},
+ {ok, NewState};
+ true ->
+ {ok, ?tr_set_reportH(NewState, Exc)}
+ end
+ end
+ end;
+ {heuristic, Exc} ->
+ catch 'ETraP_Server':forget(?tr_get_etrap(State)),
+% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
+% 'StatusRolledBack'),
+ if
+ ?tr_dont_reportH(State) ->
+ self() ! {suicide, self()},
+ {ok, State};
+ true ->
+ {ok, ?tr_set_reportH(State, {'EXCEPTION',Exc})}
+ end
+ end;
+%% All done.
+do_restart(State, {done, _Cursor}, _Phase) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
+ self() ! {suicide, self()},
+ {ok, State};
+do_restart(State, {rolled_back, Cursor}, _Phase) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
+ do_restart(State, get_next(?tr_get_terminator(State), Cursor), rolled_back);
+do_restart(State, {committed, Cursor}, _Phase) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
+ do_restart(State, get_next(?tr_get_terminator(State), Cursor), committed);
+do_restart(State, {{heuristic, SavedState, Exc}, Cursor}, _Phase) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
+ do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor),
+ {heuristic, Exc});
+do_restart(State, {{init_commit, SavedState}, Cursor}, _) ->
+ ?debug_print("Terminator:do_restart(~p)~n", [init_commit]),
+ do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor), init_commit).
+
+%%--------------- END OF MODULE ------------------------------