diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/cosTransactions/src/CosTransactions_Terminator_impl.erl | |
download | otp-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.erl | 362 |
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 ------------------------------ |