1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22-module(mnesia_schema_recovery_test).
23-author('hakan@erix.ericsson.se').
24
25-export([init_per_testcase/2, end_per_testcase/2,
26         init_per_group/2, end_per_group/2,
27         all/0, groups/0]).
28
29-export([interrupted_before_create_ram/1,
30         interrupted_before_create_disc/1,
31         interrupted_before_create_do/1,
32         interrupted_before_create_nostore/1,
33         interrupted_before_delete_ram/1,
34         interrupted_before_delete_disc/1,
35         interrupted_before_delete_do/1,
36         interrupted_before_add_ram/1,
37         interrupted_before_add_disc/1,
38         interrupted_before_add_do/1,
39         interrupted_before_add_kill_copier/1,
40         interrupted_before_move_ram/1,
41         interrupted_before_move_disc/1,
42         interrupted_before_move_do/1,
43         interrupted_before_move_kill_copier/1,
44         interrupted_before_delcopy_ram/1,
45         interrupted_before_delcopy_disc/1,
46         interrupted_before_delcopy_do/1,
47         interrupted_before_delcopy_kill_copier/1,
48         interrupted_before_addindex_ram/1,
49         interrupted_before_addindex_disc/1,
50         interrupted_before_addindex_do/1,
51         interrupted_before_delindex_ram/1,
52         interrupted_before_delindex_disc/1,
53         interrupted_before_delindex_do/1,
54         interrupted_before_change_type_ram2disc/1,
55         interrupted_before_change_type_ram2do/1,
56         interrupted_before_change_type_disc2ram/1,
57         interrupted_before_change_type_disc2do/1,
58         interrupted_before_change_type_do2ram/1,
59         interrupted_before_change_type_do2disc/1,
60         interrupted_before_change_type_other_node/1,
61         interrupted_before_change_schema_type/1,
62         interrupted_after_create_ram/1,
63         interrupted_after_create_disc/1,
64         interrupted_after_create_do/1,
65         interrupted_after_create_nostore/1,
66         interrupted_after_delete_ram/1,
67         interrupted_after_delete_disc/1,
68         interrupted_after_delete_do/1,
69         interrupted_after_add_ram/1,
70         interrupted_after_add_disc/1,
71         interrupted_after_add_do/1,
72         interrupted_after_add_kill_copier/1,
73         interrupted_after_move_ram/1,
74         interrupted_after_move_disc/1,
75         interrupted_after_move_do/1,
76         interrupted_after_move_kill_copier/1,
77         interrupted_after_delcopy_ram/1,
78         interrupted_after_delcopy_disc/1,
79         interrupted_after_delcopy_do/1,
80         interrupted_after_delcopy_kill_copier/1,
81         interrupted_after_addindex_ram/1,
82         interrupted_after_addindex_disc/1,
83         interrupted_after_addindex_do/1,
84         interrupted_after_delindex_ram/1,
85         interrupted_after_delindex_disc/1,
86         interrupted_after_delindex_do/1,
87         interrupted_after_change_type_ram2disc/1,
88         interrupted_after_change_type_ram2do/1,
89         interrupted_after_change_type_disc2ram/1,
90         interrupted_after_change_type_disc2do/1,
91         interrupted_after_change_type_do2ram/1,
92         interrupted_after_change_type_do2disc/1,
93         interrupted_after_change_type_other_node/1,
94         interrupted_after_change_schema_type/1]).
95
96
97-include("mnesia_test_lib.hrl").
98
99init_per_testcase(Func, Conf) ->
100    mnesia_test_lib:init_per_testcase(Func, Conf).
101
102end_per_testcase(Func, Conf) ->
103    mnesia_test_lib:end_per_testcase(Func, Conf).
104
105-define(receive_messages(Msgs), receive_messages(Msgs, ?FILE, ?LINE)).
106
107% First Some debug logging
108-define(dgb, true).
109-ifdef(dgb).
110-define(dl(X, Y), ?verbose("**TRACING: " ++ X ++ "**~n", Y)).
111-else.
112-define(dl(X, Y), ok).
113-endif.
114
115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116
117all() ->
118    [{group, interrupted_before_log_dump},
119     {group, interrupted_after_log_dump}].
120
121groups() ->
122    [{interrupted_before_log_dump, [],
123      [interrupted_before_create_ram,
124       interrupted_before_create_disc,
125       interrupted_before_create_do,
126       interrupted_before_create_nostore,
127       interrupted_before_delete_ram,
128       interrupted_before_delete_disc,
129       interrupted_before_delete_do,
130       interrupted_before_add_ram,
131       interrupted_before_add_disc,
132       interrupted_before_add_do,
133       interrupted_before_add_kill_copier,
134       interrupted_before_move_ram,
135       interrupted_before_move_disc,
136       interrupted_before_move_do,
137       interrupted_before_move_kill_copier,
138       interrupted_before_delcopy_ram,
139       interrupted_before_delcopy_disc,
140       interrupted_before_delcopy_do,
141       interrupted_before_delcopy_kill_copier,
142       interrupted_before_addindex_ram,
143       interrupted_before_addindex_disc,
144       interrupted_before_addindex_do,
145       interrupted_before_delindex_ram,
146       interrupted_before_delindex_disc,
147       interrupted_before_delindex_do,
148       interrupted_before_change_type_ram2disc,
149       interrupted_before_change_type_ram2do,
150       interrupted_before_change_type_disc2ram,
151       interrupted_before_change_type_disc2do,
152       interrupted_before_change_type_do2ram,
153       interrupted_before_change_type_do2disc,
154       interrupted_before_change_type_other_node,
155       interrupted_before_change_schema_type]},
156     {interrupted_after_log_dump, [],
157      [interrupted_after_create_ram,
158       interrupted_after_create_disc,
159       interrupted_after_create_do,
160       interrupted_after_create_nostore,
161       interrupted_after_delete_ram,
162       interrupted_after_delete_disc,
163       interrupted_after_delete_do,
164       interrupted_after_add_ram,
165       interrupted_after_add_disc,
166       interrupted_after_add_do,
167       interrupted_after_add_kill_copier,
168       interrupted_after_move_ram,
169       interrupted_after_move_disc,
170       interrupted_after_move_do,
171       interrupted_after_move_kill_copier,
172       interrupted_after_delcopy_ram,
173       interrupted_after_delcopy_disc,
174       interrupted_after_delcopy_do,
175       interrupted_after_delcopy_kill_copier,
176       interrupted_after_addindex_ram,
177       interrupted_after_addindex_disc,
178       interrupted_after_addindex_do,
179       interrupted_after_delindex_ram,
180       interrupted_after_delindex_disc,
181       interrupted_after_delindex_do,
182       interrupted_after_change_type_ram2disc,
183       interrupted_after_change_type_ram2do,
184       interrupted_after_change_type_disc2ram,
185       interrupted_after_change_type_disc2do,
186       interrupted_after_change_type_do2ram,
187       interrupted_after_change_type_do2disc,
188       interrupted_after_change_type_other_node,
189       interrupted_after_change_schema_type]}].
190
191init_per_group(_GroupName, Config) ->
192    Config.
193
194end_per_group(_GroupName, Config) ->
195    Config.
196
197interrupted_before_create_ram(suite) -> [];
198interrupted_before_create_ram(Config) when is_list(Config) ->
199    KillAt = {mnesia_dumper, dump_schema_op},
200    interrupted_create(Config, ram_copies, all, KillAt).
201
202interrupted_before_create_disc(suite) -> [];
203interrupted_before_create_disc(Config) when is_list(Config) ->
204    KillAt = {mnesia_dumper, dump_schema_op},
205    interrupted_create(Config, disc_copies, all, KillAt).
206
207interrupted_before_create_do(suite) -> [];
208interrupted_before_create_do(Config) when is_list(Config) ->
209    KillAt = {mnesia_dumper, dump_schema_op},
210    interrupted_create(Config, disc_only_copies, all, KillAt).
211
212interrupted_before_create_nostore(suite) -> [];
213interrupted_before_create_nostore(Config) when is_list(Config) ->
214    KillAt = {mnesia_dumper, dump_schema_op},
215    interrupted_create(Config, ram_copies, one, KillAt).
216
217interrupted_after_create_ram(suite) -> [];
218interrupted_after_create_ram(Config) when is_list(Config) ->
219    KillAt = {mnesia_dumper, post_dump},
220    interrupted_create(Config, ram_copies, all, KillAt).
221
222interrupted_after_create_disc(suite) -> [];
223interrupted_after_create_disc(Config) when is_list(Config) ->
224    KillAt = {mnesia_dumper, post_dump},
225    interrupted_create(Config, disc_copies, all, KillAt).
226
227interrupted_after_create_do(suite) -> [];
228interrupted_after_create_do(Config) when is_list(Config) ->
229    KillAt = {mnesia_dumper, post_dump},
230    interrupted_create(Config, disc_only_copies, all, KillAt).
231
232interrupted_after_create_nostore(suite) -> [];
233interrupted_after_create_nostore(Config) when is_list(Config) ->
234    KillAt = {mnesia_dumper, post_dump},
235    interrupted_create(Config, ram_copies, one, KillAt).
236
237%%% After dump don't need debug point
238interrupted_create(Config, Type, _Where, {mnesia_dumper, post_dump}) ->
239    [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]),
240    ?match({atomic, ok},mnesia:create_table(itrpt, [{Type, Nodes}])),
241    ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
242    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
243    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
244    ?match(stopped, mnesia:stop()),
245    ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])),
246    %% Verify
247    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
248    case Type of
249	ram_copies ->
250	    ?match([], mnesia:dirty_read({itrpt, before}));
251	_ ->
252	    ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before}))
253    end,
254    ?verify_mnesia(Nodes, []);
255interrupted_create(Config, Type, Where, KillAt) ->
256    ?is_debug_compiled,
257    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
258    {success, [A]} = ?start_activities([Node2]),
259    setup_dbgpoint(KillAt, Node2),
260
261    if       %% CREATE TABLE
262	Where == all ->    % tables on both nodes
263	    A ! fun() -> mnesia:create_table(itrpt, [{Type, Nodes}]) end;
264	true ->            % no table on the killed node
265	    A ! fun() -> mnesia:create_table(itrpt, [{Type, [Node1]}]) end
266    end,
267
268    kill_at_debug(),
269    ?match([], mnesia_test_lib:start_mnesia([Node2], [itrpt])),
270    %% Verify
271    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
272    verify_tab(Node1, Node2),
273    ?verify_mnesia(Nodes, []).
274
275interrupted_before_delete_ram(suite) -> [];
276interrupted_before_delete_ram(Config) when is_list(Config) ->
277    Debug_Point = {mnesia_dumper, dump_schema_op},
278    interrupted_delete(Config, ram_copies, Debug_Point).
279interrupted_before_delete_disc(suite) -> [];
280interrupted_before_delete_disc(Config) when is_list(Config) ->
281    Debug_Point = {mnesia_dumper, dump_schema_op},
282    interrupted_delete(Config, disc_copies, Debug_Point).
283interrupted_before_delete_do(suite) -> [];
284interrupted_before_delete_do(Config) when is_list(Config) ->
285    Debug_Point = {mnesia_dumper, dump_schema_op},
286    interrupted_delete(Config, disc_only_copies, Debug_Point).
287
288interrupted_after_delete_ram(suite) -> [];
289interrupted_after_delete_ram(Config) when is_list(Config) ->
290    Debug_Point = {mnesia_dumper, post_dump},
291    interrupted_delete(Config, ram_copies, Debug_Point).
292interrupted_after_delete_disc(suite) -> [];
293interrupted_after_delete_disc(Config) when is_list(Config) ->
294    Debug_Point = {mnesia_dumper, post_dump},
295    interrupted_delete(Config, disc_copies, Debug_Point).
296interrupted_after_delete_do(suite) -> [];
297interrupted_after_delete_do(Config) when is_list(Config) ->
298    Debug_Point = {mnesia_dumper, post_dump},
299    interrupted_delete(Config, disc_only_copies, Debug_Point).
300
301interrupted_delete(Config, Type, KillAt) ->
302    ?is_debug_compiled,
303    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
304    Tab = itrpt,
305    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node2]}])),
306    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
307    {_Alive, Kill} = {Node1, Node2},
308    {success, [A]} = ?start_activities([Kill]),
309
310    setup_dbgpoint(KillAt, Kill),
311    A ! fun() -> mnesia:delete_table(Tab) end,
312
313    kill_at_debug(),
314    ?match([], mnesia_test_lib:start_mnesia([Node2], [])),
315    Bad = {badrpc, {'EXIT', {aborted,{no_exists, Tab, all}}}},
316    ?match(Bad, rpc:call(Node1, mnesia, table_info, [Tab, all])),
317    ?match(Bad, rpc:call(Node2, mnesia, table_info, [Tab, all])),
318    ?verify_mnesia(Nodes, []).
319
320interrupted_before_add_ram(suite) -> [];
321interrupted_before_add_ram(Config) when is_list(Config) ->
322    Debug_Point = {mnesia_dumper, dump_schema_op},
323    interrupted_add(Config, ram_copies, kill_reciever, Debug_Point).
324interrupted_before_add_disc(suite) -> [];
325interrupted_before_add_disc(Config) when is_list(Config) ->
326    Debug_Point = {mnesia_dumper, dump_schema_op},
327    interrupted_add(Config, disc_copies, kill_reciever, Debug_Point).
328interrupted_before_add_do(suite) -> [];
329interrupted_before_add_do(Config) when is_list(Config) ->
330    Debug_Point = {mnesia_dumper, dump_schema_op},
331    interrupted_add(Config, disc_only_copies, kill_reciever, Debug_Point).
332interrupted_before_add_kill_copier(suite) -> [];
333interrupted_before_add_kill_copier(Config) when is_list(Config) ->
334    Debug_Point = {mnesia_dumper, dump_schema_op},
335    interrupted_add(Config, ram_copies, kill_copier, Debug_Point).
336
337interrupted_after_add_ram(suite) -> [];
338interrupted_after_add_ram(Config) when is_list(Config) ->
339    Debug_Point = {mnesia_dumper, post_dump},
340    interrupted_add(Config, ram_copies, kill_reciever, Debug_Point).
341interrupted_after_add_disc(suite) -> [];
342interrupted_after_add_disc(Config) when is_list(Config) ->
343    Debug_Point = {mnesia_dumper, post_dump},
344    interrupted_add(Config, disc_copies, kill_reciever, Debug_Point).
345interrupted_after_add_do(suite) -> [];
346interrupted_after_add_do(Config) when is_list(Config) ->
347    Debug_Point = {mnesia_dumper, post_dump},
348    interrupted_add(Config, disc_only_copies, kill_reciever, Debug_Point).
349interrupted_after_add_kill_copier(suite) -> [];
350interrupted_after_add_kill_copier(Config) when is_list(Config) ->
351    Debug_Point = {mnesia_dumper, post_dump},
352    interrupted_add(Config, ram_copies, kill_copier, Debug_Point).
353
354%%% After dump don't need debug point
355interrupted_add(Config, Type, _Where, {mnesia_dumper, post_dump}) ->
356    [Node1, Node2] = Nodes =
357	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
358    Tab = itrpt,
359    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node2]}, {local_content,true}])),
360    ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
361    ?match({atomic, ok}, mnesia:add_table_copy(Tab, Node1, Type)),
362    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
363    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
364    ?match(stopped, mnesia:stop()),
365    ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])),
366    %% Verify
367    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
368    case Type of
369	ram_copies ->
370	    ?match([], mnesia:dirty_read({itrpt, before}));
371	_ ->
372	    ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before}))
373    end,
374    ?verify_mnesia(Nodes, []);
375interrupted_add(Config, Type, Who, KillAt) ->
376    ?is_debug_compiled,
377    [Node1, Node2] = Nodes =
378	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
379    {_Alive, Kill} =
380	if Who == kill_reciever ->
381		{Node1, Node2};
382	   true ->
383		{Node2, Node1}
384	end,
385    {success, [A]} = ?start_activities([Kill]),
386    Tab = itrpt,
387    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])),
388    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
389
390    setup_dbgpoint(KillAt, Kill),
391
392    A ! fun() -> mnesia:add_table_copy(Tab, Node2, Type) end,
393    kill_at_debug(),
394    ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])),
395    verify_tab(Node1, Node2),
396    ?verify_mnesia(Nodes, []).
397
398interrupted_before_move_ram(suite) -> [];
399interrupted_before_move_ram(Config) when is_list(Config) ->
400    Debug_Point = {mnesia_dumper, dump_schema_op},
401    interrupted_move(Config, ram_copies, kill_reciever, Debug_Point).
402interrupted_before_move_disc(suite) -> [];
403interrupted_before_move_disc(Config) when is_list(Config) ->
404    Debug_Point = {mnesia_dumper, dump_schema_op},
405    interrupted_move(Config, disc_copies, kill_reciever, Debug_Point).
406interrupted_before_move_do(suite) -> [];
407interrupted_before_move_do(Config) when is_list(Config) ->
408    Debug_Point = {mnesia_dumper, dump_schema_op},
409    interrupted_move(Config, disc_only_copies, kill_reciever, Debug_Point).
410interrupted_before_move_kill_copier(suite) -> [];
411interrupted_before_move_kill_copier(Config) when is_list(Config) ->
412    Debug_Point = {mnesia_dumper, dump_schema_op},
413    interrupted_move(Config, ram_copies, kill_copier, Debug_Point).
414
415interrupted_after_move_ram(suite) -> [];
416interrupted_after_move_ram(Config) when is_list(Config) ->
417    Debug_Point = {mnesia_dumper, post_dump},
418    interrupted_move(Config, ram_copies, kill_reciever, Debug_Point).
419interrupted_after_move_disc(suite) -> [];
420interrupted_after_move_disc(Config) when is_list(Config) ->
421    Debug_Point = {mnesia_dumper, post_dump},
422    interrupted_move(Config, disc_copies, kill_reciever, Debug_Point).
423interrupted_after_move_do(suite) -> [];
424interrupted_after_move_do(Config) when is_list(Config) ->
425    Debug_Point = {mnesia_dumper, post_dump},
426    interrupted_move(Config, disc_only_copies, kill_reciever, Debug_Point).
427interrupted_after_move_kill_copier(suite) -> [];
428interrupted_after_move_kill_copier(Config) when is_list(Config) ->
429    Debug_Point = {mnesia_dumper, post_dump},
430    interrupted_move(Config, ram_copies, kill_copier, Debug_Point).
431
432%%% After dump don't need debug point
433interrupted_move(Config, Type, _Where, {mnesia_dumper, post_dump}) ->
434    [Node1, Node2] = Nodes =
435	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
436    Tab = itrpt,
437    ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
438    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])),
439    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
440    ?match({atomic, ok}, mnesia:move_table_copy(Tab, Node1, Node2)),
441    ?match(ok, mnesia:dirty_write({itrpt, aFter, 1})),
442    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
443    ?match(stopped, mnesia:stop()),
444    ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])),
445    %% Verify
446    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
447    ?match([{itrpt, before, 1}], mnesia:dirty_read({itrpt, before})),
448    ?match([{itrpt, aFter, 1}], mnesia:dirty_read({itrpt, aFter})),
449    ?verify_mnesia(Nodes, []);
450interrupted_move(Config, Type, Who, KillAt) ->
451    ?is_debug_compiled,
452    [Node1, Node2] = Nodes =
453	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
454    Tab = itrpt,
455    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])),
456    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
457
458    {_Alive, Kill} =
459	if Who == kill_reciever ->
460		if Type == ram_copies ->
461			{atomic, ok} = mnesia:dump_tables([Tab]);
462		   true ->
463			ignore
464		end,
465		{Node1, Node2};
466	   true ->
467		{Node2, Node1}
468	end,
469
470    {success, [A]} = ?start_activities([Kill]),
471
472    setup_dbgpoint(KillAt, Kill),
473    A ! fun() -> mnesia:move_table_copy(Tab, Node1, Node2) end,
474    kill_at_debug(),
475    ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])),
476    verify_tab(Node1, Node2),
477    ?verify_mnesia(Nodes, []).
478
479interrupted_before_delcopy_ram(suite) -> [];
480interrupted_before_delcopy_ram(Config) when is_list(Config) ->
481    Debug_Point = {mnesia_dumper, dump_schema_op},
482    interrupted_delcopy(Config, ram_copies, kill_reciever, Debug_Point).
483interrupted_before_delcopy_disc(suite) -> [];
484interrupted_before_delcopy_disc(Config) when is_list(Config) ->
485    Debug_Point = {mnesia_dumper, dump_schema_op},
486    interrupted_delcopy(Config, disc_copies, kill_reciever, Debug_Point).
487interrupted_before_delcopy_do(suite) -> [];
488interrupted_before_delcopy_do(Config) when is_list(Config) ->
489    Debug_Point = {mnesia_dumper, dump_schema_op},
490    interrupted_delcopy(Config, disc_only_copies, kill_reciever, Debug_Point).
491interrupted_before_delcopy_kill_copier(suite) -> [];
492interrupted_before_delcopy_kill_copier(Config) when is_list(Config) ->
493    Debug_Point = {mnesia_dumper, dump_schema_op},
494    interrupted_delcopy(Config, ram_copies, kill_copier, Debug_Point).
495
496interrupted_after_delcopy_ram(suite) -> [];
497interrupted_after_delcopy_ram(Config) when is_list(Config) ->
498    Debug_Point = {mnesia_dumper, post_dump},
499    interrupted_delcopy(Config, ram_copies, kill_reciever, Debug_Point).
500interrupted_after_delcopy_disc(suite) -> [];
501interrupted_after_delcopy_disc(Config) when is_list(Config) ->
502    Debug_Point = {mnesia_dumper, post_dump},
503    interrupted_delcopy(Config, disc_copies, kill_reciever, Debug_Point).
504interrupted_after_delcopy_do(suite) -> [];
505interrupted_after_delcopy_do(Config) when is_list(Config) ->
506    Debug_Point = {mnesia_dumper, post_dump},
507    interrupted_delcopy(Config, disc_only_copies, kill_reciever, Debug_Point).
508interrupted_after_delcopy_kill_copier(suite) -> [];
509interrupted_after_delcopy_kill_copier(Config) when is_list(Config) ->
510    Debug_Point = {mnesia_dumper, post_dump},
511    interrupted_delcopy(Config, ram_copies, kill_copier, Debug_Point).
512
513
514%%% After dump don't need debug point
515interrupted_delcopy(Config, Type, _Where, {mnesia_dumper, post_dump}) ->
516    [Node1, Node2] = Nodes =
517	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
518    Tab = itrpt,
519    ?match({atomic, ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
520    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1,Node2]}])),
521    ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node1)),
522    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
523    ?match(stopped, mnesia:stop()),
524    ?match([], mnesia_test_lib:start_mnesia([Node1], [test])),
525    %% Verify
526    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
527    ?match([Node2], mnesia:table_info(itrpt,Type)),
528    ?verify_mnesia(Nodes, []);
529interrupted_delcopy(Config, Type, Who, KillAt) ->
530    ?is_debug_compiled,
531    [Node1, Node2] = Nodes =
532	?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
533    Tab = itrpt,
534    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1, Node2]}])),
535    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
536
537    {_Alive, Kill} =
538	if Who == kill_reciever ->
539		{Node1, Node2};
540	   true ->
541		if
542		    Type == ram_copies ->
543			{atomic, ok} = mnesia:dump_tables([Tab]);
544		    true ->
545			ignore
546		end,
547		{Node2, Node1}
548	end,
549
550    {success, [A]} = ?start_activities([Kill]),
551    setup_dbgpoint(KillAt, Kill),
552    A ! fun() -> mnesia:del_table_copy(Tab, Node2) end,
553    kill_at_debug(),
554    ?match([], mnesia_test_lib:start_mnesia([Kill], [itrpt])),
555    verify_tab(Node1, Node2),
556    ?verify_mnesia(Nodes, []).
557
558interrupted_before_addindex_ram(suite) -> [];
559interrupted_before_addindex_ram(Config) when is_list(Config) ->
560    Debug_Point = {mnesia_dumper, dump_schema_op},
561    interrupted_addindex(Config, ram_copies, Debug_Point).
562interrupted_before_addindex_disc(suite) -> [];
563interrupted_before_addindex_disc(Config) when is_list(Config) ->
564    Debug_Point = {mnesia_dumper, dump_schema_op},
565    interrupted_addindex(Config, disc_copies, Debug_Point).
566interrupted_before_addindex_do(suite) -> [];
567interrupted_before_addindex_do(Config) when is_list(Config) ->
568    Debug_Point = {mnesia_dumper, dump_schema_op},
569    interrupted_addindex(Config, disc_only_copies, Debug_Point).
570
571interrupted_after_addindex_ram(suite) -> [];
572interrupted_after_addindex_ram(Config) when is_list(Config) ->
573    Debug_Point = {mnesia_dumper, post_dump},
574    interrupted_addindex(Config, ram_copies, Debug_Point).
575interrupted_after_addindex_disc(suite) -> [];
576interrupted_after_addindex_disc(Config) when is_list(Config) ->
577    Debug_Point = {mnesia_dumper, post_dump},
578    interrupted_addindex(Config, disc_copies, Debug_Point).
579interrupted_after_addindex_do(suite) -> [];
580interrupted_after_addindex_do(Config) when is_list(Config) ->
581    Debug_Point = {mnesia_dumper, post_dump},
582    interrupted_addindex(Config, disc_only_copies, Debug_Point).
583
584
585%%% After dump don't need debug point
586interrupted_addindex(Config, Type, {mnesia_dumper, post_dump}) ->
587    [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]),
588    Tab = itrpt,
589    ?match({atomic,ok},mnesia:create_table(Tab, [{Type, Nodes}])),
590    ?match({atomic,ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
591    ?match({atomic,ok}, mnesia:add_table_index(Tab, val)),
592    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
593    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
594    ?match(stopped, mnesia:stop()),
595    ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])),
596    %% Verify
597    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
598    case Type of
599	ram_copies ->
600	    ?match([], mnesia:dirty_index_read(itrpt, 1, val));
601	_ ->
602	    ?match([{itrpt, before, 1}], mnesia:dirty_index_read(itrpt, 1, val))
603    end,
604    ?verify_mnesia(Nodes, []);
605interrupted_addindex(Config, Type, KillAt) ->
606    ?is_debug_compiled,
607    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
608    Tab = itrpt,
609    ?match({atomic, ok}, mnesia:create_table(Tab, [{Type, [Node1]}])),
610    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
611    {_Alive, Kill} = {Node1, Node2},
612    {success, [A]} = ?start_activities([Kill]),
613
614    setup_dbgpoint(KillAt, Kill),
615    A ! fun() -> mnesia:add_table_index(Tab, val) end,
616    kill_at_debug(),
617    ?match([], mnesia_test_lib:start_mnesia([Node2], [])),
618
619    verify_tab(Node1, Node2),
620    ?match([{Tab, b, a}, {Tab, a, a}],
621	   rpc:call(Node1, mnesia, dirty_index_read, [itrpt, a, val])),
622    ?match([{Tab, b, a}, {Tab, a, a}],
623	   rpc:call(Node2, mnesia, dirty_index_read, [itrpt, a, val])),
624    ?verify_mnesia(Nodes, []).
625
626interrupted_before_delindex_ram(suite) -> [];
627interrupted_before_delindex_ram(Config) when is_list(Config) ->
628    Debug_Point = {mnesia_dumper, dump_schema_op},
629    interrupted_delindex(Config, ram_copies, Debug_Point).
630interrupted_before_delindex_disc(suite) -> [];
631interrupted_before_delindex_disc(Config) when is_list(Config) ->
632    Debug_Point = {mnesia_dumper, dump_schema_op},
633    interrupted_delindex(Config, disc_copies, Debug_Point).
634interrupted_before_delindex_do(suite) -> [];
635interrupted_before_delindex_do(Config) when is_list(Config) ->
636    Debug_Point = {mnesia_dumper, dump_schema_op},
637    interrupted_delindex(Config, disc_only_copies, Debug_Point).
638
639interrupted_after_delindex_ram(suite) -> [];
640interrupted_after_delindex_ram(Config) when is_list(Config) ->
641    Debug_Point = {mnesia_dumper, post_dump},
642    interrupted_delindex(Config, ram_copies, Debug_Point).
643interrupted_after_delindex_disc(suite) -> [];
644interrupted_after_delindex_disc(Config) when is_list(Config) ->
645    Debug_Point = {mnesia_dumper, post_dump},
646    interrupted_delindex(Config, disc_copies, Debug_Point).
647interrupted_after_delindex_do(suite) -> [];
648interrupted_after_delindex_do(Config) when is_list(Config) ->
649    Debug_Point = {mnesia_dumper, post_dump},
650    interrupted_delindex(Config, disc_only_copies, Debug_Point).
651
652%%% After dump don't need debug point
653interrupted_delindex(Config, Type, {mnesia_dumper, post_dump}) ->
654    [Node1] = Nodes = ?acquire_nodes(1, [{tc_timeout, timer:seconds(30)} | Config]),
655    Tab = itrpt,
656    ?match({atomic,ok},mnesia:create_table(Tab, [{Type, Nodes},{index,[val]}])),
657    ?match({atomic,ok},mnesia:create_table(test, [{disc_copies,[Node1]}])),
658    ?match({atomic,ok}, mnesia:del_table_index(Tab, val)),
659    ?match(ok, mnesia:dirty_write({itrpt, before, 1})),
660    ?match(ok, mnesia:dirty_write({test, found_in_log, 1})),
661    ?match(stopped, mnesia:stop()),
662    ?match([], mnesia_test_lib:start_mnesia([Node1], [itrpt,test])),
663    %% Verify
664    ?match([{test, found_in_log, 1}], mnesia:dirty_read({test, found_in_log})),
665    ?match({'EXIT',{aborted,{badarg,_}}}, mnesia:dirty_index_read(itrpt, 1, val)),
666    ?verify_mnesia(Nodes, []);
667
668interrupted_delindex(Config, Type, KillAt) ->
669    ?is_debug_compiled,
670    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
671    Tab = itrpt,
672    ?match({atomic, ok}, mnesia:create_table(Tab, [{index, [val]},
673						   {Type, [Node1]}])),
674    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
675    {_Alive, Kill} = {Node1, Node2},
676    {success, [A]} = ?start_activities([Kill]),
677    setup_dbgpoint(KillAt, Kill),
678    A ! fun() -> mnesia:del_table_index(Tab, val) end,
679    kill_at_debug(),
680    ?match([], mnesia_test_lib:start_mnesia([Node2], [])),
681    verify_tab(Node1, Node2),
682    ?match({badrpc, _}, rpc:call(Node1, mnesia, dirty_index_read, [itrpt, a, val])),
683    ?match({badrpc, _}, rpc:call(Node2, mnesia, dirty_index_read, [itrpt, a, val])),
684    ?match([], rpc:call(Node1, mnesia, table_info, [Tab, index])),
685    ?match([], rpc:call(Node2, mnesia, table_info, [Tab, index])),
686    ?verify_mnesia(Nodes, []).
687
688interrupted_before_change_type_ram2disc(suite) -> [];
689interrupted_before_change_type_ram2disc(Config) when is_list(Config) ->
690    Debug_Point = {mnesia_dumper, dump_schema_op},
691    interrupted_change_type(Config, ram_copies, disc_copies, changer, Debug_Point).
692interrupted_before_change_type_ram2do(suite) -> [];
693interrupted_before_change_type_ram2do(Config) when is_list(Config) ->
694    Debug_Point = {mnesia_dumper, dump_schema_op},
695    interrupted_change_type(Config, ram_copies, disc_only_copies, changer, Debug_Point).
696interrupted_before_change_type_disc2ram(suite) -> [];
697interrupted_before_change_type_disc2ram(Config) when is_list(Config) ->
698    Debug_Point = {mnesia_dumper, dump_schema_op},
699    interrupted_change_type(Config, disc_copies, ram_copies, changer, Debug_Point).
700interrupted_before_change_type_disc2do(suite) -> [];
701interrupted_before_change_type_disc2do(Config) when is_list(Config) ->
702    Debug_Point = {mnesia_dumper, dump_schema_op},
703    interrupted_change_type(Config, disc_copies, disc_only_copies, changer, Debug_Point).
704interrupted_before_change_type_do2ram(suite) -> [];
705interrupted_before_change_type_do2ram(Config) when is_list(Config) ->
706    Debug_Point = {mnesia_dumper, dump_schema_op},
707    interrupted_change_type(Config, disc_only_copies, ram_copies, changer, Debug_Point).
708interrupted_before_change_type_do2disc(suite) -> [];
709interrupted_before_change_type_do2disc(Config) when is_list(Config) ->
710    Debug_Point = {mnesia_dumper, dump_schema_op},
711    interrupted_change_type(Config, disc_only_copies, disc_copies, changer, Debug_Point).
712interrupted_before_change_type_other_node(suite) -> [];
713interrupted_before_change_type_other_node(Config) when is_list(Config) ->
714    Debug_Point = {mnesia_dumper, dump_schema_op},
715    interrupted_change_type(Config, ram_copies, disc_copies, the_other_one, Debug_Point).
716
717interrupted_after_change_type_ram2disc(suite) -> [];
718interrupted_after_change_type_ram2disc(Config) when is_list(Config) ->
719    Debug_Point = {mnesia_dumper, post_dump},
720    interrupted_change_type(Config, ram_copies, disc_copies, changer, Debug_Point).
721interrupted_after_change_type_ram2do(suite) -> [];
722interrupted_after_change_type_ram2do(Config) when is_list(Config) ->
723    Debug_Point = {mnesia_dumper, post_dump},
724    interrupted_change_type(Config, ram_copies, disc_only_copies, changer, Debug_Point).
725interrupted_after_change_type_disc2ram(suite) -> [];
726interrupted_after_change_type_disc2ram(Config) when is_list(Config) ->
727    Debug_Point = {mnesia_dumper, post_dump},
728    interrupted_change_type(Config, disc_copies, ram_copies, changer, Debug_Point).
729interrupted_after_change_type_disc2do(suite) -> [];
730interrupted_after_change_type_disc2do(Config) when is_list(Config) ->
731    Debug_Point = {mnesia_dumper, post_dump},
732    interrupted_change_type(Config, disc_copies, disc_only_copies, changer, Debug_Point).
733interrupted_after_change_type_do2ram(suite) -> [];
734interrupted_after_change_type_do2ram(Config) when is_list(Config) ->
735    Debug_Point = {mnesia_dumper, post_dump},
736    interrupted_change_type(Config, disc_only_copies, ram_copies, changer, Debug_Point).
737interrupted_after_change_type_do2disc(suite) -> [];
738interrupted_after_change_type_do2disc(Config) when is_list(Config) ->
739    Debug_Point = {mnesia_dumper, post_dump},
740    interrupted_change_type(Config, disc_only_copies, disc_copies, changer, Debug_Point).
741interrupted_after_change_type_other_node(suite) -> [];
742interrupted_after_change_type_other_node(Config) when is_list(Config) ->
743    Debug_Point = {mnesia_dumper, post_dump},
744    interrupted_change_type(Config, ram_copies, disc_copies, the_other_one, Debug_Point).
745
746interrupted_change_type(Config, FromType, ToType, Who, KillAt) ->
747    ?is_debug_compiled,
748    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
749    Tab = itrpt,
750    ?match({atomic, ok}, mnesia:create_table(Tab, [{FromType, [Node2, Node1]}])),
751    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
752
753    {_Alive, Kill} =
754	if Who == changer -> {Node1, Node2};
755	   true ->           {Node2, Node1}
756	end,
757
758    {success, [A]} = ?start_activities([Kill]),
759    setup_dbgpoint(KillAt, Kill),
760    A ! fun() -> mnesia:change_table_copy_type(Tab, Node2, ToType) end,
761    kill_at_debug(),
762    ?match([], mnesia_test_lib:start_mnesia(Nodes, [itrpt])),
763    verify_tab(Node1, Node2),
764    ?match(FromType, rpc:call(Node1, mnesia, table_info, [Tab, storage_type])),
765    ?match(ToType, rpc:call(Node2, mnesia, table_info, [Tab, storage_type])),
766    ?verify_mnesia(Nodes, []).
767
768interrupted_before_change_schema_type(suite) ->     [];
769interrupted_before_change_schema_type(Config) when is_list(Config) ->
770    KillAt = {mnesia_dumper, dump_schema_op},
771    interrupted_change_schema_type(Config, KillAt).
772
773interrupted_after_change_schema_type(suite) ->     [];
774interrupted_after_change_schema_type(Config) when is_list(Config) ->
775    KillAt = {mnesia_dumper, post_dump},
776    interrupted_change_schema_type(Config, KillAt).
777
778-define(cleanup(N, Config),
779	mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}],
780					  N, Config, ?FILE, ?LINE)).
781
782interrupted_change_schema_type(Config, KillAt) ->
783    ?is_debug_compiled,
784    [Node1, Node2] = Nodes = ?acquire_nodes(2, [{tc_timeout, timer:seconds(30)} | Config]),
785
786    Tab = itrpt,
787    ?match({atomic, ok}, mnesia:create_table(Tab, [{ram_copies, [Node2, Node1]}])),
788    ?match(ok, mnesia:dirty_write({Tab, before, 1})),
789
790    {success, [A]} = ?start_activities([Node2]),
791    setup_dbgpoint(KillAt, Node2),
792
793    A ! fun() -> mnesia:change_table_copy_type(schema, Node2, ram_copies) end,
794    kill_at_debug(),
795    ?match(ok, rpc:call(Node2, mnesia, start, [[{extra_db_nodes, [Node1, Node2]}]])),
796    ?match(ok, rpc:call(Node2, mnesia, wait_for_tables, [[itrpt, schema], 2000])),
797    ?match(disc_copies, rpc:call(Node1, mnesia, table_info, [schema, storage_type])),
798    ?match(ram_copies, rpc:call(Node2, mnesia, table_info,  [schema, storage_type])),
799
800    %% Go back to disc_copies !!
801    {success, [B]} = ?start_activities([Node2]),
802    setup_dbgpoint(KillAt, Node2),
803    B ! fun() -> mnesia:change_table_copy_type(schema, Node2, disc_copies) end,
804    kill_at_debug(),
805
806    ?match(ok, rpc:call(Node2, mnesia, start, [[{extra_db_nodes, [Node1, Node2]}]])),
807    ?match(ok, rpc:call(Node2, mnesia, wait_for_tables, [[itrpt, schema], 2000])),
808    ?match(disc_copies, rpc:call(Node1, mnesia, table_info, [schema, storage_type])),
809    ?match(disc_copies, rpc:call(Node2, mnesia, table_info,  [schema, storage_type])),
810
811    ?verify_mnesia(Nodes, []),
812    ?cleanup(2, Config).
813
814%%% Helpers
815verify_tab(Node1, Node2) ->
816    ?match({atomic, ok},
817	   rpc:call(Node1, mnesia, transaction, [fun() -> mnesia:dirty_write({itrpt, a, a}) end])),
818    ?match({atomic, ok},
819	   rpc:call(Node2, mnesia, transaction, [fun() -> mnesia:dirty_write({itrpt, b, a}) end])),
820    ?match([{itrpt,a,a}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, a}])),
821    ?match([{itrpt,a,a}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, a}])),
822    ?match([{itrpt,b,a}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, b}])),
823    ?match([{itrpt,b,a}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, b}])),
824    ?match([{itrpt,before,1}], rpc:call(Node1, mnesia, dirty_read, [{itrpt, before}])),
825    ?match([{itrpt,before,1}], rpc:call(Node2, mnesia, dirty_read, [{itrpt, before}])).
826
827setup_dbgpoint(DbgPoint, Where) ->
828    Self = self(),
829    TestFun = fun(_, [InitBy]) ->
830		      case InitBy of
831			  schema_prepare ->
832			      ignore;
833			  schema_begin ->
834			      ignore;
835			  _Other ->
836			      ?deactivate_debug_fun(DbgPoint),
837			      unlink(Self),
838			      Self ! {fun_done, node()},
839			      timer:sleep(infinity)
840		      end
841	      end,
842    %% Kill when debug has been reached
843    ?remote_activate_debug_fun(Where, DbgPoint, TestFun, []).
844
845kill_at_debug() ->
846    %% Wait till it's killed
847    receive
848	{fun_done, Node} ->
849	    ?match([], mnesia_test_lib:kill_mnesia([Node]))
850    after
851	timer:minutes(1) -> ?error("Timeout in kill_at_debug", [])
852    end.
853
854