File 2642-mnesia-Bump-protocol-version.patch of Package erlang

From 7e92eb6666f3d73eb683516bc4b74b827953ec4a Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Thu, 25 Jul 2019 11:59:05 +0200
Subject: [PATCH 2/2] mnesia: Bump protocol version

Remove unsupported conversions from the old protocols.
This means mnesia on OTP-R18 nodes is no longer able to connect to
OTP-22 mnesia nodes.

Add protocol conversion for old nodes and sync_asym_trans transactions.
---
 lib/mnesia/src/mnesia_monitor.erl         |  6 +--
 lib/mnesia/src/mnesia_schema.erl          | 68 +++++--------------------------
 lib/mnesia/src/mnesia_tm.erl              | 24 +++++------
 lib/mnesia/test/mnesia_isolation_test.erl | 47 +++++++++++++++++++--
 4 files changed, 67 insertions(+), 78 deletions(-)

diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl
index 4cfe16dec0..4e50b46da8 100644
--- a/lib/mnesia/src/mnesia_monitor.erl
+++ b/lib/mnesia/src/mnesia_monitor.erl
@@ -83,9 +83,9 @@
 		going_down = [], tm_started = false, early_connects = [],
 		connecting, mq = [], remote_node_status = []}).
 
--define(current_protocol_version,  {8,3}).
+-define(current_protocol_version,  {8,4}).
 
--define(previous_protocol_version, {8,2}).
+-define(previous_protocol_version, {8,3}).
 
 start() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE,
@@ -196,7 +196,7 @@ protocol_version() ->
 %% A sorted list of acceptable protocols the
 %% preferred protocols are first in the list
 acceptable_protocol_versions() ->
-    [protocol_version(), ?previous_protocol_version, {8,1}].
+    [protocol_version(), ?previous_protocol_version].
 
 needs_protocol_conversion(Node) ->
     case {?catch_val({protocol, Node}), protocol_version()} of
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index ef38adca1e..177cd374cd 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -730,7 +730,10 @@ api_list2cs(Other) ->
     mnesia:abort({badarg, Other}).
 
 vsn_cs2list(Cs) ->
-    cs2list(need_old_cstructs(), Cs).
+    cs2list(Cs).
+
+cs2list(false, Cs) ->
+    cs2list(Cs).
 
 cs2list(Cs) when is_record(Cs, cstruct) ->
     Tags = record_info(fields, cstruct),
@@ -755,25 +758,6 @@ cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 19 ->
 	    cookie,version],
     rec2list(Tags, Tags, 2, Cs).
 
