Skip to content

Commit a11c6c0

Browse files
slfritchieengelsanchez
authored andcommitted
Add option to PULSE test to create merge.txt file on bc_open()
Fix PULSE counterexample by filtering error messages. C1 = [[{set,{var,6}, {call,bitcask_pulse,fork, [[{init,{state,undefined,false,false,[]}}, {set,{not_var,7}, {not_call,bitcask_pulse,bc_open, [false,{true,{231,280,114},1}]}}, {set,{not_var,10}, {not_call,bitcask_pulse,bc_close,[{not_var,7}]}}, {set,{not_var,11}, {not_call,bitcask_pulse,bc_open, [false,{true,{170,447,173},1}]}}, {set,{not_var,13}, {not_call,bitcask_pulse,bc_close,[{not_var,11}]}}, {set,{not_var,15}, {not_call,bitcask_pulse,bc_open, [false,{true,{258,18,280},1}]}}]]}}, {set,{var,7}, {call,bitcask_pulse,fork, [[{init,{state,undefined,false,false,[]}}, {set,{not_var,2}, {not_call,bitcask_pulse,bc_open, [false,{true,{246,472,469},1}]}}, {set,{not_var,3}, {not_call,bitcask_pulse,bc_close,[{not_var,2}]}}, {set,{not_var,6}, {not_call,bitcask_pulse,bc_open, [false,{true,{73,166,183},1}]}}, {set,{not_var,7}, {not_call,bitcask_pulse,fold,[{not_var,6}]}}]]}}, {set,{var,8}, {call,bitcask_pulse,bc_open,[true,{true,{424,237,233},1}]}}, {set,{var,10},{call,bitcask_pulse,needs_merge,[{var,8}]}}, {set,{var,11},{call,bitcask_pulse,merge,[{var,8}]}}, {set,{var,12},{call,bitcask_pulse,delete,[{var,8},1]}}, {set,{var,13},{call,bitcask_pulse,merge,[{var,8}]}}], {62806,53384,84006}, [{errors,[]}]]. eqc:check(bitcask_pulse:prop_pulse(), C1). The error coming from error_logger & failing the property: errors: failed [{<0.23310.2>,"Invalid merge input file ~s, deleting : ~p", ["1399-272921-941361/merge.txt",enoent]}] /= [] This error message is not fatal, so ignore it. Fix PULSE counterexample when merge's ReadableFiles is the empty list C2 = [[{set,{var,2}, {call,bitcask_pulse,bc_open,[true,{true,{442,453,173},1}]}}, {set,{var,3},{call,bitcask_pulse,delete,[{var,2},1]}}, {set,{var,5},{call,bitcask_pulse,bc_close,[{var,2}]}}, {set,{var,8}, {call,bitcask_pulse,bc_open, [true,{true,{172,181,201},100}]}}, {set,{var,9},{call,bitcask_pulse,fork_merge,[{var,8}]}}, {set,{var,11},{call,bitcask_pulse,fork_merge,[{var,8}]}}], {41544,86022,14862}, [{errors,[]}]]. eqc:check(bitcask_pulse:prop_pulse(), C2). The error from PULSE: errors: failed [{<0.27136.3>,"Failed to merge ~p: ~p\n", [{["1399-274027-165496/1.bitcask.data"],[]}, {function_clause, [{lists,min,[[]],[{file,"lists.erl"},{line,300}]}, {bitcask,merge1,4,[{file,"src/bitcask.erl"},{line,611}]}, {bitcask_merge_worker,do_merge,1, [{file,"src/bitcask_merge_worker.erl"},{line,195}]}]}]}] /= [] Fix for Buildbot EUnit test failure Buildbot isn't quite right in the head: I've no idea why I can run this test 3000x without failure, but Buildbot fails bitcask_qc: merge2_test... =ERROR REPORT==== 5-May-2014::04:56:18 === ** Generic server <0.2324.0> terminating ** Last message in was {'DOWN',#Ref<0.0.0.50927>,process,<0.2317.0>,normal} ** When Server state == {state,undefined,undefined} ** Reason for termination == ** {{badmatch,{error,badarg}}, [{bitcask_file,handle_info,2,[{file,"src/bitcask_file.erl"},{line,193}]}, {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,604}]}, {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]} Fix: Really, we're stopping, so change the pattern match to '_' so we don't care. Fix Dialyzer type typo Fix Buildbot timeout error bitcask: merge_batch_test...*timed out* Increase timeout to something even a Buildbot can love.
1 parent a23d541 commit a11c6c0

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

