Added lock_stat/1 and lock_stat_print/1 functions to get lock stats.
This commit is contained in:
parent
05c1754e7f
commit
70dd9ee11a
|
@ -35,6 +35,7 @@ static void do_async_txnop(void* arg);
|
||||||
static void do_async_cursor_get(void* arg);
|
static void do_async_cursor_get(void* arg);
|
||||||
static void do_async_truncate(void* arg);
|
static void do_async_truncate(void* arg);
|
||||||
static void do_async_stat(void* arg);
|
static void do_async_stat(void* arg);
|
||||||
|
static void do_async_lock_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);
|
||||||
|
@ -846,6 +847,45 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
||||||
int rc = G_DB_ENV->stat_print(G_DB_ENV, flags);
|
int rc = G_DB_ENV->stat_print(G_DB_ENV, flags);
|
||||||
RETURN_INT(rc, outbuf);
|
RETURN_INT(rc, outbuf);
|
||||||
}
|
}
|
||||||
|
case CMD_LOCK_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_lock_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_LOCK_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->lock_stat_print(G_DB_ENV, flags);
|
||||||
|
RETURN_INT(rc, outbuf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*outbuf = 0;
|
*outbuf = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1302,6 +1342,81 @@ static void async_cleanup_and_send_queue_stats(PortData* d, DB_QUEUE_STAT *qsp)
|
||||||
#undef QUEUE_STATS_TUPLE
|
#undef QUEUE_STATS_TUPLE
|
||||||
#endif // ENABLE_QUEUE
|
#endif // ENABLE_QUEUE
|
||||||
|
|
||||||
|
#define ST_STATS_TUPLE(base, member) \
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(#member), \
|
||||||
|
ERL_DRV_UINT, (base)->st_##member, \
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
|
||||||
|
#define ST_STATS_INT_TUPLE(base, member) \
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom(#member), \
|
||||||
|
ERL_DRV_INT, (base)->st_##member, \
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
|
||||||
|
static void async_cleanup_and_send_lock_stats(PortData* d, DB_LOCK_STAT *lsp)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
ErlDrvTermData response[] = {
|
||||||
|
ERL_DRV_ATOM, driver_mk_atom("ok"),
|
||||||
|
// Start of list
|
||||||
|
ST_STATS_TUPLE(lsp, id), /* Last allocated locker ID. */
|
||||||
|
ST_STATS_TUPLE(lsp, cur_maxid), /* Current maximum unused ID. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxlocks), /* Maximum number of locks in table. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxlockers), /* Maximum num of lockers in table. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxobjects), /* Maximum num of objects in table. */
|
||||||
|
ST_STATS_TUPLE(lsp, partitions), /* number of partitions. */
|
||||||
|
ST_STATS_INT_TUPLE(lsp, nmodes), /* Number of lock modes. */
|
||||||
|
ST_STATS_TUPLE(lsp, nlockers), /* Current number of lockers. */
|
||||||
|
ST_STATS_TUPLE(lsp, nlocks), /* Current number of locks. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxnlocks), /* Maximum number of locks so far. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxhlocks), /* Maximum number of locks in any bucket. */
|
||||||
|
ST_STATS_TUPLE(lsp, locksteals), /* Number of lock steals so far. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxlsteals), /* Maximum number steals in any partition. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxnlockers), /* Maximum number of lockers so far. */
|
||||||
|
ST_STATS_TUPLE(lsp, nobjects), /* Current number of objects. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxnobjects), /* Maximum number of objects so far. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxhobjects), /* Maximum number of objectsin any bucket. */
|
||||||
|
ST_STATS_TUPLE(lsp, objectsteals), /* Number of objects steals so far. */
|
||||||
|
ST_STATS_TUPLE(lsp, maxosteals), /* Maximum number of steals in any partition. */
|
||||||
|
ST_STATS_TUPLE(lsp, nrequests), /* Number of lock gets. */
|
||||||
|
ST_STATS_TUPLE(lsp, nreleases), /* Number of lock puts. */
|
||||||
|
ST_STATS_TUPLE(lsp, nupgrade), /* Number of lock upgrades. */
|
||||||
|
ST_STATS_TUPLE(lsp, ndowngrade), /* Number of lock downgrades. */
|
||||||
|
ST_STATS_TUPLE(lsp, lock_wait), /* Lock conflicts w/ subsequent wait */
|
||||||
|
ST_STATS_TUPLE(lsp, lock_nowait), /* Lock conflicts w/o subsequent wait */
|
||||||
|
ST_STATS_TUPLE(lsp, ndeadlocks), /* Number of lock deadlocks. */
|
||||||
|
ST_STATS_TUPLE(lsp, locktimeout), /* Lock timeout. */
|
||||||
|
ST_STATS_TUPLE(lsp, nlocktimeouts), /* Number of lock timeouts. */
|
||||||
|
ST_STATS_TUPLE(lsp, txntimeout), /* Transaction timeout. */
|
||||||
|
ST_STATS_TUPLE(lsp, ntxntimeouts), /* Number of transaction timeouts. */
|
||||||
|
ST_STATS_TUPLE(lsp, part_wait), /* Partition lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, part_nowait), /* Partition lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, part_max_wait), /* Max partition lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, part_max_nowait), /* Max partition lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, objs_wait), /* Object lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, objs_nowait), /* Object lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, lockers_wait), /* Locker lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, lockers_nowait),/* Locker lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, region_wait), /* Region lock granted after wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, region_nowait), /* Region lock granted without wait. */
|
||||||
|
ST_STATS_TUPLE(lsp, hash_len), /* Max length of bucket. */
|
||||||
|
ST_STATS_TUPLE(lsp, regsize), /* Region size. - will have to cast to uint */
|
||||||
|
|
||||||
|
// End of list
|
||||||
|
ERL_DRV_NIL,
|
||||||
|
ERL_DRV_LIST, 42+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)
|
||||||
{
|
{
|
||||||
// Payload is: <<DbRef:32, Flags:32, KeyLen:32, Key:KeyLen, ValLen:32, Val:ValLen>>
|
// Payload is: <<DbRef:32, Flags:32, KeyLen:32, Key:KeyLen, ValLen:32, Val:ValLen>>
|
||||||
|
@ -1540,7 +1655,7 @@ static void do_async_stat(void* arg)
|
||||||
rc = db->stat(db, d->txn, &sp, flags);
|
rc = db->stat(db, d->txn, &sp, flags);
|
||||||
if (rc != 0 || sp == NULL)
|
if (rc != 0 || sp == NULL)
|
||||||
{
|
{
|
||||||
async_cleanup_and_send_rc(d, ERROR_INVALID_DB_TYPE);
|
async_cleanup_and_send_rc(d, rc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1571,6 +1686,32 @@ static void do_async_stat(void* arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_async_lock_stat(void* arg)
|
||||||
|
{
|
||||||
|
// Payload is: <<Flags:32 >>
|
||||||
|
PortData* d = (PortData*)arg;
|
||||||
|
|
||||||
|
// Extract operation flags
|
||||||
|
unsigned flags = UNPACK_INT(d->work_buffer, 0);
|
||||||
|
|
||||||
|
DB_LOCK_STAT *lsp = NULL;
|
||||||
|
int rc = G_DB_ENV->lock_stat(G_DB_ENV, &lsp, flags);
|
||||||
|
if (rc != 0 || lsp == NULL)
|
||||||
|
{
|
||||||
|
async_cleanup_and_send_rc(d, rc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
async_cleanup_and_send_lock_stats(d, lsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, clean up lock stats
|
||||||
|
if (NULL != lsp)
|
||||||
|
{
|
||||||
|
free(lsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* zalloc(unsigned int size)
|
static void* zalloc(unsigned int size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,8 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
||||||
#define CMD_DB_STAT 18
|
#define CMD_DB_STAT 18
|
||||||
#define CMD_DB_STAT_PRINT 19
|
#define CMD_DB_STAT_PRINT 19
|
||||||
#define CMD_ENV_STAT_PRINT 20
|
#define CMD_ENV_STAT_PRINT 20
|
||||||
|
#define CMD_LOCK_STAT 21
|
||||||
|
#define CMD_LOCK_STAT_PRINT 22
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command status values
|
* Command status values
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
-define(CMD_DB_STAT, 18).
|
-define(CMD_DB_STAT, 18).
|
||||||
-define(CMD_DB_STAT_PRINT, 19).
|
-define(CMD_DB_STAT_PRINT, 19).
|
||||||
-define(CMD_ENV_STAT_PRINT, 20).
|
-define(CMD_ENV_STAT_PRINT, 20).
|
||||||
|
-define(CMD_LOCK_STAT, 21).
|
||||||
|
-define(CMD_LOCK_STAT_PRINT, 22).
|
||||||
|
|
||||||
-define(DB_TYPE_BTREE, 1).
|
-define(DB_TYPE_BTREE, 1).
|
||||||
-define(DB_TYPE_HASH, 2).
|
-define(DB_TYPE_HASH, 2).
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
get_data_dirs/0,
|
get_data_dirs/0,
|
||||||
get_txn_timeout/0,
|
get_txn_timeout/0,
|
||||||
stat/2,
|
stat/2,
|
||||||
stat_print/1, stat_print/2,
|
stat_print/2,
|
||||||
|
lock_stat/1,
|
||||||
|
lock_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,
|
||||||
put_r/3, put_r/4,
|
put_r/3, put_r/4,
|
||||||
|
@ -1286,7 +1289,7 @@ get_txn_timeout() ->
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Retrieve database stats
|
%% Retrieve database stats
|
||||||
%%
|
%%
|
||||||
%% This function retrieves performance statistics from the database.
|
%% This function retrieves database statistics
|
||||||
%%
|
%%
|
||||||
%% === Options ===
|
%% === Options ===
|
||||||
%%
|
%%
|
||||||
|
@ -1336,11 +1339,12 @@ stat(Db, Opts) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Print database stats
|
%% Print database stats
|
||||||
%%
|
%%
|
||||||
%% This function prints performance statistics from the database to wherever
|
%% This function prints statistics from the database to wherever
|
||||||
%% BDB messages are being sent
|
%% BDB messages are being sent
|
||||||
%%
|
%%
|
||||||
%% === Options ===
|
%% === Options ===
|
||||||
|
@ -1382,6 +1386,87 @@ stat_print(Db, Opts) ->
|
||||||
Error -> {error, Error}
|
Error -> {error, Error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Retrieve lock stats
|
||||||
|
%%
|
||||||
|
%% This function retrieves lock statistics from the database.
|
||||||
|
%%
|
||||||
|
%% === Options ===
|
||||||
|
%%
|
||||||
|
%% <dl>
|
||||||
|
%% <dt>stat_clear</dt>
|
||||||
|
%% <dd>Reset statistics after returning their values</dd>
|
||||||
|
%% </dl>
|
||||||
|
%%
|
||||||
|
%% @spec stat(Opts) -> {ok, [{atom(), number()}]} | {error, Error}
|
||||||
|
%% where
|
||||||
|
%% Opts = [atom()]
|
||||||
|
%%
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec lock_stat(Opts :: db_flags()) ->
|
||||||
|
{ok, [{atom(), number()}]} | db_error().
|
||||||
|
|
||||||
|
lock_stat(Opts) ->
|
||||||
|
Flags = process_flags(Opts),
|
||||||
|
Cmd = <<Flags:32/native>>,
|
||||||
|
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_LOCK_STAT, Cmd),
|
||||||
|
case decode_rc(Result) of
|
||||||
|
ok ->
|
||||||
|
receive
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, decode_rc(Reason)};
|
||||||
|
{ok, Stats} ->
|
||||||
|
{ok, Stats}
|
||||||
|
end;
|
||||||
|
Error ->
|
||||||
|
{error, Error}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Print lock stats
|
||||||
|
%%
|
||||||
|
%% This function prints lock 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>
|
||||||
|
%% <dt>stat_lock_conf</dt>
|
||||||
|
%% <dd>Display the lock conflict matrix.</dd>
|
||||||
|
%% <dt>stat_lock_lockers</dt>
|
||||||
|
%% <dd>Display the lockers within hash chains.</dd>
|
||||||
|
%% <dt>stat_lock_objects</dt>
|
||||||
|
%% <dd>Display the lock objects within hash chains.</dd>
|
||||||
|
%% <dt>stat_lock_params</dt>
|
||||||
|
%% <dd>Display the locking subsystem parameters.</dd>
|
||||||
|
%% </dl>
|
||||||
|
%%
|
||||||
|
%% @spec lock_stat_print(Opts) -> ok | {error, Error}
|
||||||
|
%% where
|
||||||
|
%% Opts = [atom()]
|
||||||
|
%%
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec lock_stat_print(Opts :: db_flags()) ->
|
||||||
|
ok | db_error().
|
||||||
|
lock_stat_print(Opts) ->
|
||||||
|
Flags = process_flags(Opts),
|
||||||
|
Cmd = <<Flags:32/native>>,
|
||||||
|
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_LOCK_STAT_PRINT, Cmd),
|
||||||
|
case decode_rc(Result) of
|
||||||
|
ok -> ok;
|
||||||
|
Error -> {error, Error}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc
|
%% @doc
|
||||||
|
@ -1409,9 +1494,9 @@ stat_print(Db, Opts) ->
|
||||||
%%
|
%%
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec stat_print(Opts :: db_flags()) ->
|
-spec env_stat_print(Opts :: db_flags()) ->
|
||||||
ok | db_error().
|
ok | db_error().
|
||||||
stat_print(Opts) ->
|
env_stat_print(Opts) ->
|
||||||
Flags = process_flags(Opts),
|
Flags = process_flags(Opts),
|
||||||
Cmd = <<Flags:32/native>>,
|
Cmd = <<Flags:32/native>>,
|
||||||
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_ENV_STAT_PRINT, Cmd),
|
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_ENV_STAT_PRINT, Cmd),
|
||||||
|
@ -1537,6 +1622,10 @@ flag_value(Flag) ->
|
||||||
set_recno -> ?DB_SET_RECNO;
|
set_recno -> ?DB_SET_RECNO;
|
||||||
stat_all -> ?DB_STAT_ALL;
|
stat_all -> ?DB_STAT_ALL;
|
||||||
stat_clear -> ?DB_STAT_CLEAR;
|
stat_clear -> ?DB_STAT_CLEAR;
|
||||||
|
stat_lock_conf -> ?DB_STAT_LOCK_CONF;
|
||||||
|
stat_lock_lockers -> ?DB_STAT_LOCK_LOCKERS;
|
||||||
|
stat_lock_objects -> ?DB_STAT_LOCK_OBJECTS;
|
||||||
|
stat_lock_params -> ?DB_STAT_LOCK_PARAMS;
|
||||||
stat_subsystem -> ?DB_STAT_SUBSYSTEM;
|
stat_subsystem -> ?DB_STAT_SUBSYSTEM;
|
||||||
threaded -> ?DB_THREAD;
|
threaded -> ?DB_THREAD;
|
||||||
truncate -> ?DB_TRUNCATE;
|
truncate -> ?DB_TRUNCATE;
|
||||||
|
|
|
@ -34,7 +34,8 @@ all() ->
|
||||||
truncate_all_should_empty_all_databases,
|
truncate_all_should_empty_all_databases,
|
||||||
btree_stat_should_report_on_success,
|
btree_stat_should_report_on_success,
|
||||||
hash_stat_should_report_on_success,
|
hash_stat_should_report_on_success,
|
||||||
stat_should_fail_on_bad_dbref].
|
stat_should_fail_on_bad_dbref,
|
||||||
|
lock_stat_should_report_on_success].
|
||||||
|
|
||||||
|
|
||||||
dbconfig(Config) ->
|
dbconfig(Config) ->
|
||||||
|
@ -277,3 +278,9 @@ hash_stat_should_report_on_success(_Config) ->
|
||||||
stat_should_fail_on_bad_dbref(_Config) ->
|
stat_should_fail_on_bad_dbref(_Config) ->
|
||||||
{error, invalid_db} = bdberl:stat(10000000, []),
|
{error, invalid_db} = bdberl:stat(10000000, []),
|
||||||
done.
|
done.
|
||||||
|
|
||||||
|
lock_stat_should_report_on_success(_Config) ->
|
||||||
|
{ok, Stat} = bdberl:lock_stat([]),
|
||||||
|
%% Check a lock stat that that probably won't change
|
||||||
|
2147483647 = proplists:get_value(cur_maxid, Stat),
|
||||||
|
done.
|
||||||
|
|
Loading…
Reference in a new issue