ruby-mdbx/ext/mdbx_ext/stats.c
mahlon 79e818f774 Fix build for FreeBSD/clang.
FossilOrigin-Name: b9c4edee21f811625fec60f84a248160ddc09402d9e58d0374c03223b650a5ac
2024-03-25 03:03:17 +00:00

223 lines
5.8 KiB
C

/* vim: set noet sta sw=4 ts=4 :
*
* Expose a bunch of mdbx internals to ruby.
* This is all largely stolen from mdbx_stat.c.
*
*/
#include "mdbx_ext.h"
/*
* Metadata specific to the mdbx build.
*/
void
rmdbx_gather_build_stats( VALUE stat )
{
rb_hash_aset( stat, ID2SYM(rb_intern("build_compiler")),
rb_str_new_cstr(mdbx_build.compiler) );
rb_hash_aset( stat, ID2SYM(rb_intern("build_flags")),
rb_str_new_cstr(mdbx_build.flags) );
rb_hash_aset( stat, ID2SYM(rb_intern("build_options")),
rb_str_new_cstr(mdbx_build.options) );
rb_hash_aset( stat, ID2SYM(rb_intern("build_target")),
rb_str_new_cstr(mdbx_build.target) );
return;
}
/*
* Grab current memory usage. (Available since MDBX 0.10.0).
*/
void
rmdbx_gather_memory_stats( VALUE stat )
{
if (! ( MDBX_VERSION_MAJOR >= 0 && MDBX_VERSION_MINOR >= 10 ) )
return;
VALUE mem = rb_hash_new();
rb_hash_aset( stat, ID2SYM(rb_intern("system_memory")), mem );
intptr_t page_size;
intptr_t total_pages;
intptr_t avail_pages;
mdbx_get_sysraminfo( &page_size, &total_pages, &avail_pages );
rb_hash_aset( mem, ID2SYM(rb_intern("pagesize")), LONG2FIX( page_size ) );
rb_hash_aset( mem, ID2SYM(rb_intern("total_pages")), LONG2FIX( total_pages ) );
rb_hash_aset( mem, ID2SYM(rb_intern("avail_pages")), LONG2FIX( avail_pages ) );
return;
}
/*
* Metadata for the database file.
*/
void
rmdbx_gather_datafile_stats(
VALUE environ,
MDBX_stat mstat,
MDBX_envinfo menvinfo )
{
VALUE datafile = rb_hash_new();
rb_hash_aset( environ, ID2SYM(rb_intern("datafile")), datafile );
rb_hash_aset( datafile, ID2SYM(rb_intern("size_current")),
LONG2NUM(menvinfo.mi_geo.current) );
rb_hash_aset( datafile, ID2SYM(rb_intern("pages")),
LONG2NUM(menvinfo.mi_geo.current / mstat.ms_psize) );
if ( menvinfo.mi_geo.lower != menvinfo.mi_geo.upper ) {
rb_hash_aset( datafile, ID2SYM(rb_intern("type")),
rb_str_new_cstr("dynamic") );
rb_hash_aset( datafile, ID2SYM(rb_intern("size_lower")),
LONG2NUM( menvinfo.mi_geo.lower ) );
rb_hash_aset( datafile, ID2SYM(rb_intern("size_upper")),
LONG2FIX( menvinfo.mi_geo.upper ) );
rb_hash_aset( datafile, ID2SYM(rb_intern("growth_step")),
LONG2NUM( menvinfo.mi_geo.grow ) );
rb_hash_aset( datafile, ID2SYM(rb_intern("shrink_threshold")),
LONG2NUM( menvinfo.mi_geo.shrink ) );
}
else {
rb_hash_aset( datafile, ID2SYM(rb_intern("type")),
rb_str_new_cstr("fixed") );
}
return;
}
/*
* Metadata for the database environment.
*/
void
rmdbx_gather_environment_stats(
VALUE stat,
MDBX_stat mstat,
MDBX_envinfo menvinfo )
{
VALUE environ = rb_hash_new();
rb_hash_aset( stat, ID2SYM(rb_intern("environment")), environ );
rb_hash_aset( environ, ID2SYM(rb_intern("pagesize")),
INT2NUM(mstat.ms_psize) );
rb_hash_aset( environ, ID2SYM(rb_intern("branch_pages")),
LONG2NUM(mstat.ms_branch_pages) );
rb_hash_aset( environ, ID2SYM(rb_intern("leaf_pages")),
LONG2NUM(mstat.ms_leaf_pages) );
rb_hash_aset( environ, ID2SYM(rb_intern("overflow_pages")),
LONG2NUM(mstat.ms_overflow_pages) );
rb_hash_aset( environ, ID2SYM(rb_intern("btree_depth")),
INT2NUM(mstat.ms_depth) );
rb_hash_aset( environ, ID2SYM(rb_intern("entries")),
LONG2NUM(mstat.ms_entries) );
rb_hash_aset( environ, ID2SYM(rb_intern("last_txnid")),
LONG2NUM(menvinfo.mi_recent_txnid) );
rb_hash_aset( environ, ID2SYM(rb_intern("last_reader_txnid")),
LONG2NUM(menvinfo.mi_latter_reader_txnid) );
rb_hash_aset( environ, ID2SYM(rb_intern("max_readers")),
INT2NUM(menvinfo.mi_maxreaders) );
rb_hash_aset( environ, ID2SYM(rb_intern("readers_in_use")),
INT2NUM(menvinfo.mi_numreaders) );
rmdbx_gather_datafile_stats( environ, mstat, menvinfo );
return;
}
/*
* Callback iterator for pulling each reader's current state.
* See: https://erthink.github.io/libmdbx/group__c__statinfo.html#gad1ab5cf54d4a9f7d4c2999078920e8b0
*
*/
int
rmdbx_reader_list_cb(
void *ctx,
int num,
int slot,
mdbx_pid_t pid,
mdbx_tid_t thread,
uint64_t txnid,
uint64_t lag,
size_t bytes_used,
size_t bytes_retired )
{
VALUE reader = rb_hash_new();
rb_hash_aset( reader, ID2SYM(rb_intern("slot")),
INT2NUM( slot ) );
rb_hash_aset( reader, ID2SYM(rb_intern("pid")),
LONG2FIX( pid ) );
rb_hash_aset( reader, ID2SYM(rb_intern("thread")),
LONG2FIX( (uint64_t)thread ) );
rb_hash_aset( reader, ID2SYM(rb_intern("txnid")),
LONG2FIX( txnid ) );
rb_hash_aset( reader, ID2SYM(rb_intern("lag")),
LONG2FIX( lag ) );
rb_hash_aset( reader, ID2SYM(rb_intern("bytes_used")),
LONG2FIX( bytes_used ) );
rb_hash_aset( reader, ID2SYM(rb_intern("bytes_retired")),
LONG2FIX( bytes_retired ) );
rb_ary_push( (VALUE)ctx, reader );
return 0;
}
/*
* Metadata for current reader slots.
* Initialize an array and populate it with each reader's statistics.
*/
void
rmdbx_gather_reader_stats(
rmdbx_db_t *db,
VALUE stat,
MDBX_stat mstat,
MDBX_envinfo menvinfo )
{
VALUE readers = rb_ary_new();
mdbx_reader_list( db->env, rmdbx_reader_list_cb, (void*)readers );
rb_hash_aset( stat, ID2SYM(rb_intern("readers")), readers );
return;
}
/*
* Build and return a hash of various statistic/metadata
* for the open +db+ handle.
*/
VALUE
rmdbx_gather_stats( rmdbx_db_t *db )
{
VALUE stat = rb_hash_new();
int rc;
MDBX_stat mstat;
MDBX_envinfo menvinfo;
rmdbx_gather_memory_stats( stat );
rmdbx_gather_build_stats( stat );
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
rc = mdbx_env_info_ex( db->env, db->txn, &menvinfo, sizeof(menvinfo) );
if ( rc != MDBX_SUCCESS )
rb_raise( rmdbx_eDatabaseError, "mdbx_env_info_ex: (%d) %s", rc, mdbx_strerror(rc) );
rc = mdbx_env_stat_ex( db->env, db->txn, &mstat, sizeof(mstat) );
if ( rc != MDBX_SUCCESS )
rb_raise( rmdbx_eDatabaseError, "mdbx_env_stat_ex: (%d) %s", rc, mdbx_strerror(rc) );
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
rmdbx_gather_environment_stats( stat, mstat, menvinfo );
rmdbx_gather_reader_stats( db, stat, mstat, menvinfo );
return stat;
}