lets/test/qc/qc_leveldb.erl
2011-11-02 01:12:39 +09:00

285 lines
7.9 KiB
Erlang

%%% The MIT License
%%%
%%% Copyright (C) 2011 by Joseph Wayne Norton <norton@alum.mit.edu>
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%%% THE SOFTWARE.
-module(qc_leveldb).
%% API
-export([%% test
setup/0
, teardown/0
, is_db/1
%% lets
, open/0, open/1
, reopen/0, reopen/1
, close/1
, put/2, put/3
, delete/2, delete/3
, get/2, get/3
, first/1, first/2
, last/1, last/2
, next/2, next/3
]).
%%%===================================================================
%%% API
%%%===================================================================
setup() ->
Options = [{c_src,"../c_src/leveldb/include/leveldb/c.h"},
{additional_files, ["../c_src/leveldb/lib/libleveldb.a", "../c_src/snappy/lib/libsnappy.a"]},
{cflags, "-lstdc++ -lpthread"}],
DebugOptions = [%% verbose
%% valgrind , {exec_command_line, fun(Exe) -> {os:find_executable("valgrind"), [Exe]} end}
],
eqc_c:start(leveldb, Options ++ DebugOptions).
%% eqc_c:start(leveldb, Options).
teardown() ->
os:cmd("rm -rf " ++ ?MODULE_STRING).
is_db({ptr, {struct, leveldb_t}, _}) ->
true;
is_db(_) ->
false.
open() ->
Options = leveldb:leveldb_options_create(),
try
leveldb:leveldb_options_set_create_if_missing(Options, 1),
leveldb:leveldb_options_set_error_if_exists(Options, 1),
open(Options)
after
leveldb:leveldb_options_destroy(Options)
end.
open(Options) ->
ErrPtr = errptr(),
try
case leveldb:leveldb_open(Options, ?MODULE_STRING, ErrPtr) of
{ptr, {struct, leveldb_t}, 0} ->
read_errptr(ErrPtr);
{ptr, {struct, leveldb_t}, _}=Db ->
Db
end
after
free_ptr(ErrPtr)
end.
reopen() ->
Options = leveldb:leveldb_options_create(),
try
reopen(Options)
after
leveldb:leveldb_options_destroy(Options)
end.
reopen(Options) ->
ErrPtr = errptr(),
try
case leveldb:leveldb_open(Options, ?MODULE_STRING, ErrPtr) of
{ptr, {struct, leveldb_t}, 0} ->
read_errptr(ErrPtr);
{ptr, {struct, leveldb_t}, _}=Db ->
Db
end
after
free_ptr(ErrPtr)
end.
close(Db) ->
ok == leveldb:leveldb_close(Db).
put(Db, Obj) ->
Options = leveldb:leveldb_writeoptions_create(),
try
put(Db, Options, Obj)
after
leveldb:leveldb_writeoptions_destroy(Options)
end.
put(Db, Options, {obj,Key,Val}) ->
ErrPtr = errptr(),
try
leveldb:leveldb_put(Db, Options, binary_to_list(Key), byte_size(Key), binary_to_list(Val), byte_size(Val), ErrPtr),
read_errptr(ErrPtr)
after
free_ptr(ErrPtr)
end.
delete(Db, Key) ->
Options = leveldb:leveldb_writeoptions_create(),
try
delete(Db, Options, Key)
after
leveldb:leveldb_writeoptions_destroy(Options)
end.
delete(Db, Options, Key) ->
ErrPtr = errptr(),
try
leveldb:leveldb_delete(Db, Options, binary_to_list(Key), byte_size(Key), ErrPtr),
read_errptr(ErrPtr)
after
free_ptr(ErrPtr)
end.
get(Db, Key) ->
Options = leveldb:leveldb_readoptions_create(),
try
get(Db, Options, Key)
after
leveldb:leveldb_readoptions_destroy(Options)
end.
get(Db, Options, Key) ->
ErrPtr = errptr(),
LenPtr = lenptr(),
try
case leveldb:leveldb_get(Db, Options, binary_to_list(Key), byte_size(Key), LenPtr, ErrPtr) of
0 ->
read_errptr(ErrPtr);
ValPtr ->
read_binary(ValPtr, LenPtr)
end
after
free_ptr(ErrPtr),
free_ptr(LenPtr)
end.
first(Db) ->
Options = leveldb:leveldb_readoptions_create(),
try
first(Db, Options)
after
leveldb:leveldb_readoptions_destroy(Options)
end.
first(Db, Options) ->
Iter = leveldb:leveldb_create_iterator(Db, Options),
LenPtr = lenptr(),
try
leveldb:leveldb_iter_seek_to_first(Iter),
case leveldb:leveldb_iter_valid(Iter) of
0 ->
true;
1 ->
KeyPtr = leveldb:leveldb_iter_key(Iter, LenPtr),
read_binary(KeyPtr, LenPtr)
end
after
leveldb:leveldb_iter_destroy(Iter),
free_ptr(LenPtr)
end.
last(Db) ->
Options = leveldb:leveldb_readoptions_create(),
try
last(Db, Options)
after
leveldb:leveldb_readoptions_destroy(Options)
end.
last(Db, Options) ->
Iter = leveldb:leveldb_create_iterator(Db, Options),
LenPtr = lenptr(),
try
leveldb:leveldb_iter_seek_to_last(Iter),
case leveldb:leveldb_iter_valid(Iter) of
0 ->
true;
1 ->
KeyPtr = leveldb:leveldb_iter_key(Iter, LenPtr),
read_binary(KeyPtr, LenPtr)
end
after
leveldb:leveldb_iter_destroy(Iter),
free_ptr(LenPtr)
end.
next(Db, Key) ->
Options = leveldb:leveldb_readoptions_create(),
try
next(Db, Key, Options)
after
leveldb:leveldb_readoptions_destroy(Options)
end.
next(Db, Key, Options) ->
Iter = leveldb:leveldb_create_iterator(Db, Options),
LenPtr = lenptr(),
LenPtr1 = lenptr(),
try
leveldb:leveldb_iter_seek(Iter, binary_to_list(Key), byte_size(Key)),
case leveldb:leveldb_iter_valid(Iter) of
0 ->
true;
1 ->
KeyPtr = leveldb:leveldb_iter_key(Iter, LenPtr),
K = read_binary(KeyPtr, LenPtr),
if K =/= Key ->
K;
true ->
leveldb:leveldb_iter_next(Iter),
case leveldb:leveldb_iter_valid(Iter) of
0 ->
true;
1 ->
KeyPtr1 = leveldb:leveldb_iter_key(Iter, LenPtr1),
read_binary(KeyPtr1, LenPtr1)
end
end
end
after
leveldb:leveldb_iter_destroy(Iter),
free_ptr(LenPtr),
free_ptr(LenPtr1)
end.
%%%===================================================================
%%% Internal
%%%===================================================================
errptr() ->
eqc_c:alloc({ptr, char}, [0]).
lenptr() ->
eqc_c:alloc(unsigned_long, 0).
free_ptr(Ptr) ->
eqc_c:free(Ptr).
read_errptr(ErrPtr) ->
case eqc_c:read_string(eqc_c:deref(ErrPtr)) of
[] ->
true;
Err ->
Err
end.
read_lenptr(LenPtr) ->
eqc_c:deref(LenPtr).
read_binary({ptr, char, 0}, _LenPtr) ->
true;
read_binary(ValPtr, LenPtr) ->
list_to_binary(eqc_c:read_array(ValPtr, read_lenptr(LenPtr))).