File 0413-Relax-add_table_copy-restriction.patch of Package erlang

From 11174a0a472a59f011a3530ebeb11eaa7f9d9b02 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Thu, 9 Aug 2018 16:03:44 +0200
Subject: [PATCH] Relax add_table_copy restriction

Allow to add replicas even if all other replicas are down when the
other replicase are not stored on disk.
---
 lib/mnesia/src/mnesia_controller.erl          | 27 +++++++--------
 lib/mnesia/src/mnesia_loader.erl              |  8 ++---
 lib/mnesia/test/mnesia_evil_coverage_test.erl | 47 ++++++++++++++++++++++++++-
 3 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 77013489b3..81518c2bb3 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -771,22 +771,6 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) ->
 	    noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]})
     end;
 
-handle_call({net_load, Tab, Cs}, From, State) ->
-    State2 =
-	case State#state.schema_is_merged of
-	    true ->
-		Worker = #net_load{table = Tab,
-				   opt_reply_to = From,
-				   reason = {dumper,{add_table_copy, unknown}},
-				   cstruct = Cs
-				  },
-		add_worker(Worker, State);
-	    false ->
-		reply(From, {not_loaded, schema_not_merged}),
-		State
-	end,
-    noreply(State2);
-
 handle_call(Msg, From, State) when State#state.schema_is_merged /= true ->
     %% Buffer early messages
     Msgs = State#state.early_msgs,
@@ -2161,6 +2145,15 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
 		       {dumper,{add_table_copy,_}} -> true;
 		       _ -> false
 		   end,
+
+    OnlyRamCopies = case Cs of
+                        #cstruct{disc_copies = DC,
+                                 disc_only_copies = DOC,
+                                 external_copies = Ext} ->
+                            [] =:= (DC ++ (DOC ++ Ext)) -- [node()];
+                        _ ->
+                            false
+                    end,
     if
 	ReadNode == node() ->
 	    %% Already loaded locally
@@ -2172,6 +2165,8 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
 	    end;
 	AccessMode == read_only, not AddTableCopy ->
 	    fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+        Active =:= [], AddTableCopy, OnlyRamCopies ->
+            fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
 	true ->
 	    fun() ->
 		    %% Either we cannot read the table yet
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4c6336cb73..39704c65f9 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -66,7 +66,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
     EtsOpts = proplists:get_value(ets, StorageProps, []),
     Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
     case Reason of
-	{dumper, _} -> %% Resources already allocated
+	{dumper, DR} when is_atom(DR) -> %% Resources already allocated
 	    ignore;
 	_ ->
 	    mnesia_monitor:mktab(Tab, Args),
@@ -90,8 +90,8 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
     EtsOpts = proplists:get_value(ets, StorageProps, []),
     Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
     case Reason of
-	{dumper, _} -> %% Resources allready allocated
-	    ignore;
+	{dumper, DR} when is_atom(DR) ->
+            ignore; %% Resources already allocated
 	_ ->
 	    mnesia_monitor:mktab(Tab, Args),
 	    Fname = mnesia_lib:tab2dcd(Tab),
@@ -130,7 +130,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
 	    {repair, mnesia_monitor:get_env(auto_repair)} 
 	    | DetsOpts],
     case Reason of
-	{dumper, _} ->
+	{dumper, DR} when is_atom(DR) ->
 	    mnesia_index:init_index(Tab, Storage),
 	    snmpify(Tab, Storage),
 	    set({Tab, load_node}, node()),
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 074967469b..506b1a9372 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -65,7 +66,8 @@ all() ->
      db_node_lifecycle, evil_delete_db_node, start_and_stop,
      checkpoint, table_lifecycle, storage_options, 
      add_copy_conflict,
-     add_copy_when_going_down, replica_management, clear_table_during_load,
+     add_copy_when_going_down, add_copy_with_down, replica_management,
+     clear_table_during_load,
      schema_availability, local_content,
      {group, table_access_modifications}, replica_location,
      {group, table_sync}, user_properties, unsupp_user_props,
@@ -732,6 +734,49 @@ add_copy_when_going_down(Config) ->
     ?match_receive({test,{aborted,_}}),
     ?verify_mnesia([Node2], []).
 
+add_copy_with_down(suite) -> [];
+add_copy_with_down(Config) ->
+    %% Allow add_table_copy() with ram_copies even all other replicas are down
+    Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config),
+    ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node3]}, {disc_copies, [Node2]}])),
+    stopped = rpc:call(Node2, mnesia, stop, []),
+    stopped = rpc:call(Node3, mnesia, stop, []),
+    ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+    ?match({aborted, _}, mnesia:del_table_copy(a, Node2)),
+    ok = rpc:call(Node3, mnesia, start, []),
+    ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+    ?match([], mnesia_test_lib:start_mnesia([Node2], [a])),
+    ?match({atomic, ok}, mnesia:change_table_copy_type(a, Node2, ram_copies)),
+    stopped = rpc:call(Node2, mnesia, stop, []),
+    stopped = rpc:call(Node3, mnesia, stop, []),
+    ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, ram_copies)),
+    ?match(ok, mnesia:dirty_write({a,1,1})),
+    ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+    ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+    ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+    stopped = rpc:call(Node2, mnesia, stop, []),
+    stopped = rpc:call(Node3, mnesia, stop, []),
+    ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_copies)),
+    ?match(ok, mnesia:dirty_write({a,1,1})),
+    ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+    ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+    ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+    stopped = rpc:call(Node2, mnesia, stop, []),
+    stopped = rpc:call(Node3, mnesia, stop, []),
+    ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_only_copies)),
+    ?match(ok, mnesia:dirty_write({a,1,1})),
+    ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+    ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+    ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+    ?verify_mnesia(Nodes, []).
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Add, drop and move replicas, change storage types
-- 
2.16.4

openSUSE Build Service is sponsored by