src/bitcask.erl

+11-4
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,12 @@ merge1(Dirname, Opts, FilesToMerge0, ExpiredFiles) ->
608608
end, InFiles2),
609609
InFileIds = sets:from_list([bitcask_fileops:file_tstamp(InFile)
610610
|| InFile <- InFiles]),
611-
MinFileId = lists:min([bitcask_fileops:file_tstamp(F) ||
612-
F <- ReadableFiles]),
611+
MinFileId = if ReadableFiles == [] ->
612+
1;
613+
true ->
614+
lists:min([bitcask_fileops:file_tstamp(F) ||
615+
F <- ReadableFiles])
616+
end,
613617

614618
%% Initialize the other keydirs we need.
615619
{ok, DelKeyDir} = bitcask_nifs:keydir_new(),
@@ -679,7 +683,7 @@ consider_for_merge(FragTrigger, DeadBytesTrigger, ExpirationGraceTime) ->
679683
needs_merge(Ref) ->
680684
needs_merge(Ref, []).
681685

682-
-spec needs_merge(reference(), proplist:proplist()) -> {true, {[string()], [string()]}} | false.
686+
-spec needs_merge(reference(), proplists:proplist()) -> {true, {[string()], [string()]}} | false.
683687
needs_merge(Ref, Opts) ->
684688
State = get_state(Ref),
685689
{_KeyCount, Summary} = summary_info(Ref),
@@ -2977,7 +2981,10 @@ total_byte_stats_test() ->
29772981
?assertEqual(ExpFiles1, Files1),
29782982
bitcask:close(B).
29792983

2980-
merge_batch_test() ->
2984+
merge_batch_test_() ->
2985+
{timeout, 100, fun merge_batch_test2/0}.
2986+
2987+
merge_batch_test2() ->
29812988
Dir = "/tmp/bc.merge.batch",
29822989
% Create a valid Bitcask dir with files 10-20 present only
29832990
DataSet = [{integer_to_binary(N), <<"data">>} || N <- lists:seq(1,20)],

src/bitcask_file.erl

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ handle_cast(_Msg, State) ->
190190

