File 0964-mnesia-Fix-add_table_copy.patch of Package erlang
From 6213b70b2aba47cc60306bdafc3ef01862d532bd Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Mon, 28 Mar 2022 15:35:29 +0200
Subject: [PATCH] mnesia: Fix add_table_copy
add_table_copy done at the same time as a node started could lead to
mnesia hanging or looping forever.
---
lib/mnesia/src/mnesia_controller.erl | 29 +++++++++++++----------
lib/mnesia/src/mnesia_loader.erl | 10 ++++----
lib/mnesia/src/mnesia_schema.erl | 6 +++--
lib/mnesia/test/ext_test.erl | 2 +-
lib/mnesia/test/mnesia_isolation_test.erl | 18 +++++++++-----
5 files changed, 40 insertions(+), 25 deletions(-)
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 5ea3a896e1..4ab32a9efa 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -46,7 +46,7 @@
%% Mnesia internal stuff
-export([
start/0,
- i_have_tab/1,
+ i_have_tab/2,
info/0,
get_info/1,
get_workers/1,
@@ -354,7 +354,7 @@ get_network_copy(Tid, Tab, Cs) ->
Tab = Res#loader_done.table_name,
case Res#loader_done.needs_announce of
true ->
- i_have_tab(Tab);
+ i_have_tab(Tab, Cs);
false ->
ignore
end,
@@ -378,10 +378,12 @@ get_network_copy(Tid, Tab, Cs) ->
%% is synchronously started from mnesia_controller
create_table(Tab) ->
- {loaded, ok} = mnesia_loader:disc_load_table(Tab, {dumper,create_table}).
+ Cs = val({Tab, cstruct}),
+ {loaded, ok} = mnesia_loader:disc_load_table(Tab, {dumper,create_table}, Cs).
get_disc_copy(Tab) ->
- disc_load_table(Tab, {dumper,change_table_copy_type}, undefined).
+ Cs = val({Tab, cstruct}),
+ disc_load_table(Tab, {dumper,change_table_copy_type}, undefined, Cs).
%% Returns ok instead of yes
force_load_table(Tab) when is_atom(Tab), Tab /= schema ->
@@ -1811,13 +1813,16 @@ user_sync_tab(Tab) ->
end.
i_have_tab(Tab) ->
+ i_have_tab(Tab, val({Tab, cstruct})).
+
+i_have_tab(Tab, Cs) ->
case val({Tab, local_content}) of
true ->
mnesia_lib:set_local_content_whereabouts(Tab);
false ->
set({Tab, where_to_read}, node())
end,
- add_active_replica(Tab, node()).
+ add_active_replica(Tab, node(), Cs).
sync_and_block_table_whereabouts(Tab, ToNode, RemoteS, AccessMode) when Tab /= schema ->
Current = val({current, db_nodes}),
@@ -2199,13 +2204,13 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
fun() -> Done end;
LocalC == true ->
fun() ->
- Res = mnesia_loader:disc_load_table(Tab, load_local_content),
+ Res = mnesia_loader:disc_load_table(Tab, load_local_content, Cs),
Done#loader_done{reply = Res, needs_announce = true, needs_sync = true}
end;
AccessMode == read_only, not AddTableCopy ->
- fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ fun() -> disc_load_table(Tab, Reason, ReplyTo, Cs) end;
Active =:= [], AddTableCopy, OnlyRamCopies ->
- fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ fun() -> disc_load_table(Tab, Reason, ReplyTo, Cs) end;
true ->
fun() ->
%% Either we cannot read the table yet
@@ -2231,13 +2236,13 @@ load_table_fun(#disc_load{table=Tab, reason=Reason, opt_reply_to=ReplyTo}) ->
needs_sync = false,
needs_reply = false
},
+ Cs = val({Tab, cstruct}),
if
Active == [], ReadNode == nowhere ->
%% Not loaded anywhere, lets load it from disc
- fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ fun() -> disc_load_table(Tab, Reason, ReplyTo, Cs) end;
ReadNode == nowhere ->
%% Already loaded on other node, lets get it
- Cs = val({Tab, cstruct}),
fun() ->
case mnesia_loader:net_load_table(Tab, Reason, Active, Cs) of
{loaded, ok} ->
@@ -2254,7 +2259,7 @@ load_table_fun(#disc_load{table=Tab, reason=Reason, opt_reply_to=ReplyTo}) ->
fun() -> Done end
end.
-disc_load_table(Tab, Reason, ReplyTo) ->
+disc_load_table(Tab, Reason, ReplyTo, Cs) ->
Done = #loader_done{is_loaded = true,
table_name = Tab,
needs_announce = false,
@@ -2263,7 +2268,7 @@ disc_load_table(Tab, Reason, ReplyTo) ->
reply_to = ReplyTo,
reply = {loaded, ok}
},
- Res = mnesia_loader:disc_load_table(Tab, Reason),
+ Res = mnesia_loader:disc_load_table(Tab, Reason, Cs),
if
Res == {loaded, ok} ->
Done#loader_done{needs_announce = true,
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index da43a521a4..632c31e64e 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -24,7 +24,7 @@
-module(mnesia_loader).
%% Mnesia internal stuff
--export([disc_load_table/2,
+-export([disc_load_table/3,
net_load_table/4,
send_table/4]).
@@ -44,8 +44,8 @@ val(Var) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Load a table from local disc
-disc_load_table(Tab, Reason) ->
- Storage = val({Tab, storage_type}),
+disc_load_table(Tab, Reason, Cs) ->
+ Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
Type = val({Tab, setorbag}),
dbg_out("Getting table ~tp (~p) from disc: ~tp~n",
[Tab, Storage, Reason]),
@@ -222,7 +222,7 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
ok ->
set({Tab, load_node}, Node),
set({Tab, load_reason}, Reason),
- mnesia_controller:i_have_tab(Tab),
+ mnesia_controller:i_have_tab(Tab, Cs),
dbg_out("Table ~tp copied from ~p to ~p~n", [Tab, Node, node()]),
{loaded, ok};
Err = {error, _} when element(1, Reason) == dumper ->
@@ -383,9 +383,11 @@ do_init_table(Tab,Storage,Cs,SenderPid,
Reason ->
Msg = "[d]ets:init table failed",
verbose("~ts: ~tp: ~tp~n", [Msg, Tab, Reason]),
+ SenderPid ! {copier_done, node()},
down(Tab, Storage)
end;
Error ->
+ SenderPid ! {copier_done, node()},
Error
end.
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index ed7f362cf6..5ee3265613 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -2466,10 +2466,12 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) ->
_ ->
ok
end,
- %% Tables are created by mnesia_loader get_network code
- insert_cstruct(Tid, Cs, true),
+ mnesia_lib:verbose("~w:~w Adding table~n",[?MODULE,?LINE]),
+
case mnesia_controller:get_network_copy(Tid, Tab, Cs) of
{loaded, ok} ->
+ %% Tables are created by mnesia_loader get_network code
+ insert_cstruct(Tid, Cs, true),
{true, optional};
{not_loaded, ErrReason} ->
Reason = {system_limit, Tab, {Node, ErrReason}},
diff --git a/lib/mnesia/test/ext_test.erl b/lib/mnesia/test/ext_test.erl
index 98a425277c..dfa6d7da04 100644
--- a/lib/mnesia/test/ext_test.erl
+++ b/lib/mnesia/test/ext_test.erl
@@ -72,7 +72,7 @@ init_backend() ->
?DBG(init_backend),
%% cheat and stuff a marker in mnesia_gvar
K = backend_init_marker(),
- case try mnesia_lib:val(K) catch _:_ -> error end of
+ case try ets:lookup_element(mnesia_gvar, K, 2) catch _:_ -> error end of
error ->
mnesia_lib:set(K, true);
Other ->
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index b3cb26831c..601f46e45f 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1118,16 +1118,22 @@ add_table_copy(Config) when is_list(Config) ->
end),
receive {New,ok} -> ok end,
- Add = fun Add() ->
+ Add = fun Add(N) ->
case mnesia:add_table_copy(Tab, Node2, disc_copies) of
{atomic, ok} -> ok;
- _R -> io:format(user, "aborted with reason ~p~n", [_R]),
- timer:sleep(10),
- Add()
+ _R ->
+ case N > 0 of
+ true ->
+ timer:sleep(25),
+ Add(N-1);
+ false ->
+ io:format(user, "aborted with reason ~p~n", [_R]),
+ fail
+ end
end
end,
-
- ?match(ok, Add()),
+
+ ?match(ok, Add(200)),
?match_receive({New,ok}),
sys:get_status(whereis(mnesia_locker)), % Explicit sync, release locks is async
--
2.34.1