Adding support for list database directories and txn'lly deleting databases
This commit is contained in:
parent
f9b3354c50
commit
68813d0a53
6 changed files with 142 additions and 41 deletions
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
static int open_database(const char* name, DBTYPE type, unsigned flags, PortData* data, int* errno);
|
||||
static int close_database(int dbref, unsigned flags, PortData* data);
|
||||
static int delete_database(const char* name);
|
||||
|
||||
static void tune_system(int target, void* values, BinHelper* bh);
|
||||
|
||||
|
@ -325,7 +326,6 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
char** outbuf, int outbuf_sz)
|
||||
{
|
||||
PortData* d = (PortData*)handle;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case CMD_OPEN_DB:
|
||||
|
@ -484,11 +484,9 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
int target = UNPACK_INT(inbuf, 0);
|
||||
char* values = UNPACK_BLOB(inbuf, 4);
|
||||
|
||||
// Setup a binhelper
|
||||
BinHelper bh;
|
||||
|
||||
// Execute the tuning -- the result to send back to the caller is wrapped
|
||||
// up in the provided binhelper
|
||||
BinHelper bh;
|
||||
tune_system(target, values, &bh);
|
||||
RETURN_BH(bh, outbuf);
|
||||
}
|
||||
|
@ -562,6 +560,21 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
|
||||
RETURN_INT(0, outbuf);
|
||||
}
|
||||
case CMD_REMOVE_DB:
|
||||
{
|
||||
FAIL_IF_ASYNC_PENDING(d, outbuf);
|
||||
|
||||
// Fail if a txn is open
|
||||
if (d->txn != 0)
|
||||
{
|
||||
RETURN_INT(ERROR_TXN_OPEN, outbuf);
|
||||
}
|
||||
|
||||
// Inbuf is: << dbname/bytes, 0:8 >>
|
||||
const char* dbname = UNPACK_STRING(inbuf, 0);
|
||||
int rc = delete_database(dbname);
|
||||
RETURN_INT(rc, outbuf);
|
||||
}
|
||||
}
|
||||
*outbuf = 0;
|
||||
return 0;
|
||||
|
@ -722,6 +735,24 @@ static int close_database(int dbref, unsigned flags, PortData* data)
|
|||
}
|
||||
}
|
||||
|
||||
static int delete_database(const char* name)
|
||||
{
|
||||
// Go directly to a write lock on the global databases structure
|
||||
WRITE_LOCK(G_DATABASES_RWLOCK);
|
||||
|
||||
// Make sure the database is not opened by anyone
|
||||
if (hive_hash_get(G_DATABASES_NAMES, name))
|
||||
{
|
||||
WRITE_UNLOCK(G_DATABASES_RWLOCK);
|
||||
return ERROR_DB_ACTIVE;
|
||||
}
|
||||
|
||||
// Good, database doesn't seem to be open -- attempt the delete
|
||||
int rc = G_DB_ENV->dbremove(G_DB_ENV, 0, name, 0, DB_AUTO_COMMIT);
|
||||
WRITE_UNLOCK(G_DATABASES_RWLOCK);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a target system parameter/action adjust/return the requested value
|
||||
*/
|
||||
|
@ -729,16 +760,6 @@ static void tune_system(int target, void* values, BinHelper* bh)
|
|||
{
|
||||
switch(target)
|
||||
{
|
||||
case SYSP_CACHESIZE_SET:
|
||||
{
|
||||
unsigned int gbytes = UNPACK_INT(values, 0);
|
||||
unsigned int bytes = UNPACK_INT(values, 4);
|
||||
unsigned int ncache = UNPACK_INT(values, 8);
|
||||
int rc = G_DB_ENV->set_cachesize(G_DB_ENV, gbytes, bytes, ncache);
|
||||
bin_helper_init(bh, 4);
|
||||
bin_helper_push_int32(bh, rc);
|
||||
break;
|
||||
}
|
||||
case SYSP_CACHESIZE_GET:
|
||||
{
|
||||
unsigned int gbytes = 0;
|
||||
|
@ -769,6 +790,23 @@ static void tune_system(int target, void* values, BinHelper* bh)
|
|||
bin_helper_push_int32(bh, timeout);
|
||||
break;
|
||||
}
|
||||
case SYSP_DATA_DIR_GET:
|
||||
{
|
||||
const char** dirs = 0;
|
||||
int rc = G_DB_ENV->get_data_dirs(G_DB_ENV, &dirs);
|
||||
printf("DATA DIR: %d\n", rc);
|
||||
bin_helper_init(bh, 64);
|
||||
bin_helper_push_int32(bh, rc);
|
||||
if (dirs)
|
||||
{
|
||||
while (*dirs != 0)
|
||||
{
|
||||
bin_helper_push_string(bh, *dirs);
|
||||
dirs++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
#define CMD_CURSOR_PREV 12
|
||||
#define CMD_CURSOR_CLOSE 13
|
||||
#define CMD_PUT_COMMIT 14
|
||||
#define CMD_REMOVE_DB 15
|
||||
|
||||
|
||||
/**
|
||||
|
@ -68,19 +69,16 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
#define ERROR_NO_TXN (-29004) /* No transaction open on this port */
|
||||
#define ERROR_CURSOR_OPEN (-29005) /* Cursor already active on this port */
|
||||
#define ERROR_NO_CURSOR (-29006) /* No cursor open on this port */
|
||||
#define ERROR_DB_ACTIVE (-29007) /* Database is currently active; operation requires otherwise */
|
||||
|
||||
|
||||
/**
|
||||
* Tunable system parameters/actions
|
||||
*/
|
||||
#define SYSP_CACHESIZE_SET 0
|
||||
#define SYSP_CACHESIZE_GET 1
|
||||
#define SYSP_TXN_TIMEOUT_SET 2
|
||||
#define SYSP_TXN_TIMEOUT_GET 3
|
||||
#define SYSP_TXN_TIMEOUT 1
|
||||
#define SYSP_DEADLOCK_CHECK_INTERVAL 2
|
||||
#define SYSP_TRICKLE_INTERVAL 3
|
||||
#define SYSP_TRICKLE_PERCENTAGE 4
|
||||
#define SYSP_DATA_DIR_GET 4
|
||||
|
||||
/**
|
||||
* Driver Entry
|
||||
|
|
|
@ -14,8 +14,7 @@ static void bin_helper_check_size(BinHelper* bh, int space_needed)
|
|||
{
|
||||
if (bh->offset + space_needed > bh->bin->orig_size)
|
||||
{
|
||||
// Need to realloc space -- grow by 2 * space_needed
|
||||
bh->bin = driver_realloc_binary(bh->bin, bh->bin->orig_size + (2 * space_needed));
|
||||
bh->bin = driver_realloc_binary(bh->bin, bh->offset + space_needed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
-define(CMD_CURSOR_PREV, 12).
|
||||
-define(CMD_CURSOR_CLOSE, 13).
|
||||
-define(CMD_PUT_COMMIT, 14).
|
||||
|
||||
-define(CMD_REMOVE_DB, 15).
|
||||
|
||||
-define(DB_TYPE_BTREE, 1).
|
||||
-define(DB_TYPE_HASH, 2).
|
||||
|
||||
-define(SYSP_CACHESIZE_SET, 0).
|
||||
-define(SYSP_CACHESIZE_GET, 1).
|
||||
-define(SYSP_TXN_TIMEOUT_SET, 2).
|
||||
-define(SYSP_TXN_TIMEOUT_GET, 3).
|
||||
-define(SYSP_DATA_DIR_GET, 4).
|
||||
|
||||
-define(STATUS_OK, 0).
|
||||
-define(STATUS_ERROR, 1).
|
||||
|
@ -41,6 +41,7 @@
|
|||
-define(ERROR_NO_TXN, -29004). % No transaction open on this port
|
||||
-define(ERROR_CURSOR_OPEN, -29005). % Cursor already active on this port
|
||||
-define(ERROR_NO_CURSOR, -29006). % No cursor open on this port
|
||||
-define(ERROR_DB_ACTIVE, -29007). % Database is currently active; operation requires otherwise
|
||||
|
||||
-define(ERROR_DB_LOCK_NOTGRANTED, -30993). % Lock was busy and not granted
|
||||
-define(ERROR_DB_LOCK_DEADLOCK, -30994). % Deadlock occurred
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
close/1, close/2,
|
||||
txn_begin/0, txn_begin/1,
|
||||
txn_commit/0, txn_commit/1, txn_abort/0,
|
||||
get_cache_size/0, set_cache_size/3,
|
||||
get_cache_size/0, get_data_dirs/0,
|
||||
get_txn_timeout/0, set_txn_timeout/1,
|
||||
transaction/1, transaction/2,
|
||||
put/3, put/4,
|
||||
|
@ -20,6 +20,7 @@
|
|||
get/2, get/3,
|
||||
get_r/2, get_r/3,
|
||||
update/3, update/4,
|
||||
delete_database/1,
|
||||
cursor_open/1, cursor_next/0, cursor_prev/0, cursor_current/0, cursor_close/0]).
|
||||
|
||||
-include("bdberl.hrl").
|
||||
|
@ -236,7 +237,35 @@ cursor_close() ->
|
|||
Reason ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
|
||||
delete_database(Filename) ->
|
||||
Cmd = list_to_binary(Filename),
|
||||
<<Rc:32/native-signed>> = erlang:port_control(get_port(), ?CMD_REMOVE_DB, Cmd),
|
||||
case decode_rc(Rc) of
|
||||
ok ->
|
||||
ok;
|
||||
Reason ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
|
||||
get_data_dirs() ->
|
||||
%% Call into the BDB library and get a list of configured data directories
|
||||
Cmd = <<?SYSP_DATA_DIR_GET:32/native>>,
|
||||
<<Result:32/signed-native, Rest/bytes>> = erlang:port_control(get_port(), ?CMD_TUNE, Cmd),
|
||||
case decode_rc(Result) of
|
||||
ok ->
|
||||
Dirs = [binary_to_list(D) || D <- split_bin(0, Rest, <<>>, [])],
|
||||
%% Make sure DB_HOME is part of the list
|
||||
case lists:member(os:getenv("DB_HOME"), Dirs) of
|
||||
true ->
|
||||
Dirs;
|
||||
false ->
|
||||
[os:getenv("DB_HOME") | Dirs]
|
||||
end;
|
||||
Reason ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
get_cache_size() ->
|
||||
Cmd = <<?SYSP_CACHESIZE_GET:32/native>>,
|
||||
|
@ -249,17 +278,6 @@ get_cache_size() ->
|
|||
{error, Result}
|
||||
end.
|
||||
|
||||
set_cache_size(Gbytes, Bytes, Ncaches) ->
|
||||
Cmd = <<?SYSP_CACHESIZE_SET:32/native, Gbytes:32/native, Bytes:32/native, Ncaches:32/native>>,
|
||||
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_TUNE, Cmd),
|
||||
case Result of
|
||||
0 ->
|
||||
ok;
|
||||
_ ->
|
||||
{error, Result}
|
||||
end.
|
||||
|
||||
|
||||
get_txn_timeout() ->
|
||||
Cmd = <<?SYSP_TXN_TIMEOUT_GET:32/native>>,
|
||||
<<Result:32/signed-native, Timeout:32/native>> = erlang:port_control(get_port(), ?CMD_TUNE, Cmd),
|
||||
|
@ -281,6 +299,7 @@ set_txn_timeout(Timeout) ->
|
|||
end.
|
||||
|
||||
|
||||
|
||||
%% ====================================================================
|
||||
%% Internal functions
|
||||
%% ====================================================================
|
||||
|
@ -404,3 +423,17 @@ do_cursor_move(Direction) ->
|
|||
Reason ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%
|
||||
%% Split a binary into pieces, using a single character delimiter
|
||||
%%
|
||||
split_bin(_Delimiter, <<>>, <<>>, Acc) ->
|
||||
lists:reverse(Acc);
|
||||
split_bin(_Delimiter, <<>>, ItemAcc, Acc) ->
|
||||
lists:reverse([ItemAcc | Acc]);
|
||||
split_bin(Delimiter, <<Delimiter:8, Rest/binary>>, ItemAcc, Acc) ->
|
||||
split_bin(Delimiter, Rest, <<>> ,[ItemAcc | Acc]);
|
||||
split_bin(Delimiter, <<Other:8, Rest/binary>>, ItemAcc, Acc) ->
|
||||
split_bin(Delimiter, Rest, <<ItemAcc/binary, Other:8>>, Acc).
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
-include_lib("ct.hrl").
|
||||
|
||||
all() ->
|
||||
ball() ->
|
||||
[open_should_create_database_if_none_exists,
|
||||
open_should_allow_opening_multiple_databases,
|
||||
close_should_fail_with_invalid_db_handle,
|
||||
|
@ -25,20 +25,33 @@ all() ->
|
|||
update_should_accept_args_for_fun,
|
||||
port_should_tune_transaction_timeouts,
|
||||
cursor_should_iterate, cursor_should_fail_if_not_open,
|
||||
put_commit_should_end_txn].
|
||||
put_commit_should_end_txn,
|
||||
data_dir_should_be_priv_dir,
|
||||
delete_should_remove_file,
|
||||
delete_should_fail_if_db_inuse].
|
||||
|
||||
|
||||
init_per_suite(Config) ->
|
||||
DbHome = ?config(priv_dir, Config),
|
||||
os:putenv("DB_HOME", DbHome),
|
||||
ok = file:write_file(DbHome ++ "DB_CONFIG", <<"set_data_dir ", (list_to_binary(DbHome))/binary, "\n">>),
|
||||
Config.
|
||||
|
||||
end_per_suite(_Config) ->
|
||||
ok.
|
||||
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
{ok, Db} = bdberl:open("api_test.db", btree, [create, exclusive]),
|
||||
[{db, Db}|Config].
|
||||
|
||||
end_per_testcase(_TestCase, Config) ->
|
||||
ok = bdberl:close(?config(db, Config)),
|
||||
ok = file:delete("api_test.db").
|
||||
ok = file:delete(filename:join([?config(priv_dir, Config), "api_test.db"])).
|
||||
|
||||
|
||||
open_should_create_database_if_none_exists(_Config) ->
|
||||
true = filelib:is_file("api_test.db").
|
||||
open_should_create_database_if_none_exists(Config) ->
|
||||
DbName = filename:join([?config(priv_dir, Config), "api_test.db"]),
|
||||
true = filelib:is_file(DbName).
|
||||
|
||||
open_should_allow_opening_multiple_databases(_Config) ->
|
||||
%% Open up another db -- should use dbref 1 as that's the first available
|
||||
|
@ -171,4 +184,23 @@ put_commit_should_end_txn(Config) ->
|
|||
%% Verify data got committed
|
||||
{ok, value1} = bdberl:get(Db, key1).
|
||||
|
||||
data_dir_should_be_priv_dir(Config) ->
|
||||
PrivDir = ?config(priv_dir, Config),
|
||||
[PrivDir] = bdberl:get_data_dirs().
|
||||
|
||||
delete_should_remove_file(Config) ->
|
||||
{ok, Db} = bdberl:open("mytest.bdb", btree),
|
||||
ok = bdberl:close(Db),
|
||||
|
||||
Fname = filename:join([?config(priv_dir, Config), "mytest.bdb"]),
|
||||
true = filelib:is_file(Fname),
|
||||
|
||||
ok = bdberl:delete_database("mytest.bdb"),
|
||||
|
||||
false = filelib:is_file(Fname).
|
||||
|
||||
delete_should_fail_if_db_inuse(Config) ->
|
||||
Fname = filename:join([?config(priv_dir, Config), "api_test.db"]),
|
||||
true = filelib:is_file(Fname),
|
||||
{error, _} = bdberl:delete_database(Fname),
|
||||
true = filelib:is_file(Fname).
|
||||
|
|
Loading…
Reference in a new issue