#!/usr/bin/env escript %% -*- erlang -*- %%! -pa ebin -pa ../lager/ebin -pa ../lager/deps/goldrush/ebin -mode(compile). -include_lib("kernel/include/file.hrl"). gentestdata(Size) -> [{crypto:hash(sha256, <>), crypto:hash(sha256, <>)} || E <- lists:seq(0, Size-1)]. timeprint(Time) -> io_lib:format("~.2fs", [Time/1000000]). testinit(Filename) -> permdb:start_link(testdb, Filename). teststop() -> permdb:stop(testdb). constructdata(VSeed, Size) -> A = binary:copy(VSeed, Size div 32), B = binary:part(VSeed, 0, Size rem 32), <>. getvalue_loop([], _Port, _Datasize) -> none; getvalue_loop([{K, VSeed}|Rest], Port, Datasize) -> V = case VSeed of noentry -> noentry; _ -> constructdata(VSeed, Datasize) end, case permdb:getvalue(testdb, K) of V -> getvalue_loop(Rest, Port, Datasize); VOther -> io:format("expected: ~p got: ~p~nkey: ~p~n", [V, VOther, K]), exit(mismatch) end. keyexists_loop([], _Port, _Datasize) -> none; keyexists_loop([{K, VSeed}|Rest], Port, Datasize) -> case permdb:keyexists(testdb, K) of true -> keyexists_loop(Rest, Port, Datasize); false -> io:format("key didn't exist ~p~n", [K]), exit(mismatch) end. addvalue_loop([], _Port, _Datasize) -> none; addvalue_loop([{K, VSeed}|Rest], Port, Datasize) -> V = constructdata(VSeed, Datasize), case permdb:addvalue(testdb, K, V) of ok -> addvalue_loop(Rest, Port, Datasize); Other -> io:format("expected: 0 or 1 got: ~p~n", [Other]), exit(mismatch) end. testget(_Filename, TestData, Datasize) -> getvalue_loop(TestData, none, Datasize), ok. testcheck(_Filename, TestData, Datasize) -> keyexists_loop(TestData, none, Datasize), ok. testadd(_Filename, TestData, Datasize) -> addvalue_loop(TestData, none, Datasize), case permdb:commit(testdb, 600000) of <<0>> -> ok; Other -> io:format("commit expected: 0 got: ~p~n", [Other]), exit(mismatch) end. stop() -> teststop(), receive after 100 -> ok end. runbench(Fun, Size, Verb) -> {Time2, ok} = timer:tc(Fun), io:format("~s ~p entries: ~s ~.1f entries/s (~.2f microseconds)~n", [Verb, Size, timeprint(Time2), Size*1000000/Time2, Time2/Size]). chunk([], N) -> []; chunk(List, N) -> First = lists:sublist(List, N), Rest = lists:nthtail(N, List), [First | chunk(Rest, N)]. massive(Filename) -> Size = 200000, Datasize = 1000, ChunkSize = 200000, {Time1, TestData} = timer:tc(fun () -> gentestdata(Size) end), TestDataLists = chunk(TestData, ChunkSize), testinit(Filename), runbench(fun () -> lists:foreach(fun (E) -> testadd(Filename, E, Datasize) end, TestDataLists) end, Size, "Add"), runbench(fun () -> testget(Filename, TestData, Datasize) end, Size, "Get"), runbench(fun () -> testget(Filename, TestData, Datasize) end, Size, "Get"), runbench(fun () -> testcheck(Filename, TestData, Datasize) end, Size, "Check"), stop(). main([]) -> {ok, Cwd} = file:get_cwd(), code:add_path(Cwd ++ "/ebin"), Size = 20000, Datasize = 1000, ChunkSize = 2000, io:format("Size ~p entries, chunks of ~p entries, entry size ~p bytes~n", [Size, ChunkSize, Datasize]), Filename = "testpermdb", file:delete(Filename), file:delete(Filename ++ ".idx"), {Time1, TestData} = timer:tc(fun () -> gentestdata(Size) end), TestDataLists = chunk(TestData, ChunkSize), io:format("Init with ~p entries: ~s~n", [Size, timeprint(Time1)]), testinit(Filename), runbench(fun () -> lists:foreach(fun (E) -> testadd(Filename, E, Datasize) end, TestDataLists) end, Size, "Add"), runbench(fun () -> testget(Filename, TestData, Datasize) end, Size, "Get"), stop(), testinit(Filename), runbench(fun () -> testget(Filename, TestData, Datasize) end, Size, "Get"), stop(), {ok, FileInfo} = file:read_file_info(Filename), {ok, FileInfoIdx} = file:read_file_info(Filename ++ ".idx"), io:format("data file size ~p, index file size ~p~n", [FileInfo#file_info.size, FileInfoIdx#file_info.size]), file:delete(Filename ++ ".idx"), testinit(Filename), runbench(fun () -> testget(Filename, [hd(TestData)], Datasize) end, Size, "Rebuild"), runbench(fun () -> testget(Filename, TestData, Datasize) end, Size, "Get"), stop(), {ok, FileInfoIdx2} = file:read_file_info(Filename ++ ".idx"), io:format("rebuilt index file size ~p~n", [FileInfoIdx2#file_info.size]), massive(Filename), ok.