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