diff --git a/src/bdberl.erl b/src/bdberl.erl index 56f502a..941bf41 100644 --- a/src/bdberl.erl +++ b/src/bdberl.erl @@ -29,10 +29,31 @@ -define(is_lock_error(Error), (Error =:= deadlock orelse Error =:= lock_not_granted)). +-type db() :: non_neg_integer(). +-type db_type() :: btree | hash. +-type db_flags() :: [atom()]. +-type db_key() :: term(). +-type db_value() :: term(). +-type db_ret_value() :: not_found | db_value(). + +-type error_reason() :: term(). +-type error() :: {error, error_reason()}. + +-type txn_fun_ret() :: abort | term(). +-type txn_fun() :: fun(() -> txn_fun_ret()). +-type txn_retries() :: infinity | non_neg_integer(). + +-type db_update_fun() :: fun((db_key(), db_value(), any()) -> db_value()). + + +-spec open(Name :: nonempty_string(), Type :: db_type()) -> db(). open(Name, Type) -> open(Name, Type, [create]). + +-spec open(Name :: nonempty_string(), Type :: db_type(), Opts :: db_flags()) -> db(). + open(Name, Type, Opts) -> %% Map database type into an integer code case Type of @@ -48,9 +69,15 @@ open(Name, Type, Opts) -> {error, Errno} end. + +-spec close(Db :: db()) -> ok | error(). + close(Db) -> close(Db, []). + +-spec close(Db :: db(), Opts :: db_flags()) -> ok | error(). + close(Db, Opts) -> Flags = process_flags(Opts), Cmd = <>, @@ -62,9 +89,15 @@ close(Db, Opts) -> {error, Reason} end. + +-spec txn_begin() -> ok | error(). + txn_begin() -> txn_begin([]). + +-spec txn_begin(Opts :: db_flags()) -> ok | error(). + txn_begin(Opts) -> Flags = process_flags(Opts), Cmd = <>, @@ -74,9 +107,15 @@ txn_begin(Opts) -> Error -> {error, {txn_begin, Error}} end. + +-spec txn_commit() -> ok | error(). + txn_commit() -> txn_commit([]). + +-spec txn_commit(Opts :: db_flags()) -> ok | error(). + txn_commit(Opts) -> Flags = process_flags(Opts), Cmd = <>, @@ -91,6 +130,9 @@ txn_commit(Opts) -> {error, {txn_commit, Error}} end. + +-spec txn_abort() -> ok | error(). + txn_abort() -> <> = erlang:port_control(get_port(), ?CMD_TXN_ABORT, <<>>), case decode_rc(Result) of @@ -103,9 +145,16 @@ txn_abort() -> {error, {txn_abort, Error}} end. + +-spec transaction(Fun :: txn_fun()) -> {ok, db_value()} | {error, error()}. + transaction(Fun) -> transaction(Fun, infinity). + +-spec transaction(Fun :: txn_fun(), Retries :: txn_retries()) -> + {ok, db_value()} | {error, error()}. + transaction(_Fun, 0) -> txn_abort(), {error, {transaction_failed, retry_limit_reached}}; @@ -141,39 +190,79 @@ transaction(Fun, Retries) -> Error end. + +-spec put(Db :: db(), Key :: db_key(), Value :: db_value()) -> + ok | {error, error()}. + put(Db, Key, Value) -> put(Db, Key, Value, []). + +-spec put(Db :: db(), Key :: db_key(), Value :: db_value(), Opts :: db_flags()) -> + ok | {error, error()}. + put(Db, Key, Value, Opts) -> do_put(?CMD_PUT, Db, Key, Value, Opts). + +-spec put_r(Db :: db(), Key :: db_key(), Value :: db_value()) -> + ok | {error, error()}. + put_r(Db, Key, Value) -> put_r(Db, Key, Value, []). + +-spec put_r(Db :: db(), Key :: db_key(), Value :: db_value(), Opts :: db_flags()) -> + ok | {error, error()}. + put_r(Db, Key, Value, Opts) -> case put(Db, Key, Value, Opts) of ok -> ok; Error -> throw(Error) end. + +-spec put_commit(Db :: db(), Key :: db_key(), Value :: db_value()) -> + ok | {error, error()}. + put_commit(Db, Key, Value) -> put_commit(Db, Key, Value, []). + +-spec put_commit(Db :: db(), Key :: db_key(), Value :: db_value(), Opts :: db_flags()) -> + ok | {error, error()}. + put_commit(Db, Key, Value, Opts) -> do_put(?CMD_PUT_COMMIT, Db, Key, Value, Opts). + +-spec put_commit_r(Db :: db(), Key :: db_key(), Value :: db_value()) -> + ok | {error, error()}. + put_commit_r(Db, Key, Value) -> put_commit_r(Db, Key, Value, []). + +-spec put_commit_r(Db :: db(), Key :: db_key(), Value :: db_value(), Opts :: db_flags()) -> + ok | {error, error()}. + put_commit_r(Db, Key, Value, Opts) -> case do_put(?CMD_PUT_COMMIT, Db, Key, Value, Opts) of ok -> ok; Error -> throw(Error) end. + +-spec get(Db :: db(), Key :: db_key()) -> + {ok, db_ret_value()} | {error, error()}. + get(Db, Key) -> get(Db, Key, []). + +-spec get(Db :: db(), Key :: db_key(), Opts :: db_flags()) -> + {ok, db_ret_value()} | {error, error()}. + get(Db, Key, Opts) -> {KeyLen, KeyBin} = to_binary(Key), Flags = process_flags(Opts), @@ -190,9 +279,16 @@ get(Db, Key, Opts) -> {error, {get, decode_rc(Error)}} end. +-spec get_r(Db :: db(), Key :: db_key()) -> + {ok, db_ret_value()} | {error, error()}. + get_r(Db, Key) -> get_r(Db, Key, []). + +-spec get_r(Db :: db(), Key :: db_key(), Opts :: db_flags()) -> + {ok, db_ret_value()} | {error, error()}. + get_r(Db, Key, Opts) -> case get(Db, Key, Opts) of {ok, Value} -> {ok, Value}; @@ -200,9 +296,17 @@ get_r(Db, Key, Opts) -> Error -> throw(Error) end. + +-spec update(Db :: db(), Key :: db_key(), Fun :: db_update_fun()) -> + {ok, db_value()} | {error, error()}. + update(Db, Key, Fun) -> update(Db, Key, Fun, undefined). + +-spec update(Db :: db(), Key :: db_key(), Fun :: db_update_fun(), Args :: [any()]) -> + {ok, db_value()} | {error, error()}. + update(Db, Key, Fun, Args) -> F = fun() -> Value = case get_r(Db, Key, [rmw]) of @@ -218,9 +322,15 @@ update(Db, Key, Fun, Args) -> end, transaction(F). + +-spec truncate() -> ok | {error, error()}. + truncate() -> truncate(-1). + +-spec truncate(Db :: db()) -> ok | {error, error()}. + truncate(Db) -> Cmd = <>, <> = erlang:port_control(get_port(), ?CMD_TRUNCATE, Cmd), @@ -235,6 +345,9 @@ truncate(Db) -> {error, {truncate, decode_rc(Error)}} end. + +-spec cursor_open(Db :: db()) -> ok | {error, error()}. + cursor_open(Db) -> Cmd = <>, <> = erlang:port_control(get_port(), ?CMD_CURSOR_OPEN, Cmd), @@ -246,15 +359,26 @@ cursor_open(Db) -> end. +-spec cursor_next() -> ok | {error, error()}. + cursor_next() -> do_cursor_move(?CMD_CURSOR_NEXT). + +-spec cursor_prev() -> ok | {error, error()}. + cursor_prev() -> do_cursor_move(?CMD_CURSOR_PREV). + +-spec cursor_current() -> ok | {error, error()}. + cursor_current() -> do_cursor_move(?CMD_CURSOR_CURR). + +-spec cursor_close() -> ok | {error, error()}. + cursor_close() -> <> = erlang:port_control(get_port(), ?CMD_CURSOR_CLOSE, <<>>), case decode_rc(Rc) of @@ -264,6 +388,10 @@ cursor_close() -> {error, Reason} end. + +-spec delete_database(Filename :: nonempty_string()) -> + ok | {error, error()}. + delete_database(Filename) -> Cmd = <<(list_to_binary(Filename))/binary, 0:8>>, <> = erlang:port_control(get_port(), ?CMD_REMOVE_DB, Cmd), @@ -275,6 +403,8 @@ delete_database(Filename) -> end. +-spec get_data_dirs() -> [nonempty_string(),...] | {error, error()}. + get_data_dirs() -> %% Call into the BDB library and get a list of configured data directories Cmd = <>, @@ -293,6 +423,10 @@ get_data_dirs() -> {error, Reason} end. + +-spec get_cache_size() -> + {ok, non_neg_integer(), non_neg_integer(), non_neg_integer()} | {error, error()}. + get_cache_size() -> Cmd = <>, <> = @@ -304,6 +438,9 @@ get_cache_size() -> {error, Result} end. + +-spec get_txn_timeout() -> {ok, timeout()} | {error, error()}. + get_txn_timeout() -> Cmd = <>, <> = erlang:port_control(get_port(), ?CMD_GETINFO, Cmd),