etrap_server_impl.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,740 行 · 第 1/5 页

ERL
1,740
字号
%%--------------------------------------------------------------------%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%%%----------------------------------------------------------------------%% File    : ETraP_Server_impl.erl%% Author  : Nicklas Eklund <nick@gwaihir>%% Purpose : %% Created : 15 Oct 1998 by Nicklas Eklund <nick@gwaihir>%%----------------------------------------------------------------------%% GENERAL CODE COMMENTS:%% ######################%% TypeChecking incoming arguments:%% --------------------------------%% We allow the user to configure the system so that external calls%% (not CosTransactions calls) may be typechecked or not when calling%% for example 'replay_completion'. With typecheck the user will get%% instant feedback. But since 'is_a' add quiet a lot extra overhead %% if the object is located on a remote ORB. Hence, it is up to the%% user to decide; speed vs. "safety".%%%% Log behavior%% ------------%% Log files are created in the current directory, which is why the %% application requires read/write rights for current directory. The%% file name looks like:%% "oe_nonode@nohost_subc_939_383117_295538" (the last part is now())%% It is equal to what the object is started as, i.e., {regname, {global, X}}.%% %% If the application is unable to read the log it will exit and the %% supervisor definitions (found in ETraP_Common.hrl) determines how%% many times we will retry. If it's impossible to read the log it's%% considered as a disaster, i.e., user intervention is needed.%% %% If an Object is unreachable when a Coordinator is trying to inform%% of the true outcome of the transaction the application will retry N%% times with T seconds wait in between. If it's still impossible to %% reach the object it's considered as a disaster, i.e., user %% intervention is needed.%% %%-----------------------------------------------------------------------module('ETraP_Server_impl').%%--------------- INCLUDES ------------------------------------include_lib("orber/include/corba.hrl").%% Local-include_lib("cosTransactions/src/ETraP_Common.hrl").-include_lib("cosTransactions/include/CosTransactions.hrl").%%--------------- IMPORTS--------------------------------------import('ETraP_Common', [try_timeout/1]).%%--------------- EXPORTS-------------------------------------%%--------------- Inherit from CosTransactions::Resource -----export([prepare/2, 	 rollback/2, 	 commit/2, 	 commit_one_phase/2, 	 forget/2]).%%--------------- Inherit from CosTransactions::Control ------export([get_terminator/2, 	 get_coordinator/2]).%%----- Inherit from CosTransactions::RecoveryCoordinator ----export([replay_completion/3]).%%--------------- Inherit from CosTransactions::Coordinator --export([create_subtransaction/2,	 get_txcontext/2,	 get_transaction_name/2, 	 get_parent_status/2, 	 get_status/2, 	 get_top_level_status/2,	 hash_top_level_tran/2,	 hash_transaction/2,	 is_ancestor_transaction/3, 	 is_descendant_transaction/3,	 is_related_transaction/3,	 is_same_transaction/3, 	 is_top_level_transaction/2, 	 register_resource/3, 	 register_subtran_aware/3, 	 register_synchronization/3,	 rollback_only/2]).%%--------- Inherit from CosTransactions::Synchronization ---%-export([before_completion/2,%	 after_completion/3]).%%--------------- gen_server specific -------------------------export([init/1, terminate/2]).-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).%%--------------- LOCAL DATA ----------------------------------record(exc, 	{rollback   = false,	 mixed      = false,	 hazard     = false,	 unprepared = false,	 commit     = false}).%%--------------- LOCAL DEFINITIONS --------------------------%%--------------- MISC MACROS ---------------------------------define(etr_log(Log, Data),    etrap_logmgr:log_safe(Log, Data)).-define(etr_read(Log, Cursor), etrap_logmgr:get_next(Log, Cursor)).-record(coord, 	{status,           %% Status of the transaction. 	 members = [],     %% List of registred resources.	 votedCommit = [], %% List of the ones that voted commit.	 raisedHeuristic = [], %% The members which raised an Heur. exc.	 subAw = [],       %% Resorces which want to be informed  of outcome.	 sync = [],	 exc = void,	 self,	 etsR}).%% Selectors-define(etr_get_status(L),     L#coord.status).-define(etr_get_members(L),    lists:reverse(L#coord.members)).-define(etr_get_vc(L),         lists:reverse(L#coord.votedCommit)).-define(etr_get_raisedH(L),    lists:reverse(L#coord.raisedHeuristic)).-define(etr_get_exc(L),        L#coord.exc).-define(etr_get_subAw(L),      lists:reverse(L#coord.subAw)).-define(etr_get_sync(L),       lists:reverse(L#coord.sync)).-define(etr_get_self(L),       L#coord.self).-define(etr_get_etsR(L),       L#coord.etsR).-define(etr_get_init(Env),     #coord{}).-define(etr_get_exc_init(),    #exc{}).%% Modifiers-define(etr_set_status(L, D),  L#coord{status = D}).-define(etr_set_members(L, D), L#coord{members = D}).-define(etr_add_member(L, D),  L#coord{members = [D|L#coord.members]}).-define(etr_set_vc(L, D),      L#coord{votedCommit = D}).-define(etr_add_vc(L, D),      L#coord{votedCommit = [D|L#coord.votedCommit]}).-define(etr_remove_vc(L, D),   L#coord{votedCommit =				       lists:delete(D, ?etr_get_vc(L))}).-define(etr_set_raisedH(L, D), L#coord{raisedHeuristic = [D]}).-define(etr_add_raisedH(L, D), L#coord{raisedHeuristic = 				       [D|L#coord.raisedHeuristic]}).-define(etr_remove_raisedH(L, D), L#coord{raisedHeuristic =					  lists:delete(D, ?etr_get_raisedH(L))}).-define(etr_set_exc(L, D),     L#coord{exc = D}).-define(etr_set_subAw(L, D),   L#coord{subAw = [D]}).-define(etr_add_subAw(L, D),   L#coord{subAw = [D|L#coord.subAw]}).-define(etr_remove_subAw(L, D), L#coord{subAw =					lists:delete(D,?etr_get_subAw(L))}).-define(etr_set_sync(L, D),    L#coord{sync = [D]}).-define(etr_add_sync(L, D),    L#coord{sync = [D|L#coord.sync]}).-define(etr_remove_sync(L, D), L#coord{sync = lists:delete(D,?etr_get_sync(L))}).-define(etr_set_self(L, D),    L#coord{self = D}).-define(etr_set_etsR(L, D),    L#coord{etsR = D}).%%------------------------------------------------------------%% function : init, terminate%% Arguments: %% Returns  : %% Effect   : Functions demanded by the module ic.%%------------------------------------------------------------init(Env) ->    process_flag(trap_exit,true),    case catch start_object(Env) of	{'EXIT', Reason} ->	    %% Happens when, for example, we encounter an 	    %% error when reading from the log file.	    {stop, Reason};	{'EXCEPTION', E} ->	    self() ! {suicide, self()},	    corba:raise(E);	Other ->	    Other    end.terminate(Reason, {Env, _Local}) ->    ?debug_print("STOP ~p   ~p~n", [?tr_get_etrap(Env), Reason]),    case Reason of	normal -> 	    %% normal termination. Transaction completed.	    etrap_logmgr:stop(?tr_get_etrap(Env)),	    file:delete(?tr_get_etrap(Env)),	    ok;	_ ->	    ?tr_error_msg("Object(~p) terminated abnormal.~n",[?tr_get_etrap(Env)]),	    ok    end.%%------------------------------------------------------------%% function : handle_call, handle_cast, handle_info, code_change%% Arguments: %% Returns  : %% Effect   : Functions demanded by the gen_server module. %%------------------------------------------------------------code_change(_OldVsn, State, _Extra) ->    {ok, State}.handle_call(_,_, State) ->    {noreply, State}.handle_cast(_, State) ->    {noreply, State}.handle_info(Info, {Env, Local}) ->    ?debug_print("ETraP_Server:handle_info(~p)~n", [Info]),    Pid = self(),    case Info of	timeout ->	    ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n",			  [?tr_get_etrap(Env)]),            {stop, normal, {Env, Local}};        {suicide, Pid} ->            {stop, normal, {Env, Local}};        _->            {noreply, {Env, Local}}    end.%%--------------- Inherit from CosTransactions::Control -----%%-----------------------------------------------------------%%% function : get_terminator%% Arguments: Self  - its own object reference.%%            State - Gen-Server State%% Returns  : a Terminator object reference.%% Effect   : Supports operations for termination of a transaction%%------------------------------------------------------------get_terminator(Self, {Env, Local}) ->    %% Only allows the root-coordinator to export the termonator.    %% The reason for this is that only the root-coordinator is allowed    %% to initiate termination of a transaction. This is however possible    %% to change and add restictions elsewhere, i.e. to verify if the    %% commit or rollback call is ok.    case catch ?tr_get_parents(Env) of	[] -> % No parents, it's a root-coordinator.	    % Create terminators environment.	    TEnv = ?tr_set_etrap(Env, Self),	    T = ?tr_start_child(?SUP_TERMINATOR(TEnv)),	    {reply, T, {Env, Local}, ?tr_get_timeout(TEnv)};	_ ->	    corba:raise(?tr_unavailable)    end.%%-----------------------------------------------------------%%% function : get_coordinator%% Arguments: Self  - its own object reference.%%            State - Gen-Server State%% Returns  : a Coordinator object reference. The OMG specification%%            states that a object reference must be returned.%% Effect   : Supports operations needed by resources to participate%%            in the transaction.%%------------------------------------------------------------get_coordinator(Self, State) ->    {reply, Self, State}.%%----- Inherit from CosTransactions::RecoveryCoordinator ---%%-----------------------------------------------------------%%% function : replay_completion%% Arguments:%% Returns  : Status%% Effect   : Provides a hint to the Coordinator that the commit%%            or rollback operations have not been performed on%%            the resource.%%------------------------------------------------------------replay_completion(_Self, {Env, Local}, Resource) ->    type_check(?tr_get_typeCheck(Env), ?tr_Resource,	       "RecoveryCoordinator:replay_completion", Resource),    case ?etr_get_status(Local) of	'StatusActive' ->	    corba:raise(?tr_unprepared);	Status ->	    case lists:any(?tr_IS_MEMBER(Resource), ?etr_get_members(Local)) of		true ->		    {reply, Status, {Env, Local}};		_ ->		    corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_YES})	    end    end.%%--------------- Inherit from CosTransactions::Resource ----%%-----------------------------------------------------------%%% function : prepare%% Arguments: %% Returns  : a Vote%% Effect   : Is invoked to begin the two-phase-commit on the%%            resource.%%------------------------------------------------------------prepare(_Self, {Env, Local}) ->        %% Set status as prepared. No new Resources are allowed to register.    NewL = ?etr_set_status(Local, 'StatusPrepared'),    ?eval_debug_fun({?tr_get_etrap(Env), root_delay}, Env),    case catch send_prepare(?etr_get_members(NewL), 			    ?tr_get_alarm(Env)) of	readOnly -> 	    %% All voted ReadOnly, done. No need to log.	    {stop, normal, 'VoteReadOnly', {Env, NewL}};	%% Replace the reply above if allow synchronization%	    case ?etr_get_sync(Local) of%		[] ->%		    {stop, normal, 'VoteReadOnly', {Env, NewL}};%		_ ->%		    {reply, 'VoteReadOnly', {Env, NewL}}%	    end;	{commit, VC} -> 	    %% All voted Commit.	    NewL2 = ?etr_set_vc(NewL, VC),	    case catch try_timeout(?tr_get_alarm(Env)) of		false -> 		    case ?etr_log(?tr_get_etrap(Env), {pre_vote, commit, NewL2}) of			ok ->			    ?eval_debug_fun({?tr_get_etrap(Env), prepare1}, Env),			    {reply, 'VoteCommit', {Env, NewL2}};			_->			    %% Cannot log. Better to be safe than sorry; do rollback.			    %% However, try to log rollback.			    ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}),

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?