etrap_server_impl.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,740 行 · 第 1/5 页
ERL
1,740 行
%% File exists, perform restart. etrap_logmgr:start(LogName), ?debug_print("RESTART ~p~n", [?tr_get_etrap(Env)]), prepare_restart({Env, ?etr_set_status(Local, 'StatusUnknown')}, ?etr_read(?tr_get_etrap(Env), start)) end.%%-----------------------------------------------------------%%% function : send_prepare%% Arguments: List of registred resources. %% Returns : ok - equal to void%% Effect : calls send_prepare/3, which sends a prepare call%% to resources participating in the transaction and then collect %% their votes. send_prepare will block until%% it recieves a reply from the resource.%%------------------------------------------------------------send_prepare(RegResources, Alarm) -> send_prepare(RegResources, [], Alarm).% All voted ReadOnly. We are done.send_prepare([], [], _) -> readOnly;% All voted commit (VC) or ReadOnly.send_prepare([], VC, Alarm) -> case catch try_timeout(Alarm) of false -> {commit, VC}; _-> {rollback, VC} end;send_prepare([Rhead|Rtail], VC, Alarm) -> ?debug_print("send_prepare()~n",[]), case catch 'CosTransactions_Resource':prepare(Rhead) of 'VoteCommit' -> case catch try_timeout(Alarm) of false -> _Env = ?get_debug_data(self), ?eval_debug_fun({?tr_get_etrap(_Env), send_prepare}, _Env), send_prepare(Rtail, VC++[Rhead], Alarm); _-> %% Timeout, rollback. However, the resource did vote %% commit. Add it to the list. send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC++[Rhead]} end; 'VoteRollback' -> %% Don't care about timeout since we voted rollback. %% A rollback received. No need for more prepare-calls. %% See OMG 10-51, Transaction Service:v1.0 send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC}; 'VoteReadOnly' -> case catch try_timeout(Alarm) of false -> send_prepare(Rtail, VC, Alarm); _-> %% timeout, reply rollback. send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC} end; {'EXCEPTION',E} when record(E, 'TIMEOUT') -> ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", [Rhead]), %% Since we use presumed abort we will rollback the transaction. send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC}; {'EXCEPTION',E} when record(E, 'TRANSIENT') -> ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", [Rhead]), %% Since we use presumed abort we will rollback the transaction. send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC}; {'EXCEPTION',E} when record(E, 'COMM_FAILURE') -> ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", [Rhead]), %% Since we use presumed abort we will rollback the transaction. send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC}; {'EXCEPTION', E} when record(E, 'OBJECT_NOT_EXIST') -> ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", [Rhead]), send_info(Rtail, 'CosTransactions_Resource', rollback), {rollback, VC}; {'EXCEPTION', Exc} -> ?tr_error_msg("Coordinator:prepare( ~p )~nThe Object raised exception: ~p~n", [Rhead, Exc]), send_info(Rtail, 'CosTransactions_Resource', rollback), %% This can occur if a subtransaction get one or more %% "VoteCommit" followed by a "VoteRollback". %% The subtransaction then do a send_decision(rollback), %% which can generate Heuristic decisions. Must rollback %% since at least one participant voted rollback. {'EXCEPTION', Exc, VC, Rhead}; Other -> ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", [Rhead, Other]), send_info(Rtail, 'CosTransactions_Resource', rollback), {failed, VC} end.%%-----------------------------------------------------------%%% function : type_check%% Arguments: Bool - perform typecheck?%% ID - Type it should be.%% Func - Name of the function (for error_msg)%% Obj - objectrefernce to test.%% Returns : 'ok' or raises exception.%% Effect : %%------------------------------------------------------------type_check(false, _, _, _) -> ok;type_check(_, ID, Func, Obj) -> case catch corba_object:is_a(Obj,ID) of true -> ok; _ -> ?tr_error_msg("~p( ~p ) Bad argument!!~n", [Func, Obj]), corba:raise(?tr_badparam) end.%%-----------------------------------------------------------%%% function : is_heuristic%% Arguments: Exception%% Returns : boolean%% Effect : Returns true if the exception is a heuristic exc.%%------------------------------------------------------------is_heuristic(E) when record(E, 'CosTransactions_HeuristicMixed') -> true;is_heuristic(E) when record(E, 'CosTransactions_HeuristicHazard') -> true;is_heuristic(E) when record(E, 'CosTransactions_HeuristicCommit') -> true;is_heuristic(E) when record(E, 'CosTransactions_HeuristicRollback') -> true;is_heuristic(_) -> false.%%-----------------------------------------------------------%%% function : exception_set%% Arguments: Genserver state%% Returns : %% Effect : Used when restarting.%%------------------------------------------------------------exception_set({Env,Local}) -> case ?etr_get_exc(Local) of void -> self() ! {suicide, self()}, {ok, {Env, Local}}; _ -> {ok, {Env, Local}} end.%%-----------------------------------------------------------%%% function : set_exception%% Arguments: Locally defined #exc{}%% Heuristic mixed or hazard Exeption%% Returns : Altered locally defined #exc{}%% Effect : Set the correct tuple member to true.%%------------------------------------------------------------set_exception(Exc, E) when record(E, 'CosTransactions_HeuristicMixed') -> Exc#exc{mixed = true};set_exception(Exc, E) when record(E, 'CosTransactions_HeuristicHazard') -> Exc#exc{hazard = true};set_exception(Exc, _) -> Exc.%%-----------------------------------------------------------%%% function : send_forget %% Arguments: %% Returns : %% Effect : %%------------------------------------------------------------send_forget([], _) -> ok;send_forget([Rhead|Rtail], LogName) -> ?debug_print("send_forget()~n",[]), _Env = ?get_debug_data(self), case catch 'CosTransactions_Resource':forget(Rhead) of ok -> ?eval_debug_fun({?tr_get_etrap(_Env), send_forget1}, _Env), ?etr_log(LogName, {forgotten, Rhead}), ?eval_debug_fun({?tr_get_etrap(_Env), send_forget2}, _Env), send_forget(Rtail, LogName); Other -> ?tr_error_msg("CosTransactions_Coordinator failed sending forget to ~p~nREASON: ~p~n", [Rhead, Other]), ?eval_debug_fun({?tr_get_etrap(_Env), send_forget3}, _Env), ?etr_log(LogName, {not_forgotten, Rhead}), ?eval_debug_fun({?tr_get_etrap(_Env), send_forget4}, _Env), send_forget(Rtail, LogName) end.%%-----------------------------------------------------------%%% function : send_decision %% Arguments: List of registred resources which vote commit.%% Vote - the outcome of the transaction.%% Returns : ok - equal to void%% Effect : Inform those who voted commit of the outcome.%% They who voted rollback already knows the outcome.%% They who voted ReadOnly are not affected.%%------------------------------------------------------------%%-- Adding extra parameterssend_decision({Env, Local}, Reply, Vote) -> send_decision({Env, Local}, Reply, ?etr_get_vc(Local), Vote, #exc{}, [], 0).send_decision({Env, Local}, Reply, Vote, VC) -> send_decision({Env, Local}, Reply, VC, Vote, #exc{}, [], 0).send_decision(State, no_reply, VC, Vote, Exc) -> send_decision(State, no_reply, VC, Vote, Exc, [], 0).%%-- Decision sent to all members. Do not reply (used when restarting).send_decision({Env, Local}, no_reply, [], _, #exc{mixed = true}, [], _) -> {Env, ?etr_set_exc(Local, ?tr_mixed)};send_decision({Env, Local}, no_reply, [], _, #exc{hazard = true}, [], _) -> {Env, ?etr_set_exc(Local, ?tr_hazard)};send_decision({Env, Local}, no_reply, [], _, _, [], _) -> {Env, Local};send_decision({Env, Local}, no_reply, [], Vote, Exc, Failed, Times) -> case ?tr_get_maxR(Env) of Times -> ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), {Env, ?etr_set_exc(Local, ?tr_hazard)}; _-> timer:sleep(?tr_get_maxW(Env)), NewTimes = Times+1, send_decision({Env, Local}, no_reply, Failed, Vote, Exc, [], NewTimes) end;%%-- end special cases.%% Decision sent to all members. Test exceptions.send_decision({Env, Local}, Reply, [], Vote, Exc, [], _) -> notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), test_exc(Exc, Vote, Reply, {Env, Local});%% Decision not sent to all members (one or more failed). Retry.send_decision({Env, Local}, Reply, [], Vote, Exc, Failed, Times) -> case ?tr_get_maxR(Env) of Times -> ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), test_exc(Exc#exc{hazard = true}, Vote, Reply, {Env, Local}); _-> NewTimes = Times+1, timer:sleep(?tr_get_maxW(Env)), send_decision({Env, Local}, Reply, Failed, Vote, Exc, [], NewTimes) end;send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times) -> ?debug_print("Coordinator:send_decision(~p) Try: ~p~n",[Vote, Times]), case catch 'CosTransactions_Resource':Vote(Rhead) of ok -> ?etr_log(?tr_get_etrap(Env),{sent, Rhead}), send_decision({Env, Local}, Reply, Rtail, Vote, Exc, Failed, Times); {'EXCEPTION', E} when Vote == commit, record(E, 'CosTransactions_NotPrepared') -> ?debug_print("send_decision resource unprepared~n",[]), case catch 'CosTransactions_Resource':prepare(Rhead) of 'VoteCommit' -> send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times); 'VoteRollback' -> send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{mixed = true}, Failed, Times); {'EXCEPTION', E} -> {SetExc, NewL, DidFail} = evaluate_answer(E, Rhead, Vote, Exc, ?tr_get_etrap(Env), Local), send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times) end; {'EXCEPTION', E} -> {SetExc, NewL, DidFail} = evaluate_answer(E, Rhead, Vote, Exc, ?tr_get_etrap(Env), Local), ?tr_error_msg("Resource:~p( ~p )~nRaised Exception: ~p~n", [Vote, Rhead, E]), send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times); {'EXIT', _} -> send_decision({Env, Local}, Reply, Rtail, Vote, Exc, [Rhead|Failed], Times); Other -> ?tr_error_msg("Resource:~p( ~p ) failed.~nREASON: ~p~n", [Vote, Rhead, Other]), case catch corba_object:non_existent(Rhead) of true when Vote == commit -> %% Presumed rollback send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{mixed = true}, Failed, Times); true -> %% Presumed rollback send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{hazard = true}, Failed, Times); _ -> send_decision({Env, Local}, Reply, Rtail, Vote, Exc, [Rhead|Failed], Times) end end.%%-----------------------------------------------------------%%% function : notify_subtrAware, %% Arguments: %% Returns : %% Effect : Invoke an operation on a list of objects. We don't%% care about return values or exceptions.%%------------------------------------------------------------notify_subtrAware(commit, Resources, Self) -> send_info(Resources, Self, 'CosTransactions_SubtransactionAwareResource', commit_subtransaction);notify_subtrAware(_, Resources, _) -> send_info(Resources, 'CosTransactions_SubtransactionAwareResource', rollback_subtransaction).%%-----------------------------------------------------------%%% function : send_info%% Arguments: ObjectList - List of object refernces to call.%% M - Module%% F - Function%% (Arg - required arguments)%% Returns : ok%% Effect : A lightweight function to be used when we don't%% "care" about the return value.%%------------------------------------------------------------send_info([], _, _, _) -> ok;send_info([Rhead|Rtail], Arg, M, F) -> ?debug_print("~p( ~p )~n",[F, Arg]), case catch M:F(Rhead, Arg) of {'EXIT',R} -> ?tr_error_msg("~p:~p(~p, ~p) returned {'EXIT',~p}", [M,F,Rhead,Arg,R]); {'EXCEPTION',E} -> ?tr_error_msg("~p:~p(~p, ~p) returned {'EXCEPTION',~p}", [M,F,Rhead,Arg,E]); _-> ok end, send_info(Rtail, Arg, M, F).send_info([], _, _) -> ok;send_info([Rhead|Rtail], M, F) -> ?debug_print("~p( )~n",[F]), case catch M:F(Rhead) of {'EXIT',R} -> ?tr_error_msg("~p:~p(~p) returned {'EXIT',~p}", [M,F,Rhead,R]); {'EXCEPTION',E} -> ?tr_error_msg("~p:~p(~p) returned {'EXCEPTION',~p}", [M,F,Rhead,E]); _-> ok end, send_info(Rtail, M, F).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?