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

openSUSE Build Service is sponsored by