summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c_src/permdb.c37
-rw-r--r--src/permdb.erl26
-rwxr-xr-xtest/permdbbench.erl37
3 files changed, 95 insertions, 5 deletions
diff --git a/c_src/permdb.c b/c_src/permdb.c
index 90bb2ff..93eb02e 100644
--- a/c_src/permdb.c
+++ b/c_src/permdb.c
@@ -982,6 +982,31 @@ getvalue(permdb_object *state, const unsigned char *key, size_t keylength,
return readdata(state, olddataoffset, *datalen);
}
+unsigned int
+keyexists(permdb_object *state, const unsigned char *key, size_t keylength)
+{
+ node_entry entry = getlastnode(state, key);
+ if (entry == 0) {
+ dprintf(READ, (stderr, "getvalue: no node\n"));
+ return 0;
+ }
+
+ dprintf(READ, (stderr, "getvalue: got node\n"));
+
+ node_offset olddataoffset = entryoffset(entry);
+
+ unsigned char *datakey = readdatakey(state, olddataoffset);
+ if (datakey == NULL) {
+ return 0;
+ }
+ if (memcmp(datakey, key, keylength) != 0) {
+ free(datakey);
+ return 0;
+ }
+ free(datakey);
+ return 1;
+}
+
static int
string_length_comparison(struct nodecache *a, struct nodecache *b) {
size_t a_len = a->key->length;
@@ -1175,6 +1200,18 @@ portloop(permdb_object *state)
write_reply(&result_byte, 1, 4);
}
dprintf(PORT, (stderr, "commit reply\n"));
+ } else if (buf[0] == 3) {
+ dprintf(PORT, (stderr, "keyexists\n"));
+ if (len != keylen+1) {
+ write_reply(NULL, 0, 4);
+ continue;
+ }
+ assert(len == keylen+1);
+
+ unsigned char result_byte = keyexists(state, (buf+1), keylen);
+
+ write_reply(&result_byte, 1, 4);
+ dprintf(PORT, (stderr, "keyexists reply\n"));
} else {
dprintf(PORT, (stderr, "unknown command\n"));
write_reply(NULL, 0, 4);
diff --git a/src/permdb.erl b/src/permdb.erl
index 16ba28a..461b8b3 100644
--- a/src/permdb.erl
+++ b/src/permdb.erl
@@ -6,7 +6,7 @@
-behaviour(gen_server).
-export([start_link/2, stop/1, init_module/0]).
--export([getvalue/2, addvalue/3, commit/1, commit/2]).
+-export([getvalue/2, addvalue/3, commit/1, commit/2, keyexists/2]).
%% gen_server callbacks.
-export([init/1, handle_call/3, terminate/2, handle_cast/2, handle_info/2,
@@ -23,9 +23,15 @@ addvalue_port_command(Port, Key, Value) ->
commit_port_command(Port) ->
Port ! {self(), {command, <<2:8>>}}.
+keyexists_port_command(Port, Key) ->
+ Port ! {self(), {command, <<3:8, Key/binary>>}}.
+
getvalue(Name, Key) ->
gen_server:call(Name, {getvalue, Key}, 600000).
+keyexists(Name, Key) ->
+ gen_server:call(Name, {keyexists, Key}, 600000).
+
addvalue(Name, Key, Value) ->
gen_server:call(Name, {addvalue, Key, Value}).
@@ -74,12 +80,19 @@ handle_info({Port, {data, Data}}, State) when is_port(Port) ->
addvalue ->
case Data of
<<>> ->
- util:exit_with_error(putvalue, unknown, "Error in putvalue");
+ util:exit_with_error(addvalue, unknown, "Error in addvalue");
_ ->
ok
end;
commit ->
- Data
+ Data;
+ keyexists ->
+ case Data of
+ <<0>> ->
+ false;
+ <<1>> ->
+ true
+ end
end),
{noreply, State#state{requests = Requests}};
handle_info(_Info, State) ->
@@ -115,4 +128,9 @@ handle_call({addvalue, Key, Value}, From, State) ->
handle_call({commit}, From, State) ->
lager:debug("commit ~p ~p", [State#state.name, State#state.requestcounter]),
commit_port_command(State#state.port),
- {noreply, add_request(State, From, commit)}.
+ {noreply, add_request(State, From, commit)};
+
+handle_call({keyexists, Key}, From, State) ->
+ lager:debug("keyexists ~p ~p: ~p", [State#state.name, State#state.requestcounter, Key]),
+ keyexists_port_command(State#state.port, Key),
+ {noreply, add_request(State, From, keyexists)}.
diff --git a/test/permdbbench.erl b/test/permdbbench.erl
index e825146..1575817 100755
--- a/test/permdbbench.erl
+++ b/test/permdbbench.erl
@@ -40,6 +40,17 @@ getvalue_loop([{K, VSeed}|Rest], Port, Datasize) ->
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) ->
@@ -56,6 +67,10 @@ 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
@@ -85,12 +100,30 @@ chunk(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 = 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),
@@ -125,5 +158,7 @@ main([]) ->
{ok, FileInfoIdx2} = file:read_file_info(Filename ++ ".idx"),
io:format("rebuilt index file size ~p~n", [FileInfoIdx2#file_info.size]),
+ massive(Filename),
+
ok.