103
104
-record(state, {supervisor,
104
105
schema_is_merged = false,
108
sender_pid = [], %% Was a pid or undef is now a list pids.
107
loader_pid = [], %% Was Pid is now [{Pid,Work}|..]
108
loader_queue, %% Was list is now gb_tree
109
sender_pid = [], %% Was a pid or undef is now [{Pid,Work}|..]
109
110
sender_queue = [],
110
late_loader_queue = [],
111
dumper_pid, % Dumper or schema commit pid
112
dumper_queue = [], % Dumper or schema commit queue
113
others = [], % Processes that needs the copier_done msg
111
late_loader_queue, %% Was list is now gb_tree
112
dumper_pid, %% Dumper or schema commit pid
113
dumper_queue = [], %% Dumper or schema commit queue
114
others = [], %% Processes that needs the copier_done msg
114
115
dump_log_timer_ref,
115
116
is_stopping = false
117
118
%% Backwards Comp. Sender_pid is now a list of senders..
118
get_senders(#state{sender_pid = undefined}) -> [];
119
get_senders(#state{sender_pid = Pid}) when pid(Pid) -> [Pid];
120
119
get_senders(#state{sender_pid = Pids}) when list(Pids) -> Pids.
122
-record(worker_reply, {what,
120
%% Backwards Comp. loader_pid is now a list of loaders..
121
get_loaders(#state{loader_pid = Pids}) when list(Pids) -> Pids.
123
case ?catch_val(no_table_loaders) of
125
mnesia_lib:set(no_table_loaders,1),
127
130
-record(schema_commit_lock, {owner}).
128
131
-record(block_controller, {owner}).
302
307
call({add_other, self()}),
303
308
Reason = {dumper,add_table_copy},
304
309
Work = #net_load{table = Tab,reason = Reason,cstruct = Cs},
305
Res = (catch load_table(Work)),
310
%% I'll need this cause it's linked trough the subscriber
311
%% might be solved by using monitor in subscr instead.
312
process_flag(trap_exit, true),
313
Load = load_table_fun(Work),
314
Res = (catch Load()),
315
process_flag(trap_exit, false),
306
316
call({del_other, self()}),
308
318
#loader_done{is_loaded = true} ->
635
654
State3 = State2#state{early_msgs = [], schema_is_merged = true},
636
655
handle_early_msgs(lists:reverse(Msgs), State3);
638
handle_call(disc_load_intents, From, State) ->
639
Tabs = disc_load_intents(State#state.loader_queue) ++
640
disc_load_intents(State#state.late_loader_queue),
641
ActiveTabs = mnesia_lib:local_active_tables(),
642
reply(From, {ok, node(), mnesia_lib:union(Tabs, ActiveTabs)}),
657
handle_call(disc_load_intents,From,State = #state{loader_queue=LQ,late_loader_queue=LLQ}) ->
658
LQTabs = gb_trees:keys(LQ),
659
LLQTabs = gb_trees:keys(LLQ),
660
ActiveTabs = lists:sort(mnesia_lib:local_active_tables()),
661
reply(From, {ok, node(), ordsets:union([LQTabs,LLQTabs,ActiveTabs])}),
645
664
handle_call({update_where_to_write, [add, Tab, AddNode], _From}, _Dummy, State) ->
750
774
error("~p got unexpected call: ~p~n", [?SERVER_NAME, Msg]),
753
disc_load_intents([H | T]) when record(H, disc_load) ->
754
[H#disc_load.table | disc_load_intents(T)];
755
disc_load_intents([H | T]) when record(H, late_load) ->
756
[H#late_load.table | disc_load_intents(T)];
757
disc_load_intents( [H | T]) when record(H, net_load) ->
758
disc_load_intents(T);
759
disc_load_intents([]) ->
762
late_disc_load(TabsR, Reason, RemoteLoaders, From, State) ->
777
late_disc_load(TabsR, Reason, RemoteLoaders, From,
778
State = #state{loader_queue = LQ, late_loader_queue = LLQ}) ->
763
779
verbose("Intend to load tables: ~p~n", [TabsR]),
764
780
?eval_debug_fun({?MODULE, late_disc_load},
769
785
reply(From, queued),
770
786
%% RemoteLoaders is a list of {ok, Node, Tabs} tuples
772
%% Remove deleted tabs
773
LocalTabs = mnesia_lib:val({schema, local_tables}),
774
Filter = fun({Tab, Reas}, Acc) ->
775
case lists:member(Tab, LocalTabs) of
776
true -> [{Tab, Reas} | Acc];
780
case lists:member(Tab, LocalTabs) of
788
%% Remove deleted tabs and queued/loaded
789
LocalTabs = gb_sets:from_ordset(lists:sort(mnesia_lib:val({schema,local_tables}))),
790
Filter = fun(TabInfo0, Acc) ->
794
TabN -> {TabN,Reason}
796
case gb_sets:is_member(Tab, LocalTabs) of
798
case ?catch_val({Tab, where_to_read}) == node() of
801
case gb_trees:is_defined(Tab,LQ) of
803
false -> [TabInfo | Acc]
786
810
Tabs = lists:foldl(Filter, [], TabsR),
788
812
Nodes = val({current, db_nodes}),
789
LateLoaders = late_loaders(Tabs, Reason, RemoteLoaders, Nodes),
790
LateQueue = State#state.late_loader_queue ++ LateLoaders,
791
State#state{late_loader_queue = LateQueue}.
793
late_loaders([{Tab, Reason} | Tabs], DefaultReason, RemoteLoaders, Nodes) ->
794
LoadNodes = late_load_filter(RemoteLoaders, Tab, Nodes, []),
797
cast({disc_load, Tab, Reason}); % Ugly cast
801
LateLoad = #late_load{table = Tab, loaders = LoadNodes, reason = Reason},
802
[LateLoad | late_loaders(Tabs, DefaultReason, RemoteLoaders, Nodes)];
804
late_loaders([Tab | Tabs], Reason, RemoteLoaders, Nodes) ->
805
Loaders = late_load_filter(RemoteLoaders, Tab, Nodes, []),
808
cast({disc_load, Tab, Reason}); % Ugly cast
812
LateLoad = #late_load{table = Tab, loaders = Loaders, reason = Reason},
813
[LateLoad | late_loaders(Tabs, Reason, RemoteLoaders, Nodes)];
814
late_loaders([], _Reason, _RemoteLoaders, _Nodes) ->
813
LateQueue = late_loaders(Tabs, RemoteLoaders, Nodes, LLQ),
814
State#state{late_loader_queue = LateQueue}.
816
late_loaders([{Tab, Reason} | Tabs], RemoteLoaders, Nodes, LLQ) ->
817
case gb_trees:is_defined(Tab, LLQ) of
819
LoadNodes = late_load_filter(RemoteLoaders, Tab, Nodes, []),
821
[] -> cast({disc_load, Tab, Reason}); % Ugly cast
824
LateLoad = #late_load{table=Tab,loaders=LoadNodes,reason=Reason},
825
late_loaders(Tabs, RemoteLoaders, Nodes, gb_trees:insert(Tab,LateLoad,LLQ));
827
late_loaders(Tabs, RemoteLoaders, Nodes, LLQ)
829
late_loaders([], _RemoteLoaders, _Nodes, LLQ) ->
817
832
late_load_filter([{error, _} | RemoteLoaders], Tab, Nodes, Acc) ->
818
833
late_load_filter(RemoteLoaders, Tab, Nodes, Acc);
958
963
Msgs = State#state.early_msgs,
959
964
noreply(State#state{early_msgs = [{cast, Msg} | Msgs]});
966
%% This must be done after schema_is_merged otherwise adopt_orphan
967
%% might trigger a table load from wrong nodes as a result of that we don't
968
%% know which tables we can load safly first.
969
handle_cast({im_running, _Node, NewFriends}, State) ->
970
Tabs = mnesia_lib:local_active_tables() -- [schema],
971
Ns = mnesia_lib:intersect(NewFriends, val({current, db_nodes})),
972
abcast(Ns, {adopt_orphans, node(), Tabs}),
961
975
handle_cast({disc_load, Tab, Reason}, State) ->
962
976
Worker = #disc_load{table = Tab, reason = Reason},
963
977
State2 = add_worker(Worker, State),
1037
1051
[Tab || {Tab, Ns} <- RemoteMasters,
1038
1052
lists:member(N, Ns)],
1039
1053
mnesia_late_loader:maybe_async_late_disc_load(N, RemoteOrphans, Reason)
1041
1055
lists:foreach(Fun, Nodes),
1043
Queue = State2#state.loader_queue,
1044
State3 = State2#state{loader_queue = Queue},
1047
1058
handle_cast(Msg, State) ->
1048
1059
error("~p got unexpected cast: ~p~n", [?SERVER_NAME, Msg]),
1049
1060
noreply(State).
1051
handle_sync_tabs([Tab | Tabs], From) ->
1062
handle_sync_tabs([Tab | Tabs], From) ->
1052
1063
case val({Tab, where_to_read}) of
1054
1065
case get({sync_tab, Tab}) of
1094
1105
{stop, fatal, State}
1097
handle_info(Done, State) when record(Done, loader_done) ->
1100
Done#loader_done.worker_pid == State#state.loader_pid -> ok
1103
[_Worker | Rest] = State#state.loader_queue,
1104
LateQueue0 = State#state.late_loader_queue,
1105
{LoadQ, LateQueue} =
1108
handle_info(Done, State0) when record(Done, loader_done) ->
1109
WPid = Done#loader_done.worker_pid,
1110
LateQueue0 = State0#state.late_loader_queue,
1111
Tab = Done#loader_done.table_name,
1112
State1 = State0#state{loader_pid = lists:keydelete(WPid,1,get_loaders(State0))},
1106
1115
case Done#loader_done.is_loaded of
1108
Tab = Done#loader_done.table_name,
1110
%% Optional user sync
1111
case Done#loader_done.needs_sync of
1112
true -> user_sync_tab(Tab);
1116
1117
%% Optional table announcement
1118
1119
Done#loader_done.needs_announce == true,
1139
1140
Ns = val({current, db_nodes}),
1140
1141
AlreadyKnows = val({Tab, active_replicas}),
1141
1142
abcast(Ns -- AlreadyKnows, {i_have_tab, Tab, node()})
1143
{Rest, reply_late_load(Tab, LateQueue0)};
1144
%% Optional user sync
1145
case Done#loader_done.needs_sync of
1146
true -> user_sync_tab(Tab);
1149
State1#state{late_loader_queue=gb_trees:delete_any(Tab, LateQueue0)};
1151
%% Either the node went down or table was not
1152
%% loaded remotly yet
1145
1153
case Done#loader_done.needs_reply of
1147
1155
reply(Done#loader_done.reply_to,
1255
1259
%% Pick the load record that has the highest load order
1256
1260
%% Returns {BestLoad, RemainingQueue} or {none, []} if queue is empty
1257
1261
pick_next(Queue) ->
1258
pick_next(Queue, none, none, []).
1262
List = gb_trees:values(Queue),
1263
case pick_next(List, none, none) of
1264
none -> {none, gb_trees:empty()};
1265
{Tab, Worker} -> {Worker, gb_trees:delete(Tab,Queue)}
1260
pick_next([Head | Tail], Load, Order, Rest) when record(Head, net_load) ->
1268
pick_next([Head | Tail], Load, Order) when record(Head, net_load) ->
1261
1269
Tab = Head#net_load.table,
1262
select_best(Head, Tail, val({Tab, load_order}), Load, Order, Rest);
1263
pick_next([Head | Tail], Load, Order, Rest) when record(Head, disc_load) ->
1270
select_best(Head, Tail, ?catch_val({Tab, load_order}), Load, Order);
1271
pick_next([Head | Tail], Load, Order) when record(Head, disc_load) ->
1264
1272
Tab = Head#disc_load.table,
1265
select_best(Head, Tail, val({Tab, load_order}), Load, Order, Rest);
1266
pick_next([], Load, _Order, Rest) ->
1273
select_best(Head, Tail, ?catch_val({Tab, load_order}), Load, Order);
1274
pick_next([], none, _Order) ->
1276
pick_next([], Load, _Order) ->
1277
{element(2,Load), Load}.
1269
select_best(Load, Tail, Order, none, none, Rest) ->
1270
pick_next(Tail, Load, Order, Rest);
1271
select_best(Load, Tail, Order, OldLoad, OldOrder, Rest) when Order > OldOrder ->
1272
pick_next(Tail, Load, Order, [OldLoad | Rest]);
1273
select_best(Load, Tail, _Order, OldLoad, OldOrder, Rest) ->
1274
pick_next(Tail, OldLoad, OldOrder, [Load | Rest]).
1279
select_best(_Head, Tail, {'EXIT', _WHAT}, Load, Order) ->
1280
%% Table have been deleted drop it.
1281
pick_next(Tail, Load, Order);
1282
select_best(Load, Tail, Order, none, none) ->
1283
pick_next(Tail, Load, Order);
1284
select_best(Load, Tail, Order, _OldLoad, OldOrder) when Order > OldOrder ->
1285
pick_next(Tail, Load, Order);
1286
select_best(_Load, Tail, _Order, OldLoad, OldOrder) ->
1287
pick_next(Tail, OldLoad, OldOrder).
1276
1289
%%----------------------------------------------------------------------
1277
1290
%% Func: terminate/2
1286
1299
%% Purpose: Upgrade process when its code is to be changed
1287
1300
%% Returns: {ok, NewState}
1288
1301
%%----------------------------------------------------------------------
1289
code_change(_OldVsn, State, _Extra) ->
1302
code_change(_OldVsn, State0, _Extra) ->
1304
State1 = case State0#state.loader_pid of
1305
Pids when is_list(Pids) -> State0;
1306
undefined -> State0#state{loader_pid = [],loader_queue=gb_trees:empty()};
1307
Pid when is_pid(Pid) ->
1308
[Loader|Rest] = State0#state.loader_queue,
1309
LQ0 = [{element(2,Rec),Rec} || Rec <- Rest],
1310
LQ1 = lists:sort(LQ0),
1311
LQ = gb_trees:from_orddict(LQ1),
1312
State0#state{loader_pid=[{Pid,Loader}], loader_queue=LQ}
1315
State = if is_list(State1#state.late_loader_queue) ->
1316
LLQ0 = State1#state.late_loader_queue,
1317
LLQ1 = lists:sort([{element(2,Rec),Rec} || Rec <- LLQ0]),
1318
LLQ = gb_trees:from_orddict(LLQ1),
1319
State1#state{late_loader_queue=LLQ};
1292
1325
%%%----------------------------------------------------------------------
1293
1326
%%% Internal functions
1294
1327
%%%----------------------------------------------------------------------
1337
1370
LocalContent = Cs#cstruct.local_content,
1338
1371
RamCopyHoldersOnDiscNodes = mnesia_lib:intersect(RamCopyHolders, DiscNodes),
1339
1372
Active = val({Tab, active_replicas}),
1373
BeingCreated = (?catch_val({Tab, create_table}) == true),
1374
Read = val({Tab, where_to_read}),
1340
1375
case lists:member(Node, DiscCopyHolders) of
1376
_ when BeingCreated == true ->
1377
orphan_tables(Tabs, Node, Ns, Local, Remote);
1378
_ when Read == node() -> %% Allready loaded
1379
orphan_tables(Tabs, Node, Ns, Local, Remote);
1341
1380
true when Active == [] ->
1342
1381
case DiscCopyHolders -- Ns of
1372
1411
{LocalOrphans, RemoteMasters}.
1374
1413
node_has_tabs([Tab | Tabs], Node, State) when Node /= node() ->
1375
State2 = update_whereabouts(Tab, Node, State),
1415
case catch update_whereabouts(Tab, Node, State) of
1416
State1 = #state{} -> State1;
1417
{'EXIT', R} -> %% Tab was just deleted?
1418
case ?catch_val({Tab, cstruct}) of
1419
{'EXIT', _} -> State; % yes
1420
_ -> erlang:fault(R)
1376
1423
node_has_tabs(Tabs, Node, State2);
1377
1424
node_has_tabs([Tab | Tabs], Node, State) ->
1378
1425
user_sync_tab(Tab),
1561
1606
[M|remove_early_messages(R,Node)].
1563
1608
%% Drop loader from late load queue and possibly trigger a disc_load
1564
drop_loaders(Tab, Node, [H | T]) when H#late_load.table == Tab ->
1565
%% Check if it is time to issue a disc_load request
1566
case H#late_load.loaders of
1568
Reason = {H#late_load.reason, last_loader_down, Node},
1569
cast({disc_load, Tab, Reason}); % Ugly cast
1573
%% Drop the node from the list of loaders
1574
H2 = H#late_load{loaders = H#late_load.loaders -- [Node]},
1575
[H2 | drop_loaders(Tab, Node, T)];
1576
drop_loaders(Tab, Node, [H | T]) ->
1577
[H | drop_loaders(Tab, Node, T)];
1578
drop_loaders(_, _, []) ->
1609
drop_loaders(Tab, Node, LLQ) ->
1610
case gb_trees:lookup(Tab,LLQ) of
1614
%% Check if it is time to issue a disc_load request
1615
case H#late_load.loaders of
1617
Reason = {H#late_load.reason, last_loader_down, Node},
1618
cast({disc_load, Tab, Reason}); % Ugly cast
1622
%% Drop the node from the list of loaders
1623
H2 = H#late_load{loaders = H#late_load.loaders -- [Node]},
1624
gb_trees:update(Tab, H2, LLQ)
1581
1627
add_active_replica(Tab, Node) ->
1582
1628
add_active_replica(Tab, Node, val({Tab, cstruct})).
1816
1867
State2 = State#state{dumper_queue = Queue2},
1817
1868
opt_start_worker(State2);
1818
1869
add_worker(Worker, State) when record(Worker, net_load) ->
1819
Queue = State#state.loader_queue,
1820
State2 = State#state{loader_queue = Queue ++ [Worker]},
1821
opt_start_worker(State2);
1870
opt_start_worker(add_loader(Worker#net_load.table,Worker,State));
1822
1871
add_worker(Worker, State) when record(Worker, send_table) ->
1823
1872
Queue = State#state.sender_queue,
1824
1873
State2 = State#state{sender_queue = Queue ++ [Worker]},
1825
1874
opt_start_worker(State2);
1826
1875
add_worker(Worker, State) when record(Worker, disc_load) ->
1827
Queue = State#state.loader_queue,
1828
State2 = State#state{loader_queue = Queue ++ [Worker]},
1829
opt_start_worker(State2);
1876
opt_start_worker(add_loader(Worker#disc_load.table,Worker,State));
1830
1877
% Block controller should be used for upgrading mnesia.
1831
1878
add_worker(Worker, State) when record(Worker, block_controller) ->
1832
1879
Queue = State#state.dumper_queue,
1900
1953
opt_start_sender2([Sender|R], Pids, Kept, LoaderQ) ->
1901
1954
Tab = Sender#send_table.table,
1902
1955
Active = val({Tab, active_replicas}),
1903
IgotIt = lists:member(node(), Active),
1956
IgotIt = lists:member(node(), Active),
1957
IsLoading = lists:any(fun({_Pid,Loader}) ->
1958
Tab == element(#net_load.table, Loader)
1905
(hd(LoaderQ))#net_load.table == Tab ->
1906
%% I'm currently loading the table let him wait
1961
IgotIt, IsLoading ->
1962
%% I'm currently finishing loading the table let him wait
1907
1963
opt_start_sender2(R,Pids, [Sender|Kept], LoaderQ);
1909
1965
%% Start worker but keep him in the queue
1910
Pid = spawn_link(?MODULE, send_and_reply,
1966
Pid = spawn_link(?MODULE, send_and_reply,[self(), Sender]),
1912
1967
opt_start_sender2(R,[{Pid,Sender}|Pids],Kept,LoaderQ);
1913
length(Active) > 0 ->
1914
%% Someone else has loaded the table redirect him with a fail msg.
1969
verbose("Send table failed ~p not active on this node ~n", [Tab]),
1915
1970
Sender#send_table.receiver_pid ! {copier_done, node()},
1916
opt_start_sender2(R,Pids, Kept, LoaderQ);
1918
%% No one else is active and the remote loader has decided
1919
%% that I should load the table first => Keep him in queue
1920
opt_start_sender2(R,Pids, [Sender|Kept], LoaderQ)
1971
opt_start_sender2(R,Pids, Kept, LoaderQ)
1923
opt_start_loader(State) ->
1924
LoaderQueue = State#state.loader_queue,
1926
LoaderQueue == [] ->
1930
State#state.loader_pid /= undefined ->
1931
%% Bad luck, an loader is already running
1974
opt_start_loader(State = #state{loader_queue = LoaderQ}) ->
1975
Current = get_loaders(State),
1976
Max = max_loaders(),
1977
case gb_trees:is_empty(LoaderQ) of
1980
_ when length(Current) >= Max ->
1935
1983
SchemaQueue = State#state.dumper_queue,
1936
case lists:keymember(schema_commit, 1, SchemaQueue) of
1984
case lists:keymember(schema_commit_lock, 1, SchemaQueue) of
1938
{Worker, Rest} = pick_next(LoaderQueue),
1940
%% Start worker but keep him in the queue
1941
Pid = spawn_link(?MODULE, load_and_reply, [self(), Worker]),
1942
State#state{loader_pid = Pid,
1943
loader_queue = [Worker | Rest]};
1986
case pick_next(LoaderQ) of
1988
State#state{loader_queue=Rest};
1990
case already_loading(Worker, get_loaders(State)) of
1992
opt_start_loader(State#state{loader_queue = Rest});
1994
%% Start worker but keep him in the queue
1995
Pid = load_and_reply(self(), Worker),
1996
State#state{loader_pid=[{Pid,Worker}|get_loaders(State)],
1997
loader_queue = Rest}
1945
2001
%% Bad luck, we must wait for the schema commit
2006
already_loading(#net_load{table=Tab},Loaders) ->
2007
already_loading2(Tab,Loaders);
2008
already_loading(#disc_load{table=Tab},Loaders) ->
2009
already_loading2(Tab,Loaders).
2011
already_loading2(Tab, [{_,#net_load{table=Tab}}|_]) -> true;
2012
already_loading2(Tab, [{_,#disc_load{table=Tab}}|_]) -> true;
2013
already_loading2(Tab, [_|Rest]) -> already_loading2(Tab,Rest);
2014
already_loading2(_,[]) -> false.
1950
2016
start_remote_sender(Node, Tab, Receiver, Storage) ->
1951
2017
Msg = #send_table{table = Tab,
1952
2018
receiver_pid = Receiver,
1971
2037
unlink(ReplyTo),
1975
2040
load_and_reply(ReplyTo, Worker) ->
1976
process_flag(trap_exit, true),
1977
Done = load_table(Worker),
1978
ReplyTo ! Done#loader_done{worker_pid = self()},
2041
Load = load_table_fun(Worker),
2044
process_flag(trap_exit, true),
2046
ReplyTo ! Done#loader_done{worker_pid = self()},
2050
spawn_link(SendAndReply).
1982
2052
%% Now it is time to load the table
1983
2053
%% but first we must check if it still is neccessary
1984
load_table(Load) when record(Load, net_load) ->
2054
load_table_fun(Load) when record(Load, net_load) ->
1985
2055
Tab = Load#net_load.table,
1986
2056
ReplyTo = Load#net_load.opt_reply_to,
1987
2057
Reason = Load#net_load.reason,
2001
2071
ReadNode == node() ->
2002
2072
%% Already loaded locally
2004
2074
LocalC == true ->
2005
Res = mnesia_loader:disc_load_table(Tab, load_local_content),
2006
Done#loader_done{reply = Res, needs_announce = true, needs_sync = true};
2076
Res = mnesia_loader:disc_load_table(Tab, load_local_content),
2077
Done#loader_done{reply = Res, needs_announce = true, needs_sync = true}
2007
2079
AccessMode == read_only, Reason /= {dumper,add_table_copy} ->
2008
disc_load_table(Tab, Reason, ReplyTo);
2080
fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
2010
%% Either we cannot read the table yet
2011
%% or someone is moving a replica between
2013
Cs = Load#net_load.cstruct,
2014
Res = mnesia_loader:net_load_table(Tab, Reason, Active, Cs),
2017
Done#loader_done{needs_sync = true,
2020
Done#loader_done{is_loaded = false,
2083
%% Either we cannot read the table yet
2084
%% or someone is moving a replica between
2086
Cs = Load#net_load.cstruct,
2087
Res = mnesia_loader:net_load_table(Tab, Reason, Active, Cs),
2090
Done#loader_done{needs_sync = true,
2093
Done#loader_done{is_loaded = false,
2025
load_table(Load) when record(Load, disc_load) ->
2098
load_table_fun(Load) when record(Load, disc_load) ->
2026
2099
Tab = Load#disc_load.table,
2027
2100
Reason = Load#disc_load.reason,
2028
2101
ReplyTo = Load#disc_load.opt_reply_to,
2038
2111
Active == [], ReadNode == nowhere ->
2039
2112
%% Not loaded anywhere, lets load it from disc
2040
disc_load_table(Tab, Reason, ReplyTo);
2113
fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
2041
2114
ReadNode == nowhere ->
2042
2115
%% Already loaded on other node, lets get it
2043
2116
Cs = val({Tab, cstruct}),
2044
case mnesia_loader:net_load_table(Tab, Reason, Active, Cs) of
2046
Done#loader_done{needs_sync = true};
2047
{not_loaded, storage_unknown} ->
2048
Done#loader_done{is_loaded = false};
2049
{not_loaded, ErrReason} ->
2050
Done#loader_done{is_loaded = false,
2051
reply = {not_loaded,ErrReason}}
2118
case mnesia_loader:net_load_table(Tab, Reason, Active, Cs) of
2120
Done#loader_done{needs_sync = true};
2121
{not_loaded, storage_unknown} ->
2122
Done#loader_done{is_loaded = false};
2123
{not_loaded, ErrReason} ->
2124
Done#loader_done{is_loaded = false,
2125
reply = {not_loaded,ErrReason}}
2054
2129
%% Already readable, do not worry be happy
2058
2133
disc_load_table(Tab, Reason, ReplyTo) ->