diff --git a/mdbx.h b/mdbx.h index 475dcc47..4413da60 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1606,6 +1606,31 @@ typedef struct MDBX_envinfo { uint32_t mi_numreaders; /* max reader slots used in the environment */ uint32_t mi_dxb_pagesize; /* database pagesize */ uint32_t mi_sys_pagesize; /* system pagesize */ + + uint64_t + mi_bootid[2]; /* A mostly unique ID that is regenerated on each boot. + As such it can be used to identify the local + machine's current boot. MDBX uses such when open + the database to determine whether rollback required + to the last steady sync point or not. I.e. if current + bootid is differ from the value within a database then + the system was rebooted and all changes since last steady + sync must be reverted for data integrity. Zeros mean that + no relevant information is available from the system. */ + uint64_t mi_unsync_volume; /* bytes not explicitly synchronized to disk */ + uint64_t mi_autosync_threshold; /* current auto-sync threshold, see + mdbx_env_set_syncbytes(). */ + uint32_t mi_since_sync_seconds16dot16; /* time since the last steady sync in + 1/65536 of second */ + uint32_t mi_autosync_period_seconds16dot16 /* current auto-sync period in + 1/65536 of second, see + mdbx_env_set_syncperiod(). */ + ; + uint32_t mi_since_reader_check_seconds16dot16; /* time since the last readers + check in 1/65536 of second, + see mdbx_reader_check(). */ + uint32_t mi_mode; /* current environment mode, the same as + mdbx_env_get_flags() returns. */ } MDBX_envinfo; /* Return information about the MDBX environment. diff --git a/src/elements/core.c b/src/elements/core.c index 3e6c680d..fe9bd349 100644 --- a/src/elements/core.c +++ b/src/elements/core.c @@ -13027,12 +13027,14 @@ int __cold mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, env = txn->mt_env; } - if (unlikely(bytes != sizeof(MDBX_envinfo))) + const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); + if (unlikely(bytes != sizeof(MDBX_envinfo)) && bytes != size_before_bootid) return MDBX_EINVAL; const MDBX_meta *const meta0 = METAPAGE(env, 0); const MDBX_meta *const meta1 = METAPAGE(env, 1); const MDBX_meta *const meta2 = METAPAGE(env, 2); + pgno_t unsynced_pages; while (1) { if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) return MDBX_PANIC; @@ -13063,6 +13065,8 @@ int __cold mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, arg->mi_geo.upper = pgno2bytes(env, txn_meta->mm_geo.upper); arg->mi_geo.shrink = pgno2bytes(env, txn_meta->mm_geo.shrink); arg->mi_geo.grow = pgno2bytes(env, txn_meta->mm_geo.grow); + unsynced_pages = *env->me_unsynced_pages + + (*env->me_meta_sync_txnid != (uint32_t)arg->mi_last_pgno); arg->mi_mapsize = env->me_mapsize; mdbx_compiler_barrier(); @@ -13082,15 +13086,32 @@ int __cold mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, arg->mi_dxb_pagesize = env->me_psize; arg->mi_sys_pagesize = env->me_os_psize; + const MDBX_lockinfo *const lck = env->me_lck; + if (likely(bytes > size_before_bootid)) { + arg->mi_unsync_volume = pgno2bytes(env, unsynced_pages); + const uint64_t monotime_now = mdbx_osal_monotime(); + arg->mi_since_sync_seconds16dot16 = + mdbx_osal_monotime_to_16dot16(monotime_now - *env->me_sync_timestamp); + arg->mi_since_reader_check_seconds16dot16 = + lck ? mdbx_osal_monotime_to_16dot16(monotime_now - + lck->mti_reader_check_timestamp) + : 0; + arg->mi_autosync_threshold = pgno2bytes(env, *env->me_autosync_threshold); + arg->mi_autosync_period_seconds16dot16 = + mdbx_osal_monotime_to_16dot16(*env->me_autosync_period); + arg->mi_bootid[0] = lck ? lck->mti_bootid[0] : 0; + arg->mi_bootid[1] = lck ? lck->mti_bootid[1] : 0; + arg->mi_mode = lck ? lck->mti_envmode : env->me_flags; + } + arg->mi_self_latter_reader_txnid = arg->mi_latter_reader_txnid = 0; - if (env->me_lck) { - MDBX_reader *rlt = env->me_lck->mti_readers; + if (lck) { arg->mi_self_latter_reader_txnid = arg->mi_latter_reader_txnid = arg->mi_recent_txnid; for (unsigned i = 0; i < arg->mi_numreaders; ++i) { - const uint32_t pid = rlt[i].mr_pid; + const uint32_t pid = lck->mti_readers[i].mr_pid; if (pid) { - const txnid_t txnid = safe64_read(&rlt[i].mr_txnid); + const txnid_t txnid = safe64_read(&lck->mti_readers[i].mr_txnid); if (arg->mi_latter_reader_txnid > txnid) arg->mi_latter_reader_txnid = txnid; if (pid == env->me_pid && arg->mi_self_latter_reader_txnid > txnid) diff --git a/src/elements/internals.h b/src/elements/internals.h index a7814153..d1f8caa2 100644 --- a/src/elements/internals.h +++ b/src/elements/internals.h @@ -535,8 +535,12 @@ typedef struct MDBX_lockinfo { /* Marker to distinguish uniqueness of DB/CLK.*/ volatile uint64_t mti_bait_uniqueness; - /* the hash of /proc/sys/kernel/random/boot_id or analogue */ - volatile uint64_t mti_boot_id; + /* The analogue /proc/sys/kernel/random/boot_id or similar to determine + * whether the system was rebooted after the last use of the database files. + * If there was no reboot, but there is no need to rollback to the last + * steady sync point. Zeros mean that no relevant information is available + * from the system. */ + volatile uint64_t mti_bootid[2]; alignas(MDBX_CACHELINE_SIZE) /* cacheline ---------------------------------*/ #ifdef MDBX_OSAL_LOCK