191191
handle_info({'DOWN', _Ref, _, _Pid, _Status}, State=#state{fd=Fd}) ->
192192
%% Owner has stopped, close file and shutdown
193-
ok = file:close(Fd),
193+
_ = file:close(Fd),
194194
{stop, normal, State};
195195
handle_info(_Info, State) ->
196196
{noreply, State}.

test/bitcask_pulse.erl

+39-6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ not_commands(Module, State) ->
6969
?LET(Cmds, commands(Module, State),
7070
uncommand(Cmds)).
7171

72+
gen_make_merge_file() ->
73+
%% {true|false, Seed, Probability}
74+
{
75+
frequency([{100, false}, {109999, true}]),
76+
noshrink({choose(0, 500), choose(0, 500), choose(0, 500)}),
77+
%% weighting: use either 100% or 1-100%
78+
frequency([{2, 100}, {8, choose(1, 100)}])
79+
}.
80+
7281
%% Command generator. S is the state.
7382
command(S) ->
7483
frequency(
@@ -94,7 +103,7 @@ command(S) ->
94103
%% race bugs, so keep doing it.
95104
[ {50, {call, ?MODULE, delete, [S#state.handle, key()]}}
96105
|| S#state.is_writer, S#state.handle /= undefined ] ++
97-
[ {2, {call, ?MODULE, bc_open, [S#state.is_writer]}}
106+
[ {2, {call, ?MODULE, bc_open, [S#state.is_writer, gen_make_merge_file()]}}
98107
|| S#state.handle == undefined ] ++
99108
[ {2, {call, ?MODULE, sync, [S#state.handle]}}
100109
|| S#state.handle /= undefined ] ++
@@ -156,7 +165,7 @@ precondition(S, {call, _, kill, [Pid]}) ->
156165
(Pid == bitcask_merge_worker orelse lists:member(Pid, S#state.readers));
157166
precondition(S, {call, _, bc_close, [H]}) ->
158167
S#state.handle == H;
159-
precondition(S, {call, _, bc_open, [Writer]}) ->
168+
precondition(S, {call, _, bc_open, [Writer, _MakeMergeFile]}) ->
160169
%% The writer can open for reading but not the other way around.
161170
S#state.is_writer >= Writer andalso S#state.handle == undefined.
162171

@@ -223,7 +232,7 @@ postcondition(_S, {call, _, needs_merge, _}, V) ->
223232
false -> true;
224233
_ -> {needs_merge, V}
225234
end;
226-
postcondition(_S, {call, _, bc_open, [IsWriter]}, V) ->
235+
postcondition(_S, {call, _, bc_open, [IsWriter, _MakeMergeFile]}, V) ->
227236
case V of
228237
_ when is_reference(V) andalso IsWriter -> check_no_tombstones(V, true);
229238
_ when is_reference(V) -> true;
@@ -361,7 +370,9 @@ prop_pulse(LocalOrSlave, Verbose, KeepFiles) ->
361370
{badrpc, timeout} = Bad ->
362371
io:format(user, "GOT ~p, aborting. Stop PULSE and restart!\n", [Bad]),
363372
exit({stopping, Bad});
364-
{H, S, Res, PidRs, Trace, Schedule, Errors} ->
373+
{H, S, Res, PidRs, Trace, Schedule, Errors0} ->
374+
Errors = [E || E <- Errors0,
375+
re:run(element(2, E), "Invalid merge input") == nomatch],
365376
?WHENFAIL(
366377
?QC_FMT("\nState: ~p\n", [S]),
367378
aggregate(zipwith(fun command_data/2, Cmds, H),
@@ -422,7 +433,7 @@ prop_pulse_test_() ->
422433
end,
423434
io:format(user, "prop_pulse_test time: ~p + ~p seconds\n",
424435
[Timeout, ExtraTO]),
425-
{timeout, (Timeout+ExtraTO),
436+
{timeout, (Timeout+ExtraTO+30), % 30 = a bit more fudge time
426437
fun() ->
427438
copy_bitcask_app(),
428439
?assert(eqc:quickcheck(eqc:testing_time(Timeout,
@@ -785,8 +796,13 @@ fold_keys(H) ->
785796
?LOG({fold_keys, H},
786797
?CHECK_HANDLE(H, [], bitcask:fold_keys(H, fun(#bitcask_entry{key = Kb}, Ks) -> [un_nice_key(Kb)|Ks] end, []))).
787798

788-
bc_open(Writer) ->
799+
bc_open(Writer, {MakeMergeFileP, Seed, Probability}) ->
789800
erlang:put(?BITCASK_TESTING_KEY, ?MODULE),
801+
if MakeMergeFileP ->
802+
make_merge_file(?BITCASK, Seed, Probability);
803+
true ->
804+
ok
805+
end,
790806
?LOG({open, Writer},
791807
case Writer of
792808
true -> catch bitcask:open(?BITCASK, [read_write, {max_file_size, ?FILE_SIZE}, {open_timeout, 1234}]);
@@ -1091,4 +1107,21 @@ check_no_tombstones(Ref, Good) ->
10911107
{check_no_tombstones, Else}
10921108
end.
10931109

1110+
make_merge_file(Dir, Seed, Probability) ->
1111+
random:seed(Seed),
1112+
case filelib:is_dir(Dir) of
1113+
true ->
1114+
DataFiles = filelib:wildcard("*.data", Dir),
1115+
{ok, FH} = file:open(Dir ++ "/merge.txt", [write]),
1116+
[case random:uniform(100) < Probability of
1117+
true ->
1118+
io:format(FH, "~s\n", [DF]);
1119+
false ->
1120+
ok
1121+
end || DF <- DataFiles],
1122+
ok = file:close(FH);
1123+
false ->
1124+
ok
1125+
end.
1126+
10941127
-endif.

0 commit comments

Comments
 (0)