-cs2list(false, Cs) ->
-    cs2list(Cs);
-cs2list({8,3}, Cs) ->
-    cs2list(Cs);
-cs2list({8,Minor}, Cs) when Minor =:= 2; Minor =:= 1 ->
-    Orig = record_info(fields, cstruct),
-    Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
-	    load_order,access_mode,majority,index,snmp,local_content,
-	    record_name,attributes,
-	    user_properties,frag_properties,storage_properties,
-	    cookie,version],
-    CsList = rec2list(Tags, Orig, 2, Cs),
-    case proplists:get_value(index, CsList, []) of
-	[] -> CsList;
-	NewFormat ->
-	    OldFormat = [Pos || {Pos, _Pref} <- NewFormat],
-	    lists:keyreplace(index, 1, CsList, {index, OldFormat})
-    end.
-
 rec2list([index | Tags], [index|Orig], Pos, Rec) ->
     Val = element(Pos, Rec),
     [{index, lists:map(
@@ -796,19 +780,8 @@ rec2list([], _, _Pos, _Rec) ->
 rec2list(Tags, [_|Orig], Pos, Rec) ->
     rec2list(Tags, Orig, Pos+1, Rec).
 
-normalize_cs(Cstructs, Node) ->
-    %% backward-compatibility hack; normalize before returning
-    case need_old_cstructs([Node]) of
-	false ->
-	    Cstructs;
-	Version ->
-	    %% some other format
-	    [convert_cs(Version, Cs) || Cs <- Cstructs]
-    end.
-
-convert_cs(Version, Cs) ->
-    Fields = [Value || {_, Value} <- cs2list(Version, Cs)],
-    list_to_tuple([cstruct|Fields]).
+normalize_cs(Cstructs, _Node) ->
+    Cstructs.
 
 list2cs(List) ->
     list2cs(List, get_ext_types()).
@@ -1864,11 +1837,7 @@ do_move_table(schema, _FromNode, _ToNode) ->
     mnesia:abort({bad_type, schema});
 do_move_table(Tab, FromNode, ToNode) when is_atom(FromNode), is_atom(ToNode) ->
     TidTs = get_tid_ts_and_lock(schema, write),
-    AnyOld = lists:any(fun(Node) -> mnesia_monitor:needs_protocol_conversion(Node) end,
-		       [ToNode|val({Tab, where_to_write})]),
-    if AnyOld -> ignore;  %% Leads to deadlock on old nodes
-       true -> get_tid_ts_and_lock(Tab, write)
-    end,
+    get_tid_ts_and_lock(Tab, write),
     insert_schema_ops(TidTs, make_move_table(Tab, FromNode, ToNode));
 do_move_table(Tab, FromNode, ToNode) ->
     mnesia:abort({badarg, Tab, FromNode, ToNode}).
@@ -3438,15 +3407,14 @@ do_merge_schema(LockTabs0) ->
                                                   mnesia_lib:intersect(Ns,NeedsLock))
                      || {T,Ns} <- LockTabs],
 
-		    NeedsConversion = need_old_cstructs(NeedsLock ++ LockedAlready),
 		    {value, SchemaCs} = lists:keysearch(schema, #cstruct.name, Cstructs),
-		    SchemaDef = cs2list(NeedsConversion, SchemaCs),
+		    SchemaDef = cs2list(false, SchemaCs),
 		    %% Announce that Node is running
 		    A = [{op, announce_im_running, node(), SchemaDef, Running, RemoteRunning}],
 		    do_insert_schema_ops(Store, A),
 
 		    %% Introduce remote tables to local node
-		    do_insert_schema_ops(Store, make_merge_schema(Node, NeedsConversion, Cstructs)),
+		    do_insert_schema_ops(Store, make_merge_schema(Node, false, Cstructs)),
 
 		    %% Introduce local tables to remote nodes
 		    Tabs = val({schema, tables}),
@@ -3471,23 +3439,7 @@ warn_user_connect_failed(Missing) ->
 
 
 fetch_cstructs(Node) ->
-    Convert = mnesia_monitor:needs_protocol_conversion(Node),
-    case rpc:call(Node, mnesia_controller, get_remote_cstructs, [])  of
-	{cstructs, Cs0, RemoteRunning1} when Convert ->
-	    {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RemoteRunning1};
-	Result ->
-	    Result
-    end.
-
-need_old_cstructs() ->
-    need_old_cstructs(val({schema, where_to_write})).
-
-need_old_cstructs(Nodes) ->
-    Filter = fun(Node) -> mnesia_monitor:needs_protocol_conversion(Node) end,
-    case lists:filter(Filter, Nodes) of
-	[] -> false;
-	Ns -> lists:min([element(1, ?catch_val({protocol, Node})) || Node <- Ns])
-    end.
+    rpc:call(Node, mnesia_controller, get_remote_cstructs, []).
 
 tab_to_nodes(Tab) when is_atom(Tab) ->
     Cs = val({Tab, cstruct}),
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 1fa920321b..8a4113422a 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1992,7 +1992,7 @@ sync_send_dirty(Tid, [Head | Tail], Tab, WaitFor) ->
 	    Res =  do_dirty(Tid, Head),
 	    {WF, Res};
 	true ->
-	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, ext_format(Head), Tab}},
+	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}},
 	    sync_send_dirty(Tid, Tail, Tab, [Node | WaitFor])
     end;
 sync_send_dirty(_Tid, [], _Tab, WaitFor) ->
@@ -2011,11 +2011,11 @@ async_send_dirty(Tid, [Head | Tail], Tab, ReadNode, WaitFor, Res) ->
 	    NewRes =  do_dirty(Tid, Head),
 	    async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, NewRes);
 	ReadNode == Node ->
-	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, ext_format(Head), Tab}},
+	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}},
 	    NewRes = {'EXIT', {aborted, {node_not_running, Node}}},
 	    async_send_dirty(Tid, Tail, Tab, ReadNode, [Node | WaitFor], NewRes);
 	true ->
-	    {?MODULE, Node} ! {self(), {async_dirty, Tid, ext_format(Head), Tab}},
+	    {?MODULE, Node} ! {self(), {async_dirty, Tid, Head, Tab}},
 	    async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, Res)
     end;
 async_send_dirty(_Tid, [], _Tab, _ReadNode, WaitFor, Res) ->
@@ -2072,24 +2072,20 @@ ask_commit(Protocol, Tid, [Head | Tail], DiscNs, RamNs, WaitFor, Local) ->
 	Node == node() ->
 	    ask_commit(Protocol, Tid, Tail, DiscNs, RamNs, WaitFor, Head);
 	true ->
-	    CR = ext_format(Head),
-	    Msg = {ask_commit, Protocol, Tid, CR, DiscNs, RamNs},
+	    Msg = {ask_commit, convert_old(Protocol, Node), Tid, Head, DiscNs, RamNs},
 	    {?MODULE, Node} ! {self(), Msg},
 	    ask_commit(Protocol, Tid, Tail, DiscNs, RamNs, [Node | WaitFor], Local)
     end;
 ask_commit(_Protocol, _Tid, [], _DiscNs, _RamNs, WaitFor, Local) ->
     {WaitFor, Local}.
 
