1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: mnesia_monitor.erl,v 1.1 2008/12/17 09:53:38 mikpe Exp $ 18-module(mnesia_monitor). 19 20-behaviour(gen_server). 21 22%% Public exports 23-export([ 24 close_dets/1, 25 close_log/1, 26 detect_inconcistency/2, 27 get_env/1, 28 init/0, 29 mktab/2, 30 unsafe_mktab/2, 31 mnesia_down/2, 32 needs_protocol_conversion/1, 33 negotiate_protocol/1, 34 disconnect/1, 35 open_dets/2, 36 unsafe_open_dets/2, 37 open_log/1, 38 patch_env/2, 39 protocol_version/0, 40 reopen_log/3, 41 set_env/2, 42 start/0, 43 start_proc/4, 44 terminate_proc/3, 45 unsafe_close_dets/1, 46 unsafe_close_log/1, 47 use_dir/0, 48 do_check_type/2 49 ]). 50 51%% gen_server callbacks 52-export([ 53 init/1, 54 handle_call/3, 55 handle_cast/2, 56 handle_info/2, 57 terminate/2, 58 code_change/3 59 ]). 60 61%% Internal exports 62-export([ 63 call/1, 64 cast/1, 65 detect_partitioned_network/2, 66 has_remote_mnesia_down/1 67 ]). 68 69-import(mnesia_lib, [dbg_out/2, verbose/2, error/2, fatal/2, set/2]). 70 71-include("mnesia.hrl"). 72 73-record(state, {supervisor, pending_negotiators = [], 74 going_down = [], tm_started = false, early_connects = []}). 75 76-define(current_protocol_version, {7,6}). 77 78-define(previous_protocol_version, {7,5}). 79 80start() -> 81 gen_server:start_link({local, ?MODULE}, ?MODULE, 82 [self()], [{timeout, infinity} 83 %% ,{debug, [trace]} 84 ]). 85 86init() -> 87 call(init). 88 89mnesia_down(From, Node) -> 90 cast({mnesia_down, From, Node}). 91 92mktab(Tab, Args) -> 93 unsafe_call({mktab, Tab, Args}). 94unsafe_mktab(Tab, Args) -> 95 unsafe_call({unsafe_mktab, Tab, Args}). 96 97open_dets(Tab, Args) -> 98 unsafe_call({open_dets, Tab, Args}). 99unsafe_open_dets(Tab, Args) -> 100 unsafe_call({unsafe_open_dets, Tab, Args}). 101 102close_dets(Tab) -> 103 unsafe_call({close_dets, Tab}). 104 105unsafe_close_dets(Name) -> 106 unsafe_call({unsafe_close_dets, Name}). 107 108open_log(Args) -> 109 unsafe_call({open_log, Args}). 110 111reopen_log(Name, Fname, Head) -> 112 unsafe_call({reopen_log, Name, Fname, Head}). 113 114close_log(Name) -> 115 unsafe_call({close_log, Name}). 116 117unsafe_close_log(Name) -> 118 unsafe_call({unsafe_close_log, Name}). 119 120 121disconnect(Node) -> 122 cast({disconnect, Node}). 123 124%% Returns GoodNoodes 125%% Creates a link to each compatible monitor and 126%% protocol_version to agreed version upon success 127 128negotiate_protocol(Nodes) -> 129 Version = mnesia:system_info(version), 130 Protocols = acceptable_protocol_versions(), 131 MonitorPid = whereis(?MODULE), 132 Msg = {negotiate_protocol, MonitorPid, Version, Protocols}, 133 {Replies, _BadNodes} = multicall(Nodes, Msg), 134 check_protocol(Replies, Protocols). 135 136check_protocol([{Node, {accept, Mon, _Version, Protocol}} | Tail], Protocols) -> 137 case lists:member(Protocol, Protocols) of 138 true -> 139 case Protocol == protocol_version() of 140 true -> 141 set({protocol, Node}, {Protocol, false}); 142 false -> 143 set({protocol, Node}, {Protocol, true}) 144 end, 145 [node(Mon) | check_protocol(Tail, Protocols)]; 146 false -> 147 unlink(Mon), % Get rid of unnecessary link 148 check_protocol(Tail, Protocols) 149 end; 150check_protocol([{Node, {reject, _Mon, Version, Protocol}} | Tail], Protocols) -> 151 verbose("Failed to connect with ~p. ~p protocols rejected. " 152 "expected version = ~p, expected protocol = ~p~n", 153 [Node, Protocols, Version, Protocol]), 154 check_protocol(Tail, Protocols); 155check_protocol([{error, _Reason} | Tail], Protocols) -> 156 check_protocol(Tail, Protocols); 157check_protocol([{badrpc, _Reason} | Tail], Protocols) -> 158 check_protocol(Tail, Protocols); 159check_protocol([], [Protocol | _Protocols]) -> 160 set(protocol_version, Protocol), 161 []; 162check_protocol([], []) -> 163 set(protocol_version, protocol_version()), 164 []. 165 166protocol_version() -> 167 case ?catch_val(protocol_version) of 168 {'EXIT', _} -> ?current_protocol_version; 169 Version -> Version 170 end. 171 172%% A sorted list of acceptable protocols the 173%% preferred protocols are first in the list 174acceptable_protocol_versions() -> 175 [protocol_version(), ?previous_protocol_version]. 176 177needs_protocol_conversion(Node) -> 178 case {?catch_val({protocol, Node}), protocol_version()} of 179 {{'EXIT', _}, _} -> 180 false; 181 {{_, Bool}, ?current_protocol_version} -> 182 Bool; 183 {{_, Bool}, _} -> 184 not Bool 185 end. 186 187cast(Msg) -> 188 case whereis(?MODULE) of 189 undefined -> ignore; 190 Pid -> gen_server:cast(Pid, Msg) 191 end. 192 193unsafe_call(Msg) -> 194 case whereis(?MODULE) of 195 undefined -> {error, {node_not_running, node()}}; 196 Pid -> gen_server:call(Pid, Msg, infinity) 197 end. 198 199call(Msg) -> 200 case whereis(?MODULE) of 201 undefined -> 202 {error, {node_not_running, node()}}; 203 Pid -> 204 link(Pid), 205 Res = gen_server:call(Pid, Msg, infinity), 206 unlink(Pid), 207 208 %% We get an exit signal if server dies 209 receive 210 {'EXIT', Pid, _Reason} -> 211 {error, {node_not_running, node()}} 212 after 0 -> 213 ignore 214 end, 215 Res 216 end. 217 218multicall(Nodes, Msg) -> 219 rpc:multicall(Nodes, ?MODULE, call, [Msg]). 220 221start_proc(Who, Mod, Fun, Args) -> 222 Args2 = [Who, Mod, Fun, Args], 223 proc_lib:start_link(mnesia_sp, init_proc, Args2, infinity). 224 225terminate_proc(Who, R, State) when R /= shutdown, R /= killed -> 226 fatal("~p crashed: ~p state: ~p~n", [Who, R, State]); 227 228terminate_proc(Who, Reason, _State) -> 229 mnesia_lib:verbose("~p terminated: ~p~n", [Who, Reason]), 230 ok. 231 232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 233%%% Callback functions from gen_server 234 235%%---------------------------------------------------------------------- 236%% Func: init/1 237%% Returns: {ok, State} | 238%% {ok, State, Timeout} | 239%% {stop, Reason} 240%%---------------------------------------------------------------------- 241init([Parent]) -> 242 process_flag(trap_exit, true), 243 ?ets_new_table(mnesia_gvar, [set, public, named_table]), 244 set(subscribers, []), 245 mnesia_lib:verbose("~p starting: ~p~n", [?MODULE, self()]), 246 Version = mnesia:system_info(version), 247 set(version, Version), 248 dbg_out("Version: ~p~n", [Version]), 249 250 case catch process_config_args(env()) of 251 ok -> 252 mnesia_lib:set({'$$$_report', current_pos}, 0), 253 Level = mnesia_lib:val(debug), 254 mnesia_lib:verbose("Mnesia debug level set to ~p\n", [Level]), 255 set(mnesia_status, starting), %% set start status 256 set({current, db_nodes}, [node()]), 257 set(use_dir, use_dir()), 258 mnesia_lib:create_counter(trans_aborts), 259 mnesia_lib:create_counter(trans_commits), 260 mnesia_lib:create_counter(trans_log_writes), 261 Left = get_env(dump_log_write_threshold), 262 mnesia_lib:set_counter(trans_log_writes_left, Left), 263 mnesia_lib:create_counter(trans_log_writes_prev), 264 mnesia_lib:create_counter(trans_restarts), 265 mnesia_lib:create_counter(trans_failures), 266 ?ets_new_table(mnesia_held_locks, [bag, public, named_table]), 267 ?ets_new_table(mnesia_tid_locks, [bag, public, named_table]), 268 ?ets_new_table(mnesia_sticky_locks, [set, public, named_table]), 269 ?ets_new_table(mnesia_lock_queue, 270 [bag, public, named_table, {keypos, 2}]), 271 ?ets_new_table(mnesia_lock_counter, [set, public, named_table]), 272 set(checkpoints, []), 273 set(pending_checkpoints, []), 274 set(pending_checkpoint_pids, []), 275 276 {ok, #state{supervisor = Parent}}; 277 {'EXIT', Reason} -> 278 mnesia_lib:report_fatal("Bad configuration: ~p~n", [Reason]), 279 {stop, {bad_config, Reason}} 280 end. 281 282use_dir() -> 283 case ?catch_val(use_dir) of 284 {'EXIT', _} -> 285 case get_env(schema_location) of 286 disc -> true; 287 opt_disc -> non_empty_dir(); 288 ram -> false 289 end; 290 Bool -> 291 Bool 292 end. 293 294%% Returns true if the Mnesia directory contains 295%% important files 296non_empty_dir() -> 297 mnesia_lib:exists(mnesia_bup:fallback_bup()) or 298 mnesia_lib:exists(mnesia_lib:tab2dmp(schema)) or 299 mnesia_lib:exists(mnesia_lib:tab2dat(schema)). 300 301%%---------------------------------------------------------------------- 302%% Func: handle_call/3 303%% Returns: {reply, Reply, State} | 304%% {reply, Reply, State, Timeout} | 305%% {noreply, State} | 306%% {noreply, State, Timeout} | 307%% {stop, Reason, Reply, State} | (terminate/2 is called) 308%%---------------------------------------------------------------------- 309 310handle_call({mktab, Tab, Args}, _From, State) -> 311 case catch ?ets_new_table(Tab, Args) of 312 {'EXIT', ExitReason} -> 313 Msg = "Cannot create ets table", 314 Reason = {system_limit, Msg, Tab, Args, ExitReason}, 315 fatal("~p~n", [Reason]), 316 {noreply, State}; 317 Reply -> 318 {reply, Reply, State} 319 end; 320 321handle_call({unsafe_mktab, Tab, Args}, _From, State) -> 322 case catch ?ets_new_table(Tab, Args) of 323 {'EXIT', ExitReason} -> 324 {reply, {error, ExitReason}, State}; 325 Reply -> 326 {reply, Reply, State} 327 end; 328 329 330handle_call({open_dets, Tab, Args}, _From, State) -> 331 case mnesia_lib:dets_sync_open(Tab, Args) of 332 {ok, Tab} -> 333 {reply, {ok, Tab}, State}; 334 335 {error, Reason} -> 336 Msg = "Cannot open dets table", 337 Error = {error, {Msg, Tab, Args, Reason}}, 338 fatal("~p~n", [Error]), 339 {noreply, State} 340 end; 341 342handle_call({unsafe_open_dets, Tab, Args}, _From, State) -> 343 case mnesia_lib:dets_sync_open(Tab, Args) of 344 {ok, Tab} -> 345 {reply, {ok, Tab}, State}; 346 {error, Reason} -> 347 {reply, {error,Reason}, State} 348 end; 349 350handle_call({close_dets, Tab}, _From, State) -> 351 case mnesia_lib:dets_sync_close(Tab) of 352 ok -> 353 {reply, ok, State}; 354 {error, Reason} -> 355 Msg = "Cannot close dets table", 356 Error = {error, {Msg, Tab, Reason}}, 357 fatal("~p~n", [Error]), 358 {noreply, State} 359 end; 360 361handle_call({unsafe_close_dets, Tab}, _From, State) -> 362 mnesia_lib:dets_sync_close(Tab), 363 {reply, ok, State}; 364 365handle_call({open_log, Args}, _From, State) -> 366 Res = disk_log:open([{notify, true}|Args]), 367 {reply, Res, State}; 368 369handle_call({reopen_log, Name, Fname, Head}, _From, State) -> 370 case disk_log:reopen(Name, Fname, Head) of 371 ok -> 372 {reply, ok, State}; 373 374 {error, Reason} -> 375 Msg = "Cannot rename disk_log file", 376 Error = {error, {Msg, Name, Fname, Head, Reason}}, 377 fatal("~p~n", [Error]), 378 {noreply, State} 379 end; 380 381handle_call({close_log, Name}, _From, State) -> 382 case disk_log:close(Name) of 383 ok -> 384 {reply, ok, State}; 385 386 {error, Reason} -> 387 Msg = "Cannot close disk_log file", 388 Error = {error, {Msg, Name, Reason}}, 389 fatal("~p~n", [Error]), 390 {noreply, State} 391 end; 392 393handle_call({unsafe_close_log, Name}, _From, State) -> 394 disk_log:close(Name), 395 {reply, ok, State}; 396 397handle_call({negotiate_protocol, Mon, _Version, _Protocols}, _From, State) 398 when State#state.tm_started == false -> 399 State2 = State#state{early_connects = [node(Mon) | State#state.early_connects]}, 400 {reply, {node(), {reject, self(), uninitialized, uninitialized}}, State2}; 401 402handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State) 403 when node(Mon) /= node() -> 404 Protocol = protocol_version(), 405 MyVersion = mnesia:system_info(version), 406 case lists:member(Protocol, Protocols) of 407 true -> 408 accept_protocol(Mon, MyVersion, Protocol, From, State); 409 false -> 410 %% in this release we should be able to handle the previous 411 %% protocol 412 case hd(Protocols) of 413 ?previous_protocol_version -> 414 accept_protocol(Mon, MyVersion, ?previous_protocol_version, From, State); 415 _ -> 416 verbose("Connection with ~p rejected. " 417 "version = ~p, protocols = ~p, " 418 "expected version = ~p, expected protocol = ~p~n", 419 [node(Mon), Version, Protocols, MyVersion, Protocol]), 420 {reply, {node(), {reject, self(), MyVersion, Protocol}}, State} 421 end 422 end; 423 424handle_call(init, _From, State) -> 425 net_kernel:monitor_nodes(true), 426 EarlyNodes = State#state.early_connects, 427 State2 = State#state{tm_started = true}, 428 {reply, EarlyNodes, State2}; 429 430handle_call(Msg, _From, State) -> 431 error("~p got unexpected call: ~p~n", [?MODULE, Msg]), 432 {noreply, State}. 433 434accept_protocol(Mon, Version, Protocol, From, State) -> 435 Reply = {node(), {accept, self(), Version, Protocol}}, 436 Node = node(Mon), 437 Pending0 = State#state.pending_negotiators, 438 Pending = lists:keydelete(Node, 1, Pending0), 439 case lists:member(Node, State#state.going_down) of 440 true -> 441 %% Wait for the mnesia_down to be processed, 442 %% before we reply 443 P = Pending ++ [{Node, Mon, From, Reply}], 444 {noreply, State#state{pending_negotiators = P}}; 445 false -> 446 %% No need for wait 447 link(Mon), %% link to remote Monitor 448 case Protocol == protocol_version() of 449 true -> 450 set({protocol, Node}, {Protocol, false}); 451 false -> 452 set({protocol, Node}, {Protocol, true}) 453 end, 454 {reply, Reply, State#state{pending_negotiators = Pending}} 455 end. 456 457%%---------------------------------------------------------------------- 458%% Func: handle_cast/2 459%% Returns: {noreply, State} | 460%% {noreply, State, Timeout} | 461%% {stop, Reason, State} (terminate/2 is called) 462%%---------------------------------------------------------------------- 463 464handle_cast({mnesia_down, mnesia_controller, Node}, State) -> 465 mnesia_tm:mnesia_down(Node), 466 {noreply, State}; 467 468handle_cast({mnesia_down, mnesia_tm, {Node, Pending}}, State) -> 469 mnesia_locker:mnesia_down(Node, Pending), 470 {noreply, State}; 471 472handle_cast({mnesia_down, mnesia_locker, Node}, State) -> 473 Down = {mnesia_down, Node}, 474 mnesia_lib:report_system_event(Down), 475 GoingDown = lists:delete(Node, State#state.going_down), 476 State2 = State#state{going_down = GoingDown}, 477 Pending = State#state.pending_negotiators, 478 case lists:keysearch(Node, 1, Pending) of 479 {value, {Node, Mon, ReplyTo, Reply}} -> 480 %% Late reply to remote monitor 481 link(Mon), %% link to remote Monitor 482 gen_server:reply(ReplyTo, Reply), 483 P2 = lists:keydelete(Node, 1,Pending), 484 State3 = State2#state{pending_negotiators = P2}, 485 {noreply, State3}; 486 false -> 487 %% No pending remote monitors 488 {noreply, State2} 489 end; 490 491handle_cast({disconnect, Node}, State) -> 492 case rpc:call(Node, erlang, whereis, [?MODULE]) of 493 {badrpc, _} -> 494 ignore; 495 RemoteMon when pid(RemoteMon) -> 496 unlink(RemoteMon) 497 end, 498 {noreply, State}; 499 500handle_cast({inconsistent_database, Context, Node}, State) -> 501 Msg = {inconsistent_database, Context, Node}, 502 mnesia_lib:report_system_event(Msg), 503 {noreply, State}; 504 505handle_cast(Msg, State) -> 506 error("~p got unexpected cast: ~p~n", [?MODULE, Msg]), 507 {noreply, State}. 508 509%%---------------------------------------------------------------------- 510%% Func: handle_info/2 511%% Returns: {noreply, State} | 512%% {noreply, State, Timeout} | 513%% {stop, Reason, State} (terminate/2 is called) 514%%---------------------------------------------------------------------- 515 516handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> 517 dbg_out("~p was ~p by supervisor~n",[?MODULE, R]), 518 {stop, R, State}; 519 520handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() -> 521 dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]), 522 exit(State#state.supervisor, shutdown), 523 {noreply, State}; 524 525handle_info({'EXIT', Pid, Reason}, State) -> 526 Node = node(Pid), 527 if 528 Node /= node() -> 529 %% Remotly linked process died, assume that it was a mnesia_monitor 530 mnesia_recover:mnesia_down(Node), 531 mnesia_controller:mnesia_down(Node), 532 {noreply, State#state{going_down = [Node | State#state.going_down]}}; 533 true -> 534 %% We have probably got an exit signal from from 535 %% disk_log or dets 536 Hint = "Hint: check that the disk still is writable", 537 Msg = {'EXIT', Pid, Reason}, 538 fatal("~p got unexpected info: ~p; ~p~n", 539 [?MODULE, Msg, Hint]) 540 end; 541 542handle_info({nodeup, Node}, State) -> 543 %% Ok, we are connected to yet another Erlang node 544 %% Let's check if Mnesia is running there in order 545 %% to detect if the network has been partitioned 546 %% due to communication failure. 547 548 HasDown = mnesia_recover:has_mnesia_down(Node), 549 ImRunning = mnesia_lib:is_running(), 550 551 if 552 %% If I'm not running the test will be made later. 553 HasDown == true, ImRunning == yes -> 554 spawn_link(?MODULE, detect_partitioned_network, [self(), Node]); 555 true -> 556 ignore 557 end, 558 {noreply, State}; 559 560handle_info({nodedown, _Node}, State) -> 561 %% Ignore, we are only caring about nodeup's 562 {noreply, State}; 563 564handle_info({disk_log, _Node, Log, Info}, State) -> 565 case Info of 566 {truncated, _No} -> 567 ok; 568 _ -> 569 mnesia_lib:important("Warning Log file ~p error reason ~s~n", 570 [Log, disk_log:format_error(Info)]) 571 end, 572 {noreply, State}; 573 574handle_info(Msg, State) -> 575 error("~p got unexpected info (~p): ~p~n", [?MODULE, State, Msg]). 576 577%%---------------------------------------------------------------------- 578%% Func: terminate/2 579%% Purpose: Shutdown the server 580%% Returns: any (ignored by gen_server) 581%%---------------------------------------------------------------------- 582terminate(Reason, State) -> 583 terminate_proc(?MODULE, Reason, State). 584 585%%---------------------------------------------------------------------- 586%% Func: code_change/3 587%% Purpose: Upgrade process when its code is to be changed 588%% Returns: {ok, NewState} 589%%---------------------------------------------------------------------- 590 591code_change(_OldVsn, State, _Extra) -> 592 {ok, State}. 593 594%%%---------------------------------------------------------------------- 595%%% Internal functions 596%%%---------------------------------------------------------------------- 597 598process_config_args([]) -> 599 ok; 600process_config_args([C|T]) -> 601 V = get_env(C), 602 dbg_out("Env ~p: ~p~n", [C, V]), 603 mnesia_lib:set(C, V), 604 process_config_args(T). 605 606set_env(E,Val) -> 607 mnesia_lib:set(E, check_type(E,Val)), 608 ok. 609 610get_env(E) -> 611 case ?catch_val(E) of 612 {'EXIT', _} -> 613 case application:get_env(mnesia, E) of 614 {ok, Val} -> 615 check_type(E, Val); 616 undefined -> 617 check_type(E, default_env(E)) 618 end; 619 Val -> 620 Val 621 end. 622 623env() -> 624 [ 625 access_module, 626 auto_repair, 627 backup_module, 628 debug, 629 dir, 630 dump_log_load_regulation, 631 dump_log_time_threshold, 632 dump_log_update_in_place, 633 dump_log_write_threshold, 634 event_module, 635 extra_db_nodes, 636 ignore_fallback_at_startup, 637 fallback_error_function, 638 max_wait_for_decision, 639 schema_location, 640 core_dir 641 ]. 642 643default_env(access_module) -> 644 mnesia; 645default_env(auto_repair) -> 646 true; 647default_env(backup_module) -> 648 mnesia_backup; 649default_env(debug) -> 650 none; 651default_env(dir) -> 652 Name = lists:concat(["Mnesia.", node()]), 653 filename:absname(Name); 654default_env(dump_log_load_regulation) -> 655 false; 656default_env(dump_log_time_threshold) -> 657 timer:minutes(3); 658default_env(dump_log_update_in_place) -> 659 true; 660default_env(dump_log_write_threshold) -> 661 1000; 662default_env(event_module) -> 663 mnesia_event; 664default_env(extra_db_nodes) -> 665 []; 666default_env(ignore_fallback_at_startup) -> 667 false; 668default_env(fallback_error_function) -> 669 {mnesia, lkill}; 670default_env(max_wait_for_decision) -> 671 infinity; 672default_env(schema_location) -> 673 opt_disc; 674default_env(core_dir) -> 675 false. 676 677check_type(Env, Val) -> 678 case catch do_check_type(Env, Val) of 679 {'EXIT', _Reason} -> 680 exit({bad_config, Env, Val}); 681 NewVal -> 682 NewVal 683 end. 684 685do_check_type(access_module, A) when atom(A) -> A; 686do_check_type(auto_repair, B) -> bool(B); 687do_check_type(backup_module, B) when atom(B) -> B; 688do_check_type(debug, debug) -> debug; 689do_check_type(debug, false) -> none; 690do_check_type(debug, none) -> none; 691do_check_type(debug, trace) -> trace; 692do_check_type(debug, true) -> debug; 693do_check_type(debug, verbose) -> verbose; 694do_check_type(dir, V) -> filename:absname(V); 695do_check_type(dump_log_load_regulation, B) -> bool(B); 696do_check_type(dump_log_time_threshold, I) when integer(I), I > 0 -> I; 697do_check_type(dump_log_update_in_place, B) -> bool(B); 698do_check_type(dump_log_write_threshold, I) when integer(I), I > 0 -> I; 699do_check_type(event_module, A) when atom(A) -> A; 700do_check_type(ignore_fallback_at_startup, B) -> bool(B); 701do_check_type(fallback_error_function, {Mod, Func}) 702 when atom(Mod), atom(Func) -> {Mod, Func}; 703do_check_type(extra_db_nodes, L) when list(L) -> 704 Fun = fun(N) when N == node() -> false; 705 (A) when atom(A) -> true 706 end, 707 lists:filter(Fun, L); 708do_check_type(max_wait_for_decision, infinity) -> infinity; 709do_check_type(max_wait_for_decision, I) when integer(I), I > 0 -> I; 710do_check_type(schema_location, M) -> media(M); 711do_check_type(core_dir, "false") -> false; 712do_check_type(core_dir, false) -> false; 713do_check_type(core_dir, Dir) when list(Dir) -> Dir. 714 715 716bool(true) -> true; 717bool(false) -> false. 718 719media(disc) -> disc; 720media(opt_disc) -> opt_disc; 721media(ram) -> ram. 722 723patch_env(Env, Val) -> 724 case catch do_check_type(Env, Val) of 725 {'EXIT', _Reason} -> 726 {error, {bad_type, Env, Val}}; 727 NewVal -> 728 application_controller:set_env(mnesia, Env, NewVal), 729 NewVal 730 end. 731 732detect_partitioned_network(Mon, Node) -> 733 GoodNodes = negotiate_protocol([Node]), 734 detect_inconcistency(GoodNodes, running_partitioned_network), 735 unlink(Mon), 736 exit(normal). 737 738detect_inconcistency([], _Context) -> 739 ok; 740detect_inconcistency(Nodes, Context) -> 741 Downs = [N || N <- Nodes, mnesia_recover:has_mnesia_down(N)], 742 {Replies, _BadNodes} = 743 rpc:multicall(Downs, ?MODULE, has_remote_mnesia_down, [node()]), 744 report_inconsistency(Replies, Context, ok). 745 746has_remote_mnesia_down(Node) -> 747 HasDown = mnesia_recover:has_mnesia_down(Node), 748 Master = mnesia_recover:get_master_nodes(schema), 749 if 750 HasDown == true, Master == [] -> 751 {true, node()}; 752 true -> 753 {false, node()} 754 end. 755 756report_inconsistency([{true, Node} | Replies], Context, _Status) -> 757 %% Oops, Mnesia is already running on the 758 %% other node AND we both regard each 759 %% other as down. The database is 760 %% potentially inconsistent and we has to 761 %% do tell the applications about it, so 762 %% they may perform some clever recovery 763 %% action. 764 Msg = {inconsistent_database, Context, Node}, 765 mnesia_lib:report_system_event(Msg), 766 report_inconsistency(Replies, Context, inconsistent_database); 767report_inconsistency([{false, _Node} | Replies], Context, Status) -> 768 report_inconsistency(Replies, Context, Status); 769report_inconsistency([{badrpc, _Reason} | Replies], Context, Status) -> 770 report_inconsistency(Replies, Context, Status); 771report_inconsistency([], _Context, Status) -> 772 Status. 773