%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1998-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(mnesia_schema_recovery_test). -author('hakan@erix.ericsson.se'). -compile([export_all]). -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). fin_per_testcase(Func, Conf) -> mnesia_test_lib:fin_per_testcase(Func, Conf). -define(receive_messages(Msgs), receive_messages(Msgs, ?FILE, ?LINE)). % First Some debug logging -define(dgb, true). -ifdef(dgb). -define(dl(X, Y), ?verbose("**TRACING: " ++ X ++ "**~n", Y)). -else. -define(dl(X, Y), ok). -endif. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all(doc) -> ["Verify recoverabiliy of schema transactions.", " Verify that a schema transaction", " can be completed when it has been logged correctly and Mnesia", " crashed before the log has been dumped. Then the transaction ", " should be handled during the log dump at startup" ]; all(suite) -> [interrupted_before_log_dump, interrupted_after_log_dump]. interrupted_before_log_dump(suite) -> [interrupted_before_create_ram, interrupted_before_create_disc, interrupted_before_create_disc_only, interrupted_before_create_nostore, interrupted_before_delete_ram, interrupted_before_delete_disc, interrupted_before_delete_disc_only, interrupted_before_add_ram, interrupted_before_add_disc, interrupted_before_add_disc_only, interrupted_before_add_kill_copier, interrupted_before_move_ram, interrupted_before_move_disc, interrupted_before_move_disc_only, interrupted_before_move_kill_copier, interrupted_before_delcopy_ram, interrupted_before_delcopy_disc, interrupted_before_delcopy_disc_only, interrupted_before_delcopy_kill_copier, interrupted_before_addindex_ram, interrupted_before_addindex_disc, interrupted_before_addindex_disc_only, interrupted_before_delindex_ram, interrupted_before_delindex_disc, interrupted_before_delindex_disc_only, interrupted_before_change_type_ram2disc, interrupted_before_change_type_ram2disc_only, interrupted_before_change_type_disc2ram, interrupted_before_change_type_disc2disc_only, interrupted_before_change_type_disc_only2ram, interrupted_before_change_type_disc_only2disc, interrupted_before_change_type_other_node, interrupted_before_change_schema_type %% Change schema table copy type!! ]. interrupted_after_log_dump(suite) -> [interrupted_after_create_ram, interrupted_after_create_disc, interrupted_after_create_disc_only, interrupted_after_create_nostore, interrupted_after_delete_ram, interrupted_after_delete_disc, interrupted_after_delete_disc_only, interrupted_after_add_ram, interrupted_after_add_disc, interrupted_after_add_disc_only, interrupted_after_add_kill_copier, interrupted_after_move_ram, interrupted_after_move_disc, interrupted_after_move_disc_only, interrupted_after_move_kill_copier, interrupted_after_delcopy_ram, interrupted_after_delcopy_disc, interrupted_after_delcopy_disc_only, interrupted_after_delcopy_kill_copier, interrupted_after_addindex_ram, interrupted_after_addindex_disc, interrupted_after_addindex_disc_only, interrupted_after_delindex_ram, interrupted_after_delindex_disc, interrupted_after_delindex_disc_only, interrupted_after_change_type_ram2disc, interrupted_after_change_type_ram2disc_only, interrupted_after_change_type_disc2ram, interrupted_after_change_type_disc2disc_only, interrupted_after_change_type_disc_only2ram, interrupted_after_change_type_disc_only2disc, interrupted_after_change_type_other_node, interrupted_after_change_schema_type %% Change schema table copy type!! % interrupted_before_change_access_mode, % interrupted_before_transform, % interrupted_before_restore, ]. interrupted_before_create_ram(suite) -> []; interrupted_before_create_ram(Config) when is_list(Config) -> KillAt = {mnesia_dumper, dump_schema_op}, interrupted_create(Config, ram_copies, all, KillAt). interrupted_before_create_disc(suite) -> []; interrupted_before_create_disc(Config) when is_list(Config) -> KillAt = {mnesia_dumper, dump_schema_op}, interrupted_create(Config, disc_copies, all, KillAt). interrupted_before_create_disc_only(suite) -> []; interrupted_before_create_disc_only(Config) when is_list(Config) -> KillAt = {mnesia_dumper, dump_schema_op}, interrupted_create(Config, disc_only_copies, all, KillAt). interrupted_before_create_nostore(suite) -> []; interrupted_before_create_nostore(Config) when is_list(Config) -> KillAt = {mnesia_dumper, dump_schema_op}, interrupted_create(Config, ram_copies, one, KillAt). interrupted_after_create_ram(suite) -> []; interrupted_after_create_ram(Config) when is_list(Config) -> KillAt = {mnesia_dumper, post_dump}, interrupted_create(Config, ram_copies, all, KillAt). interrupted_after_create_disc(suite) -> []; interrupted_after_create_disc(Config) when is_list(Config) -> KillAt = {mnesia_dumper, post_dump}, interrupted_create(Config, disc_copies, all, KillAt). interrupted_after_create_disc_only(suite) -> []; interrupted_after_create_disc_only(Config) when is_list(Config) -> KillAt = {mnesia_dumper, post_dump}, interrupted_create(Config, disc_only_copies, all, KillAt). interrupted_after_create_nostore(suite) -> []; interrupted_after_create_nostore(Config) when is_list(Config) -> KillAt = {mnesia_dumper, post_dump}, interrupted_create(Config, ram_copies, one, KillAt). %%% After dump don't need debug point interrupted_create(Config, Type, _Where, {mnesia_dumper, post_dump}) -> [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]), ?match({atomic, ok},mnesia:create_table(itrpt, [{Type, Nodes}])), ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match(ok, mnesia:dirty_write({itrpt, before, 1})), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), case Type of ram_copies -> ?match([], mnesia:dirty_read({itrpt, before})); _ -> ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before})) end, ?verify_mnesia(Nodes, []); interrupted_create(Config, Type, Where, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), {success, [A]} = ?start_activities([Node2]), setup_dbgpoint(KillAt, Node2), if %% CREATE TABLE Where == all -> % tables on both nodes A ! fun() -> mnesia:create_table(itrpt, [{Type, Nodes}]) end; true -> % no table on the killed node A ! fun() -> mnesia:create_table(itrpt, [{Type, [Node1]}]) end end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Node2], [itrpt])), %% Verify ?match(ok, mnesia:dirty_write({itrpt, before, 1})), verify_tab(Node1, Node2), ?verify_mnesia(Nodes, []). interrupted_before_delete_ram(suite) -> []; interrupted_before_delete_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delete(Config, ram_copies, Debug_Point). interrupted_before_delete_disc(suite) -> []; interrupted_before_delete_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delete(Config, disc_copies, Debug_Point). interrupted_before_delete_disc_only(suite) -> []; interrupted_before_delete_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delete(Config, disc_only_copies, Debug_Point). interrupted_after_delete_ram(suite) -> []; interrupted_after_delete_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delete(Config, ram_copies, Debug_Point). interrupted_after_delete_disc(suite) -> []; interrupted_after_delete_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delete(Config, disc_copies, Debug_Point). interrupted_after_delete_disc_only(suite) -> []; interrupted_after_delete_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delete(Config, disc_only_copies, Debug_Point). interrupted_delete(Config, Type, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node2]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = {Node1, Node2}, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:delete_table(Tab) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Node2], [])), Bad = {badrpc, {'EXIT', {aborted,{no_exists, Tab, all}}}}, ?match(Bad, rpc:call(Node1, mnesia, table_info, [Tab, all])), ?match(Bad, rpc:call(Node2, mnesia, table_info, [Tab, all])), ?verify_mnesia(Nodes, []). interrupted_before_add_ram(suite) -> []; interrupted_before_add_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_add(Config, ram_copies, kill_reciever, Debug_Point). interrupted_before_add_disc(suite) -> []; interrupted_before_add_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_add(Config, disc_copies, kill_reciever, Debug_Point). interrupted_before_add_disc_only(suite) -> []; interrupted_before_add_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_add(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_before_add_kill_copier(suite) -> []; interrupted_before_add_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_add(Config, ram_copies, kill_copier, Debug_Point). interrupted_after_add_ram(suite) -> []; interrupted_after_add_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_add(Config, ram_copies, kill_reciever, Debug_Point). interrupted_after_add_disc(suite) -> []; interrupted_after_add_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_add(Config, disc_copies, kill_reciever, Debug_Point). interrupted_after_add_disc_only(suite) -> []; interrupted_after_add_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_add(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_after_add_kill_copier(suite) -> []; interrupted_after_add_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_add(Config, ram_copies, kill_copier, Debug_Point). %%% After dump don't need debug point interrupted_add(Config, Type, _Where, {mnesia_dumper, post_dump}) -> [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node2]}, {local_content,true}])), ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match({atomic, ok}, mnesia:add_table_copy(Tab, Node1, Type)), ?match(ok, mnesia:dirty_write({itrpt, before, 1})), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), case Type of ram_copies -> ?match([], mnesia:dirty_read({itrpt, before})); _ -> ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before})) end, ?verify_mnesia(Nodes, []); interrupted_add(Config, Type, Who, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), {_Alive, Kill} = if Who == kill_reciever -> {Node1, Node2}; true -> {Node2, Node1} end, {success, [A]} = ?start_activities([Kill]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:add_table_copy(Tab, Node2, Type) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])), verify_tab(Node1, Node2), ?verify_mnesia(Nodes, []). interrupted_before_move_ram(suite) -> []; interrupted_before_move_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_move(Config, ram_copies, kill_reciever, Debug_Point). interrupted_before_move_disc(suite) -> []; interrupted_before_move_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_move(Config, disc_copies, kill_reciever, Debug_Point). interrupted_before_move_disc_only(suite) -> []; interrupted_before_move_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_move(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_before_move_kill_copier(suite) -> []; interrupted_before_move_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_move(Config, ram_copies, kill_copier, Debug_Point). interrupted_after_move_ram(suite) -> []; interrupted_after_move_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_move(Config, ram_copies, kill_reciever, Debug_Point). interrupted_after_move_disc(suite) -> []; interrupted_after_move_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_move(Config, disc_copies, kill_reciever, Debug_Point). interrupted_after_move_disc_only(suite) -> []; interrupted_after_move_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_move(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_after_move_kill_copier(suite) -> []; interrupted_after_move_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_move(Config, ram_copies, kill_copier, Debug_Point). %%% After dump don't need debug point interrupted_move(Config, Type, _Where, {mnesia_dumper, post_dump}) -> [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])), ?match(ok, mnesia:dirty_write({itrpt, before, 1})), ?match({atomic, ok}, mnesia:move_table_copy(Tab, Node1, Node2)), ?match(ok, mnesia:dirty_write({itrpt, aFter, 1})), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before})), ?match([{itrpt, aFter, 1}], mnesia:dirty_read({itrpt, aFter})), ?verify_mnesia(Nodes, []); interrupted_move(Config, Type, Who, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = if Who == kill_reciever -> if Type == ram_copies -> {atomic, ok} = mnesia:dump_tables([Tab]); true -> ignore end, {Node1, Node2}; true -> {Node2, Node1} end, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:move_table_copy(Tab, Node1, Node2) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])), verify_tab(Node1, Node2), ?verify_mnesia(Nodes, []). interrupted_before_delcopy_ram(suite) -> []; interrupted_before_delcopy_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delcopy(Config, ram_copies, kill_reciever, Debug_Point). interrupted_before_delcopy_disc(suite) -> []; interrupted_before_delcopy_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delcopy(Config, disc_copies, kill_reciever, Debug_Point). interrupted_before_delcopy_disc_only(suite) -> []; interrupted_before_delcopy_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delcopy(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_before_delcopy_kill_copier(suite) -> []; interrupted_before_delcopy_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delcopy(Config, ram_copies, kill_copier, Debug_Point). interrupted_after_delcopy_ram(suite) -> []; interrupted_after_delcopy_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delcopy(Config, ram_copies, kill_reciever, Debug_Point). interrupted_after_delcopy_disc(suite) -> []; interrupted_after_delcopy_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delcopy(Config, disc_copies, kill_reciever, Debug_Point). interrupted_after_delcopy_disc_only(suite) -> []; interrupted_after_delcopy_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delcopy(Config, disc_only_copies, kill_reciever, Debug_Point). interrupted_after_delcopy_kill_copier(suite) -> []; interrupted_after_delcopy_kill_copier(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delcopy(Config, ram_copies, kill_copier, Debug_Point). %%% After dump don't need debug point interrupted_delcopy(Config, Type, _Where, {mnesia_dumper, post_dump}) -> [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1,Node2]}])), ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node1)), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), ?match([Node2], mnesia:table_info(itrpt,Type)), ?verify_mnesia(Nodes, []); interrupted_delcopy(Config, Type, Who, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1, Node2]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = if Who == kill_reciever -> {Node1, Node2}; true -> if Type == ram_copies -> {atomic, ok} = mnesia:dump_tables([Tab]); true -> ignore end, {Node2, Node1} end, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:del_table_copy(Tab, Node2) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])), verify_tab(Node1, Node2), ?verify_mnesia(Nodes, []). interrupted_before_addindex_ram(suite) -> []; interrupted_before_addindex_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_addindex(Config, ram_copies, Debug_Point). interrupted_before_addindex_disc(suite) -> []; interrupted_before_addindex_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_addindex(Config, disc_copies, Debug_Point). interrupted_before_addindex_disc_only(suite) -> []; interrupted_before_addindex_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_addindex(Config, disc_only_copies, Debug_Point). interrupted_after_addindex_ram(suite) -> []; interrupted_after_addindex_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_addindex(Config, ram_copies, Debug_Point). interrupted_after_addindex_disc(suite) -> []; interrupted_after_addindex_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_addindex(Config, disc_copies, Debug_Point). interrupted_after_addindex_disc_only(suite) -> []; interrupted_after_addindex_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_addindex(Config, disc_only_copies, Debug_Point). %%% After dump don't need debug point interrupted_addindex(Config, Type, {mnesia_dumper, post_dump}) -> [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic,ok},mnesia:create_table(Tab, [{Type, Nodes}])), ?match({atomic,ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match({atomic,ok}, mnesia:add_table_index(Tab, val)), ?match(ok, mnesia:dirty_write({itrpt, before, 1})), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), case Type of ram_copies -> ?match([], mnesia:dirty_index_read(itrpt, 1, val)); _ -> ?match([{itrpt, before, 1}], mnesia:dirty_index_read(itrpt, 1, val)) end, ?verify_mnesia(Nodes, []); interrupted_addindex(Config, Type, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = {Node1, Node2}, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:add_table_index(Tab, val) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Node2], [])), verify_tab(Node1, Node2), ?match([{Tab, b, a}, {Tab, a, a}], rpc:call(Node1, mnesia, dirty_index_read, [itrpt, a, val])), ?match([{Tab, b, a}, {Tab, a, a}], rpc:call(Node2, mnesia, dirty_index_read, [itrpt, a, val])), ?verify_mnesia(Nodes, []). interrupted_before_delindex_ram(suite) -> []; interrupted_before_delindex_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delindex(Config, ram_copies, Debug_Point). interrupted_before_delindex_disc(suite) -> []; interrupted_before_delindex_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delindex(Config, disc_copies, Debug_Point). interrupted_before_delindex_disc_only(suite) -> []; interrupted_before_delindex_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_delindex(Config, disc_only_copies, Debug_Point). interrupted_after_delindex_ram(suite) -> []; interrupted_after_delindex_ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delindex(Config, ram_copies, Debug_Point). interrupted_after_delindex_disc(suite) -> []; interrupted_after_delindex_disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delindex(Config, disc_copies, Debug_Point). interrupted_after_delindex_disc_only(suite) -> []; interrupted_after_delindex_disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_delindex(Config, disc_only_copies, Debug_Point). %%% After dump don't need debug point interrupted_delindex(Config, Type, {mnesia_dumper, post_dump}) -> [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic,ok},mnesia:create_table(Tab, [{Type, Nodes},{index,[val]}])), ?match({atomic,ok},mnesia:create_table(test, [{disc_copies,[Node1]}])), ?match({atomic,ok}, mnesia:del_table_index(Tab, val)), ?match(ok, mnesia:dirty_write({itrpt, before, 1})), ?match(ok, mnesia:dirty_write({test, found_in_log, 1})), ?match(stopped, mnesia:stop()), ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])), %% Verify ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})), ?match({'EXIT',{aborted,{badarg,_}}}, mnesia:dirty_index_read(itrpt, 1, val)), ?verify_mnesia(Nodes, []); interrupted_delindex(Config, Type, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{index, [val]}, {Type, [Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = {Node1, Node2}, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:del_table_index(Tab, val) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia([Node2], [])), verify_tab(Node1, Node2), ?match({badrpc, _}, rpc:call(Node1, mnesia, dirty_index_read, [itrpt, a, val])), ?match({badrpc, _}, rpc:call(Node2, mnesia, dirty_index_read, [itrpt, a, val])), ?match([], rpc:call(Node1, mnesia, table_info, [Tab, index])), ?match([], rpc:call(Node2, mnesia, table_info, [Tab, index])), ?verify_mnesia(Nodes, []). interrupted_before_change_type_ram2disc(suite) -> []; interrupted_before_change_type_ram2disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, ram_copies, disc_copies, changer, Debug_Point). interrupted_before_change_type_ram2disc_only(suite) -> []; interrupted_before_change_type_ram2disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, ram_copies, disc_only_copies, changer, Debug_Point). interrupted_before_change_type_disc2ram(suite) -> []; interrupted_before_change_type_disc2ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, disc_copies, ram_copies, changer, Debug_Point). interrupted_before_change_type_disc2disc_only(suite) -> []; interrupted_before_change_type_disc2disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, disc_copies, disc_only_copies, changer, Debug_Point). interrupted_before_change_type_disc_only2ram(suite) -> []; interrupted_before_change_type_disc_only2ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, disc_only_copies, ram_copies, changer, Debug_Point). interrupted_before_change_type_disc_only2disc(suite) -> []; interrupted_before_change_type_disc_only2disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, disc_only_copies, disc_copies, changer, Debug_Point). interrupted_before_change_type_other_node(suite) -> []; interrupted_before_change_type_other_node(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, dump_schema_op}, interrupted_change_type(Config, ram_copies, disc_copies, the_other_one, Debug_Point). interrupted_after_change_type_ram2disc(suite) -> []; interrupted_after_change_type_ram2disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, ram_copies, disc_copies, changer, Debug_Point). interrupted_after_change_type_ram2disc_only(suite) -> []; interrupted_after_change_type_ram2disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, ram_copies, disc_only_copies, changer, Debug_Point). interrupted_after_change_type_disc2ram(suite) -> []; interrupted_after_change_type_disc2ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, disc_copies, ram_copies, changer, Debug_Point). interrupted_after_change_type_disc2disc_only(suite) -> []; interrupted_after_change_type_disc2disc_only(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, disc_copies, disc_only_copies, changer, Debug_Point). interrupted_after_change_type_disc_only2ram(suite) -> []; interrupted_after_change_type_disc_only2ram(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, disc_only_copies, ram_copies, changer, Debug_Point). interrupted_after_change_type_disc_only2disc(suite) -> []; interrupted_after_change_type_disc_only2disc(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, disc_only_copies, disc_copies, changer, Debug_Point). interrupted_after_change_type_other_node(suite) -> []; interrupted_after_change_type_other_node(Config) when is_list(Config) -> Debug_Point = {mnesia_dumper, post_dump}, interrupted_change_type(Config, ram_copies, disc_copies, the_other_one, Debug_Point). interrupted_change_type(Config, FromType, ToType, Who, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{FromType, [Node2, Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {_Alive, Kill} = if Who == changer -> {Node1, Node2}; true -> {Node2, Node1} end, {success, [A]} = ?start_activities([Kill]), setup_dbgpoint(KillAt, Kill), A ! fun() -> mnesia:change_table_copy_type(Tab, Node2, ToType) end, kill_at_debug(), ?match([], mnesia_test_lib:start_mnesia(Nodes, [itrpt])), verify_tab(Node1, Node2), ?match(FromType, rpc:call(Node1, mnesia, table_info, [Tab, storage_type])), ?match(ToType, rpc:call(Node2, mnesia, table_info, [Tab, storage_type])), ?verify_mnesia(Nodes, []). interrupted_before_change_schema_type(suite) -> []; interrupted_before_change_schema_type(Config) when is_list(Config) -> KillAt = {mnesia_dumper, dump_schema_op}, interrupted_change_schema_type(Config, KillAt). interrupted_after_change_schema_type(suite) -> []; interrupted_after_change_schema_type(Config) when is_list(Config) -> KillAt = {mnesia_dumper, post_dump}, interrupted_change_schema_type(Config, KillAt). -define(cleanup(N, Config), mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}], N, Config, ?FILE, ?LINE)). interrupted_change_schema_type(Config, KillAt) -> ?is_debug_compiled, [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]), Tab = itrpt, ?match({atomic, ok}, mnesia:create_table(Tab, [{ram_copies, [Node2, Node1]}])), ?match(ok, mnesia:dirty_write({Tab, before, 1})), {success, [A]} = ?start_activities([Node2]), setup_dbgpoint(KillAt, Node2), A ! fun() -> mnesia:change_table_copy_type(schema, Node2, ram_copies) end, kill_at_debug(), ?match(ok, rpc:call(Node2, mnesia, start, [[{extra_db_nodes, [Node1, Node2]}]])), ?match(ok, rpc:call(Node2, mnesia, wait_for_tables, [[itrpt, schema], 2000])), ?match(disc_copies, rpc:call(Node1, mnesia, table_info, [schema, storage_type])), ?match(ram_copies, rpc:call(Node2, mnesia, table_info, [schema, storage_type])), %% Go back to disc_copies !! {success, [B]} = ?start_activities([Node2]), setup_dbgpoint(KillAt, Node2), B ! fun() -> mnesia:change_table_copy_type(schema, Node2, disc_copies) end, kill_at_debug(), ?match(ok, rpc:call(Node2, mnesia, start, [[{extra_db_nodes, [Node1, Node2]}]])), ?match(ok, rpc:call(Node2, mnesia, wait_for_tables, [[itrpt, schema], 2000])), ?match(disc_copies, rpc:call(Node1, mnesia, table_info, [schema, storage_type])), ?match(disc_copies, rpc:call(Node2, mnesia, table_info, [schema, storage_type])), ?verify_mnesia(Nodes, []), ?cleanup(2, Config). %%% Helpers verify_tab(Node1, Node2) -> ?match({atomic, ok}, rpc:call(Node1, mnesia, transaction, [fun() -> mnesia:dirty_write({itrpt, a, a}) end])), ?match({atomic, ok}, rpc:call(Node2, mnesia, transaction, [fun() -> mnesia:dirty_write({itrpt, b, a}) end])), ?match([{itrpt,a,a}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, a}])), ?match([{itrpt,a,a}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, a}])), ?match([{itrpt,b,a}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, b}])), ?match([{itrpt,b,a}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, b}])), ?match([{itrpt,before,1}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, before}])), ?match([{itrpt,before,1}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, before}])). setup_dbgpoint(DbgPoint, Where) -> Self = self(), TestFun = fun(_, [InitBy]) -> case InitBy of schema_prepare -> ignore; schema_begin -> ignore; _Other -> ?deactivate_debug_fun(DbgPoint), unlink(Self), Self ! {fun_done, node()}, timer:sleep(infinity) end end, %% Kill when debug has been reached ?remote_activate_debug_fun(Where, DbgPoint, TestFun, []). kill_at_debug() -> %% Wait till it's killed receive {fun_done, Node} -> ?match([], mnesia_test_lib:kill_mnesia([Node])) after timer:minutes(1) -> ?error("Timeout in kill_at_debug", []) end.