Renamed get_lg_dir() to get_lg_dir_info and added get_data_dirs_info().

Both new calls return the filesystem id and the number of mbytes available
on that filesystem.
This commit is contained in:
Jon Meredith 2009-05-29 12:13:19 -06:00
parent 2c6277bdf4
commit 1409096860
6 changed files with 266 additions and 2 deletions

View file

@ -9,12 +9,15 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/statvfs.h>
#include "hive_hash.h"
#include "bdberl_drv.h"
@ -40,7 +43,9 @@ static void do_async_log_stat(void* arg);
static void do_async_memp_stat(void* arg);
static void do_async_mutex_stat(void* arg);
static void do_async_txn_stat(void* arg);
static void do_sync_data_dirs_info(PortData *p);
static int send_dir_info(ErlDrvPort port, ErlDrvTermData pid, const char *path);
static void send_rc(ErlDrvPort port, ErlDrvTermData pid, int rc);
static int add_dbref(PortData* data, int dbref);
@ -1039,6 +1044,44 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
int rc = G_DB_ENV->txn_stat_print(G_DB_ENV, flags);
RETURN_INT(rc, outbuf);
}
case CMD_DATA_DIRS_INFO:
{
FAIL_IF_ASYNC_PENDING(d, outbuf);
do_sync_data_dirs_info(d);
// Let caller know that the operation is in progress
// Outbuf is: <<0:32>>
RETURN_INT(0, outbuf);
}
case CMD_LOG_DIR_INFO:
{
FAIL_IF_ASYNC_PENDING(d, outbuf);
// Find the log dir or use DB_HOME - error if not present
const char *lg_dir = NULL;
int rc = G_DB_ENV->get_lg_dir(G_DB_ENV, &lg_dir);
if (0 == rc && NULL == lg_dir)
{
rc = G_DB_ENV->get_home(G_DB_ENV, &lg_dir);
}
// Send info if we can get a dir, otherwise return the error
if (0 == rc)
{
// send a dirinfo message - will send an error message on a NULL lg_dir
send_dir_info(d->port, d->port_owner, lg_dir);
}
else
{
send_rc(d->port, d->port_owner, rc);
}
// Let caller know that the operation is in progress
// Outbuf is: <<0:32>>
RETURN_INT(0, outbuf);
}
}
*outbuf = 0;
@ -1271,6 +1314,21 @@ static void get_info(int target, void* values, BinHelper* bh)
}
break;
}
case SYSP_LOG_DIR_GET:
{
const char* dir = 0;
// Get the log dir - according to BDB docs, if not set
// the DB_HOME is used.
int rc = G_DB_ENV->get_lg_dir(G_DB_ENV, &dir);
if (NULL == dir)
{
dir = getenv("DB_HOME");
}
bin_helper_init(bh);
bin_helper_push_int32(bh, rc);
bin_helper_push_string(bh, dir);
break;
}
}
}
@ -1328,6 +1386,53 @@ static char *rc_to_atom_str(int rc)
}
// Send a {dirinfo, Path, FsId, MbyteAvail} message to pid given.
// Send an {errno, Reason} on failure
// returns 0 on success, errno on failure
static int send_dir_info(ErlDrvPort port, ErlDrvTermData pid, const char *path)
{
struct statvfs svfs;
int rc;
if (NULL == path)
{
rc = EINVAL;
}
else if (0 != statvfs(path, &svfs))
{
rc = errno;
}
else
{
rc = 0;
}
if (0 != rc)
{
send_rc(port, pid, rc);
}
else
{
fsblkcnt_t blocks_per_mbyte = 1024 * 1024 / svfs.f_frsize;
assert(blocks_per_mbyte > 0);
unsigned int mbyte_avail = (unsigned int) (svfs.f_bavail / blocks_per_mbyte);
int path_len = strlen(path);
ErlDrvTermData response[] = { ERL_DRV_ATOM, driver_mk_atom("dirinfo"),
ERL_DRV_STRING, (ErlDrvTermData) path, path_len,
// send fsid as a binary as will only be used
// to compare which physical filesystem is on
// and the definintion varies between platforms.
ERL_DRV_BUF2BINARY, (ErlDrvTermData) &svfs.f_fsid,
sizeof(svfs.f_fsid),
ERL_DRV_UINT, mbyte_avail,
ERL_DRV_TUPLE, 4};
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
}
return rc;
}
static void send_rc(ErlDrvPort port, ErlDrvTermData pid, int rc)
{
// TODO: May need to tag the messages a bit more explicitly so that if another async
@ -2334,6 +2439,71 @@ static void do_async_txn_stat(void* arg)
}
}
static void do_sync_data_dirs_info(PortData *d)
{
// Get DB_HOME and find the real path
const char *db_home = NULL;
const char *data_dir = NULL;
const char **data_dirs = NULL;
char db_home_realpath[PATH_MAX+1];
char data_dir_realpath[PATH_MAX+1];
int got_db_home = 0;
// Lookup the environment and add it if not explicitly included in the data_dirs
int rc = G_DB_ENV->get_home(G_DB_ENV, &db_home);
if (rc != 0 || NULL == db_home)
{
// If no db_home we'll have to rely on whatever the global environment is configured with
got_db_home = 1;
}
else
{
if (NULL == realpath(db_home, db_home_realpath))
rc = errno;
}
// Get the data first
rc = G_DB_ENV->get_data_dirs(G_DB_ENV, &data_dirs);
int i;
for (i = 0; 0 == rc && NULL != data_dirs && NULL != data_dirs[i]; i++)
{
data_dir = data_dirs[i];
if (!got_db_home)
{
// Get the real path of the data dir
if (NULL == realpath(data_dir, data_dir_realpath))
{
rc = errno;
}
else
{
// Set got_db_home if it matches
if (0 == strcmp(data_dir_realpath, db_home_realpath))
{
got_db_home = 1;
}
}
}
if (0 == rc)
{
rc = send_dir_info(d->port, d->port_owner, data_dir);
}
}
// BDB always searches the environment home too so add it to the list
if (!got_db_home && rc == 0)
{
rc = send_dir_info(d->port, d->port_owner, db_home);
}
// Send the return code - will termiante the receive loop in bdberl.erl
send_rc(d->port, d->port_owner, rc);
}
static void* zalloc(unsigned int size)
{
void* res = driver_alloc(size);

View file

@ -59,6 +59,8 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
#define CMD_MUTEX_STAT_PRINT 28
#define CMD_TXN_STAT 29
#define CMD_TXN_STAT_PRINT 30
#define CMD_DATA_DIRS_INFO 31
#define CMD_LOG_DIR_INFO 32
/**
* Command status values
@ -96,6 +98,7 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
#define SYSP_CACHESIZE_GET 1
#define SYSP_TXN_TIMEOUT_GET 2
#define SYSP_DATA_DIR_GET 3
#define SYSP_LOG_DIR_GET 4
/**
* Driver Entry

View file

@ -44,6 +44,10 @@ void bin_helper_push_int32(BinHelper* bh, int value)
void bin_helper_push_string(BinHelper* bh, const char* string)
{
if (NULL == string)
{
string = "<null>";
}
int sz = strlen(string);
bin_helper_check_size(bh, sz+1);
strncpy(bh->bin->orig_bytes+(bh->offset), string, sz+1);

View file

@ -36,6 +36,8 @@
-define(CMD_MUTEX_STAT_PRINT,28).
-define(CMD_TXN_STAT, 29).
-define(CMD_TXN_STAT_PRINT, 30).
-define(CMD_DATA_DIRS_INFO, 31).
-define(CMD_LOG_DIR_INFO, 32).
-define(DB_TYPE_BTREE, 1).
-define(DB_TYPE_HASH, 2).
@ -44,6 +46,7 @@
-define(SYSP_CACHESIZE_GET, 1).
-define(SYSP_TXN_TIMEOUT_GET, 2).
-define(SYSP_DATA_DIR_GET, 3).
-define(SYSP_LOG_DIR_GET, 4).
-define(STATUS_OK, 0).
-define(STATUS_ERROR, 1).

View file

@ -13,6 +13,8 @@
txn_commit/0, txn_commit/1, txn_abort/0,
get_cache_size/0,
get_data_dirs/0,
get_data_dirs_info/0,
get_lg_dir_info/0,
get_txn_timeout/0,
stat/1, stat/2,
stat_print/1, stat_print/2,
@ -48,10 +50,11 @@
-type db_name() :: [byte(),...].
-type db_type() :: btree | hash.
-type db_flags() :: [atom()].
-type db_fsid() :: binary().
-type db_key() :: term().
-type db_mbytes() :: non_neg_integer().
-type db_value() :: term().
-type db_ret_value() :: not_found | db_value().
-type db_error_reason() :: atom() | {unknown, integer()}.
-type db_error() :: {error, db_error_reason()}.
@ -1267,6 +1270,63 @@ get_data_dirs() ->
end.
%%--------------------------------------------------------------------
%% @doc
%% Returns the list of directories that bdberl searches to find databases
%% with the number of megabytes available for each dir
%%
%% @spec get_data_dirs_info() -> {ok, [DirName, Fsid, MbytesAvail]} | {error, Error}
%% where
%% DirName = string()
%% Fsid = binary()
%% MbytesAvail = integer()
%%
%% @end
%%--------------------------------------------------------------------
-spec get_data_dirs_info() -> {ok, [{string(), db_fsid(), db_mbytes()}]} | db_error().
get_data_dirs_info() ->
% Call into the BDB library and get a list of configured data directories
Cmd = <<>>,
<<Result:32/signed-native>> = erlang:port_control(get_port(),?CMD_DATA_DIRS_INFO, Cmd),
case decode_rc(Result) of
ok ->
recv_dirs_info([]);
Reason ->
{error, Reason}
end.
%%--------------------------------------------------------------------
%% @doc
%% Returns the log directory info (name and megabytes available)
%%
%% @spec get_lg_dir_info() -> {ok, DirName, Fsid, MbytesAvail} | {error, Error}
%% where
%% DirName = string()
%% Fsid = binary()
%% MbytesAvail = integer()
%%
%% @end
%%--------------------------------------------------------------------
-spec get_lg_dir_info() -> {ok, string(), db_fsid(), db_mbytes()} | db_error().
get_lg_dir_info() ->
% Call into the BDB library and get the log dir and filesystem info
Cmd = <<>>,
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_LOG_DIR_INFO, Cmd),
case decode_rc(Result) of
ok ->
receive
{dirinfo, Path, FsId, MbytesAvail} ->
{ok, Path, FsId, MbytesAvail};
{error, Reason} ->
{error, Reason}
end;
Reason ->
{error, Reason}
end.
%%--------------------------------------------------------------------
%% @doc
%% Returns the size of the in-memory cache.
@ -2196,3 +2256,17 @@ recv_txn_stat(Tstats) ->
{ok, Stats} ->
{ok, Stats, Tstats}
end.
%%
%% Receive directory info messages until ok
%%
recv_dirs_info(DirInfos) ->
receive
{dirinfo, Path, FsId, MbytesAvail} ->
recv_dirs_info([{Path, FsId, MbytesAvail} | DirInfos]);
{error, Reason} ->
{error, Reason};
ok ->
{ok, DirInfos}
end.

View file

@ -39,7 +39,10 @@ all() ->
log_stat_should_report_on_success,
memp_stat_should_report_on_success,
mutex_stat_should_report_on_success,
txn_stat_should_report_on_success].
txn_stat_should_report_on_success,
data_dirs_info_should_report_on_success,
lg_dir_info_should_report_on_success].
dbconfig(Config) ->
@ -312,3 +315,10 @@ txn_stat_should_report_on_success(_Config) ->
bdberl:txn_abort(),
{ok, _GStat3, []} = bdberl:txn_stat([]),
done.
data_dirs_info_should_report_on_success(_Config) ->
{ok, _DataDirs} = bdberl:get_data_dirs_info().
lg_dir_info_should_report_on_success(_Config) ->
{ok, _LgDir, _Fsid, _MBytesAvail} = bdberl:get_lg_dir_info().