1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22-module(mnesia_late_loader).
23
24-export([
25	 async_late_disc_load/3,
26	 maybe_async_late_disc_load/3,
27	 init/1,
28	 start/0
29	]).
30
31%% sys callback functions
32-export([
33	 system_continue/3,
34	 system_terminate/4,
35	 system_code_change/4
36	]).
37
38-define(SERVER_NAME, ?MODULE).
39
40-include("mnesia.hrl").
41
42-record(state, {supervisor}).
43
44async_late_disc_load(_, [], _) -> ok;
45async_late_disc_load(Node, Tabs, Reason) ->
46    Msg = {async_late_disc_load, Tabs, Reason},
47    ?SAFE({?SERVER_NAME, Node} ! {self(), Msg}).
48
49maybe_async_late_disc_load(_, [], _) -> ok;
50maybe_async_late_disc_load(Node, Tabs, Reason) ->
51    Msg = {maybe_async_late_disc_load, Tabs, Reason},
52    ?SAFE({?SERVER_NAME, Node} ! {self(), Msg}).
53
54start() ->
55    mnesia_monitor:start_proc(?SERVER_NAME, ?MODULE, init, [self()]).
56
57init(Parent) ->
58    %% Trap exit omitted intentionally
59    register(?SERVER_NAME, self()),
60    link(whereis(mnesia_controller)),  %% We may not hang
61    mnesia_controller:merge_schema(),
62    unlink(whereis(mnesia_controller)),
63    mnesia_lib:set(mnesia_status, running),
64    proc_lib:init_ack(Parent, {ok, self()}),
65    loop(#state{supervisor = Parent}).
66
67loop(State) ->
68    receive
69	{_From, {async_late_disc_load, Tabs, Reason}} ->
70	    mnesia_controller:schedule_late_disc_load(Tabs, Reason),
71	    loop(State);
72
73	{_From, {maybe_async_late_disc_load, Tabs, Reason}} ->
74	    CheckMaster =
75		fun(Tab, Good) ->
76			case mnesia_recover:get_master_nodes(Tab) of
77			    [] -> [Tab|Good];
78			    Masters ->
79				case lists:member(node(),Masters) of
80				    true -> [Tab|Good];
81				    false -> Good
82				end
83			end
84		end,
85	    GoodTabs = lists:foldl(CheckMaster, [], Tabs),
86	    mnesia_controller:schedule_late_disc_load(GoodTabs, Reason),
87	    loop(State);
88
89	{system, From, Msg} ->
90	    mnesia_lib:dbg_out("~p got {system, ~p, ~tp}~n",
91			       [?SERVER_NAME, From, Msg]),
92	    Parent = State#state.supervisor,
93	    sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], State);
94
95	Msg ->
96	    mnesia_lib:error("~p got unexpected message: ~tp~n",
97			     [?SERVER_NAME, Msg]),
98	    loop(State)
99    end.
100
101%%%%%%%%%%%%%%%%%%%%%%%%%%%
102%% System upgrade
103
104system_continue(_Parent, _Debug, State) ->
105    loop(State).
106
107system_terminate(Reason, _Parent, _Debug, _State) ->
108    exit(Reason).
109
110system_code_change(State, _Module, _OldVsn, _Extra) ->
111    {ok, State}.
112