summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Gudmundsson <dgud@erlang.org>2021-08-18 13:32:08 +0200
committerDan Gudmundsson <dgud@erlang.org>2021-08-18 13:32:08 +0200
commit0835f0bf7a0f897eac6fc0e971ce54538feca175 (patch)
treef9ed12794748cde90e3e3417aff3311ae28e71e8
parent6d5a5f31c36bbdaad21585d25974177bd1b75e66 (diff)
downloaderlang-0835f0bf7a0f897eac6fc0e971ce54538feca175.tar.gz
mnesia: Do not unconditionally delete index keys
delete_object(NonExistingRecord) deleted index keys even if the record didn't exist, in set tables, and nothing was deleted from the real table. Solve this by doing the same checks as was done for bag tables. Fixes GH-5040
-rw-r--r--lib/mnesia/src/mnesia_index.erl23
-rw-r--r--lib/mnesia/test/mnesia_trans_access_test.erl34
2 files changed, 40 insertions, 17 deletions
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 2ca6c55870..964c50aa52 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -139,22 +139,15 @@ del_object_index(#index{pos_list = PosL, setorbag = SorB}, Storage, Tab, K, Obj)
del_object_index2(PosL, SorB, Storage, Tab, K, Obj).
del_object_index2([], _, _Storage, _Tab, _K, _Obj) -> ok;
-del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, K, Obj) ->
+del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, Key, Obj) ->
ValsF = index_vals_f(Storage, Tab, Pos),
- case SoB of
- bag ->
- del_object_bag(Type, ValsF, Tab, K, Obj, Ixt);
- _ -> %% If set remove the tuple in index table
- del_ixes(Type, Ixt, ValsF, Obj, K)
- end,
- del_object_index2(Tail, SoB, Storage, Tab, K, Obj).
-
-del_object_bag(Type, ValsF, Tab, Key, Obj, Ixt) ->
- IxKeys = ValsF(Obj),
Found = [{X, ValsF(X)} || X <- mnesia_lib:db_get(Tab, Key)],
- del_object_bag_(IxKeys, Found, Type, Tab, Key, Obj, Ixt).
+ IxKeys = ValsF(Obj),
+ del_object_index3(IxKeys, Found, Type, Tab, Key, Obj, Ixt),
+ del_object_index2(Tail, SoB, Storage, Tab, Key, Obj).
+
-del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
+del_object_index3([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
case [X || {X, Ixes} <- Found, lists:member(IxK, Ixes)] of
[Old] when Old =:= Obj ->
case Type of
@@ -166,8 +159,8 @@ del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
_ ->
ok
end,
- del_object_bag_(IxKs, Found, Type, Tab, Key, Obj, Ixt);
-del_object_bag_([], _, _, _, _, _, _) ->
+ del_object_index3(IxKs, Found, Type, Tab, Key, Obj, Ixt);
+del_object_index3([], _, _, _, _, _, _) ->
ok.
clear_index(Index, Tab, K, Obj) ->
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index 723a85fd2c..dec396252b 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -31,7 +31,7 @@
basic_nested/1, mix_of_nested_activities/1,
nested_trans_both_ok/1, nested_trans_child_dies/1,
nested_trans_parent_dies/1, nested_trans_both_dies/1,
- index_match_object/1, index_read/1,index_write/1,
+ index_match_object/1, index_read/1,index_write/1, index_delete_object/1,
index_update_set/1, index_update_bag/1,
add_table_index_ram/1, add_table_index_disc/1,
add_table_index_disc_only/1, create_live_table_index_ram/1,
@@ -77,7 +77,7 @@ groups() ->
nested_trans_parent_dies, nested_trans_both_dies]},
{index_tabs, [],
[index_match_object, index_read, {group, index_update},
- index_write]},
+ index_write, index_delete_object]},
{index_update, [],
[index_update_set, index_update_bag]},
{index_lifecycle, [],
@@ -1078,6 +1078,36 @@ index_write(Config)when is_list(Config) ->
?verify_mnesia(Nodes, []).
+index_delete_object(suite) -> [];
+index_delete_object(doc) -> ["See issue: GH-5040"];
+index_delete_object(Config) when is_list(Config) ->
+ Nodes = ?acquire_nodes(1, Config),
+ {atomic, ok} = mnesia:create_table(ram_set,[{index, [ix]}, {attributes, [key, ix, val]},
+ {ram_copies, Nodes}]),
+ {atomic, ok} = mnesia:create_table(do_set, [{index, [ix]}, {attributes, [key, ix, val]},
+ {disc_only_copies, Nodes}]),
+ {atomic, ok} = mnesia:create_table(ram_bag,[{index, [ix]}, {attributes, [key, ix, val]},
+ {ram_copies, Nodes}]),
+ {atomic, ok} = mnesia:create_table(do_bag, [{index, [ix]}, {attributes, [key, ix, val]},
+ {disc_only_copies, Nodes}]),
+ Test = fun(Tab) ->
+ io:format("Testing: ~p~n",[Tab]),
+ Rec = {Tab, 2, 4, data},
+ Rec2 = {Tab, 3, 5, data},
+ ok = mnesia:dirty_write(Rec),
+ ok = mnesia:dirty_write(Rec2),
+ [Rec] = mnesia:dirty_index_read(Tab, 4, ix),
+ ?match(ok, mnesia:dirty_delete_object({Tab, 2, 4, does_not_exist})),
+ [Rec] = mnesia:dirty_read(Tab, 2),
+ [Rec] = mnesia:dirty_index_read(Tab, 4, ix),
+ ?match(ok, mnesia:dirty_delete_object(Rec)),
+ [] = mnesia:dirty_read(Tab, 2),
+ [] = mnesia:dirty_index_read(Tab, 4, ix),
+ [Rec2] = mnesia:dirty_read(Tab, 3),
+ [Rec2] = mnesia:dirty_index_read(Tab, 5, ix)
+ end,
+ [Test(Tab) || Tab <- [ram_set,do_set,ram_bag,do_bag]],
+ ?verify_mnesia(Nodes, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add and drop indecies