1%%-------------------------------------------------------------------- 2%% 3%% %CopyrightBegin% 4%% 5%% Copyright Ericsson AB 1999-2016. All Rights Reserved. 6%% 7%% Licensed under the Apache License, Version 2.0 (the "License"); 8%% you may not use this file except in compliance with the License. 9%% You may obtain a copy of the License at 10%% 11%% http://www.apache.org/licenses/LICENSE-2.0 12%% 13%% Unless required by applicable law or agreed to in writing, software 14%% distributed under the License is distributed on an "AS IS" BASIS, 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16%% See the License for the specific language governing permissions and 17%% limitations under the License. 18%% 19%% %CopyrightEnd% 20%% 21%% 22%%---------------------------------------------------------------------- 23%% File : ETraP_Server_impl.erl 24%% Purpose : 25%%---------------------------------------------------------------------- 26%% GENERAL CODE COMMENTS: 27%% ###################### 28%% TypeChecking incoming arguments: 29%% -------------------------------- 30%% We allow the user to configure the system so that external calls 31%% (not CosTransactions calls) may be typechecked or not when calling 32%% for example 'replay_completion'. With typecheck the user will get 33%% instant feedback. But since 'is_a' add quiet a lot extra overhead 34%% if the object is located on a remote ORB. Hence, it is up to the 35%% user to decide; speed vs. "safety". 36%% 37%% Log behavior 38%% ------------ 39%% Log files are created in the current directory, which is why the 40%% application requires read/write rights for current directory. The 41%% file name looks like: 42%% "oe_nonode@nohost_subc_1429872479809947099_438" (the two last parts are 43%% erlang:system_time() and erlang:unique_integer([positive])) 44%% It is equal to what the object is started as, i.e., {regname, {global, X}}. 45%% 46%% If the application is unable to read the log it will exit and the 47%% supervisor definitions (found in ETraP_Common.hrl) determines how 48%% many times we will retry. If it's impossible to read the log it's 49%% considered as a disaster, i.e., user intervention is needed. 50%% 51%% If an Object is unreachable when a Coordinator is trying to inform 52%% of the true outcome of the transaction the application will retry N 53%% times with T seconds wait in between. If it's still impossible to 54%% reach the object it's considered as a disaster, i.e., user 55%% intervention is needed. 56%% 57%%---------------------------------------------------------------------- 58 59-module('ETraP_Server_impl'). 60 61%%--------------- INCLUDES ----------------------------------- 62-include_lib("orber/include/corba.hrl"). 63 64%% Local 65-include_lib("cosTransactions/src/ETraP_Common.hrl"). 66-include_lib("cosTransactions/include/CosTransactions.hrl"). 67 68 69%%--------------- IMPORTS------------------------------------- 70-import('ETraP_Common', [try_timeout/1]). 71 72%%--------------- EXPORTS------------------------------------- 73%%--------------- Inherit from CosTransactions::Resource ---- 74-export([prepare/2, 75 rollback/2, 76 commit/2, 77 commit_one_phase/2, 78 forget/2]). 79 80%%--------------- Inherit from CosTransactions::Control ----- 81-export([get_terminator/2, 82 get_coordinator/2]). 83 84%%----- Inherit from CosTransactions::RecoveryCoordinator --- 85-export([replay_completion/3]). 86 87%%--------------- Inherit from CosTransactions::Coordinator - 88-export([create_subtransaction/2, 89 get_txcontext/2, 90 get_transaction_name/2, 91 get_parent_status/2, 92 get_status/2, 93 get_top_level_status/2, 94 hash_top_level_tran/2, 95 hash_transaction/2, 96 is_ancestor_transaction/3, 97 is_descendant_transaction/3, 98 is_related_transaction/3, 99 is_same_transaction/3, 100 is_top_level_transaction/2, 101 register_resource/3, 102 register_subtran_aware/3, 103 register_synchronization/3, 104 rollback_only/2]). 105 106%%--------- Inherit from CosTransactions::Synchronization --- 107%-export([before_completion/2, 108% after_completion/3]). 109 110 111%%--------------- gen_server specific ------------------------ 112-export([init/1, terminate/2]). 113-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]). 114 115 116 117%%--------------- LOCAL DATA --------------------------------- 118-record(exc, 119 {rollback = false, 120 mixed = false, 121 hazard = false, 122 unprepared = false, 123 commit = false}). 124 125%%--------------- LOCAL DEFINITIONS -------------------------- 126 127%%--------------- MISC MACROS -------------------------------- 128-define(etr_log(Log, Data), etrap_logmgr:log_safe(Log, Data)). 129-define(etr_read(Log, Cursor), etrap_logmgr:get_next(Log, Cursor)). 130 131-record(coord, 132 {status, %% Status of the transaction. 133 members = [], %% List of registred resources. 134 votedCommit = [], %% List of the ones that voted commit. 135 raisedHeuristic = [], %% The members which raised an Heur. exc. 136 subAw = [], %% Resorces which want to be informed of outcome. 137 sync = [], 138 exc = void, 139 self, 140 etsR}). 141 142%% Selectors 143-define(etr_get_status(L), L#coord.status). 144-define(etr_get_members(L), lists:reverse(L#coord.members)). 145-define(etr_get_vc(L), lists:reverse(L#coord.votedCommit)). 146-define(etr_get_raisedH(L), lists:reverse(L#coord.raisedHeuristic)). 147-define(etr_get_exc(L), L#coord.exc). 148-define(etr_get_subAw(L), lists:reverse(L#coord.subAw)). 149-define(etr_get_sync(L), lists:reverse(L#coord.sync)). 150-define(etr_get_self(L), L#coord.self). 151-define(etr_get_etsR(L), L#coord.etsR). 152-define(etr_get_init(Env), #coord{}). 153-define(etr_get_exc_init(), #exc{}). 154%% Modifiers 155-define(etr_set_status(L, D), L#coord{status = D}). 156-define(etr_set_members(L, D), L#coord{members = D}). 157-define(etr_add_member(L, D), L#coord{members = [D|L#coord.members]}). 158-define(etr_set_vc(L, D), L#coord{votedCommit = D}). 159-define(etr_add_vc(L, D), L#coord{votedCommit = [D|L#coord.votedCommit]}). 160-define(etr_remove_vc(L, D), L#coord{votedCommit = 161 lists:delete(D, ?etr_get_vc(L))}). 162-define(etr_set_raisedH(L, D), L#coord{raisedHeuristic = [D]}). 163-define(etr_add_raisedH(L, D), L#coord{raisedHeuristic = 164 [D|L#coord.raisedHeuristic]}). 165-define(etr_remove_raisedH(L, D), L#coord{raisedHeuristic = 166 lists:delete(D, ?etr_get_raisedH(L))}). 167-define(etr_set_exc(L, D), L#coord{exc = D}). 168-define(etr_set_subAw(L, D), L#coord{subAw = [D]}). 169-define(etr_add_subAw(L, D), L#coord{subAw = [D|L#coord.subAw]}). 170-define(etr_remove_subAw(L, D), L#coord{subAw = 171 lists:delete(D,?etr_get_subAw(L))}). 172-define(etr_set_sync(L, D), L#coord{sync = [D]}). 173-define(etr_add_sync(L, D), L#coord{sync = [D|L#coord.sync]}). 174-define(etr_remove_sync(L, D), L#coord{sync = lists:delete(D,?etr_get_sync(L))}). 175-define(etr_set_self(L, D), L#coord{self = D}). 176-define(etr_set_etsR(L, D), L#coord{etsR = D}). 177 178 179%%------------------------------------------------------------ 180%% function : init, terminate 181%% Arguments: 182%% Returns : 183%% Effect : Functions demanded by the module ic. 184%%------------------------------------------------------------ 185 186init(Env) -> 187 process_flag(trap_exit,true), 188 case catch start_object(Env) of 189 {'EXIT', Reason} -> 190 %% Happens when, for example, we encounter an 191 %% error when reading from the log file. 192 {stop, Reason}; 193 {'EXCEPTION', E} -> 194 self() ! {suicide, self()}, 195 corba:raise(E); 196 Other -> 197 Other 198 end. 199 200 201 202terminate(Reason, {Env, _Local}) -> 203 ?debug_print("STOP ~p ~p~n", [?tr_get_etrap(Env), Reason]), 204 case Reason of 205 normal -> 206 %% normal termination. Transaction completed. 207 etrap_logmgr:stop(?tr_get_etrap(Env)), 208 file:delete(?tr_get_etrap(Env)), 209 ok; 210 _ -> 211 ?tr_error_msg("Object(~p) terminated abnormal.~n",[?tr_get_etrap(Env)]), 212 ok 213 end. 214 215 216%%------------------------------------------------------------ 217%% function : handle_call, handle_cast, handle_info, code_change 218%% Arguments: 219%% Returns : 220%% Effect : Functions demanded by the gen_server module. 221%%------------------------------------------------------------ 222 223code_change(_OldVsn, State, _Extra) -> 224 {ok, State}. 225 226handle_call(_,_, State) -> 227 {noreply, State}. 228 229handle_cast(_, State) -> 230 {noreply, State}. 231 232 233handle_info(Info, {Env, Local}) -> 234 ?debug_print("ETraP_Server:handle_info(~p)~n", [Info]), 235 Pid = self(), 236 case Info of 237 timeout -> 238 ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n", 239 [?tr_get_etrap(Env)]), 240 {stop, normal, {Env, Local}}; 241 {suicide, Pid} -> 242 {stop, normal, {Env, Local}}; 243 _-> 244 {noreply, {Env, Local}} 245 end. 246 247 248%%--------------- Inherit from CosTransactions::Control ----- 249%%-----------------------------------------------------------% 250%% function : get_terminator 251%% Arguments: Self - its own object reference. 252%% State - Gen-Server State 253%% Returns : a Terminator object reference. 254%% Effect : Supports operations for termination of a transaction 255%%------------------------------------------------------------ 256 257get_terminator(Self, {Env, Local}) -> 258 %% Only allows the root-coordinator to export the termonator. 259 %% The reason for this is that only the root-coordinator is allowed 260 %% to initiate termination of a transaction. This is however possible 261 %% to change and add restictions elsewhere, i.e. to verify if the 262 %% commit or rollback call is ok. 263 case catch ?tr_get_parents(Env) of 264 [] -> % No parents, it's a root-coordinator. 265 % Create terminators environment. 266 TEnv = ?tr_set_etrap(Env, Self), 267 T = ?tr_start_child(?SUP_TERMINATOR(TEnv)), 268 {reply, T, {Env, Local}, ?tr_get_timeout(TEnv)}; 269 _ -> 270 corba:raise(?tr_unavailable) 271 end. 272 273%%-----------------------------------------------------------% 274%% function : get_coordinator 275%% Arguments: Self - its own object reference. 276%% State - Gen-Server State 277%% Returns : a Coordinator object reference. The OMG specification 278%% states that a object reference must be returned. 279%% Effect : Supports operations needed by resources to participate 280%% in the transaction. 281%%------------------------------------------------------------ 282 283get_coordinator(Self, State) -> 284 {reply, Self, State}. 285 286%%----- Inherit from CosTransactions::RecoveryCoordinator --- 287%%-----------------------------------------------------------% 288%% function : replay_completion 289%% Arguments: 290%% Returns : Status 291%% Effect : Provides a hint to the Coordinator that the commit 292%% or rollback operations have not been performed on 293%% the resource. 294%%------------------------------------------------------------ 295 296replay_completion(_Self, {Env, Local}, Resource) -> 297 type_check(?tr_get_typeCheck(Env), ?tr_Resource, 298 "RecoveryCoordinator:replay_completion", Resource), 299 case ?etr_get_status(Local) of 300 'StatusActive' -> 301 corba:raise(?tr_unprepared); 302 Status -> 303 case lists:any(?tr_IS_MEMBER(Resource), ?etr_get_members(Local)) of 304 true -> 305 {reply, Status, {Env, Local}}; 306 _ -> 307 corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_YES}) 308 end 309 end. 310 311%%--------------- Inherit from CosTransactions::Resource ---- 312%%-----------------------------------------------------------% 313%% function : prepare 314%% Arguments: 315%% Returns : a Vote 316%% Effect : Is invoked to begin the two-phase-commit on the 317%% resource. 318%%------------------------------------------------------------ 319 320prepare(_Self, {Env, Local}) -> 321 %% Set status as prepared. No new Resources are allowed to register. 322 NewL = ?etr_set_status(Local, 'StatusPrepared'), 323 324 ?eval_debug_fun({?tr_get_etrap(Env), root_delay}, Env), 325 326 case catch send_prepare(?etr_get_members(NewL), 327 ?tr_get_alarm(Env)) of 328 readOnly -> 329 %% All voted ReadOnly, done. No need to log. 330 {stop, normal, 'VoteReadOnly', {Env, NewL}}; 331 %% Replace the reply above if allow synchronization 332% case ?etr_get_sync(Local) of 333% [] -> 334% {stop, normal, 'VoteReadOnly', {Env, NewL}}; 335% _ -> 336% {reply, 'VoteReadOnly', {Env, NewL}} 337% end; 338 {commit, VC} -> 339 %% All voted Commit. 340 NewL2 = ?etr_set_vc(NewL, VC), 341 case catch try_timeout(?tr_get_alarm(Env)) of 342 false -> 343 case ?etr_log(?tr_get_etrap(Env), {pre_vote, commit, NewL2}) of 344 ok -> 345 ?eval_debug_fun({?tr_get_etrap(Env), prepare1}, Env), 346 {reply, 'VoteCommit', {Env, NewL2}}; 347 _-> 348 %% Cannot log. Better to be safe than sorry; do rollback. 349 %% However, try to log rollback. 350 ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}), 351 send_decision({Env, NewL2}, 'VoteRollback', rollback) 352 end; 353 _-> 354 ?etr_log(?tr_get_etrap(Env), 355 {pre_vote, rollback, NewL2}), 356 %% timeout, reply rollback. 357 send_decision({Env, NewL2}, 'VoteRollback', rollback) 358 end; 359 {rollback, VC} -> 360 %% Rollback vote received. 361 %% Send rollback to commit voters. 362 N2 = ?etr_set_vc(NewL, VC), 363 NewL2 = ?etr_set_status(N2,'StatusRolledBack'), 364 ?etr_log(?tr_get_etrap(Env), {pre_vote, rollback, NewL2}), 365 send_decision({Env, NewL2}, 'VoteRollback', rollback); 366 {'EXCEPTION', E, VC, Obj} -> 367 NewL2 = case is_heuristic(E) of 368 true -> 369 N2 = ?etr_set_vc(NewL, VC), 370 N3 = ?etr_set_exc(N2, E), 371 ?etr_set_raisedH(N3, Obj); 372 _-> 373 ?etr_set_vc(NewL, VC) 374 end, 375 ?etr_log(?tr_get_etrap(Env),{pre_vote,rollback, NewL2}), 376 ?eval_debug_fun({?tr_get_etrap(Env), prepare2}, Env), 377 send_decision({Env, NewL2}, {'EXCEPTION', E}, rollback); 378 {failed, VC} -> 379 NewL2 = ?etr_set_vc(NewL, VC), 380 ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}), 381 send_decision({Env, NewL2}, 382 {'EXCEPTION', ?tr_hazard}, rollback) 383 end. 384 385 386%%-----------------------------------------------------------% 387%% function : rollback 388%% Arguments: Self - the servers own objref. 389%% {Env, Local} - the servers internal state. 390%% Returns : ok 391%% Effect : Rollback the transaction. If its status is 392%% "StatusRolledBack", this is not the first 393%% rollback call to this server. Might occur if 394%% the parent coordinator just recoeverd from a crasch. 395%% Exception: HeuristicCommit, HeuristicMixed, HeuristicHazard 396%%------------------------------------------------------------ 397 398rollback(Self, {Env, Local}) -> 399 case ?etr_get_status(Local) of 400 'StatusRolledBack' -> 401 case ?etr_get_exc(Local) of 402 void -> 403 {stop, normal, ok, {Env, Local}}; 404 %% Replace the reply above if allow synchronization 405 %% Rolled back successfullly earlier. 406% case ?etr_get_sync(Local) of 407% [] -> 408% {stop, normal, ok, {Env, Local}}; 409% _ -> 410% {reply, ok, {Env, Local}} 411% end; 412 E -> 413 %% Already rolledback with heuristic decision 414 corba:raise(E) 415 end; 416 'StatusPrepared' -> 417 NewL = ?etr_set_status(Local, 'StatusRolledBack'), 418 ?eval_debug_fun({?tr_get_etrap(Env), rollback}, Env), 419 ?etr_log(?tr_get_etrap(Env), rollback), 420 ?eval_debug_fun({?tr_get_etrap(Env), rollback2}, Env), 421 send_decision({Env, NewL}, ok, rollback); 422 'StatusActive' -> 423 NewL = ?etr_set_status(Local, 'StatusRolledBack'), 424 ?etr_log(?tr_get_etrap(Env), {rollback, NewL}), 425 send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), 426 notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self), 427 {stop, normal, ok, {Env, NewL}} 428%% Replace the reply above if allow synchronization 429% case ?etr_get_sync(Local) of 430% [] -> 431% {stop, normal, ok, {NewEnv, NewL}}; 432% _ -> 433% {reply, ok, {NewEnv, NewL}} 434% end; 435 end. 436 437 438%%-----------------------------------------------------------% 439%% function : commit 440%% Arguments: Self - the servers own objref. 441%% {Env, Local} - the servers internal state. 442%% Returns : ok 443%% Effect : Commit the transaction. 444%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard, 445%% NotPrepared 446%%------------------------------------------------------------ 447 448commit(_Self, {Env, Local}) -> 449 case ?etr_get_status(Local) of 450 'StatusPrepared' -> 451 ?eval_debug_fun({?tr_get_etrap(Env), commit}, Env), 452 NewL = ?etr_set_status(Local, 'StatusCommitted'), 453 ?etr_log(?tr_get_etrap(Env),commit), 454 ?eval_debug_fun({?tr_get_etrap(Env), commit2}, Env), 455 send_decision({Env, NewL}, ok, commit); 456 'StatusCommitted' -> 457 case ?etr_get_exc(Local) of 458 void -> 459 {stop, normal, ok, {Env, Local}}; 460 %% Replace the reply above if allow synchronization 461% case ?etr_get_sync(Local) of 462% [] -> 463% {stop, normal, ok, {Env, Local}}; 464% _ -> 465% {reply, ok, {Env, Local}} 466% end; 467 E-> 468 corba:raise(E) 469 end; 470 _ -> 471 corba:raise(?tr_unprepared) 472 end. 473 474%%-----------------------------------------------------------% 475%% function : commit_one_phase 476%% Arguments: Self - the servers own objref. 477%% {Env, Local} - the servers internal state. 478%% Returns : ok 479%% Effect : Commit the transaction using one-phase commit. 480%% Use ONLY when there is only one registered Resource. 481%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard, 482%% TRANSACTION_ROLLEDBACK 483%%------------------------------------------------------------ 484 485commit_one_phase(_Self, {Env, Local}) -> 486 case ?etr_get_members(Local) of 487 [Resource] -> 488 case ?etr_get_status(Local) of 489 'StatusActive' -> 490 %% Set status as prepared. No new Resources are allowed to register. 491 NewL = ?etr_set_status(Local, 'StatusPrepared'), 492 ?eval_debug_fun({?tr_get_etrap(Env), onePC}, Env), 493 case try_timeout(?tr_get_alarm(Env)) of 494 false -> 495 case catch 'CosTransactions_Resource':prepare(Resource) of 496 'VoteCommit' -> 497 case try_timeout(?tr_get_alarm(Env)) of 498 false -> 499 send_decision({Env, NewL}, ok, commit, [Resource]); 500 _-> 501 %% Timeout, rollback. 502 send_decision({Env, NewL}, 503 {'EXCEPTION', 504 #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 505 rollback, [Resource]) 506 end; 507 'VoteRollback' -> 508 {stop, normal, 509 {'EXCEPTION', 510 #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 511 {Env, NewL}}; 512 'VoteReadOnly' -> 513 {stop, normal, ok, {Env, NewL}}; 514 {'EXCEPTION', E} 515 when is_record(E, 'CosTransactions_HeuristicMixed') -> 516 {reply, {'EXCEPTION', E}, {Env, NewL}}; 517 {'EXCEPTION', E} 518 when is_record(E, 'CosTransactions_HeuristicHazard') -> 519 {reply, {'EXCEPTION', E}, {Env, NewL}}; 520 Other -> 521 ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", 522 [Resource, Other]), 523 {stop, normal, 524 {'EXCEPTION', 525 #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 526 {Env, NewL}} 527 end; 528 _-> 529 NewL2 = ?etr_set_status(NewL, 'StatusRolledBack'), 530 send_info(Resource, 'CosTransactions_Resource', rollback), 531 {stop, normal, 532 {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 533 {Env, NewL2}} 534 %% Replace the reply above if allow synchronization 535% case ?etr_get_sync(NewL2) of 536% [] -> 537% send_info(Resource, 'CosTransactions_Resource', rollback), 538% {stop, normal, 539% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 540% {Env, NewL2}}; 541% _ -> 542% send_info(Resource, 'CosTransactions_Resource', rollback), 543% {reply, 544% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 545% {Env, NewL2}} 546% end 547 end; 548 _ -> 549 case evaluate_status(?etr_get_status(Local)) of 550 commit -> 551 test_exc(set_exception(?etr_get_exc_init(), 552 ?etr_get_exc(Local)), 553 commit, ok, {Env, Local}); 554 _-> 555 test_exc(set_exception(?etr_get_exc_init(), 556 ?etr_get_exc(Local)), 557 rollback, 558 {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, 559 {Env, Local}) 560 end 561 end; 562 _-> 563 {reply, {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}}, 564 {Env, Local}} 565 end. 566 567%%-----------------------------------------------------------% 568%% function : forget 569%% Arguments: Self - the servers own objref. 570%% State - the servers internal state. 571%% Returns : ok 572%% Effect : The resource can forget all knowledge about the 573%% transaction. Terminate this server. 574%%------------------------------------------------------------ 575 576forget(_Self, {Env, Local}) -> 577 ?etr_log(?tr_get_etrap(Env), forget_phase), 578 send_forget(?etr_get_raisedH(Local), ?tr_get_etrap(Env)), 579 {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}}. 580%% Replace the reply above if allow synchronization 581% case ?etr_get_sync(Local) of 582% [] -> 583% {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}}; 584% _ -> 585% {reply, ok, {Env, ?etr_set_exc(Local, void)}} 586% end. 587 588%%--------------- Inherrit from CosTransactions::Coordinator - 589 590%%-----------------------------------------------------------% 591%% function : get_status 592%% Arguments: Self - its own object reference. 593%% State - Gen-Server State 594%% Returns : Status 595%% Effect : Returns the status of the transaction associated 596%% with the target object. 597%%------------------------------------------------------------ 598 599get_status(_Self, {Env, Local}) -> 600 {reply, ?etr_get_status(Local), {Env, Local}}. 601 602 603%%-----------------------------------------------------------% 604%% function : get_parent_status 605%% Arguments: Self - its own object reference. 606%% State - Gen-Server State 607%% Returns : Status 608%% Effect : Returns the status of the parent transaction 609%% associated with the target object. If top-level 610%% transaction equal to get_status. 611%%------------------------------------------------------------ 612 613get_parent_status(_Self, {Env, Local}) -> 614 case catch ?tr_get_parents(Env) of 615 [] -> 616 {reply, ?etr_get_status(Local), {Env, Local}}; 617 [Parent|_] -> 618 case catch 'CosTransactions_Coordinator':get_status(Parent) of 619 {'EXCEPTION', _E} -> 620 corba:raise(?tr_unavailable); 621 {'EXIT', _} -> 622 corba:raise(?tr_unavailable); 623 Status -> 624 {reply, Status, {Env, Local}} 625 end 626 end. 627 628 629%%-----------------------------------------------------------% 630%% function : get_top_level_status 631%% Arguments: Self - its own object reference. 632%% State - Gen-Server State 633%% Returns : Status 634%% Effect : Returns the status of the top-level transaction 635%% associated with the target object. If top-level 636%% transaction equal to get_status. 637%%------------------------------------------------------------ 638 639get_top_level_status(_Self, {Env, Local}) -> 640 case catch ?tr_get_parents(Env) of 641 [] -> 642 {reply, ?etr_get_status(Local), {Env, Local}}; 643 Ancestrors -> 644 case catch 'CosTransactions_Coordinator':get_status(lists:last(Ancestrors)) of 645 {'EXCEPTION', _E} -> 646 corba:raise(?tr_unavailable); 647 {'EXIT', _} -> 648 corba:raise(?tr_unavailable); 649 Status -> 650 {reply, Status, {Env, Local}} 651 end 652 end. 653 654 655%%-----------------------------------------------------------% 656%% function : is_same_transaction 657%% Arguments: Self - its own object reference. 658%% State - Gen-Server State 659%% Coordinator object reference 660%% Returns : boolean 661%% Effect : 662%%------------------------------------------------------------ 663 664is_same_transaction(Self, {Env, Local}, Coordinator) -> 665 type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, 666 "Coordinator:is_same_transaction", Coordinator), 667 {reply, corba_object:is_equivalent(Self, Coordinator), {Env, Local}}. 668 669%%------------------------------------------------------------ 670%% function : is_related_transaction 671%% Arguments: Self - its own object reference. 672%% State - Gen-Server State 673%% Coordinator object reference 674%% Returns : boolean 675%% Effect : 676%%------------------------------------------------------------ 677 678-spec is_related_transaction(_, _, _) -> no_return(). 679is_related_transaction(_Self, {_Env, _Local}, _Coordinator) -> 680 corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). 681% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, 682% "Coordinator:is_related_transaction", Coordinator), 683% {reply, false, {Env, Local}}. 684 685 686%%------------------------------------------------------------ 687%% function : is_ancestor_transaction 688%% Coordinator object reference 689%% Returns : boolean 690%% Effect : 691%%------------------------------------------------------------ 692 693-spec is_ancestor_transaction(_, _, _) -> no_return(). 694is_ancestor_transaction(_Self, {_Env, _Local}, _Coordinator) -> 695 corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). 696% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, 697% "Coordinator:is_ancestor_transaction", Coordinator), 698% {reply, false, {Env, Local}}. 699 700 701%%-----------------------------------------------------------% 702%% function : is_descendant_transaction 703%% Arguments: Self - its own object reference. 704%% State - Gen-Server State 705%% Coordinator object reference 706%% Returns : boolean 707%% Effect : 708%%------------------------------------------------------------ 709 710is_descendant_transaction(Self, {Env, Local}, Coordinator) -> 711 type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, 712 "Coordinator:is_descendant_transaction", Coordinator), 713 {reply, 714 lists:any(?tr_IS_MEMBER(Coordinator), [Self|?tr_get_parents(Env)]), 715 {Env, Local}}. 716 717%%-----------------------------------------------------------% 718%% function : is_top_level_transaction 719%% Arguments: Self - its own object reference. 720%% State - Gen-Server State 721%% Returns : boolean 722%% Effect : 723%%------------------------------------------------------------ 724 725is_top_level_transaction(_Self, {Env, Local}) -> 726 case catch ?tr_get_parents(Env) of 727 [] -> 728 {reply, true, {Env, Local}}; 729 _ -> 730 {reply, false, {Env, Local}} 731 end. 732 733%%-----------------------------------------------------------% 734%% function : hash_transaction 735%% Arguments: Self - its own object reference. 736%% State - Gen-Server State 737%% Returns : hash code 738%% Effect : Returns a hash code for the transaction associated 739%% with the target object. 740%%------------------------------------------------------------ 741 742hash_transaction(Self, {Env, Local}) -> 743 {reply, corba_object:hash(Self, ?tr_get_hashMax(Env)), {Env, Local}}. 744 745 746%%-----------------------------------------------------------% 747%% function : hash_top_level_tran 748%% Arguments: Self - its own object reference. 749%% State - Gen-Server State 750%% Returns : hash code 751%% Effect : Returns a hash code for the top-level transaction 752%% associated with the target object. Equals 753%% hash_transaction if it's a top-level transaction. 754%%------------------------------------------------------------ 755 756hash_top_level_tran(Self, {Env, Local}) -> 757 case ?tr_get_parents(Env) of 758 [] -> 759 {reply, 760 corba_object:hash(Self, ?tr_get_hashMax(Env)), 761 {Env, Local}}; 762 Ancestrors -> 763 case catch corba_object:hash(lists:last(Ancestrors), 764 ?tr_get_hashMax(Env)) of 765 {'EXCEPTION', _E} -> 766 corba:raise(?tr_unavailable); 767 Hash -> 768 {reply, Hash, {Env, Local}} 769 end 770 end. 771 772 773 774%%-----------------------------------------------------------% 775%% function : register_resource 776%% Arguments: Self - its own object reference. 777%% State - Gen-Server State 778%% Resource object reference 779%% Returns : RecoveryCoordinator (can be used during recovery) 780%% Effect : Registers the specified resource as as participant 781%% in the transaction associated with the target object. 782%% Exception: Inactive - Is prepared or terminated. 783%%------------------------------------------------------------ 784 785register_resource(Self, {Env, Local}, Resource) -> 786 type_check(?tr_get_typeCheck(Env), ?tr_Resource, 787 "Coordinator:register_resource", Resource), 788 case ?etr_get_status(Local) of 789 'StatusActive' -> % ok to register the Resource. 790 NewLocal = ?etr_add_member(Local, Resource), 791 RecoveryCoord = corba:create_subobject_key(Self, ?tr_get_etrap(Env)), 792 {reply, RecoveryCoord, {Env, NewLocal}, ?tr_get_timeout(Env)}; 793 _-> % Not active anymore. New members not ok. 794 corba:raise(?tr_inactive) 795 end. 796 797 798 799%%-----------------------------------------------------------% 800%% function : register_subtran_aware 801%% Arguments: Self - its own object reference. 802%% State - Gen-Server State 803%% SubTransactionAwareResource object reference 804%% Returns : - 805%% Effect : Registers the specified object such that it 806%% will be notified when the subtransaction has 807%% commited or rolled back. 808%%------------------------------------------------------------ 809 810register_subtran_aware(Self, {Env, Local}, SubTrAwareResource) -> 811 case ?tr_get_parents(Env) of 812 [] -> 813 corba:raise(?tr_NotSubtr); 814 _-> 815 type_check(?tr_get_typeCheck(Env), ?tr_SubtransactionAwareResource, 816 "Coordinator:register_subtran_aware", SubTrAwareResource), 817 NewL = ?etr_add_subAw(Local, SubTrAwareResource), 818 {reply, ok, {Env, ?etr_set_self(NewL, Self)}, 819 ?tr_get_timeout(Env)} 820 end. 821 822%%-----------------------------------------------------------% 823%% function : register_synchronization 824%% Arguments: Self - its own object reference. 825%% State - Gen-Server State 826%% Synchronization 827%% Returns : - 828%% Effect : 829%%------------------------------------------------------------ 830 831-spec register_synchronization(_, _, _) -> no_return(). 832register_synchronization(_Self, {_Env, _Local}, _Synchronization) -> 833 corba:raise(#'CosTransactions_SynchronizationUnavailable'{}). 834 835%register_synchronization(Self, {Env, Local}, Synchronization) -> 836% type_check(?tr_get_typeCheck(Env), ?tr_Synchronization, 837% "Coordinator:register_synchronization", Synchronization), 838% case ?etr_get_status(Local) of 839% 'StatusActive' -> 840% case catch ?tr_get_parents(Env) of 841% [] -> 842% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)}, 843% ?tr_get_timeout(Env)}; 844% [Parent|_] -> 845% case catch 'ETraP_Server':register_synchronization(Parent, Self) of 846% {'EXCEPTION', E} -> 847% corba:raise(E); 848% ok -> 849% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)}, 850% ?tr_get_timeout(Env)}; 851% What -> 852% corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE}) 853% end 854% end; 855% _ -> 856% corba:raise(?tr_inactive) 857% end. 858 859%%-----------------------------------------------------------% 860%% function : rollback_only 861%% Arguments: Self - its own object reference. 862%% State - Gen-Server State 863%% Returns : - 864%% Effect : The transaction associated with the target object 865%% is modified so that rollback IS the result. 866%%------------------------------------------------------------ 867 868rollback_only(Self, {Env, Local}) -> 869 case ?etr_get_status(Local) of 870 'StatusActive' -> 871 NewL = ?etr_set_status(Local, 'StatusRolledBack'), 872 NewEnv = ?tr_set_rollback(Env, true), 873 ?etr_log(?tr_get_etrap(Env),{rollback, NewL}), 874 send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), 875 notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self), 876 {stop, normal, ok, {NewEnv, NewL}}; 877%% Replace the reply above if allow synchronization 878% case ?etr_get_sync(Local) of 879% [] -> 880% {stop, normal, ok, {NewEnv, NewL}}; 881% _ -> 882% {reply, ok, {NewEnv, NewL}} 883% end; 884 _ -> 885 corba:raise(?tr_inactive) 886 end. 887 888%%-----------------------------------------------------------% 889%% function : get_transaction_name 890%% Arguments: Self - its own object reference. 891%% State - Gen-Server State 892%% Returns : string - which describes the transaction associated 893%% with the target object. 894%% Effect : Intended for debugging. 895%%------------------------------------------------------------ 896 897get_transaction_name(_Self, {Env, Local}) -> 898 {reply, ?tr_get_etrap(Env), {Env, Local}}. 899 900%%-----------------------------------------------------------% 901%% function : create_subtransaction 902%% Arguments: Self - its own object reference. 903%% State - Gen-Server State 904%% Returns : A control object if subtransactions are allowed, 905%% otherwise an exception is raised. 906%% Effect : A new subtransaction is created whos parent is 907%% the transaction associated with the target object. 908%% Exception: SubtransactionUnavailabe - no support for nested 909%% transactions. 910%% Inactive - already been prepared. 911%%------------------------------------------------------------ 912 913create_subtransaction(Self, {Env, Local}) -> 914 case ?etr_get_status(Local) of 915 'StatusActive' -> 916 case ?tr_get_subTraOK(Env) of 917 true -> 918 ETraPName = 'ETraP_Common':create_name("subc"), 919 Tname = 'ETraP_Common':create_name("subt"), 920 921 %% Create context for the new object. 922 State = ?tr_create_context(ETraPName, Tname, 923 ?tr_get_typeCheck(Env), 924 ?tr_get_hashMax(Env), 925 ?tr_get_subTraOK(Env), 926 ?tr_get_maxR(Env), 927 ?tr_get_maxW(Env)), 928 929 930 State2 = ?tr_add_parent(State, Self), 931 932 State3 = ?tr_set_alarm(State2, ?tr_get_alarm(Env)), 933 934 State4 = ?tr_set_timeout(State3, ?tr_get_timeout(Env)), 935 936 Control = ?tr_start_child(?SUP_ETRAP(State4)), 937 %% Set the SubCoordinator object reference and register it as participant. 938 SubCoord = 'CosTransactions_Control':get_coordinator(Control), 939 NewLocal = ?etr_add_member(Local, SubCoord), 940 {reply, Control, {Env, NewLocal}, ?tr_get_timeout(Env)}; 941 _ -> 942 %% subtransactions not allowed, raise exception. 943 corba:raise(?tr_subunavailable) 944 end; 945 _-> 946 corba:raise(?tr_inactive) 947 end. 948 949%%-----------------------------------------------------------% 950%% function : get_txcontext 951%% Arguments: 952%% Returns : PropagationContext 953%% Effect : 954%%------------------------------------------------------------ 955 956-spec get_txcontext(_, _) -> no_return(). 957get_txcontext(_Self, {_Env, _Local}) -> 958 corba:raise(#'CosTransactions_Unavailable'{}). 959 960%get_txcontext(Self, {Env, Local}) -> 961% Otid = #'CosTransactions_otid_t'{formatID=0, 962% bqual_length=0, 963% tid=[corba_object:hash(Self, 964% ?tr_get_hashMax(Env))]}, 965% TrIDs = create_TransIdentities(?tr_get_parents(Env), Env, [], Otid), 966% C=case ?tr_get_parents(Env) of 967% [] -> 968% #'CosTransactions_TransIdentity'{coord=Self, 969% term=?tr_get_terminator(Env), 970% otid=Otid}; 971% _-> 972% #'CosTransactions_TransIdentity'{coord=Self, 973% term=?tr_NIL_OBJ_REF, 974% otid=Otid} 975% end, 976% case ?tr_get_timeout(Env) of 977% infinity -> 978% #'CosTransactions_PropagationContext'{timeout=0, 979% current= C, 980% parents=TrIDs}; 981% T -> 982% #'CosTransactions_PropagationContext'{timeout=T/1000, 983% current= C, 984% parents=TrIDs} 985% end. 986 987%create_TransIdentities([], _, Parents, _) -> Parents; 988%create_TransIdentities([Phead|Ptail], Env, Parents, Otid) -> 989% NO=Otid#'CosTransactions_TransIdentity'{otid= 990% corba_object:hash(Phead, 991% ?tr_get_hashMax(Env))}, 992% create_TransIdentities([Phead|Ptail], Env, Parents++ 993% [#'CosTransactions_TransIdentity'{coord=Phead, 994% term=?tr_NIL_OBJ_REF, 995% otid=NO}], 996% Otid). 997 998 999%%--------- Inherit from CosTransactions::Synchronization --- 1000 1001%%-----------------------------------------------------------% 1002%% function : before_completion 1003%% Arguments: 1004%% Returns : 1005%% Effect : 1006%%------------------------------------------------------------ 1007 1008%before_completion(Self, {Env, Local}) -> 1009% send_info(?etr_get_sync(Local), 1010% 'CosTransactions_Synchronization', before_completion), 1011% {reply, ok, {Env, Local}}. 1012 1013%%-----------------------------------------------------------% 1014%% function : after_completion 1015%% Arguments: 1016%% Returns : 1017%% Effect : 1018%%------------------------------------------------------------ 1019 1020%after_completion(Self, {Env, Local}, Status) -> 1021% send_info(?etr_get_sync(Local), Status, 1022% 'CosTransactions_Synchronization', after_completion), 1023% {stop, normal, ok, {Env, Local}}. 1024 1025%%--------------- IMPLEMENTATION SPECIFIC ------------------- 1026%%-----------------------------------------------------------% 1027%% function : start_object 1028%% Arguments: 1029%% Returns : EXIT, EXCEPTION, or {ok, State} 1030%% Effect : used by init/1 only. 1031%%------------------------------------------------------------ 1032 1033start_object(Env)-> 1034 ?put_debug_data(self, Env), 1035 Local = ?etr_get_init(Env), 1036 LogName = ?tr_get_etrap(Env), 1037 case catch file:read_file_info(LogName) of 1038 {error, enoent} -> 1039 %% File does not exist. It's the first time. No restart. 1040 ?debug_print("ETraP_Server:init(~p)~n",[?tr_get_etrap(Env)]), 1041 etrap_logmgr:start(LogName), 1042 {ok, 1043 {Env, ?etr_set_status(Local, 'StatusActive')}, 1044 ?tr_get_timeout(Env)}; 1045 {error, Reason} -> 1046 %% File exist but error occurred. 1047 ?tr_error_msg("Control (~p) Cannot open log file: ~p~n", 1048 [LogName, Reason]), 1049 {stop, "unable_to_open_log"}; 1050 _ -> 1051 %% File exists, perform restart. 1052 etrap_logmgr:start(LogName), 1053 ?debug_print("RESTART ~p~n", [?tr_get_etrap(Env)]), 1054 prepare_restart({Env, ?etr_set_status(Local, 'StatusUnknown')}, 1055 ?etr_read(?tr_get_etrap(Env), start)) 1056 end. 1057 1058 1059%%-----------------------------------------------------------% 1060%% function : send_prepare 1061%% Arguments: List of registred resources. 1062%% Returns : ok - equal to void 1063%% Effect : calls send_prepare/3, which sends a prepare call 1064%% to resources participating in the transaction and then collect 1065%% their votes. send_prepare will block until 1066%% it recieves a reply from the resource. 1067%%------------------------------------------------------------ 1068 1069send_prepare(RegResources, Alarm) -> 1070 send_prepare(RegResources, [], Alarm). 1071 1072% All voted ReadOnly. We are done. 1073send_prepare([], [], _) -> 1074 readOnly; 1075 1076% All voted commit (VC) or ReadOnly. 1077send_prepare([], VC, Alarm) -> 1078 case catch try_timeout(Alarm) of 1079 false -> 1080 {commit, VC}; 1081 _-> 1082 {rollback, VC} 1083 end; 1084 1085send_prepare([Rhead|Rtail], VC, Alarm) -> 1086 ?debug_print("send_prepare()~n",[]), 1087 case catch 'CosTransactions_Resource':prepare(Rhead) of 1088 'VoteCommit' -> 1089 case catch try_timeout(Alarm) of 1090 false -> 1091 _Env = ?get_debug_data(self), 1092 ?eval_debug_fun({?tr_get_etrap(_Env), send_prepare}, _Env), 1093 send_prepare(Rtail, VC++[Rhead], Alarm); 1094 _-> 1095 %% Timeout, rollback. However, the resource did vote 1096 %% commit. Add it to the list. 1097 send_info(Rtail, 'CosTransactions_Resource', rollback), 1098 {rollback, VC++[Rhead]} 1099 end; 1100 'VoteRollback' -> 1101 %% Don't care about timeout since we voted rollback. 1102 %% A rollback received. No need for more prepare-calls. 1103 %% See OMG 10-51, Transaction Service:v1.0 1104 send_info(Rtail, 'CosTransactions_Resource', rollback), 1105 {rollback, VC}; 1106 'VoteReadOnly' -> 1107 case catch try_timeout(Alarm) of 1108 false -> 1109 send_prepare(Rtail, VC, Alarm); 1110 _-> 1111 %% timeout, reply rollback. 1112 send_info(Rtail, 'CosTransactions_Resource', rollback), 1113 {rollback, VC} 1114 end; 1115 {'EXCEPTION',E} when is_record(E, 'TIMEOUT') -> 1116 ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", 1117 [Rhead]), 1118 %% Since we use presumed abort we will rollback the transaction. 1119 send_info(Rtail, 'CosTransactions_Resource', rollback), 1120 {rollback, VC}; 1121 {'EXCEPTION',E} when is_record(E, 'TRANSIENT') -> 1122 ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", 1123 [Rhead]), 1124 %% Since we use presumed abort we will rollback the transaction. 1125 send_info(Rtail, 'CosTransactions_Resource', rollback), 1126 {rollback, VC}; 1127 {'EXCEPTION',E} when is_record(E, 'COMM_FAILURE') -> 1128 ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", 1129 [Rhead]), 1130 %% Since we use presumed abort we will rollback the transaction. 1131 send_info(Rtail, 'CosTransactions_Resource', rollback), 1132 {rollback, VC}; 1133 {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> 1134 ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", 1135 [Rhead]), 1136 send_info(Rtail, 'CosTransactions_Resource', rollback), 1137 {rollback, VC}; 1138 {'EXCEPTION', Exc} -> 1139 ?tr_error_msg("Coordinator:prepare( ~p )~nThe Object raised exception: ~p~n", 1140 [Rhead, Exc]), 1141 send_info(Rtail, 'CosTransactions_Resource', rollback), 1142 %% This can occur if a subtransaction get one or more 1143 %% "VoteCommit" followed by a "VoteRollback". 1144 %% The subtransaction then do a send_decision(rollback), 1145 %% which can generate Heuristic decisions. Must rollback 1146 %% since at least one participant voted rollback. 1147 {'EXCEPTION', Exc, VC, Rhead}; 1148 Other -> 1149 ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", 1150 [Rhead, Other]), 1151 send_info(Rtail, 'CosTransactions_Resource', rollback), 1152 {failed, VC} 1153 end. 1154 1155%%-----------------------------------------------------------% 1156%% function : type_check 1157%% Arguments: Bool - perform typecheck? 1158%% ID - Type it should be. 1159%% Func - Name of the function (for error_msg) 1160%% Obj - objectrefernce to test. 1161%% Returns : 'ok' or raises exception. 1162%% Effect : 1163%%------------------------------------------------------------ 1164type_check(false, _, _, _) -> 1165 ok; 1166type_check(_, ID, Func, Obj) -> 1167 case catch corba_object:is_a(Obj,ID) of 1168 true -> 1169 ok; 1170 _ -> 1171 ?tr_error_msg("~p( ~p ) Bad argument!!~n", [Func, Obj]), 1172 corba:raise(?tr_badparam) 1173 end. 1174 1175%%-----------------------------------------------------------% 1176%% function : is_heuristic 1177%% Arguments: Exception 1178%% Returns : boolean 1179%% Effect : Returns true if the exception is a heuristic exc. 1180%%------------------------------------------------------------ 1181 1182is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicMixed') -> true; 1183is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicHazard') -> true; 1184is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicCommit') -> true; 1185is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicRollback') -> true; 1186is_heuristic(_) -> false. 1187 1188%%-----------------------------------------------------------% 1189%% function : exception_set 1190%% Arguments: Genserver state 1191%% Returns : 1192%% Effect : Used when restarting. 1193%%------------------------------------------------------------ 1194 1195exception_set({Env,Local}) -> 1196 case ?etr_get_exc(Local) of 1197 void -> 1198 self() ! {suicide, self()}, 1199 {ok, {Env, Local}}; 1200 _ -> 1201 {ok, {Env, Local}} 1202 end. 1203 1204%%-----------------------------------------------------------% 1205%% function : set_exception 1206%% Arguments: Locally defined #exc{} 1207%% Heuristic mixed or hazard Exeption 1208%% Returns : Altered locally defined #exc{} 1209%% Effect : Set the correct tuple member to true. 1210%%------------------------------------------------------------ 1211 1212set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicMixed') -> 1213 Exc#exc{mixed = true}; 1214set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicHazard') -> 1215 Exc#exc{hazard = true}; 1216set_exception(Exc, _) -> Exc. 1217 1218%%-----------------------------------------------------------% 1219%% function : send_forget 1220%% Arguments: 1221%% Returns : 1222%% Effect : 1223%%------------------------------------------------------------ 1224 1225send_forget([], _) -> ok; 1226send_forget([Rhead|Rtail], LogName) -> 1227 ?debug_print("send_forget()~n",[]), 1228 _Env = ?get_debug_data(self), 1229 case catch 'CosTransactions_Resource':forget(Rhead) of 1230 ok -> 1231 ?eval_debug_fun({?tr_get_etrap(_Env), send_forget1}, _Env), 1232 ?etr_log(LogName, {forgotten, Rhead}), 1233 ?eval_debug_fun({?tr_get_etrap(_Env), send_forget2}, _Env), 1234 send_forget(Rtail, LogName); 1235 Other -> 1236 ?tr_error_msg("CosTransactions_Coordinator failed sending forget to ~p~nREASON: ~p~n", 1237 [Rhead, Other]), 1238 ?eval_debug_fun({?tr_get_etrap(_Env), send_forget3}, _Env), 1239 ?etr_log(LogName, {not_forgotten, Rhead}), 1240 ?eval_debug_fun({?tr_get_etrap(_Env), send_forget4}, _Env), 1241 send_forget(Rtail, LogName) 1242 end. 1243 1244%%-----------------------------------------------------------% 1245%% function : send_decision 1246%% Arguments: List of registred resources which vote commit. 1247%% Vote - the outcome of the transaction. 1248%% Returns : ok - equal to void 1249%% Effect : Inform those who voted commit of the outcome. 1250%% They who voted rollback already knows the outcome. 1251%% They who voted ReadOnly are not affected. 1252%%------------------------------------------------------------ 1253 1254%%-- Adding extra parameters 1255send_decision({Env, Local}, Reply, Vote) -> 1256 send_decision({Env, Local}, Reply, ?etr_get_vc(Local), Vote, #exc{}, [], 0). 1257send_decision({Env, Local}, Reply, Vote, VC) -> 1258 send_decision({Env, Local}, Reply, VC, Vote, #exc{}, [], 0). 1259send_decision(State, no_reply, VC, Vote, Exc) -> 1260 send_decision(State, no_reply, VC, Vote, Exc, [], 0). 1261 1262%%-- Decision sent to all members. Do not reply (used when restarting). 1263send_decision({Env, Local}, no_reply, [], _, #exc{mixed = true}, [], _) -> 1264 {Env, ?etr_set_exc(Local, ?tr_mixed)}; 1265send_decision({Env, Local}, no_reply, [], _, #exc{hazard = true}, [], _) -> 1266 {Env, ?etr_set_exc(Local, ?tr_hazard)}; 1267send_decision({Env, Local}, no_reply, [], _, _, [], _) -> 1268 {Env, Local}; 1269send_decision({Env, Local}, no_reply, [], Vote, Exc, Failed, Times) -> 1270 case ?tr_get_maxR(Env) of 1271 Times -> 1272 ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), 1273 {Env, ?etr_set_exc(Local, ?tr_hazard)}; 1274 _-> 1275 timer:sleep(?tr_get_maxW(Env)), 1276 NewTimes = Times+1, 1277 send_decision({Env, Local}, no_reply, Failed, Vote, Exc, [], NewTimes) 1278 end; 1279%%-- end special cases. 1280 1281%% Decision sent to all members. Test exceptions. 1282send_decision({Env, Local}, Reply, [], Vote, Exc, [], _) -> 1283 notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), 1284 test_exc(Exc, Vote, Reply, {Env, Local}); 1285%% Decision not sent to all members (one or more failed). Retry. 1286send_decision({Env, Local}, Reply, [], Vote, Exc, Failed, Times) -> 1287 case ?tr_get_maxR(Env) of 1288 Times -> 1289 ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), 1290 notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), 1291 test_exc(Exc#exc{hazard = true}, Vote, Reply, {Env, Local}); 1292 _-> 1293 NewTimes = Times+1, 1294 timer:sleep(?tr_get_maxW(Env)), 1295 send_decision({Env, Local}, Reply, Failed, Vote, Exc, [], NewTimes) 1296 end; 1297 1298send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times) -> 1299 ?debug_print("Coordinator:send_decision(~p) Try: ~p~n",[Vote, Times]), 1300 case catch 'CosTransactions_Resource':Vote(Rhead) of 1301 ok -> 1302 ?etr_log(?tr_get_etrap(Env),{sent, Rhead}), 1303 send_decision({Env, Local}, Reply, Rtail, Vote, Exc, Failed, Times); 1304 {'EXCEPTION', E} when Vote == commit andalso 1305 is_record(E, 'CosTransactions_NotPrepared') -> 1306 ?debug_print("send_decision resource unprepared~n",[]), 1307 case catch 'CosTransactions_Resource':prepare(Rhead) of 1308 'VoteCommit' -> 1309 send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times); 1310 'VoteRollback' -> 1311 send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{mixed = true}, Failed, Times); 1312 {'EXCEPTION', E} -> 1313 {SetExc, NewL, DidFail} = 1314 evaluate_answer(E, Rhead, Vote, Exc, 1315 ?tr_get_etrap(Env), Local), 1316 send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times) 1317 end; 1318 {'EXCEPTION', E} -> 1319 {SetExc, NewL, DidFail} = 1320 evaluate_answer(E, Rhead, Vote, Exc, ?tr_get_etrap(Env), Local), 1321 ?tr_error_msg("Resource:~p( ~p )~nRaised Exception: ~p~n", 1322 [Vote, Rhead, E]), 1323 send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times); 1324 {'EXIT', _} -> 1325 send_decision({Env, Local}, Reply, Rtail, 1326 Vote, Exc, [Rhead|Failed], Times); 1327 Other -> 1328 ?tr_error_msg("Resource:~p( ~p ) failed.~nREASON: ~p~n", 1329 [Vote, Rhead, Other]), 1330 case catch corba_object:non_existent(Rhead) of 1331 true when Vote == commit -> 1332 %% Presumed rollback 1333 send_decision({Env, Local}, Reply, Rtail, Vote, 1334 Exc#exc{mixed = true}, Failed, Times); 1335 true -> 1336 %% Presumed rollback 1337 send_decision({Env, Local}, Reply, Rtail, Vote, 1338 Exc#exc{hazard = true}, Failed, Times); 1339 _ -> 1340 send_decision({Env, Local}, Reply, Rtail, 1341 Vote, Exc, [Rhead|Failed], Times) 1342 end 1343 end. 1344 1345%%-----------------------------------------------------------% 1346%% function : notify_subtrAware, 1347%% Arguments: 1348%% Returns : 1349%% Effect : Invoke an operation on a list of objects. We don't 1350%% care about return values or exceptions. 1351%%------------------------------------------------------------ 1352 1353notify_subtrAware(commit, Resources, Self) -> 1354 send_info(Resources, Self, 1355 'CosTransactions_SubtransactionAwareResource', 1356 commit_subtransaction); 1357notify_subtrAware(_, Resources, _) -> 1358 send_info(Resources, 'CosTransactions_SubtransactionAwareResource', 1359 rollback_subtransaction). 1360 1361%%-----------------------------------------------------------% 1362%% function : send_info 1363%% Arguments: ObjectList - List of object refernces to call. 1364%% M - Module 1365%% F - Function 1366%% (Arg - required arguments) 1367%% Returns : ok 1368%% Effect : A lightweight function to be used when we don't 1369%% "care" about the return value. 1370%%------------------------------------------------------------ 1371 1372send_info([], _, _, _) -> 1373 ok; 1374send_info([Rhead|Rtail], Arg, M, F) -> 1375 ?debug_print("~p( ~p )~n",[F, Arg]), 1376 case catch M:F(Rhead, Arg) of 1377 {'EXIT',R} -> 1378 ?tr_error_msg("~p:~p(~p, ~p) returned {'EXIT',~p}", [M,F,Rhead,Arg,R]); 1379 {'EXCEPTION',E} -> 1380 ?tr_error_msg("~p:~p(~p, ~p) returned {'EXCEPTION',~p}", [M,F,Rhead,Arg,E]); 1381 _-> 1382 ok 1383 end, 1384 send_info(Rtail, Arg, M, F). 1385 1386send_info([], _, _) -> 1387 ok; 1388send_info([Rhead|Rtail], M, F) -> 1389 ?debug_print("~p( )~n",[F]), 1390 case catch M:F(Rhead) of 1391 {'EXIT',R} -> 1392 ?tr_error_msg("~p:~p(~p) returned {'EXIT',~p}", [M,F,Rhead,R]); 1393 {'EXCEPTION',E} -> 1394 ?tr_error_msg("~p:~p(~p) returned {'EXCEPTION',~p}", [M,F,Rhead,E]); 1395 _-> 1396 ok 1397 end, 1398 send_info(Rtail, M, F). 1399 1400%%-----------------------------------------------------------% 1401%% function : evaluate_answer 1402%% Arguments: 1403%% Returns : 1404%% Effect : Check what kind of exception we received. 1405%%------------------------------------------------------------ 1406 1407evaluate_answer(E, Rhead, _Vote, Exc, Log, Local) 1408 when is_record(E, 'CosTransactions_HeuristicMixed') -> 1409 ?etr_log(Log, {heuristic, {Rhead, E}}), 1410 {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}; 1411evaluate_answer(E, Rhead, _Vote, Exc, Log, Local) 1412 when is_record(E, 'CosTransactions_HeuristicHazard') -> 1413 ?etr_log(Log, {heuristic, {Rhead, E}}), 1414 {Exc#exc{hazard = true}, ?etr_add_raisedH(Local, Rhead), []}; 1415evaluate_answer(E, Rhead, Vote, Exc, Log, Local) 1416 when is_record(E, 'CosTransactions_HeuristicCommit') -> 1417 case Vote of 1418 commit -> 1419 ?etr_log(Log, {heuristic, {Rhead, E}}), 1420 {Exc, ?etr_add_raisedH(Local, Rhead), []}; 1421 _-> 1422 ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), 1423 {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []} 1424 end; 1425evaluate_answer(E, Rhead, Vote, Exc, Log, Local) 1426 when is_record(E, 'CosTransactions_HeuristicRollback')-> 1427 case Vote of 1428 rollback -> 1429 ?etr_log(Log, {heuristic, {Rhead, ?tr_rollback}}), 1430 {Exc, ?etr_add_raisedH(Local, Rhead), []}; 1431 _-> 1432 ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), 1433 {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []} 1434 end; 1435evaluate_answer(E, Rhead, Vote, Exc, Log, Local) 1436 when Vote == commit andalso is_record(E, 'TRANSACTION_ROLLEDBACK') -> 1437 ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), 1438 {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}; 1439evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TIMEOUT') -> 1440 ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", 1441 [Vote, Rhead, E]), 1442 case catch corba_object:non_existent(Rhead) of 1443 true -> 1444 %% Since we have presumed abort, the child will 1445 %% assume rollback if this server do not exist any more. 1446 ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), 1447 {Exc#exc{hazard = true}, Local, []}; 1448 _ -> 1449 {Exc, Local, [Rhead]} 1450 end; 1451evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TRANSIENT') -> 1452 ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", 1453 [Vote, Rhead, E]), 1454 case catch corba_object:non_existent(Rhead) of 1455 true -> 1456 %% Since we have presumed abort, the child will 1457 %% assume rollback if this server do not exist any more. 1458 ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), 1459 {Exc#exc{hazard = true}, Local, []}; 1460 _ -> 1461 {Exc, Local, [Rhead]} 1462 end; 1463evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'COMM_FAILURE') -> 1464 ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", 1465 [Vote, Rhead, E]), 1466 case catch corba_object:non_existent(Rhead) of 1467 true -> 1468 %% Since we have presumed abort, the child will 1469 %% assume rollback if this server do not exist any more. 1470 ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), 1471 {Exc#exc{hazard = true}, Local, []}; 1472 _ -> 1473 {Exc, Local, [Rhead]} 1474 end; 1475evaluate_answer(E, Rhead, Vote, Exc, Log, Local)when is_record(E, 'OBJECT_NOT_EXIST') -> 1476 ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", 1477 [Vote, Rhead, E]), 1478 %% Since we have presumed abort, the child will 1479 %% assume rollback if this server do not exist any more. 1480 ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), 1481 {Exc#exc{hazard = true}, Local, []}; 1482evaluate_answer(Unknown, Rhead, Vote, Exc, _Log, Local)-> 1483 ?tr_error_msg("Coordinator:~p( ~p ). Unknown reply: ~p.~n", 1484 [Vote, Rhead, Unknown]), 1485 {Exc, Local, []}. 1486 1487 1488%%-----------------------------------------------------------% 1489%% function : test_exc 1490%% Arguments: Exc - instance of #exc{} locally declared. 1491%% Vote - 'rollback' or 'commit' 1492%% Reply - If no exceptions this is the default reply. 1493%% State - genserver state 1494%% Returns : 1495%% Effect : Raise the correct exception or simply reply to 1496%% the genserver. NOTE that the testing for exceptions 1497%% differs if we are performing a rollback or commit. 1498%% Check if Mixed first; takes priority over Hazard. 1499%% HeuristicRollback and VoteCommit together give 1500%% HeuristicMixed 1501%% HeuristicCommit and VoteRollback together give 1502%% HeuristicMixed 1503%%------------------------------------------------------------ 1504 1505test_exc(#exc{mixed = true}, _, _, {Env, Local}) -> 1506 {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; 1507% Left out for now to avoid dialyzer warning. 1508%test_exc(#exc{rollback = true}, commit, _, {Env, Local}) -> 1509% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; 1510% Left out for now to avoid dialyzer warning. 1511%test_exc(#exc{commit = true}, rollback, _, {Env, Local}) -> 1512% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; 1513test_exc(#exc{hazard = true}, _, _, {Env, Local}) -> 1514 {reply, {'EXCEPTION', ?tr_hazard}, {Env, ?etr_set_exc(Local, ?tr_hazard)}}; 1515test_exc(_, _, {'EXCEPTION', E}, {Env, Local}) 1516 when is_record(E, 'TRANSACTION_ROLLEDBACK')-> 1517 {stop, normal, {'EXCEPTION', E}, {Env, Local}}; 1518%% Replace the case above if allow synchronization 1519%test_exc(_, _, {'EXCEPTION', E}, {Env, Local}) 1520% when record(E, 'TRANSACTION_ROLLEDBACK')-> 1521% case ?etr_get_sync(Local) of 1522% [] -> 1523% {stop, normal, {'EXCEPTION', E}, {Env, Local}}; 1524% _-> 1525% {reply, {'EXCEPTION', E}, {Env, Local}} 1526% end; 1527test_exc(_, _, {'EXCEPTION', E}, State) -> 1528 {reply, {'EXCEPTION', E}, State}; 1529test_exc(_, _, Reply, {Env, Local}) -> 1530 {stop, normal, Reply, {Env, Local}}. 1531%% Replace the case above if allow synchronization 1532%test_exc(_, _, Reply, {Env, Local}) -> 1533% case ?etr_get_sync(Local) of 1534% [] -> 1535% {stop, normal, Reply, {Env, Local}}; 1536% _ -> 1537% {reply, Reply, {Env, Local}} 1538% end. 1539 1540%%-----------------------------------------------------------% 1541%% function : evaluate_status 1542%% Arguments: 1543%% Returns : 1544%% Effect : 1545%%------------------------------------------------------------ 1546 1547evaluate_status(Status) -> 1548 case Status of 1549 'StatusCommitted' -> commit; 1550 'StatusCommitting' -> commit; 1551 'StatusMarkedRollback' -> rollback; 1552 'StatusRollingBack' -> rollback; 1553 'StatusRolledBack' -> rollback; 1554 'StatusActive' -> rollback; 1555 'StatusPrepared' -> rollback; 1556 'StatusUnknown' -> rollback; 1557 'StatusNoTransaction' -> rollback; 1558 'StatusPreparing' -> rollback; 1559 _-> rollback 1560 end. 1561 1562 1563%%-----------------------------------------------------------% 1564%% function : prepare_restart 1565%% Arguments: 1566%% Returns : 1567%% Effect : 1568%%------------------------------------------------------------ 1569 1570%% The file contains no data. The coordinator crashed before 1571%% a prepare-call was made. Presumed rollback. 1572prepare_restart(State, eof) -> 1573 ?debug_print("prepare_restart: eof, init~n",[]), 1574 self() ! {suicide, self()}, 1575 {ok, State}; 1576%% Collected all necessary votes. Do commit_restart. 1577prepare_restart({Env, _}, {{pre_vote, _Vote, Data}, Cursor}) -> 1578 ?debug_print("prepare_restart: pre_vote( ~p )~n",[_Vote]), 1579 if 1580 ?tr_is_root(Env) -> 1581 commit_restart({Env, Data}, 1582 ?etr_read(?tr_get_etrap(Env), Cursor), root); 1583 true -> 1584 commit_restart({Env, Data}, 1585 ?etr_read(?tr_get_etrap(Env), Cursor), subCoord) 1586 end; 1587%% 'rollback' called without 'prepare'. This case occurs if the Coordinator 1588%% crashes when send_info or notify_subtrAware. 1589prepare_restart({Env, _}, {{rollback, NewL}, _Cursor}) -> 1590 ?debug_print("prepare_restart: pre_vote( rollback )~n",[]), 1591 send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), 1592 notify_subtrAware(rollback, ?etr_get_subAw(NewL), ?etr_get_self(NewL)), 1593 self() ! {suicide, self()}, 1594 {ok, {Env, NewL}}; 1595%% Something is wrong in the log. 1596prepare_restart(_, _) -> 1597 ?tr_error_msg("Internal log read failed:~n", []), 1598 {stop, {error, "restart failed"}}. 1599 1600%%-----------------------------------------------------------% 1601%% function : commit_restart 1602%% Arguments: Env - server context 1603%% Returns : 1604%% Effect : 1605%%------------------------------------------------------------ 1606commit_restart({Env, Local}, Data, Phase) -> 1607 Exc = set_exception(#exc{}, ?etr_get_exc(Local)), 1608 commit_restart({Env, Local}, Data, Phase, Exc). 1609 1610%% Normal case. No errors no exceptions. 1611commit_restart({Env, Local}, {{sent, Obj}, Cursor}, Vote, Exc) -> 1612 ?debug_print("commit_restart: sent~n",[]), 1613 commit_restart({Env, ?etr_remove_vc(Local, Obj)}, 1614 ?etr_read(?tr_get_etrap(Env), Cursor), Vote, Exc); 1615commit_restart({Env, Local}, {{heuristic, {Obj,E}}, Cursor}, Vote, Exc) -> 1616 ?debug_print("commit_restart: heuristic ~p~n",[E]), 1617 NewExc = set_exception(Exc, E), 1618 commit_restart({Env, ?etr_add_raisedH(Local, Obj)}, 1619 ?etr_read(?tr_get_etrap(Env), Cursor), Vote, NewExc); 1620 1621 1622%% --- cases which only can occure once in the log ------------ 1623 1624%% The file contains no data. The coordinator crashed before 1625%% a decision was made. Causes rollback. 1626commit_restart({E, L}, eof, root, Exc) -> 1627 ?debug_print("commit_restart: eof init (root only)~n",[]), 1628 {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L), 1629 rollback, Exc), 1630 exception_set({Env, Local}); 1631%% Replace the reply above if allow synchronization 1632% case ?etr_get_sync(Local) of 1633% [] -> 1634% exception_set({Env, Local}); 1635% SynchObjs -> 1636% {ok, {Env, Local}} 1637% end; 1638 1639 1640%% Passed the prepare_restart. Not received a commit decision from the 1641%% parent. 1642commit_restart({E, L}, eof, subCoord, Exc) -> 1643 ?debug_print("commit_restart: eof init (subcoord only)~n",[]), 1644 case catch corba_object:non_existent(?tr_get_parent(E)) of 1645 true -> 1646 %% Presumed rollback. 1647 {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L), 1648 rollback, Exc), 1649 self() ! {suicide, self()}, 1650 {ok, {Env, Local}}; 1651%% Replace the reply above if allow synchronization 1652% case ?etr_get_sync(Local) of 1653% [] -> 1654% self() ! {suicide, self()}, 1655% {ok, {Env, Local}}; 1656% SynchObjs -> 1657% case ?tr_get_parents(Env) of 1658% [] -> 1659% send_info(SynchObjs, ?etr_get_status(Local), 1660% 'CosTransactions_Synchronization', after_completion); 1661% _-> 1662% ok 1663% end, 1664% self() ! {suicide, self()}, 1665% {ok, {Env, Local}} 1666% end; 1667 _-> 1668 {ok, {E, L}} 1669 end; 1670 1671commit_restart({Env, Local}, eof, Vote, Exc) -> 1672 ?debug_print("commit_restart: eof VOTE: ~p~n",[Vote]), 1673 case ?etr_get_vc(Local) of 1674 [] -> 1675 ?debug_print("commit_restart: all sent, test exc~n",[]), 1676 exception_set({Env, Local}); 1677 VC -> 1678 ?debug_print("commit_restart: note done. send more~n",[]), 1679 State = send_decision({Env, Local}, no_reply, VC, Vote, Exc), 1680 exception_set(State) 1681 end; 1682 1683%% Decision made, i.e. rollback or commit. 1684commit_restart({Env, Local}, {rollback, Cursor}, _Phase, Exc) -> 1685 ?debug_print("commit_restart: decided rollback~n",[]), 1686 commit_restart({Env, ?etr_set_status(Local, 'StatusRolledBack')}, 1687 ?etr_read(?tr_get_etrap(Env), Cursor), rollback, Exc); 1688commit_restart({Env, Local}, {commit, Cursor}, _Phase, Exc) -> 1689 ?debug_print("commit_restart: decided commit~n",[]), 1690 commit_restart({Env, ?etr_set_status(Local, 'StatusCommitted')}, 1691 ?etr_read(?tr_get_etrap(Env), Cursor), commit, Exc); 1692commit_restart({Env, Local}, {forget_phase, Cursor}, _, _) -> 1693 ?debug_print("commit_restart: start sending forget~n",[]), 1694 forget_restart({Env, Local}, ?etr_read(?tr_get_etrap(Env), Cursor)); 1695 1696commit_restart({_Env, _Local}, _R, _, _) -> 1697 ?debug_print("RESTART FAIL: ~p~n",[_R]), 1698 ?tr_error_msg("Internal log read failed:~n", []), 1699 exit("restart failed"). 1700 1701%%-----------------------------------------------------------% 1702%% function : forget_restart 1703%% Arguments: {Env, Local} - server context 1704%% Returns : 1705%% Effect : 1706%%------------------------------------------------------------ 1707 1708%% Exception logged. Test if we issued a 'forget()' to the Resource. 1709forget_restart({Env, Local}, eof) -> 1710 case ?etr_get_raisedH(Local) of 1711 [] -> 1712 ?debug_print("forget_restart: all done~n",[]); 1713 Left -> 1714 ?debug_print("forget_restart: not done. send more~n",[]), 1715 send_forget(Left, ?tr_get_etrap(Env)) 1716 end, 1717 self() ! {suicide, self()}, 1718 {ok, {Env, Local}}; 1719%% Replace the reply above if allow synchronization 1720% case ?etr_get_sync(Local) of 1721% [] -> 1722% self() ! {suicide, self()}, 1723% {ok, {Env, Local}}; 1724% SynchObjs -> 1725% case ?tr_get_parents(Env) of 1726% [] -> 1727% send_info(SynchObjs, ?etr_get_status(Local), 1728% 'CosTransactions_Synchronization', after_completion), 1729% self() ! {suicide, self()}, 1730% {ok, {Env, Local}}; 1731% _-> 1732% {ok, {Env, Local}} 1733% end 1734% end; 1735forget_restart({Env, Local}, {{forgotten, Obj}, Cursor}) -> 1736 ?debug_print("forget_restart: forgotten heuristic~n",[]), 1737 NewL = ?etr_remove_raisedH(Local, Obj), 1738 forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor)); 1739forget_restart({Env, Local}, {{not_forgotten, Obj}, Cursor}) -> 1740 ?debug_print("forget_restart: not_forgotten~n",[]), 1741 NewL = ?etr_remove_raisedH(Local, Obj), 1742 send_forget([Obj], dummy), 1743 forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor)). 1744 1745%%--------------- END OF MODULE ------------------------------ 1746