mdbx: fix operation for unusual small/large system page size.

More for https://github.com/erthink/libmdbx/issues/157

Change-Id: I4f2ed54b50653d0375538b82c48590d1037cd93b
This commit is contained in:
Leonid Yuriev 2021-01-29 21:19:58 +03:00
parent 6cfac546a1
commit f698f07ff9
6 changed files with 34 additions and 14 deletions

View File

@ -46,6 +46,7 @@ New features:
- a spilled pages, including overflow/large pages, now can be reused and refunded/compactified in nested transactions; - a spilled pages, including overflow/large pages, now can be reused and refunded/compactified in nested transactions;
- more effective refunding/compactification especially for the loosed page cache. - more effective refunding/compactification especially for the loosed page cache.
- Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options. - Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options.
- Added `mdbx_default_pagesize()` function.
Fixes: Fixes:
@ -58,6 +59,7 @@ Fixes:
- Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit. - Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit.
- Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://github.com/erthink/libmdbx/issues/153). - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://github.com/erthink/libmdbx/issues/153).
- Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://github.com/erthink/libmdbx/issues/123). - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://github.com/erthink/libmdbx/issues/123).
- Fixed operation on systems with unusual small/large page size, including PowerPC (https://github.com/erthink/libmdbx/issues/157).
## v0.9.2 at 2020-11-27 ## v0.9.2 at 2020-11-27

6
mdbx.h
View File

@ -2852,6 +2852,12 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_maxdbs,
return rc; return rc;
} }
/** \brief Returns the default size of database page for the current system.
* \ingroup c_statinfo
* \details Default size of database page depends on the size of the system
* page and usually exactly match it. */
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API size_t mdbx_default_pagesize(void);
/** \brief Get the maximum size of keys can write. /** \brief Get the maximum size of keys can write.
* \ingroup c_statinfo * \ingroup c_statinfo
* *

View File

@ -1838,7 +1838,9 @@ public:
bool is_empty() const; bool is_empty() const;
/// \brief Returns default page size for current system/platform. /// \brief Returns default page size for current system/platform.
static size_t default_pagesize() noexcept; static size_t default_pagesize() noexcept {
return ::mdbx_default_pagesize();
}
struct limits { struct limits {
limits() = delete; limits() = delete;

View File

@ -346,10 +346,18 @@ __cold int mdbx_env_get_maxkeysize_ex(const MDBX_env *env,
return (int)mdbx_limits_keysize_max((intptr_t)env->me_psize, flags); return (int)mdbx_limits_keysize_max((intptr_t)env->me_psize, flags);
} }
size_t mdbx_default_pagesize(void) {
size_t pagesize = mdbx_syspagesize();
mdbx_ensure(nullptr, is_powerof2(pagesize));
pagesize = (pagesize >= MIN_PAGESIZE) ? pagesize : MIN_PAGESIZE;
pagesize = (pagesize <= MAX_PAGESIZE) ? pagesize : MAX_PAGESIZE;
return pagesize;
}
__cold intptr_t mdbx_limits_keysize_max(intptr_t pagesize, __cold intptr_t mdbx_limits_keysize_max(intptr_t pagesize,
MDBX_db_flags_t flags) { MDBX_db_flags_t flags) {
if (pagesize < 1) if (pagesize < 1)
pagesize = (intptr_t)mdbx_syspagesize(); pagesize = (intptr_t)mdbx_default_pagesize();
if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE || if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
pagesize > (intptr_t)MAX_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!is_powerof2((size_t)pagesize))) !is_powerof2((size_t)pagesize)))
@ -383,7 +391,7 @@ __cold int mdbx_env_get_maxvalsize_ex(const MDBX_env *env,
__cold intptr_t mdbx_limits_valsize_max(intptr_t pagesize, __cold intptr_t mdbx_limits_valsize_max(intptr_t pagesize,
MDBX_db_flags_t flags) { MDBX_db_flags_t flags) {
if (pagesize < 1) if (pagesize < 1)
pagesize = (intptr_t)mdbx_syspagesize(); pagesize = (intptr_t)mdbx_default_pagesize();
if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE || if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
pagesize > (intptr_t)MAX_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!is_powerof2((size_t)pagesize))) !is_powerof2((size_t)pagesize)))
@ -10004,7 +10012,8 @@ __cold int mdbx_env_create(MDBX_env **penv) {
goto bailout; goto bailout;
} }
env->me_os_psize = (unsigned)os_psize; env->me_os_psize = (unsigned)os_psize;
mdbx_setup_pagesize(env, env->me_os_psize); mdbx_setup_pagesize(env, (env->me_os_psize < MAX_PAGESIZE) ? env->me_os_psize
: MAX_PAGESIZE);
rc = mdbx_fastmutex_init(&env->me_dbi_lock); rc = mdbx_fastmutex_init(&env->me_dbi_lock);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
@ -10969,12 +10978,14 @@ static __cold int mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
const size_t maxreaders = const size_t maxreaders =
((size_t)size - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader); ((size_t)size - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader);
if (size > 65536 || maxreaders < 2 || maxreaders > MDBX_READERS_LIMIT) { if (maxreaders < 4) {
mdbx_error("lck-size too big (up to %" PRIuPTR " readers)", maxreaders); mdbx_error("lck-size too small (up to %" PRIuPTR " readers)", maxreaders);
err = MDBX_PROBLEM; err = MDBX_PROBLEM;
goto bailout; goto bailout;
} }
env->me_maxreaders = (unsigned)maxreaders; env->me_maxreaders = (maxreaders <= MDBX_READERS_LIMIT)
? (unsigned)maxreaders
: (unsigned)MDBX_READERS_LIMIT;
err = mdbx_mmap((env->me_flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, err = mdbx_mmap((env->me_flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP,
&env->me_lck_mmap, (size_t)size, (size_t)size, &env->me_lck_mmap, (size_t)size, (size_t)size,
@ -11388,7 +11399,8 @@ __cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) {
memset(&dummy_env, 0, sizeof(dummy_env)); memset(&dummy_env, 0, sizeof(dummy_env));
dummy_env.me_flags = dummy_env.me_flags =
(mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS; (mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS;
dummy_env.me_psize = dummy_env.me_os_psize = (unsigned)mdbx_syspagesize(); dummy_env.me_os_psize = (unsigned)mdbx_syspagesize();
dummy_env.me_psize = (unsigned)mdbx_default_pagesize();
dummy_env.me_pathname = (char *)pathname; dummy_env.me_pathname = (char *)pathname;
MDBX_handle_env_pathname env_pathname; MDBX_handle_env_pathname env_pathname;
@ -20119,7 +20131,7 @@ __cold MDBX_NOTHROW_CONST_FUNCTION intptr_t mdbx_limits_pgsize_max(void) {
__cold intptr_t mdbx_limits_dbsize_min(intptr_t pagesize) { __cold intptr_t mdbx_limits_dbsize_min(intptr_t pagesize) {
if (pagesize < 1) if (pagesize < 1)
pagesize = (intptr_t)mdbx_syspagesize(); pagesize = (intptr_t)mdbx_default_pagesize();
else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE || else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
pagesize > (intptr_t)MAX_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!is_powerof2((size_t)pagesize))) !is_powerof2((size_t)pagesize)))
@ -20130,7 +20142,7 @@ __cold intptr_t mdbx_limits_dbsize_min(intptr_t pagesize) {
__cold intptr_t mdbx_limits_dbsize_max(intptr_t pagesize) { __cold intptr_t mdbx_limits_dbsize_max(intptr_t pagesize) {
if (pagesize < 1) if (pagesize < 1)
pagesize = (intptr_t)mdbx_syspagesize(); pagesize = (intptr_t)mdbx_default_pagesize();
else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE || else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
pagesize > (intptr_t)MAX_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!is_powerof2((size_t)pagesize))) !is_powerof2((size_t)pagesize)))
@ -20144,7 +20156,7 @@ __cold intptr_t mdbx_limits_dbsize_max(intptr_t pagesize) {
__cold intptr_t mdbx_limits_txnsize_max(intptr_t pagesize) { __cold intptr_t mdbx_limits_txnsize_max(intptr_t pagesize) {
if (pagesize < 1) if (pagesize < 1)
pagesize = (intptr_t)mdbx_syspagesize(); pagesize = (intptr_t)mdbx_default_pagesize();
else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE || else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
pagesize > (intptr_t)MAX_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!is_powerof2((size_t)pagesize))) !is_powerof2((size_t)pagesize)))

View File

@ -628,7 +628,7 @@ typedef struct MDBX_lockinfo {
#if MDBX_WORDBITS >= 64 #if MDBX_WORDBITS >= 64
#define MAX_MAPSIZE MAX_MAPSIZE64 #define MAX_MAPSIZE MAX_MAPSIZE64
#define MDBX_READERS_LIMIT \ #define MDBX_READERS_LIMIT \
((65536 - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader)) ((MAX_PAGESIZE - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader))
#define MDBX_PGL_LIMIT MAX_PAGENO #define MDBX_PGL_LIMIT MAX_PAGENO
#else #else
#define MDBX_READERS_LIMIT 1024 #define MDBX_READERS_LIMIT 1024

View File

@ -985,8 +985,6 @@ template class LIBMDBX_API_TYPE buffer<polymorphic_allocator>;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
size_t env::default_pagesize() noexcept { return ::mdbx_syspagesize(); }
static inline MDBX_env_flags_t mode2flags(env::mode mode) { static inline MDBX_env_flags_t mode2flags(env::mode mode) {
switch (mode) { switch (mode) {
default: default: