mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx-tools: rework mdbx_reader_list() & mdbx_stat.
Change-Id: I0524cad93ca439e74eba9486cbcbeacf4253dd84
This commit is contained in:
parent
2f2df1ee76
commit
7c39c16829
40
mdbx.h
40
mdbx.h
@ -2716,31 +2716,49 @@ LIBMDBX_API int mdbx_cmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
|||||||
LIBMDBX_API int mdbx_dcmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
LIBMDBX_API int mdbx_dcmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
||||||
const MDBX_val *b);
|
const MDBX_val *b);
|
||||||
|
|
||||||
/* A callback function used to print a message from the library.
|
/* A callback function used to enumerate the reader lock table.
|
||||||
*
|
*
|
||||||
* [in] msg The string to be printed.
|
|
||||||
* [in] ctx An arbitrary context pointer for the callback.
|
* [in] ctx An arbitrary context pointer for the callback.
|
||||||
|
* [in] num The serial number during enumeration, starting from 1.
|
||||||
|
* [in] slot The reader lock table slot number.
|
||||||
|
* [in] txnid The ID of the transaction being read,
|
||||||
|
* i.e. the MVCC-snaphot number.
|
||||||
|
* [in] lag The lag from a recent MVCC-snapshot, i.e. the number of
|
||||||
|
* committed transaction since read transaction started.
|
||||||
|
* [in] pid The reader process ID.
|
||||||
|
* [in] thread The reader thread ID.
|
||||||
|
* [in] bytes_used The number of last used page in the MVCC-snapshot which
|
||||||
|
* being read, i.e. database file can't shrinked beyond this.
|
||||||
|
* [in] bytes_retired The total size of the database pages that were retired by
|
||||||
|
* committed write transactions after the reader's
|
||||||
|
* MVCC-snapshot, i.e. the space which would be freed after
|
||||||
|
* the Reader releases the MVCC-snapshot for reuse by
|
||||||
|
* completion read transaction.
|
||||||
*
|
*
|
||||||
* Returns < 0 on failure, >= 0 on success. */
|
* Returns < 0 on failure, >= 0 on success. */
|
||||||
typedef int(MDBX_msg_func)(const char *msg, void *ctx);
|
typedef int(MDBX_reader_list_func)(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);
|
||||||
|
|
||||||
/* FIXME: Rework this function.
|
/* Enumarete the entries in the reader lock table.
|
||||||
*
|
|
||||||
* Dump the entries in the reader lock table.
|
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create()
|
||||||
* [in] func A MDBX_msg_func function
|
* [in] func A MDBX_reader_list_func function
|
||||||
* [in] ctx Anything the message function needs
|
* [in] ctx An arbitrary context pointer for the enumeration function.
|
||||||
*
|
*
|
||||||
* Returns < 0 on failure, >= 0 on success. */
|
* Returns A non-zero error value on failure and 0 on success,
|
||||||
LIBMDBX_API int mdbx_reader_list(MDBX_env *env, MDBX_msg_func *func, void *ctx);
|
* or MDBX_RESULT_TRUE (-1) if the reader lock table is empty. */
|
||||||
|
LIBMDBX_API int mdbx_reader_list(MDBX_env *env, MDBX_reader_list_func *func,
|
||||||
|
void *ctx);
|
||||||
|
|
||||||
/* Check for stale entries in the reader lock table.
|
/* Check for stale entries in the reader lock table.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create()
|
||||||
* [out] dead Number of stale slots that were cleared
|
* [out] dead Number of stale slots that were cleared
|
||||||
*
|
*
|
||||||
* Returns 0 on success, non-zero on failure. */
|
* Returns A non-zero error value on failure and 0 on success,
|
||||||
|
* or MDBX_RESULT_TRUE (-1) if a dead reader(s) found or mutex was recovered. */
|
||||||
LIBMDBX_API int mdbx_reader_check(MDBX_env *env, int *dead);
|
LIBMDBX_API int mdbx_reader_check(MDBX_env *env, int *dead);
|
||||||
|
|
||||||
/* Returns a lag of the reading for the given transaction.
|
/* Returns a lag of the reading for the given transaction.
|
||||||
|
@ -13195,46 +13195,66 @@ int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __cold mdbx_reader_list(MDBX_env *env, MDBX_msg_func *func, void *ctx) {
|
int __cold mdbx_reader_list(MDBX_env *env, MDBX_reader_list_func *func,
|
||||||
char buf[64];
|
void *ctx) {
|
||||||
int rc = 0, first = 1;
|
|
||||||
|
|
||||||
if (unlikely(!env || !func))
|
if (unlikely(!env || !func))
|
||||||
return (MDBX_EINVAL > 0) ? -MDBX_EINVAL : MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||||
return MDBX_EBADSIGN;
|
return MDBX_EBADSIGN;
|
||||||
|
|
||||||
const MDBX_lockinfo *const lck = env->me_lck;
|
int rc = MDBX_RESULT_TRUE;
|
||||||
if (likely(lck)) {
|
int serial = 0;
|
||||||
const unsigned snap_nreaders = lck->mti_numreaders;
|
if (likely(env->me_lck)) {
|
||||||
|
const unsigned snap_nreaders = env->me_lck->mti_numreaders;
|
||||||
for (unsigned i = 0; i < snap_nreaders; i++) {
|
for (unsigned i = 0; i < snap_nreaders; i++) {
|
||||||
if (lck->mti_readers[i].mr_pid) {
|
const MDBX_reader *r = env->me_lck->mti_readers + i;
|
||||||
const txnid_t txnid = lck->mti_readers[i].mr_txnid;
|
retry_reader:;
|
||||||
if (txnid == ~(txnid_t)0)
|
const mdbx_pid_t pid = r->mr_pid;
|
||||||
snprintf(buf, sizeof(buf), "%10" PRIuPTR " %" PRIxPTR " -\n",
|
if (!pid)
|
||||||
(uintptr_t)lck->mti_readers[i].mr_pid,
|
continue;
|
||||||
(uintptr_t)lck->mti_readers[i].mr_tid);
|
txnid_t txnid = r->mr_txnid;
|
||||||
else
|
const mdbx_tid_t tid = r->mr_tid;
|
||||||
snprintf(buf, sizeof(buf),
|
const pgno_t pages_used = r->mr_snapshot_pages_used;
|
||||||
"%10" PRIuPTR " %" PRIxPTR " %" PRIaTXN "\n",
|
const uint64_t reader_pages_retired = r->mr_snapshot_pages_retired;
|
||||||
(uintptr_t)lck->mti_readers[i].mr_pid,
|
mdbx_compiler_barrier();
|
||||||
(uintptr_t)lck->mti_readers[i].mr_tid, txnid);
|
if (unlikely(pid != r->mr_pid || txnid != r->mr_txnid ||
|
||||||
|
tid != r->mr_tid ||
|
||||||
|
pages_used != r->mr_snapshot_pages_used ||
|
||||||
|
reader_pages_retired != r->mr_snapshot_pages_retired))
|
||||||
|
goto retry_reader;
|
||||||
|
|
||||||
if (first) {
|
mdbx_assert(env, txnid > 0);
|
||||||
first = 0;
|
if (txnid == ~(txnid_t)0)
|
||||||
rc = func(" pid thread txnid\n", ctx);
|
txnid = 0;
|
||||||
if (rc < 0)
|
|
||||||
break;
|
size_t bytes_used = 0;
|
||||||
|
size_t bytes_retained = 0;
|
||||||
|
uint64_t lag = 0;
|
||||||
|
if (txnid) {
|
||||||
|
retry_header:;
|
||||||
|
const MDBX_meta *const recent_meta = mdbx_meta_head(env);
|
||||||
|
const uint64_t head_pages_retired = recent_meta->mm_pages_retired;
|
||||||
|
const txnid_t head_txnid = mdbx_meta_txnid_fluid(env, recent_meta);
|
||||||
|
mdbx_compiler_barrier();
|
||||||
|
if (unlikely(recent_meta != mdbx_meta_head(env) ||
|
||||||
|
head_pages_retired != recent_meta->mm_pages_retired) ||
|
||||||
|
head_txnid != mdbx_meta_txnid_fluid(env, recent_meta))
|
||||||
|
goto retry_header;
|
||||||
|
|
||||||
|
lag = head_txnid - txnid;
|
||||||
|
bytes_used = pgno2bytes(env, pages_used);
|
||||||
|
bytes_retained = (head_pages_retired > reader_pages_retired)
|
||||||
|
? pgno2bytes(env, (pgno_t)(head_pages_retired -
|
||||||
|
reader_pages_retired))
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
rc = func(buf, ctx);
|
rc = func(ctx, ++serial, i, pid, tid, txnid, lag, bytes_used,
|
||||||
if (rc < 0)
|
bytes_retained);
|
||||||
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (first)
|
|
||||||
rc = func("(no active readers)\n", ctx);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,27 @@ static void usage(char *prog) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int reader_list_func(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) {
|
||||||
|
(void)ctx;
|
||||||
|
if (num == 1)
|
||||||
|
printf("Reader Table Status\n"
|
||||||
|
" #\tslot\t%6s %*s %20s %10s %13s %13s\n",
|
||||||
|
"pid", (int)sizeof(size_t) * 2, "thread", "txnid", "lag", "used",
|
||||||
|
"retained");
|
||||||
|
|
||||||
|
printf(" %3d)\t[%d]\t%6" PRIdSIZE " %*" PRIxSIZE, num, slot, (size_t)pid,
|
||||||
|
(int)sizeof(size_t) * 2, (size_t)thread);
|
||||||
|
if (txnid)
|
||||||
|
printf(" %20" PRIu64 " %10" PRIu64 " %12.1fM %12.1fM\n", txnid, lag,
|
||||||
|
bytes_used / 1048576.0, bytes_retired / 1048576.0);
|
||||||
|
else
|
||||||
|
printf(" %20s %10s %13s %13s\n", "-", "0", "0", "0");
|
||||||
|
|
||||||
|
return user_break ? MDBX_RESULT_TRUE : MDBX_RESULT_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int o, rc;
|
int o, rc;
|
||||||
MDBX_env *env;
|
MDBX_env *env;
|
||||||
@ -206,13 +227,24 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rdrinfo) {
|
if (rdrinfo) {
|
||||||
printf("Reader Table Status\n");
|
rc = mdbx_reader_list(env, reader_list_func, nullptr);
|
||||||
rc = mdbx_reader_list(env, (MDBX_msg_func *)fputs, stdout);
|
if (rc == MDBX_RESULT_TRUE)
|
||||||
if (rdrinfo > 1) {
|
printf("Reader Table is empty\n");
|
||||||
|
else if (rc == MDBX_SUCCESS && rdrinfo > 1) {
|
||||||
int dead;
|
int dead;
|
||||||
mdbx_reader_check(env, &dead);
|
rc = mdbx_reader_check(env, &dead);
|
||||||
|
if (rc == MDBX_RESULT_TRUE) {
|
||||||
printf(" %d stale readers cleared.\n", dead);
|
printf(" %d stale readers cleared.\n", dead);
|
||||||
rc = mdbx_reader_list(env, (MDBX_msg_func *)fputs, stdout);
|
rc = mdbx_reader_list(env, reader_list_func, nullptr);
|
||||||
|
if (rc == MDBX_RESULT_TRUE)
|
||||||
|
printf(" Now Reader Table is empty\n");
|
||||||
|
} else
|
||||||
|
printf(" No stale readers.\n");
|
||||||
|
}
|
||||||
|
if (MDBX_IS_ERROR(rc)) {
|
||||||
|
fprintf(stderr, "mdbx_txn_begin failed, error %d %s\n", rc,
|
||||||
|
mdbx_strerror(rc));
|
||||||
|
goto env_close;
|
||||||
}
|
}
|
||||||
if (!(subname || alldbs || freinfo))
|
if (!(subname || alldbs || freinfo))
|
||||||
goto env_close;
|
goto env_close;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user