diff options
author | Dan Gudmundsson <dgud@erlang.org> | 2021-08-18 13:32:08 +0200 |
---|---|---|
committer | Dan Gudmundsson <dgud@erlang.org> | 2021-08-18 13:32:08 +0200 |
commit | 0835f0bf7a0f897eac6fc0e971ce54538feca175 (patch) | |
tree | f9ed12794748cde90e3e3417aff3311ae28e71e8 | |
parent | 6d5a5f31c36bbdaad21585d25974177bd1b75e66 (diff) | |
download | erlang-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.erl | 23 | ||||
-rw-r--r-- | lib/mnesia/test/mnesia_trans_access_test.erl | 34 |
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 |