Roll in fix for intermittently failing test

As descibed in https://github.com/martinsumner/leveled/issues/92

Only the first fix was made.

Just to eb safe - archiving means renaming to another file with a different extension.  Assumption is that renamed files cna be manually reaped if necessary.
This commit is contained in:
Martin Sumner 2017-09-27 23:52:49 +01:00
parent 433cc37eb6
commit 3950942da3
5 changed files with 138 additions and 52 deletions

View file

@ -620,7 +620,7 @@ build_metadata_object(PrimaryKey, MD) ->
%% The metadata object should be returned with the full list of last %% The metadata object should be returned with the full list of last
%% modified dates (which will be used for recent anti-entropy index creation) %% modified dates (which will be used for recent anti-entropy index creation)
riak_extract_metadata(delete, Size) -> riak_extract_metadata(delete, Size) ->
{{delete, null, null, null, Size}, []}; {{delete, null, null, Size}, []};
riak_extract_metadata(ObjBin, Size) -> riak_extract_metadata(ObjBin, Size) ->
{VclockBin, SibBin, LastMods} = riak_metadata_from_binary(ObjBin), {VclockBin, SibBin, LastMods} = riak_metadata_from_binary(ObjBin),
{{SibBin, {{SibBin,

View file

@ -120,7 +120,8 @@
{"P0030", {"P0030",
{warn, "We're doomed - intention recorded to destroy all files"}}, {warn, "We're doomed - intention recorded to destroy all files"}},
{"P0031", {"P0031",
{info, "Completion of update to levelzero"}}, {info, "Completion of update to levelzero"
++ " with cache size status ~w ~w"}},
{"P0032", {"P0032",
{info, "Head timing for result ~w is sample ~w total ~w and max ~w"}}, {info, "Head timing for result ~w is sample ~w total ~w and max ~w"}},
{"P0033", {"P0033",
@ -141,6 +142,8 @@
{"P0039", {"P0039",
{info, "Failed to release pid=~w " {info, "Failed to release pid=~w "
++ "leaving SnapshotCount=~w and MinSQN=~w"}}, ++ "leaving SnapshotCount=~w and MinSQN=~w"}},
{"P0040",
{info, "Archiving filename ~s as unused at startup"}},
{"PC001", {"PC001",
{info, "Penciller's clerk ~w started with owner ~w"}}, {info, "Penciller's clerk ~w started with owner ~w"}},

View file

@ -206,6 +206,8 @@
-define(FILES_FP, "ledger_files"). -define(FILES_FP, "ledger_files").
-define(CURRENT_FILEX, "crr"). -define(CURRENT_FILEX, "crr").
-define(PENDING_FILEX, "pnd"). -define(PENDING_FILEX, "pnd").
-define(SST_FILEX, ".sst").
-define(ARCHIVE_FILEX, ".bak").
-define(MEMTABLE, mem). -define(MEMTABLE, mem).
-define(MAX_TABLESIZE, 28000). % This is less than max - but COIN_SIDECOUNT -define(MAX_TABLESIZE, 28000). % This is less than max - but COIN_SIDECOUNT
-define(SUPER_MAX_TABLE_SIZE, 40000). -define(SUPER_MAX_TABLE_SIZE, 40000).
@ -819,7 +821,8 @@ sst_rootpath(RootPath) ->
FP. FP.
sst_filename(ManSQN, Level, Count) -> sst_filename(ManSQN, Level, Count) ->
lists:flatten(io_lib:format("./~w_~w_~w.sst", [ManSQN, Level, Count])). lists:flatten(io_lib:format("./~w_~w_~w" ++ ?SST_FILEX,
[ManSQN, Level, Count])).
%%%============================================================================ %%%============================================================================
@ -859,41 +862,73 @@ start_from_file(PCLopts) ->
Pid Pid
end, end,
SQNFun = fun leveled_sst:sst_getmaxsequencenumber/1, SQNFun = fun leveled_sst:sst_getmaxsequencenumber/1,
{MaxSQN, Manifest1} = leveled_pmanifest:load_manifest(Manifest0, {MaxSQN, Manifest1, FileList} =
OpenFun, leveled_pmanifest:load_manifest(Manifest0, OpenFun, SQNFun),
SQNFun),
leveled_log:log("P0014", [MaxSQN]), leveled_log:log("P0014", [MaxSQN]),
ManSQN = leveled_pmanifest:get_manifest_sqn(Manifest1), ManSQN = leveled_pmanifest:get_manifest_sqn(Manifest1),
leveled_log:log("P0035", [ManSQN]), leveled_log:log("P0035", [ManSQN]),
%% Find any L0 files %% Find any L0 files
L0FN = sst_filename(ManSQN + 1, 0, 0), L0FN = sst_filename(ManSQN + 1, 0, 0),
case filelib:is_file(filename:join(sst_rootpath(RootPath), L0FN)) of {State0, FileList0} =
true -> case filelib:is_file(filename:join(sst_rootpath(RootPath), L0FN)) of
leveled_log:log("P0015", [L0FN]), true ->
L0Open = leveled_sst:sst_open(sst_rootpath(RootPath), L0FN), leveled_log:log("P0015", [L0FN]),
{ok, L0Pid, {L0StartKey, L0EndKey}} = L0Open, L0Open = leveled_sst:sst_open(sst_rootpath(RootPath), L0FN),
L0SQN = leveled_sst:sst_getmaxsequencenumber(L0Pid), {ok, L0Pid, {L0StartKey, L0EndKey}} = L0Open,
L0Entry = #manifest_entry{start_key = L0StartKey, L0SQN = leveled_sst:sst_getmaxsequencenumber(L0Pid),
end_key = L0EndKey, L0Entry = #manifest_entry{start_key = L0StartKey,
filename = L0FN, end_key = L0EndKey,
owner = L0Pid}, filename = L0FN,
Manifest2 = leveled_pmanifest:insert_manifest_entry(Manifest1, owner = L0Pid},
ManSQN + 1, Manifest2 = leveled_pmanifest:insert_manifest_entry(Manifest1,
0, ManSQN + 1,
L0Entry), 0,
leveled_log:log("P0016", [L0SQN]), L0Entry),
LedgerSQN = max(MaxSQN, L0SQN), leveled_log:log("P0016", [L0SQN]),
{ok, LedgerSQN = max(MaxSQN, L0SQN),
InitState#state{manifest = Manifest2, {InitState#state{manifest = Manifest2,
ledger_sqn = LedgerSQN, ledger_sqn = LedgerSQN,
persisted_sqn = LedgerSQN}}; persisted_sqn = LedgerSQN},
false -> [L0FN|FileList]};
leveled_log:log("P0017", []), false ->
{ok, leveled_log:log("P0017", []),
InitState#state{manifest = Manifest1, {InitState#state{manifest = Manifest1,
ledger_sqn = MaxSQN, ledger_sqn = MaxSQN,
persisted_sqn = MaxSQN}} persisted_sqn = MaxSQN},
end. FileList}
end,
ok = archive_files(RootPath, FileList0),
{ok, State0}.
archive_files(RootPath, FileList) ->
{ok, AllFiles} = file:list_dir(sst_rootpath(RootPath)),
FileCheckFun =
fun(FN, UnusedFiles) ->
FN0 = "./" ++ FN,
case filename:extension(FN0) of
?SST_FILEX ->
case lists:member(FN0, FileList) of
true ->
UnusedFiles;
false ->
leveled_log:log("P0040", [FN0]),
[FN0|UnusedFiles]
end;
_ ->
UnusedFiles
end
end,
RenameFun =
fun(FN) ->
AltName = filename:join(sst_rootpath(RootPath),
filename:basename(FN, ?SST_FILEX))
++ ?ARCHIVE_FILEX,
file:rename(filename:join(sst_rootpath(RootPath), FN),
AltName)
end,
FilesToArchive = lists:foldl(FileCheckFun, [], AllFiles),
lists:foreach(RenameFun, FilesToArchive),
ok.
update_levelzero(L0Size, {PushedTree, PushedIdx, MinSQN, MaxSQN}, update_levelzero(L0Size, {PushedTree, PushedIdx, MinSQN, MaxSQN},
@ -934,11 +969,13 @@ update_levelzero(L0Size, {PushedTree, PushedIdx, MinSQN, MaxSQN},
case {CacheTooBig, L0Free, JitterCheck, NoPendingManifestChange} of case {CacheTooBig, L0Free, JitterCheck, NoPendingManifestChange} of
{true, true, true, true} -> {true, true, true, true} ->
L0Constructor = roll_memory(UpdState, false), L0Constructor = roll_memory(UpdState, false),
leveled_log:log_timer("P0031", [], SW), leveled_log:log_timer("P0031", [true, true], SW),
UpdState#state{levelzero_pending=true, UpdState#state{levelzero_pending=true,
levelzero_constructor=L0Constructor}; levelzero_constructor=L0Constructor};
_ -> _ ->
leveled_log:log_timer("P0031", [], SW), leveled_log:log_timer("P0031",
[CacheTooBig, JitterCheck],
SW),
UpdState UpdState
end end
end. end.

View file

@ -136,7 +136,8 @@ copy_manifest(Manifest) ->
% about is switched to undefined % about is switched to undefined
Manifest#manifest{snapshots = undefined, pending_deletes = undefined}. Manifest#manifest{snapshots = undefined, pending_deletes = undefined}.
-spec load_manifest(manifest(), fun(), fun()) -> {integer(), manifest()}. -spec load_manifest(manifest(), fun(), fun()) ->
{integer(), manifest(), list()}.
%% @doc %% @doc
%% Roll over the manifest starting a process to manage each file in the %% Roll over the manifest starting a process to manage each file in the
%% manifest. The PidFun should be able to return the Pid of a file process %% manifest. The PidFun should be able to return the Pid of a file process
@ -144,13 +145,15 @@ copy_manifest(Manifest) ->
%% of that file, if passed the Pid that owns it. %% of that file, if passed the Pid that owns it.
load_manifest(Manifest, PidFun, SQNFun) -> load_manifest(Manifest, PidFun, SQNFun) ->
UpdateLevelFun = UpdateLevelFun =
fun(LevelIdx, {AccMaxSQN, AccMan}) -> fun(LevelIdx, {AccMaxSQN, AccMan, AccFL}) ->
L0 = array:get(LevelIdx, AccMan#manifest.levels), L0 = array:get(LevelIdx, AccMan#manifest.levels),
{L1, SQN1} = load_level(LevelIdx, L0, PidFun, SQNFun), {L1, SQN1, FileList} = load_level(LevelIdx, L0, PidFun, SQNFun),
UpdLevels = array:set(LevelIdx, L1, AccMan#manifest.levels), UpdLevels = array:set(LevelIdx, L1, AccMan#manifest.levels),
{max(AccMaxSQN, SQN1), AccMan#manifest{levels = UpdLevels}} {max(AccMaxSQN, SQN1),
AccMan#manifest{levels = UpdLevels},
AccFL ++ FileList}
end, end,
lists:foldl(UpdateLevelFun, {0, Manifest}, lists:foldl(UpdateLevelFun, {0, Manifest, []},
lists:seq(0, Manifest#manifest.basement)). lists:seq(0, Manifest#manifest.basement)).
-spec close_manifest(manifest(), fun()) -> ok. -spec close_manifest(manifest(), fun()) -> ok.
@ -488,27 +491,33 @@ levelzero_present(Manifest) ->
load_level(LevelIdx, Level, PidFun, SQNFun) -> load_level(LevelIdx, Level, PidFun, SQNFun) ->
HigherLevelLoadFun = HigherLevelLoadFun =
fun(ME, {L_Out, L_MaxSQN}) -> fun(ME, {L_Out, L_MaxSQN, FileList}) ->
FN = ME#manifest_entry.filename, FN = ME#manifest_entry.filename,
P = PidFun(FN), P = PidFun(FN),
SQN = SQNFun(P), SQN = SQNFun(P),
{[ME#manifest_entry{owner=P}|L_Out], max(SQN, L_MaxSQN)} {[ME#manifest_entry{owner=P}|L_Out],
max(SQN, L_MaxSQN),
[FN|FileList]}
end, end,
LowerLevelLoadFun = LowerLevelLoadFun =
fun({EK, ME}, {L_Out, L_MaxSQN}) -> fun({EK, ME}, {L_Out, L_MaxSQN, FileList}) ->
FN = ME#manifest_entry.filename, FN = ME#manifest_entry.filename,
P = PidFun(FN), P = PidFun(FN),
SQN = SQNFun(P), SQN = SQNFun(P),
{[{EK, ME#manifest_entry{owner=P}}|L_Out], max(SQN, L_MaxSQN)} {[{EK, ME#manifest_entry{owner=P}}|L_Out],
max(SQN, L_MaxSQN),
[FN|FileList]}
end, end,
case LevelIdx =< 1 of case LevelIdx =< 1 of
true -> true ->
lists:foldr(HigherLevelLoadFun, {[], 0}, Level); lists:foldr(HigherLevelLoadFun, {[], 0, []}, Level);
false -> false ->
{L0, MaxSQN} = lists:foldr(LowerLevelLoadFun, {L0, MaxSQN, Flist} = lists:foldr(LowerLevelLoadFun,
{[], 0}, {[], 0, []},
leveled_tree:to_list(Level)), leveled_tree:to_list(Level)),
{leveled_tree:from_orderedlist(L0, ?TREE_TYPE, ?TREE_WIDTH), MaxSQN} {leveled_tree:from_orderedlist(L0, ?TREE_TYPE, ?TREE_WIDTH),
MaxSQN,
Flist}
end. end.
close_level(LevelIdx, Level, CloseEntryFun) when LevelIdx =< 1 -> close_level(LevelIdx, Level, CloseEntryFun) when LevelIdx =< 1 ->

View file

@ -580,22 +580,59 @@ space_clear_ondelete(_Config) ->
io:format("This should cause a final ledger merge event~n"), io:format("This should cause a final ledger merge event~n"),
io:format("Will require the penciller to resolve the issue of creating" ++ io:format("Will require the penciller to resolve the issue of creating" ++
" an empty file as all keys compact on merge~n"), " an empty file as all keys compact on merge~n"),
timer:sleep(12000),
CheckFun =
fun(X, FileCount) ->
case FileCount of
0 ->
0;
_ ->
timer:sleep(X),
{ok, NewFC} =
file:list_dir(RootPath ++ "/ledger/ledger_files"),
io:format("Looping with ledger file count ~w~n",
[length(NewFC)]),
length(strip_nonsst(NewFC))
end
end,
FC = lists:foldl(CheckFun, infinity, [2000, 3000, 5000, 8000]),
ok = leveled_bookie:book_close(Book3), ok = leveled_bookie:book_close(Book3),
case FC of
0 ->
ok;
_ ->
{ok, Book4} = leveled_bookie:book_start(StartOpts1),
lists:foldl(CheckFun, infinity, [2000, 3000, 5000, 8000]),
leveled_bookie:book_close(Book4)
end,
{ok, FNsD_L} = file:list_dir(RootPath ++ "/ledger/ledger_files"), {ok, FNsD_L} = file:list_dir(RootPath ++ "/ledger/ledger_files"),
io:format("FNsD - Bookie has ~w ledger files " ++ io:format("FNsD - Bookie has ~w ledger files " ++
"after second close~n", [length(FNsD_L)]), "after second close~n", [length(strip_nonsst(FNsD_L))]),
lists:foreach(fun(FN) -> lists:foreach(fun(FN) ->
io:format("FNsD - Ledger file is ~s~n", [FN]) io:format("FNsD - Ledger file is ~s~n", [FN])
end, end,
FNsD_L), FNsD_L),
true = PointB_Journals < length(FNsA_J), true = PointB_Journals < length(FNsA_J),
true = length(FNsD_L) < length(FNsA_L), true = length(strip_nonsst(FNsD_L)) < length(strip_nonsst(FNsA_L)),
true = length(FNsD_L) < length(FNsB_L), true = length(strip_nonsst(FNsD_L)) < length(strip_nonsst(FNsB_L)),
true = length(FNsD_L) < length(FNsC_L), true = length(strip_nonsst(FNsD_L)) < length(strip_nonsst(FNsC_L)),
true = length(FNsD_L) == 0. true = length(strip_nonsst(FNsD_L)) == 0.
strip_nonsst(FileList) ->
SSTOnlyFun =
fun(FN, Acc) ->
case filename:extension(FN) of
".sst" ->
[FN|Acc];
_ ->
Acc
end
end,
lists:foldl(SSTOnlyFun, [], FileList).
is_empty_test(_Config) -> is_empty_test(_Config) ->
RootPath = testutil:reset_filestructure(), RootPath = testutil:reset_filestructure(),