Added transaction stats.
This commit is contained in:
parent
e4757031a2
commit
c74beeba9f
|
@ -39,6 +39,7 @@ static void do_async_lock_stat(void* arg);
|
||||||
static void do_async_log_stat(void* arg);
|
static void do_async_log_stat(void* arg);
|
||||||
static void do_async_memp_stat(void* arg);
|
static void do_async_memp_stat(void* arg);
|
||||||
static void do_async_mutex_stat(void* arg);
|
static void do_async_mutex_stat(void* arg);
|
||||||
|
static void do_async_txn_stat(void* arg);
|
||||||
|
|
||||||
static int add_dbref(PortData* data, int dbref);
|
static int add_dbref(PortData* data, int dbref);
|
||||||
static int del_dbref(PortData* data, int dbref);
|
static int del_dbref(PortData* data, int dbref);
|
||||||
|
@ -1006,6 +1007,46 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
||||||
int rc = G_DB_ENV->mutex_stat_print(G_DB_ENV, flags);
|
int rc = G_DB_ENV->mutex_stat_print(G_DB_ENV, flags);
|
||||||
RETURN_INT(rc, outbuf);
|
RETURN_INT(rc, outbuf);
|
||||||
}
|
}
|
||||||
|
case CMD_TXN_STAT:
|
||||||
|
{
|
||||||
|
FAIL_IF_ASYNC_PENDING(d, outbuf);
|
||||||
|
|
||||||
|
// Inbuf is <<Flags:32 >>
|
||||||
|
// If the working buffer is large enough, copy the data to put/get into it. Otherwise, realloc
|
||||||
|
// until it is large enough
|
||||||
|
if (d->work_buffer_sz < inbuf_sz)
|
||||||
|
{
|
||||||
|
d->work_buffer = driver_realloc(d->work_buffer, inbuf_sz);
|
||||||
|
d->work_buffer_sz = inbuf_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the payload into place
|
||||||
|
memcpy(d->work_buffer, inbuf, inbuf_sz);
|
||||||
|
d->work_buffer_offset = inbuf_sz;
|
||||||
|
|
||||||
|
// Mark the port as busy and then schedule the appropriate async operation
|
||||||
|
d->async_op = cmd;
|
||||||
|
d->async_pool = G_TPOOL_GENERAL;
|
||||||
|
bdberl_tpool_run(d->async_pool, &do_async_txn_stat, d, 0, &d->async_job);
|
||||||
|
|
||||||
|
// Let caller know that the operation is in progress
|
||||||
|
// Outbuf is: <<0:32>>
|
||||||
|
RETURN_INT(0, outbuf);
|
||||||
|
}
|
||||||
|
case CMD_TXN_STAT_PRINT:
|
||||||
|
{
|
||||||
|
FAIL_IF_ASYNC_PENDING(d, outbuf);
|
||||||
|
|
||||||
|
// Inbuf is << Flags:32 >>
|
||||||
|
unsigned int flags = UNPACK_INT(inbuf, 0);
|
||||||
|
|
||||||
|
// Outbuf is <<Rc:32>>
|
||||||
|
// Run the command on the VM thread - this is for debugging only,
|
||||||
|
// any real monitoring will use the async lock_stat
|
||||||
|
int rc = G_DB_ENV->txn_stat_print(G_DB_ENV, flags);
|
||||||
|
RETURN_INT(rc, outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
*outbuf = 0;
|
*outbuf = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1711,6 +1752,127 @@ static void async_cleanup_and_send_mutex_stats(PortData* d, DB_MUTEX_STAT *msp)
|
||||||
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
|
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define STATS_TUPLE(base, member) \
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(#member), \
|
||||||
|
ERL_DRV_UINT, (base)->member, \
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
|
||||||
|
#define STATS_LSN_TUPLE(base, member) \
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(#member), \
|
||||||
|
ERL_DRV_UINT, (base)->member.file, \
|
||||||
|
ERL_DRV_UINT, (base)->member.offset, \
|
||||||
|
ERL_DRV_TUPLE, 2, \
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
|
||||||
|
static void send_txn_tstat(ErlDrvPort port, ErlDrvTermData pid, DB_TXN_ACTIVE *tasp)
|
||||||
|
{
|
||||||
|
char *name = tasp->name ? tasp->name : "<null>";
|
||||||
|
int name_len = strlen(name);
|
||||||
|
char tid_str[32];
|
||||||
|
char *status_str;
|
||||||
|
switch (tasp->status)
|
||||||
|
{
|
||||||
|
case TXN_ABORTED:
|
||||||
|
status_str = "aborted";
|
||||||
|
break;
|
||||||
|
case TXN_COMMITTED:
|
||||||
|
status_str = "committed";
|
||||||
|
break;
|
||||||
|
case TXN_PREPARED:
|
||||||
|
status_str = "prepared";
|
||||||
|
break;
|
||||||
|
case TXN_RUNNING:
|
||||||
|
status_str = "running";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status_str = "undefined";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tid_str_len = snprintf(tid_str, sizeof(tid_str), "%lu", (unsigned long) tasp->tid);
|
||||||
|
|
||||||
|
ErlDrvTermData response[] = {
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("txn"),
|
||||||
|
STATS_TUPLE(tasp, txnid), /* Transaction ID */
|
||||||
|
STATS_TUPLE(tasp, parentid), /* Transaction ID of parent */
|
||||||
|
STATS_TUPLE(tasp, pid), /* Process owning txn ID - pid_t */
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("tid"),/* OSX has 32-bit ints in erlang, so return as */
|
||||||
|
ERL_DRV_STRING, (ErlDrvTermData) tid_str, tid_str_len, /* a string */
|
||||||
|
ERL_DRV_TUPLE, 2,
|
||||||
|
STATS_LSN_TUPLE(tasp, lsn), /* LSN when transaction began */
|
||||||
|
STATS_LSN_TUPLE(tasp, read_lsn), /* Read LSN for MVCC */
|
||||||
|
STATS_TUPLE(tasp, mvcc_ref), /* MVCC reference count */
|
||||||
|
|
||||||
|
// Start of list
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("status"),
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(status_str),
|
||||||
|
ERL_DRV_TUPLE, 2,
|
||||||
|
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("name"),
|
||||||
|
ERL_DRV_STRING, (ErlDrvTermData) name, name_len,
|
||||||
|
ERL_DRV_TUPLE, 2,
|
||||||
|
|
||||||
|
|
||||||
|
// End of list
|
||||||
|
ERL_DRV_NIL,
|
||||||
|
ERL_DRV_LIST, 9+1,
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
};
|
||||||
|
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ST_STATS_LSN_TUPLE(base, member) \
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(#member), \
|
||||||
|
ERL_DRV_UINT, (base)->st_##member.file, \
|
||||||
|
ERL_DRV_UINT, (base)->st_##member.offset, \
|
||||||
|
ERL_DRV_TUPLE, 2, \
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
|
||||||
|
static void async_cleanup_and_send_txn_stats(PortData* d, DB_TXN_STAT *tsp)
|
||||||
|
{
|
||||||
|
// Save the port and pid references -- we need copies independent from the PortData
|
||||||
|
// structure. Once we release the port_lock after clearing the cmd, it's possible that
|
||||||
|
// the port could go away without waiting on us to finish. This is acceptable, but we need
|
||||||
|
// to be certain that there is no overlap of data between the two threads. driver_send_term
|
||||||
|
// is safe to use from a thread, even if the port you're sending from has already expired.
|
||||||
|
ErlDrvPort port = d->port;
|
||||||
|
ErlDrvTermData pid = d->port_owner;
|
||||||
|
async_cleanup(d);
|
||||||
|
|
||||||
|
// First send the array of active transactions */
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < tsp->st_nactive; i++)
|
||||||
|
{
|
||||||
|
send_txn_tstat(port, pid, tsp->st_txnarray+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then send the global stats
|
||||||
|
ErlDrvTermData response[] = {
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("ok"),
|
||||||
|
// Start of list
|
||||||
|
ST_STATS_TUPLE(tsp, nrestores), /* number of restored transactions
|
||||||
|
after recovery. */
|
||||||
|
ST_STATS_LSN_TUPLE(tsp, last_ckp), /* lsn of the last checkpoint */
|
||||||
|
ST_STATS_TUPLE(tsp, time_ckp), /* time of last checkpoint (time_t to uint) */
|
||||||
|
ST_STATS_TUPLE(tsp, last_txnid), /* last transaction id given out */
|
||||||
|
ST_STATS_TUPLE(tsp, maxtxns), /* maximum txns possible */
|
||||||
|
ST_STATS_TUPLE(tsp, naborts), /* number of aborted transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, nbegins), /* number of begun transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, ncommits), /* number of committed transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, nactive), /* number of active transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, nsnapshot), /* number of snapshot transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, maxnactive), /* maximum active transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, maxnsnapshot), /* maximum snapshot transactions */
|
||||||
|
ST_STATS_TUPLE(tsp, region_wait), /* Region lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(tsp, region_nowait), /* Region lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(tsp, regsize), /* Region size. */
|
||||||
|
// End of list
|
||||||
|
ERL_DRV_NIL,
|
||||||
|
ERL_DRV_LIST, 15+1,
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
};
|
||||||
|
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
|
||||||
|
}
|
||||||
|
|
||||||
static void do_async_put(void* arg)
|
static void do_async_put(void* arg)
|
||||||
{
|
{
|
||||||
|
@ -2090,6 +2252,33 @@ static void do_async_mutex_stat(void* arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void do_async_txn_stat(void* arg)
|
||||||
|
{
|
||||||
|
// Payload is: <<Flags:32 >>
|
||||||
|
PortData* d = (PortData*)arg;
|
||||||
|
|
||||||
|
// Extract operation flags
|
||||||
|
unsigned flags = UNPACK_INT(d->work_buffer, 0);
|
||||||
|
|
||||||
|
DB_TXN_STAT *tsp = NULL;
|
||||||
|
int rc = G_DB_ENV->txn_stat(G_DB_ENV, &tsp, flags);
|
||||||
|
if (rc != 0 || tsp == NULL)
|
||||||
|
{
|
||||||
|
async_cleanup_and_send_rc(d, rc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
async_cleanup_and_send_txn_stats(d, tsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, clean up stats
|
||||||
|
if (NULL != tsp)
|
||||||
|
{
|
||||||
|
free(tsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void* zalloc(unsigned int size)
|
static void* zalloc(unsigned int size)
|
||||||
{
|
{
|
||||||
void* res = driver_alloc(size);
|
void* res = driver_alloc(size);
|
||||||
|
|
|
@ -57,6 +57,8 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
||||||
#define CMD_MEMP_STAT_PRINT 26
|
#define CMD_MEMP_STAT_PRINT 26
|
||||||
#define CMD_MUTEX_STAT 27
|
#define CMD_MUTEX_STAT 27
|
||||||
#define CMD_MUTEX_STAT_PRINT 28
|
#define CMD_MUTEX_STAT_PRINT 28
|
||||||
|
#define CMD_TXN_STAT 29
|
||||||
|
#define CMD_TXN_STAT_PRINT 30
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command status values
|
* Command status values
|
||||||
|
|
|
@ -21,7 +21,7 @@ rm -rf system db-${DB_VER}
|
||||||
tar -xzf db-${DB_VER}.tar.gz && \
|
tar -xzf db-${DB_VER}.tar.gz && \
|
||||||
##(cd db-${DB_VER} && patch -p0 < ../bdb-align.patch ) && \
|
##(cd db-${DB_VER} && patch -p0 < ../bdb-align.patch ) && \
|
||||||
(cd db-${DB_VER}/build_unix && \
|
(cd db-${DB_VER}/build_unix && \
|
||||||
../dist/configure --prefix=$WORKDIR --disable-replication --disable-shared --with-pic && make && ranlib libdb-*.a && make install) && \
|
../dist/configure --prefix=$WORKDIR --enable-debug --disable-replication --disable-shared --with-pic && make && ranlib libdb-*.a && make install) && \
|
||||||
rm -rf db-${DB_VER}
|
rm -rf db-${DB_VER}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
-define(CMD_MEMP_STAT_PRINT, 26).
|
-define(CMD_MEMP_STAT_PRINT, 26).
|
||||||
-define(CMD_MUTEX_STAT, 27).
|
-define(CMD_MUTEX_STAT, 27).
|
||||||
-define(CMD_MUTEX_STAT_PRINT,28).
|
-define(CMD_MUTEX_STAT_PRINT,28).
|
||||||
|
-define(CMD_TXN_STAT, 29).
|
||||||
|
-define(CMD_TXN_STAT_PRINT, 30).
|
||||||
|
|
||||||
-define(DB_TYPE_BTREE, 1).
|
-define(DB_TYPE_BTREE, 1).
|
||||||
-define(DB_TYPE_HASH, 2).
|
-define(DB_TYPE_HASH, 2).
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
memp_stat_print/1,
|
memp_stat_print/1,
|
||||||
mutex_stat/1,
|
mutex_stat/1,
|
||||||
mutex_stat_print/1,
|
mutex_stat_print/1,
|
||||||
|
txn_stat/1,
|
||||||
|
txn_stat_print/1,
|
||||||
env_stat_print/1,
|
env_stat_print/1,
|
||||||
transaction/1, transaction/2, transaction/3,
|
transaction/1, transaction/2, transaction/3,
|
||||||
put/3, put/4,
|
put/3, put/4,
|
||||||
|
@ -1687,6 +1689,72 @@ mutex_stat_print(Opts) ->
|
||||||
Error -> {error, Error}
|
Error -> {error, Error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Retrieve transaction stats
|
||||||
|
%%
|
||||||
|
%% This function retrieves transaction statistics
|
||||||
|
%%
|
||||||
|
%% === Options ===
|
||||||
|
%%
|
||||||
|
%% <dl>
|
||||||
|
%% <dt>stat_clear</dt>
|
||||||
|
%% <dd>Reset statistics after returning their values</dd>
|
||||||
|
%% </dl>
|
||||||
|
%%
|
||||||
|
%% @spec txn_stat(Opts) -> {ok, [{atom(), number()}]} | {error, Error}
|
||||||
|
%% where
|
||||||
|
%% Opts = [atom()]
|
||||||
|
%%
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec txn_stat(Opts :: db_flags()) ->
|
||||||
|
{ok, [{atom(), number()}], [any()]} | db_error().
|
||||||
|
|
||||||
|
txn_stat(Opts) ->
|
||||||
|
Flags = process_flags(Opts),
|
||||||
|
Cmd = <<Flags:32/native>>,
|
||||||
|
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_TXN_STAT, Cmd),
|
||||||
|
case decode_rc(Result) of
|
||||||
|
ok ->
|
||||||
|
recv_txn_stat([]);
|
||||||
|
Error ->
|
||||||
|
{error, Error}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Print transaction stats
|
||||||
|
%%
|
||||||
|
%% This function prints transaction statistics to wherever
|
||||||
|
%% BDB messages are being sent
|
||||||
|
%%
|
||||||
|
%% === Options ===
|
||||||
|
%%
|
||||||
|
%% <dl>
|
||||||
|
%% <dt>stat_all</dt>
|
||||||
|
%% <dd>Display all available information.</dd>
|
||||||
|
%% <dt>stat_clear</dt>
|
||||||
|
%% <dd>Reset statistics after displaying their values.</dd>
|
||||||
|
%% </dl>
|
||||||
|
%%
|
||||||
|
%% @spec txn_stat_print(Opts) -> ok | {error, Error}
|
||||||
|
%% where
|
||||||
|
%% Opts = [atom()]
|
||||||
|
%%
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec txn_stat_print(Opts :: db_flags()) ->
|
||||||
|
ok | db_error().
|
||||||
|
txn_stat_print(Opts) ->
|
||||||
|
Flags = process_flags(Opts),
|
||||||
|
Cmd = <<Flags:32/native>>,
|
||||||
|
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_TXN_STAT_PRINT, Cmd),
|
||||||
|
case decode_rc(Result) of
|
||||||
|
ok -> ok;
|
||||||
|
Error -> {error, Error}
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc
|
%% @doc
|
||||||
|
@ -1926,3 +1994,16 @@ recv_memp_stat(Fstats) ->
|
||||||
{ok, Stats} ->
|
{ok, Stats} ->
|
||||||
{ok, Stats, Fstats}
|
{ok, Stats, Fstats}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Receive transaction stats
|
||||||
|
%%
|
||||||
|
recv_txn_stat(Tstats) ->
|
||||||
|
receive
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, decode_rc(Reason)};
|
||||||
|
{txn, Tstat} ->
|
||||||
|
recv_txn_stat([Tstat|Tstats]);
|
||||||
|
{ok, Stats} ->
|
||||||
|
{ok, Stats, Tstats}
|
||||||
|
end.
|
||||||
|
|
|
@ -38,7 +38,8 @@ all() ->
|
||||||
lock_stat_should_report_on_success,
|
lock_stat_should_report_on_success,
|
||||||
log_stat_should_report_on_success,
|
log_stat_should_report_on_success,
|
||||||
memp_stat_should_report_on_success,
|
memp_stat_should_report_on_success,
|
||||||
mutex_stat_should_report_on_success].
|
mutex_stat_should_report_on_success,
|
||||||
|
txn_stat_should_report_on_success].
|
||||||
|
|
||||||
|
|
||||||
dbconfig(Config) ->
|
dbconfig(Config) ->
|
||||||
|
@ -303,3 +304,11 @@ memp_stat_should_report_on_success(_Config) ->
|
||||||
mutex_stat_should_report_on_success(_Config) ->
|
mutex_stat_should_report_on_success(_Config) ->
|
||||||
{ok, _Stat} = bdberl:mutex_stat([]),
|
{ok, _Stat} = bdberl:mutex_stat([]),
|
||||||
done.
|
done.
|
||||||
|
|
||||||
|
txn_stat_should_report_on_success(_Config) ->
|
||||||
|
{ok, _GStat1, []} = bdberl:txn_stat([]),
|
||||||
|
bdberl:txn_begin(),
|
||||||
|
{ok, _GStat2, [_ATxnStat]} = bdberl:txn_stat([]),
|
||||||
|
bdberl:txn_abort(),
|
||||||
|
{ok, _GStat3, []} = bdberl:txn_stat([]),
|
||||||
|
done.
|
||||||
|
|
Loading…
Reference in a new issue