diff options
author | Magnus Ahltorp <map@kth.se> | 2016-05-13 17:20:08 +0200 |
---|---|---|
committer | Magnus Ahltorp <map@kth.se> | 2016-05-13 17:22:09 +0200 |
commit | cc037396bf405ec942352ea834e137ea1b24e6af (patch) | |
tree | af9d2df2ddb095f50d344ecf8002f0a7c0144762 | |
parent | 8a19f620874ebecf125f831c633aec02c3922fd6 (diff) |
Added 'keyexists' command to permdb
-rw-r--r-- | c_src/permdb.c | 37 | ||||
-rw-r--r-- | src/permdb.erl | 26 | ||||
-rwxr-xr-x | test/permdbbench.erl | 37 |
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. |