-ext_format(#commit{ext=[]}=CR) -> CR;
-ext_format(#commit{node=Node, ext=Ext}=CR) ->
+convert_old(sync_asym_trans, Node) ->
     case mnesia_monitor:needs_protocol_conversion(Node) of
-	true  ->
-	    case lists:keyfind(snmp, 1, Ext) of
-		false -> CR#commit{ext=[]};
-		{snmp, List} -> CR#commit{ext=List}
-	    end;
-	false -> CR
-    end.
+        true -> asym_trans;
+        false -> sync_asym_trans
+    end;
+convert_old(Protocol, _) ->
+    Protocol.
 
 new_cr_format(#commit{ext=[]}=Cr) -> Cr;
 new_cr_format(#commit{ext=[{_,_}|_]}=Cr) -> Cr;
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index 49bcec14af..26a69b9d61 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -29,7 +29,7 @@
 -export([no_conflict/1, simple_queue_conflict/1,
          advanced_queue_conflict/1, simple_deadlock_conflict/1,
          advanced_deadlock_conflict/1, schema_deadlock/1, lock_burst/1,
-         nasty/1, basic_sticky_functionality/1,
+         nasty/1, basic_sticky_functionality/1, sticky_sync/1,
          unbound1/1, unbound2/1,
          create_table/1, delete_table/1, move_table_copy/1,
          add_table_index/1, del_table_index/1, transform_table/1,
@@ -71,7 +71,8 @@ groups() ->
        advanced_deadlock_conflict, schema_deadlock, lock_burst,
        {group, sticky_locks}, {group, unbound_locking},
        {group, admin_conflict}, nasty]},
-     {sticky_locks, [], [basic_sticky_functionality]},
+     {sticky_locks, [],
+      [basic_sticky_functionality,sticky_sync]},
      {unbound_locking, [], [unbound1, unbound2]},
      {admin_conflict, [],
       [create_table, delete_table, move_table_copy,
@@ -594,9 +595,49 @@ get_held() ->
     mnesia_locker ! {get_table, self(), mnesia_sticky_locks},
     receive {mnesia_sticky_locks, Locks} -> Locks end.
 
+sticky_sync(suite) -> [];
+sticky_sync(Config) when is_list(Config) ->
+    %% BUG ERIERL-768
+    Nodes = [N1, N2] = ?acquire_nodes(2, Config),
+
+    mnesia:create_table(dc, [{type, ordered_set}, {disc_copies, Nodes}]),
+    mnesia:create_table(ec, [{type, ordered_set}, {ram_copies, [N2]}]),
+
+    TestFun =
+        fun(I) ->
+                %% In first transaction we initialise {dc, I} record with value 0
+                First = fun() ->
+                                %% Do a lot of writes into ram copies table
+                                %% which on the Slave in do_commit will be
+                                %% processed first
+                                lists:foreach(fun(J) -> ok = mnesia:write(ec, {ec, J, 0}, write) end,
+                                              lists:seq(1, 750)),
+                                %% Then set initial value of {dc, I} record to 0 with sticky_write
+                                mnesia:write(dc, {dc, I, 0}, sticky_write)
+                        end,
+                ok = mnesia:activity(transaction, First),
+                %% In second transaction we set value of {dc, I} record to 1
+                Upd = fun() ->
+                              %% Modify a single ram copies record with ensured lock grant
+                              %% (key not used in previous transactions)
+                              %% we use this second table only to force asym_trans protocol
+                              mnesia:write(ec, {ec, 1001 + I, 0}, write),
+                              %% And set final version of {dc, I} record to 1 with sticky_write
+                              mnesia:write(dc, {dc, I, 1}, sticky_write)
+                    end,
+                ok = mnesia:activity(transaction, Upd)
+        end,
+
+    %% Fill 1000 dc records. At the end all dc records should have value 1.
+    lists:foreach(TestFun, lists:seq(1,1000)),
+    io:format("Written, check content~n",[]),
+    All = fun() -> mnesia:select(dc, [ {{dc, '_', 0}, [] ,['$_']} ]) end,
+    ?match({atomic, []}, rpc:call(N1, mnesia, sync_transaction, [All])),
+    ?match({atomic, []}, rpc:call(N2, mnesia, sync_transaction, [All])),
 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    ?verify_mnesia(Nodes, []).
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 unbound1(suite) -> [];
 unbound1(Config) when is_list(Config) ->
-- 
2.16.4

openSUSE Build Service is sponsored by