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 + -
显示快捷键?