2016-10-09 22:33:45 +01:00
|
|
|
%% -------- PENCILLER's CLERK ---------
|
|
|
|
%%
|
|
|
|
%% The Penciller's clerk is responsible for compaction work within the Ledger.
|
|
|
|
%%
|
2017-01-12 13:48:43 +00:00
|
|
|
%% The Clerk will periodically poll the Penciller to check there is no work
|
|
|
|
%% at level zero pending completion, and if not the Clerk will examine the
|
|
|
|
%% manifest to see if work is necessary.
|
2016-10-09 22:33:45 +01:00
|
|
|
%%
|
|
|
|
%% -------- COMMITTING MANIFEST CHANGES ---------
|
|
|
|
%%
|
2016-12-29 02:07:14 +00:00
|
|
|
%% Once the Penciller has taken a manifest change, the SST file owners which no
|
2016-10-09 22:33:45 +01:00
|
|
|
%% longer form part of the manifest will be marked for delete. By marking for
|
|
|
|
%% deletion, the owners will poll to confirm when it is safe for them to be
|
|
|
|
%% deleted.
|
|
|
|
%%
|
|
|
|
%% It is imperative that the file is not marked for deletion until it is
|
|
|
|
%% certain that the manifest change has been committed. Some uncollected
|
|
|
|
%% garbage is considered acceptable.
|
|
|
|
%%
|
2017-01-12 13:48:43 +00:00
|
|
|
|
2016-07-22 16:57:28 +01:00
|
|
|
|
2016-09-20 16:13:36 +01:00
|
|
|
-module(leveled_pclerk).
|
2016-07-22 16:57:28 +01:00
|
|
|
|
2016-08-09 16:09:29 +01:00
|
|
|
-behaviour(gen_server).
|
|
|
|
|
2016-10-18 01:59:03 +01:00
|
|
|
-include("include/leveled.hrl").
|
2016-08-09 16:09:29 +01:00
|
|
|
|
2017-01-13 18:23:57 +00:00
|
|
|
-export([
|
|
|
|
init/1,
|
2016-08-09 16:09:29 +01:00
|
|
|
handle_call/3,
|
|
|
|
handle_cast/2,
|
|
|
|
handle_info/2,
|
|
|
|
terminate/2,
|
2017-01-13 18:23:57 +00:00
|
|
|
code_change/3
|
|
|
|
]).
|
|
|
|
|
|
|
|
-export([
|
|
|
|
clerk_new/2,
|
2016-10-30 18:25:30 +00:00
|
|
|
clerk_prompt/1,
|
2017-01-15 00:52:43 +00:00
|
|
|
clerk_push/2,
|
2017-01-17 10:12:15 +00:00
|
|
|
clerk_close/1,
|
|
|
|
clerk_promptdeletions/2
|
2017-01-13 18:23:57 +00:00
|
|
|
]).
|
2016-07-22 16:57:28 +01:00
|
|
|
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
|
2017-01-15 00:52:43 +00:00
|
|
|
-define(MAX_TIMEOUT, 2000).
|
2017-01-13 18:23:57 +00:00
|
|
|
-define(MIN_TIMEOUT, 200).
|
2016-08-12 01:05:59 +01:00
|
|
|
|
2016-10-08 22:15:48 +01:00
|
|
|
-record(state, {owner :: pid(),
|
2017-01-17 10:12:15 +00:00
|
|
|
root_path :: string(),
|
2017-01-17 19:01:59 +00:00
|
|
|
pending_deletions = dict:new() % OTP 16 does not like type
|
|
|
|
}).
|
2016-08-09 16:09:29 +01:00
|
|
|
|
|
|
|
%%%============================================================================
|
|
|
|
%%% API
|
|
|
|
%%%============================================================================
|
|
|
|
|
2017-01-12 13:48:43 +00:00
|
|
|
clerk_new(Owner, Manifest) ->
|
2016-08-09 16:09:29 +01:00
|
|
|
{ok, Pid} = gen_server:start(?MODULE, [], []),
|
2017-01-12 13:48:43 +00:00
|
|
|
ok = gen_server:call(Pid, {load, Owner, Manifest}, infinity),
|
2016-11-02 18:14:46 +00:00
|
|
|
leveled_log:log("PC001", [Pid, Owner]),
|
2016-08-09 16:09:29 +01:00
|
|
|
{ok, Pid}.
|
|
|
|
|
2016-10-30 18:25:30 +00:00
|
|
|
clerk_prompt(Pid) ->
|
2016-10-08 22:15:48 +01:00
|
|
|
gen_server:cast(Pid, prompt).
|
2016-08-15 16:43:39 +01:00
|
|
|
|
2017-01-17 10:12:15 +00:00
|
|
|
clerk_promptdeletions(Pid, ManifestSQN) ->
|
|
|
|
gen_server:cast(Pid, {prompt_deletions, ManifestSQN}).
|
|
|
|
|
2017-01-15 00:52:43 +00:00
|
|
|
clerk_push(Pid, Work) ->
|
|
|
|
gen_server:cast(Pid, {push_work, Work}).
|
|
|
|
|
2017-01-12 13:48:43 +00:00
|
|
|
clerk_close(Pid) ->
|
2017-01-14 22:59:04 +00:00
|
|
|
gen_server:call(Pid, close, 20000).
|
2016-10-27 20:56:18 +01:00
|
|
|
|
2016-08-09 16:09:29 +01:00
|
|
|
%%%============================================================================
|
|
|
|
%%% gen_server callbacks
|
|
|
|
%%%============================================================================
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
{ok, #state{}}.
|
2016-07-22 16:57:28 +01:00
|
|
|
|
2017-01-13 18:23:57 +00:00
|
|
|
handle_call({load, Owner, RootPath}, _From, State) ->
|
2017-01-14 22:59:04 +00:00
|
|
|
{reply, ok, State#state{owner=Owner, root_path=RootPath}, ?MIN_TIMEOUT};
|
|
|
|
handle_call(close, _From, State) ->
|
|
|
|
{stop, normal, ok, State}.
|
2016-10-08 22:15:48 +01:00
|
|
|
|
|
|
|
handle_cast(prompt, State) ->
|
2017-01-15 00:52:43 +00:00
|
|
|
handle_info(timeout, State);
|
|
|
|
handle_cast({push_work, Work}, State) ->
|
2017-01-17 10:12:15 +00:00
|
|
|
{ManifestSQN, Deletions} = handle_work(Work, State),
|
|
|
|
PDs = dict:store(ManifestSQN, Deletions, State#state.pending_deletions),
|
Resolve pclerk crash
Need to add extra logging to understand why pclerk crashes in some
volume tests.
Penciller's Clerk <0.813.0> shutdown now complete for reason
{badarg,[{dict,fetch,[63,{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}],[{file,[100,105,99,116,46,101,114,108]},{line,126}]},{leveled_pclerk,handle_cast,2,[{file,[115,114,99,47,108,101,118,101,108,101,100,95,112,99,108,101,114,107,46,101,114,108]},{line,96}]},{gen_server,handle_msg,5,[{file,[103,101,110,95,115,101,114,118,101,114,46,101,114,108]},{line,604}]},{proc_lib,init_p_do_apply,3,[{file,[112,114,111,99,95,108,105,98,46,101,114,108]},{line,239}]}]}
Should only be prompted after prompt deletions had bene updated.
Perhaps a race whereby somehow it is prompted again after it is emptied.
2017-02-09 14:33:39 +00:00
|
|
|
leveled_log:log("PC022", [ManifestSQN]),
|
2017-01-17 10:12:15 +00:00
|
|
|
{noreply, State#state{pending_deletions = PDs}, ?MAX_TIMEOUT};
|
|
|
|
handle_cast({prompt_deletions, ManifestSQN}, State) ->
|
Resolve pclerk crash
Need to add extra logging to understand why pclerk crashes in some
volume tests.
Penciller's Clerk <0.813.0> shutdown now complete for reason
{badarg,[{dict,fetch,[63,{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}],[{file,[100,105,99,116,46,101,114,108]},{line,126}]},{leveled_pclerk,handle_cast,2,[{file,[115,114,99,47,108,101,118,101,108,101,100,95,112,99,108,101,114,107,46,101,114,108]},{line,96}]},{gen_server,handle_msg,5,[{file,[103,101,110,95,115,101,114,118,101,114,46,101,114,108]},{line,604}]},{proc_lib,init_p_do_apply,3,[{file,[112,114,111,99,95,108,105,98,46,101,114,108]},{line,239}]}]}
Should only be prompted after prompt deletions had bene updated.
Perhaps a race whereby somehow it is prompted again after it is emptied.
2017-02-09 14:33:39 +00:00
|
|
|
{Deletions, UpdD} = return_deletions(ManifestSQN,
|
|
|
|
State#state.pending_deletions),
|
2017-01-17 10:12:15 +00:00
|
|
|
ok = notify_deletions(Deletions, State#state.owner),
|
Resolve pclerk crash
Need to add extra logging to understand why pclerk crashes in some
volume tests.
Penciller's Clerk <0.813.0> shutdown now complete for reason
{badarg,[{dict,fetch,[63,{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}],[{file,[100,105,99,116,46,101,114,108]},{line,126}]},{leveled_pclerk,handle_cast,2,[{file,[115,114,99,47,108,101,118,101,108,101,100,95,112,99,108,101,114,107,46,101,114,108]},{line,96}]},{gen_server,handle_msg,5,[{file,[103,101,110,95,115,101,114,118,101,114,46,101,114,108]},{line,604}]},{proc_lib,init_p_do_apply,3,[{file,[112,114,111,99,95,108,105,98,46,101,114,108]},{line,239}]}]}
Should only be prompted after prompt deletions had bene updated.
Perhaps a race whereby somehow it is prompted again after it is emptied.
2017-02-09 14:33:39 +00:00
|
|
|
{noreply, State#state{pending_deletions = UpdD}, ?MIN_TIMEOUT}.
|
2016-10-08 22:15:48 +01:00
|
|
|
|
2017-01-13 18:23:57 +00:00
|
|
|
handle_info(timeout, State) ->
|
2017-01-15 00:52:43 +00:00
|
|
|
request_work(State),
|
|
|
|
{noreply, State, ?MAX_TIMEOUT}.
|
2016-08-09 16:09:29 +01:00
|
|
|
|
2016-10-21 21:26:28 +01:00
|
|
|
terminate(Reason, _State) ->
|
2016-11-02 18:14:46 +00:00
|
|
|
leveled_log:log("PC005", [self(), Reason]).
|
2016-08-09 16:09:29 +01:00
|
|
|
|
|
|
|
code_change(_OldVsn, State, _Extra) ->
|
|
|
|
{ok, State}.
|
|
|
|
|
|
|
|
|
|
|
|
%%%============================================================================
|
|
|
|
%%% Internal functions
|
|
|
|
%%%============================================================================
|
|
|
|
|
2017-01-15 00:52:43 +00:00
|
|
|
request_work(State) ->
|
|
|
|
ok = leveled_penciller:pcl_workforclerk(State#state.owner).
|
|
|
|
|
|
|
|
handle_work({SrcLevel, Manifest}, State) ->
|
|
|
|
{UpdManifest, EntriesToDelete} = merge(SrcLevel,
|
|
|
|
Manifest,
|
|
|
|
State#state.root_path),
|
|
|
|
leveled_log:log("PC007", []),
|
2017-01-15 10:36:50 +00:00
|
|
|
SWMC = os:timestamp(),
|
2017-01-15 00:52:43 +00:00
|
|
|
ok = leveled_penciller:pcl_manifestchange(State#state.owner,
|
|
|
|
UpdManifest),
|
2017-01-15 10:36:50 +00:00
|
|
|
leveled_log:log_timer("PC017", [], SWMC),
|
|
|
|
SWSM = os:timestamp(),
|
2017-01-17 14:11:50 +00:00
|
|
|
ok = leveled_pmanifest:save_manifest(UpdManifest,
|
2017-01-15 00:52:43 +00:00
|
|
|
State#state.root_path),
|
2017-01-15 10:36:50 +00:00
|
|
|
leveled_log:log_timer("PC018", [], SWSM),
|
2017-01-17 14:11:50 +00:00
|
|
|
{leveled_pmanifest:get_manifest_sqn(UpdManifest), EntriesToDelete}.
|
2016-08-12 01:05:59 +01:00
|
|
|
|
2017-01-13 18:23:57 +00:00
|
|
|
merge(SrcLevel, Manifest, RootPath) ->
|
2017-01-17 14:11:50 +00:00
|
|
|
Src = leveled_pmanifest:mergefile_selector(Manifest, SrcLevel),
|
|
|
|
NewSQN = leveled_pmanifest:get_manifest_sqn(Manifest) + 1,
|
|
|
|
SinkList = leveled_pmanifest:merge_lookup(Manifest,
|
2017-01-13 18:23:57 +00:00
|
|
|
SrcLevel + 1,
|
|
|
|
Src#manifest_entry.start_key,
|
|
|
|
Src#manifest_entry.end_key),
|
|
|
|
Candidates = length(SinkList),
|
|
|
|
leveled_log:log("PC008", [SrcLevel, Candidates]),
|
|
|
|
case Candidates of
|
2016-08-09 16:09:29 +01:00
|
|
|
0 ->
|
2016-11-02 18:14:46 +00:00
|
|
|
leveled_log:log("PC009",
|
2017-01-13 18:23:57 +00:00
|
|
|
[Src#manifest_entry.filename, SrcLevel + 1]),
|
2017-01-17 14:11:50 +00:00
|
|
|
Man0 = leveled_pmanifest:switch_manifest_entry(Manifest,
|
2017-01-13 18:23:57 +00:00
|
|
|
NewSQN,
|
|
|
|
SrcLevel,
|
|
|
|
Src),
|
2017-01-17 10:12:15 +00:00
|
|
|
{Man0, []};
|
2016-08-09 16:09:29 +01:00
|
|
|
_ ->
|
2017-03-09 21:32:36 +00:00
|
|
|
SST_RP = leveled_penciller:sst_rootpath(RootPath),
|
|
|
|
perform_merge(Manifest, Src, SinkList, SrcLevel, SST_RP, NewSQN)
|
2016-08-10 13:02:08 +01:00
|
|
|
end.
|
|
|
|
|
2017-01-13 18:23:57 +00:00
|
|
|
notify_deletions([], _Penciller) ->
|
2016-08-10 13:02:08 +01:00
|
|
|
ok;
|
2017-01-13 18:23:57 +00:00
|
|
|
notify_deletions([Head|Tail], Penciller) ->
|
2016-12-29 02:07:14 +00:00
|
|
|
ok = leveled_sst:sst_setfordelete(Head#manifest_entry.owner, Penciller),
|
2017-01-13 18:23:57 +00:00
|
|
|
notify_deletions(Tail, Penciller).
|
|
|
|
|
2016-07-22 16:57:28 +01:00
|
|
|
|
2016-12-29 02:07:14 +00:00
|
|
|
%% Assumption is that there is a single SST from a higher level that needs
|
2017-01-13 18:23:57 +00:00
|
|
|
%% to be merged into multiple SSTs at a lower level.
|
2016-07-22 16:57:28 +01:00
|
|
|
%%
|
2017-01-13 18:23:57 +00:00
|
|
|
%% SrcLevel is the level of the src sst file, the sink should be srcLevel + 1
|
|
|
|
|
|
|
|
perform_merge(Manifest, Src, SinkList, SrcLevel, RootPath, NewSQN) ->
|
|
|
|
leveled_log:log("PC010", [Src#manifest_entry.filename, NewSQN]),
|
2017-01-17 10:12:15 +00:00
|
|
|
SrcList = [{next, Src, all}],
|
2017-01-13 18:23:57 +00:00
|
|
|
MaxSQN = leveled_sst:sst_getmaxsequencenumber(Src#manifest_entry.owner),
|
|
|
|
SinkLevel = SrcLevel + 1,
|
2017-01-17 14:11:50 +00:00
|
|
|
SinkBasement = leveled_pmanifest:is_basement(Manifest, SinkLevel),
|
2017-01-17 10:12:15 +00:00
|
|
|
Additions = do_merge(SrcList, SinkList,
|
|
|
|
SinkLevel, SinkBasement,
|
|
|
|
RootPath, NewSQN, MaxSQN,
|
|
|
|
[]),
|
|
|
|
RevertPointerFun =
|
|
|
|
fun({next, ME, _SK}) ->
|
|
|
|
ME
|
|
|
|
end,
|
2017-01-17 10:21:29 +00:00
|
|
|
SinkManifestList = lists:map(RevertPointerFun, SinkList),
|
2017-01-23 11:02:54 +00:00
|
|
|
Man0 = leveled_pmanifest:replace_manifest_entry(Manifest,
|
2017-01-17 10:12:15 +00:00
|
|
|
NewSQN,
|
|
|
|
SinkLevel,
|
2017-01-23 11:02:54 +00:00
|
|
|
SinkManifestList,
|
2017-01-17 10:37:46 +00:00
|
|
|
Additions),
|
2017-01-23 11:02:54 +00:00
|
|
|
Man2 = leveled_pmanifest:remove_manifest_entry(Man0,
|
2017-01-17 10:12:15 +00:00
|
|
|
NewSQN,
|
|
|
|
SrcLevel,
|
|
|
|
Src),
|
2017-01-17 10:21:29 +00:00
|
|
|
{Man2, [Src|SinkManifestList]}.
|
2017-01-13 18:23:57 +00:00
|
|
|
|
2017-01-17 10:12:15 +00:00
|
|
|
do_merge([], [], SinkLevel, _SinkB, _RP, NewSQN, _MaxSQN, Additions) ->
|
|
|
|
leveled_log:log("PC011", [NewSQN, SinkLevel, length(Additions)]),
|
|
|
|
Additions;
|
|
|
|
do_merge(KL1, KL2, SinkLevel, SinkB, RP, NewSQN, MaxSQN, Additions) ->
|
2017-03-09 21:23:09 +00:00
|
|
|
FileName = leveled_penciller:sst_filename(NewSQN,
|
|
|
|
SinkLevel,
|
|
|
|
length(Additions)),
|
2017-01-14 21:19:51 +00:00
|
|
|
leveled_log:log("PC012", [NewSQN, FileName, SinkB]),
|
2016-08-10 13:02:08 +01:00
|
|
|
TS1 = os:timestamp(),
|
2017-03-09 21:23:09 +00:00
|
|
|
case leveled_sst:sst_new(RP, FileName,
|
|
|
|
KL1, KL2, SinkB, SinkLevel, MaxSQN) of
|
2016-12-29 05:09:47 +00:00
|
|
|
empty ->
|
2016-11-02 18:14:46 +00:00
|
|
|
leveled_log:log("PC013", [FileName]),
|
2017-01-17 10:12:15 +00:00
|
|
|
do_merge([], [],
|
|
|
|
SinkLevel, SinkB,
|
|
|
|
RP, NewSQN, MaxSQN,
|
|
|
|
Additions);
|
2016-12-29 09:35:58 +00:00
|
|
|
{ok, Pid, Reply} ->
|
|
|
|
{{KL1Rem, KL2Rem}, SmallestKey, HighestKey} = Reply,
|
2017-01-13 18:23:57 +00:00
|
|
|
Entry = #manifest_entry{start_key=SmallestKey,
|
|
|
|
end_key=HighestKey,
|
|
|
|
owner=Pid,
|
|
|
|
filename=FileName},
|
2016-12-29 09:35:58 +00:00
|
|
|
leveled_log:log_timer("PC015", [], TS1),
|
|
|
|
do_merge(KL1Rem, KL2Rem,
|
2017-01-13 18:23:57 +00:00
|
|
|
SinkLevel, SinkB,
|
|
|
|
RP, NewSQN, MaxSQN,
|
2017-01-17 10:12:15 +00:00
|
|
|
Additions ++ [Entry])
|
2016-08-09 16:09:29 +01:00
|
|
|
end.
|
2016-07-22 16:57:28 +01:00
|
|
|
|
|
|
|
|
Resolve pclerk crash
Need to add extra logging to understand why pclerk crashes in some
volume tests.
Penciller's Clerk <0.813.0> shutdown now complete for reason
{badarg,[{dict,fetch,[63,{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}],[{file,[100,105,99,116,46,101,114,108]},{line,126}]},{leveled_pclerk,handle_cast,2,[{file,[115,114,99,47,108,101,118,101,108,101,100,95,112,99,108,101,114,107,46,101,114,108]},{line,96}]},{gen_server,handle_msg,5,[{file,[103,101,110,95,115,101,114,118,101,114,46,101,114,108]},{line,604}]},{proc_lib,init_p_do_apply,3,[{file,[112,114,111,99,95,108,105,98,46,101,114,108]},{line,239}]}]}
Should only be prompted after prompt deletions had bene updated.
Perhaps a race whereby somehow it is prompted again after it is emptied.
2017-02-09 14:33:39 +00:00
|
|
|
return_deletions(ManifestSQN, PendingDeletionD) ->
|
2017-02-09 23:49:12 +00:00
|
|
|
% The returning of deletions had been seperated out as a failure to fetch
|
|
|
|
% here had caased crashes of the clerk. The root cause of the failure to
|
|
|
|
% fetch was the same clerk being asked to do the same work twice - and this
|
|
|
|
% should be blocked now by the ongoing_work boolean in the Penciller
|
|
|
|
% LoopData
|
|
|
|
%
|
|
|
|
% So this is now allowed to crash again
|
|
|
|
PendingDeletions = dict:fetch(ManifestSQN, PendingDeletionD),
|
|
|
|
leveled_log:log("PC021", [ManifestSQN]),
|
|
|
|
{PendingDeletions, dict:erase(ManifestSQN, PendingDeletionD)}.
|
Resolve pclerk crash
Need to add extra logging to understand why pclerk crashes in some
volume tests.
Penciller's Clerk <0.813.0> shutdown now complete for reason
{badarg,[{dict,fetch,[63,{dict,0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}],[{file,[100,105,99,116,46,101,114,108]},{line,126}]},{leveled_pclerk,handle_cast,2,[{file,[115,114,99,47,108,101,118,101,108,101,100,95,112,99,108,101,114,107,46,101,114,108]},{line,96}]},{gen_server,handle_msg,5,[{file,[103,101,110,95,115,101,114,118,101,114,46,101,114,108]},{line,604}]},{proc_lib,init_p_do_apply,3,[{file,[112,114,111,99,95,108,105,98,46,101,114,108]},{line,239}]}]}
Should only be prompted after prompt deletions had bene updated.
Perhaps a race whereby somehow it is prompted again after it is emptied.
2017-02-09 14:33:39 +00:00
|
|
|
|
2016-07-22 16:57:28 +01:00
|
|
|
%%%============================================================================
|
|
|
|
%%% Test
|
|
|
|
%%%============================================================================
|
|
|
|
|
2016-10-09 22:33:45 +01:00
|
|
|
-ifdef(TEST).
|
2016-07-22 16:57:28 +01:00
|
|
|
|
|
|
|
generate_randomkeys(Count, BucketRangeLow, BucketRangeHigh) ->
|
|
|
|
generate_randomkeys(Count, [], BucketRangeLow, BucketRangeHigh).
|
|
|
|
|
|
|
|
generate_randomkeys(0, Acc, _BucketLow, _BucketHigh) ->
|
|
|
|
Acc;
|
|
|
|
generate_randomkeys(Count, Acc, BucketLow, BRange) ->
|
|
|
|
BNumber = string:right(integer_to_list(BucketLow + random:uniform(BRange)),
|
|
|
|
4, $0),
|
|
|
|
KNumber = string:right(integer_to_list(random:uniform(1000)), 4, $0),
|
2016-12-11 01:02:56 +00:00
|
|
|
K = {o, "Bucket" ++ BNumber, "Key" ++ KNumber},
|
|
|
|
RandKey = {K, {Count + 1,
|
|
|
|
{active, infinity},
|
|
|
|
leveled_codec:magic_hash(K),
|
|
|
|
null}},
|
2016-07-22 16:57:28 +01:00
|
|
|
generate_randomkeys(Count - 1, [RandKey|Acc], BucketLow, BRange).
|
|
|
|
|
|
|
|
|
|
|
|
merge_file_test() ->
|
2016-12-11 20:17:05 +00:00
|
|
|
KL1_L1 = lists:sort(generate_randomkeys(8000, 0, 1000)),
|
2017-03-09 21:23:09 +00:00
|
|
|
{ok, PidL1_1, _} = leveled_sst:sst_new("../test/",
|
|
|
|
"KL1_L1.sst",
|
2016-12-29 02:07:14 +00:00
|
|
|
1,
|
|
|
|
KL1_L1,
|
2017-05-18 12:29:56 +01:00
|
|
|
999999),
|
2016-12-11 20:17:05 +00:00
|
|
|
KL1_L2 = lists:sort(generate_randomkeys(8000, 0, 250)),
|
2017-03-09 21:23:09 +00:00
|
|
|
{ok, PidL2_1, _} = leveled_sst:sst_new("../test/",
|
|
|
|
"KL1_L2.sst",
|
2016-12-29 02:07:14 +00:00
|
|
|
2,
|
|
|
|
KL1_L2,
|
2017-05-18 12:29:56 +01:00
|
|
|
999999),
|
2016-12-11 20:17:05 +00:00
|
|
|
KL2_L2 = lists:sort(generate_randomkeys(8000, 250, 250)),
|
2017-03-09 21:23:09 +00:00
|
|
|
{ok, PidL2_2, _} = leveled_sst:sst_new("../test/",
|
|
|
|
"KL2_L2.sst",
|
2016-12-29 02:07:14 +00:00
|
|
|
2,
|
|
|
|
KL2_L2,
|
2017-05-18 12:29:56 +01:00
|
|
|
999999),
|
2016-12-11 20:17:05 +00:00
|
|
|
KL3_L2 = lists:sort(generate_randomkeys(8000, 500, 250)),
|
2017-03-09 21:23:09 +00:00
|
|
|
{ok, PidL2_3, _} = leveled_sst:sst_new("../test/",
|
|
|
|
"KL3_L2.sst",
|
2016-12-29 02:07:14 +00:00
|
|
|
2,
|
|
|
|
KL3_L2,
|
2017-05-18 12:29:56 +01:00
|
|
|
999999),
|
2016-12-11 20:17:05 +00:00
|
|
|
KL4_L2 = lists:sort(generate_randomkeys(8000, 750, 250)),
|
2017-03-09 21:23:09 +00:00
|
|
|
{ok, PidL2_4, _} = leveled_sst:sst_new("../test/",
|
|
|
|
"KL4_L2.sst",
|
2016-12-29 02:07:14 +00:00
|
|
|
2,
|
|
|
|
KL4_L2,
|
2017-05-18 12:29:56 +01:00
|
|
|
999999),
|
2017-01-15 01:47:23 +00:00
|
|
|
|
|
|
|
E1 = #manifest_entry{owner = PidL1_1,
|
2017-03-09 21:23:09 +00:00
|
|
|
filename = "./KL1_L1.sst",
|
2017-01-15 01:47:23 +00:00
|
|
|
end_key = lists:last(KL1_L1),
|
|
|
|
start_key = lists:nth(1, KL1_L1)},
|
|
|
|
E2 = #manifest_entry{owner = PidL2_1,
|
2017-03-09 21:23:09 +00:00
|
|
|
filename = "./KL1_L2.sst",
|
2017-01-15 01:47:23 +00:00
|
|
|
end_key = lists:last(KL1_L2),
|
|
|
|
start_key = lists:nth(1, KL1_L2)},
|
|
|
|
E3 = #manifest_entry{owner = PidL2_2,
|
2017-03-09 21:23:09 +00:00
|
|
|
filename = "./KL2_L2.sst",
|
2017-01-15 01:47:23 +00:00
|
|
|
end_key = lists:last(KL2_L2),
|
|
|
|
start_key = lists:nth(1, KL2_L2)},
|
|
|
|
E4 = #manifest_entry{owner = PidL2_3,
|
2017-03-09 21:23:09 +00:00
|
|
|
filename = "./KL3_L2.sst",
|
2017-01-15 01:47:23 +00:00
|
|
|
end_key = lists:last(KL3_L2),
|
|
|
|
start_key = lists:nth(1, KL3_L2)},
|
|
|
|
E5 = #manifest_entry{owner = PidL2_4,
|
2017-03-09 21:23:09 +00:00
|
|
|
filename = "./KL4_L2.sst",
|
2017-01-15 01:47:23 +00:00
|
|
|
end_key = lists:last(KL4_L2),
|
|
|
|
start_key = lists:nth(1, KL4_L2)},
|
2017-01-13 18:23:57 +00:00
|
|
|
|
2017-01-17 14:11:50 +00:00
|
|
|
Man0 = leveled_pmanifest:new_manifest(),
|
|
|
|
Man1 = leveled_pmanifest:insert_manifest_entry(Man0, 1, 2, E2),
|
|
|
|
Man2 = leveled_pmanifest:insert_manifest_entry(Man1, 1, 2, E3),
|
|
|
|
Man3 = leveled_pmanifest:insert_manifest_entry(Man2, 1, 2, E4),
|
|
|
|
Man4 = leveled_pmanifest:insert_manifest_entry(Man3, 1, 2, E5),
|
|
|
|
Man5 = leveled_pmanifest:insert_manifest_entry(Man4, 2, 1, E1),
|
2017-01-13 18:23:57 +00:00
|
|
|
|
2017-01-17 10:12:15 +00:00
|
|
|
PointerList = lists:map(fun(ME) -> {next, ME, all} end,
|
|
|
|
[E2, E3, E4, E5]),
|
|
|
|
{Man6, _Dels} = perform_merge(Man5, E1, PointerList, 1, "../test", 3),
|
2017-01-13 18:23:57 +00:00
|
|
|
|
2017-01-17 14:11:50 +00:00
|
|
|
?assertMatch(3, leveled_pmanifest:get_manifest_sqn(Man6)).
|
2016-10-09 22:33:45 +01:00
|
|
|
|
2016-11-14 20:43:38 +00:00
|
|
|
coverage_cheat_test() ->
|
|
|
|
{ok, _State1} = code_change(null, #state{}, null).
|
|
|
|
|
2016-11-05 17:50:28 +00:00
|
|
|
-endif.
|