1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#!/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, <<E:32, 0:32>>), crypto:hash(sha256, <<E:32, 1:32>>)} || 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),
<<A/binary, B/binary>>.
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.
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.
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)].
main([]) ->
{ok, Cwd} = file:get_cwd(),
code:add_path(Cwd ++ "/ebin"),
Size = 20000,
Datasize = 1000,
ChunkSize = 1000,
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]),
ok.
|