mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-04 17:14:12 +08:00
mdbx: fix/rework mdbx_env_stat_ex()
to return stat of the whole env.
Resolves https://github.com/erthink/libmdbx/issues/190 Included fix for the first version of this change. Change-Id: I8357de24fda2ab4c93510574055b52d6e16b0c15
This commit is contained in:
parent
a56c72d190
commit
732d3cd2d4
158
src/core.c
158
src/core.c
@ -18866,66 +18866,130 @@ __cold int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *arg) {
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common code for mdbx_dbi_stat() and mdbx_env_stat().
|
|
||||||
* [in] env the environment to operate in.
|
|
||||||
* [in] db the MDBX_db record containing the stats to return.
|
|
||||||
* [out] arg the address of an MDBX_stat structure to receive the stats.
|
|
||||||
* Returns 0, this function always succeeds. */
|
|
||||||
static void mdbx_stat0(const MDBX_env *env, const MDBX_db *db, MDBX_stat *dest,
|
|
||||||
size_t bytes) {
|
|
||||||
dest->ms_psize = env->me_psize;
|
|
||||||
dest->ms_depth = db->md_depth;
|
|
||||||
dest->ms_branch_pages = db->md_branch_pages;
|
|
||||||
dest->ms_leaf_pages = db->md_leaf_pages;
|
|
||||||
dest->ms_overflow_pages = db->md_overflow_pages;
|
|
||||||
dest->ms_entries = db->md_entries;
|
|
||||||
if (likely(bytes >=
|
|
||||||
offsetof(MDBX_stat, ms_mod_txnid) + sizeof(dest->ms_mod_txnid)))
|
|
||||||
dest->ms_mod_txnid = db->md_mod_txnid;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
|
#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
|
||||||
__cold int mdbx_env_stat(const MDBX_env *env, MDBX_stat *stat, size_t bytes) {
|
__cold int mdbx_env_stat(const MDBX_env *env, MDBX_stat *stat, size_t bytes) {
|
||||||
return __inline_mdbx_env_stat(env, stat, bytes);
|
return __inline_mdbx_env_stat(env, stat, bytes);
|
||||||
}
|
}
|
||||||
#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
|
#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
|
||||||
|
|
||||||
|
static void stat_get(const MDBX_db *db, MDBX_stat *st, size_t bytes) {
|
||||||
|
st->ms_depth = db->md_depth;
|
||||||
|
st->ms_branch_pages = db->md_branch_pages;
|
||||||
|
st->ms_leaf_pages = db->md_leaf_pages;
|
||||||
|
st->ms_overflow_pages = db->md_overflow_pages;
|
||||||
|
st->ms_entries = db->md_entries;
|
||||||
|
if (likely(bytes >=
|
||||||
|
offsetof(MDBX_stat, ms_mod_txnid) + sizeof(st->ms_mod_txnid)))
|
||||||
|
st->ms_mod_txnid = db->md_mod_txnid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stat_add(const MDBX_db *db, MDBX_stat *const st,
|
||||||
|
const size_t bytes) {
|
||||||
|
st->ms_depth += db->md_depth;
|
||||||
|
st->ms_branch_pages += db->md_branch_pages;
|
||||||
|
st->ms_leaf_pages += db->md_leaf_pages;
|
||||||
|
st->ms_overflow_pages += db->md_overflow_pages;
|
||||||
|
st->ms_entries += db->md_entries;
|
||||||
|
if (likely(bytes >=
|
||||||
|
offsetof(MDBX_stat, ms_mod_txnid) + sizeof(st->ms_mod_txnid)))
|
||||||
|
st->ms_mod_txnid = (st->ms_mod_txnid > db->md_mod_txnid) ? st->ms_mod_txnid
|
||||||
|
: db->md_mod_txnid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __cold int stat_acc(const MDBX_txn *txn, MDBX_stat *st, size_t bytes) {
|
||||||
|
int err = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||||
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
st->ms_psize = txn->mt_env->me_psize;
|
||||||
|
#if 1
|
||||||
|
/* assuming GC is internal and not subject for accounting */
|
||||||
|
stat_get(&txn->mt_dbs[MAIN_DBI], st, bytes);
|
||||||
|
#else
|
||||||
|
stat_get(&txn->mt_dbs[FREE_DBI], st, bytes);
|
||||||
|
stat_add(&txn->mt_dbs[MAIN_DBI], st, bytes);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* account opened named subDBs */
|
||||||
|
for (MDBX_dbi dbi = CORE_DBS; dbi < txn->mt_numdbs; dbi++)
|
||||||
|
if ((txn->mt_dbistate[dbi] & (DBI_VALID | DBI_STALE)) == DBI_VALID)
|
||||||
|
stat_add(txn->mt_dbs + dbi, st, bytes);
|
||||||
|
|
||||||
|
if (!(txn->mt_dbs[MAIN_DBI].md_flags & (MDBX_DUPSORT | MDBX_INTEGERKEY)) &&
|
||||||
|
txn->mt_dbs[MAIN_DBI].md_entries /* TODO: use `md_subs` field */) {
|
||||||
|
MDBX_cursor_couple cx;
|
||||||
|
err = mdbx_cursor_init(&cx.outer, (MDBX_txn *)txn, MAIN_DBI);
|
||||||
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* scan and account not opened named subDBs */
|
||||||
|
err = mdbx_page_search(&cx.outer, NULL, MDBX_PS_FIRST);
|
||||||
|
while (err == MDBX_SUCCESS) {
|
||||||
|
const MDBX_page *mp = cx.outer.mc_pg[cx.outer.mc_top];
|
||||||
|
for (unsigned i = 0; i < page_numkeys(mp); i++) {
|
||||||
|
const MDBX_node *node = page_node(mp, i);
|
||||||
|
if (node_flags(node) != F_SUBDATA)
|
||||||
|
continue;
|
||||||
|
if (unlikely(node_ds(node) != sizeof(MDBX_db)))
|
||||||
|
return MDBX_CORRUPTED;
|
||||||
|
|
||||||
|
/* skip opened and already accounted */
|
||||||
|
for (MDBX_dbi dbi = CORE_DBS; dbi < txn->mt_numdbs; dbi++)
|
||||||
|
if ((txn->mt_dbistate[dbi] & (DBI_VALID | DBI_STALE)) == DBI_VALID &&
|
||||||
|
node_ks(node) == txn->mt_dbxs[dbi].md_name.iov_len &&
|
||||||
|
memcmp(node_key(node), txn->mt_dbxs[dbi].md_name.iov_base,
|
||||||
|
node_ks(node)) == 0) {
|
||||||
|
node = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
MDBX_db db;
|
||||||
|
memcpy(&db, node_data(node), sizeof(db));
|
||||||
|
stat_add(&db, st, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = mdbx_cursor_sibling(&cx.outer, SIBLING_RIGHT);
|
||||||
|
}
|
||||||
|
if (unlikely(err != MDBX_NOTFOUND))
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MDBX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
__cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
|
__cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
|
||||||
MDBX_stat *dest, size_t bytes) {
|
MDBX_stat *dest, size_t bytes) {
|
||||||
if (unlikely((env == NULL && txn == NULL) || dest == NULL))
|
if (unlikely(!dest))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
if (txn) {
|
|
||||||
int err = check_txn(txn, MDBX_TXN_BLOCKED);
|
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (env) {
|
|
||||||
int err = check_env(env, true);
|
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
|
||||||
return err;
|
|
||||||
if (txn && unlikely(txn->mt_env != env))
|
|
||||||
return MDBX_EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
|
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
|
||||||
if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
|
if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
if (txn) {
|
if (likely(txn)) {
|
||||||
mdbx_stat0(txn->mt_env, &txn->mt_dbs[MAIN_DBI], dest, bytes);
|
if (env && unlikely(txn->mt_env != env))
|
||||||
return MDBX_SUCCESS;
|
return MDBX_EINVAL;
|
||||||
|
return stat_acc(txn, dest, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
int err = check_env(env, true);
|
||||||
const MDBX_meta *const recent_meta = mdbx_meta_head(env);
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
const txnid_t txnid = mdbx_meta_txnid_fluid(env, recent_meta);
|
return err;
|
||||||
mdbx_stat0(env, &recent_meta->mm_dbs[MAIN_DBI], dest, bytes);
|
|
||||||
mdbx_compiler_barrier();
|
if (env->me_txn0 && env->me_txn0->mt_owner == mdbx_thread_self())
|
||||||
if (likely(txnid == mdbx_meta_txnid_fluid(env, recent_meta) &&
|
/* inside write-txn */
|
||||||
recent_meta == mdbx_meta_head(env)))
|
return stat_acc(env->me_txn, dest, bytes);
|
||||||
return MDBX_SUCCESS;
|
|
||||||
}
|
MDBX_txn *tmp_txn;
|
||||||
|
err = mdbx_txn_begin((MDBX_env *)env, NULL, MDBX_TXN_RDONLY, &tmp_txn);
|
||||||
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
const int rc = stat_acc(tmp_txn, dest, bytes);
|
||||||
|
err = mdbx_txn_abort(tmp_txn);
|
||||||
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
|
return err;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
__cold int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
__cold int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
@ -19479,7 +19543,9 @@ __cold int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
|
|||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
mdbx_stat0(txn->mt_env, &txn->mt_dbs[dbi], dest, bytes);
|
|
||||||
|
dest->ms_psize = txn->mt_env->me_psize;
|
||||||
|
stat_get(&txn->mt_dbs[dbi], dest, bytes);
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user