From ee6a045f17dec1512c588b3c52c5af0f81b0cd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 9 Oct 2025 21:39:07 +0300 Subject: [PATCH] mdbx: add `MDBX_DBG_NOFALLOC_INCORE`. It is a workaround to sporadic test failures due to lack of space in tmpfs and/or free memory. --- mdbx.h | 6 +++++- src/bits.md | 2 +- src/cogs.h | 4 ++++ src/dxb.c | 10 ++++++++-- src/osal.c | 6 +++--- src/osal.h | 3 +++ 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/mdbx.h b/mdbx.h index c679d47d..9076f273 100644 --- a/mdbx.h +++ b/mdbx.h @@ -929,8 +929,12 @@ typedef enum MDBX_debug_flags { * \note Nonetheless a new write transactions will use and store the last signature regardless this flag */ MDBX_DBG_DONT_UPGRADE = 64, + /** Disables the use of fallocate() for an in-core database(s) to avoid sporadic test failures + * due to lack of space in tmpfs and/or free memory. */ + MDBX_DBG_NOFALLOC_INCORE = 128, + #ifdef ENABLE_UBSAN - MDBX_DBG_MAX = ((unsigned)MDBX_LOG_MAX) << 16 | 127 /* avoid UBSAN false-positive trap by a tests */, + MDBX_DBG_MAX = ((unsigned)MDBX_LOG_MAX) << 16 | 255 /* avoid UBSAN false-positive trap by a tests */, #endif /* ENABLE_UBSAN */ /** for mdbx_setup_debug() only: Don't change current settings */ diff --git a/src/bits.md b/src/bits.md index 96fae211..fdb33945 100644 --- a/src/bits.md +++ b/src/bits.md @@ -10,7 +10,7 @@ N | MASK | ENV | TXN | DB | PUT | DBI | NOD 7 |0000 0080| |TXN_DRAINED_GC|DB_VALID |ALLDUPS |DBI_LINDO | | | | 8 |0000 0100| _MAY_MOVE |TXN_CURSORS | | | | | | <= | 9 |0000 0200| _MAY_UNMAP| | | | | | | <= | -10|0000 0400| | | | | | | | | +10|0000 0400| _NO_FALLOC| | | | | | | <= | 11|0000 0800| | | | | | | | | 12|0000 1000| | | | | | | | | 13|0000 2000|VALIDATION | | | | | |P_SPILLED | | diff --git a/src/cogs.h b/src/cogs.h index bd8c98f5..d229f10a 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -522,6 +522,10 @@ MDBX_INTERNAL void munlock_after(const MDBX_env *env, const pgno_t aligned_pgno, MDBX_INTERNAL void munlock_all(const MDBX_env *env); +static inline bool fallocate_disabled(const MDBX_env *env) { + return env->incore && (globals.runtime_flags & MDBX_DBG_NOFALLOC_INCORE) != 0; +} + /*----------------------------------------------------------------------------*/ /* Cache coherence and mmap invalidation */ #ifndef MDBX_CPU_WRITEBACK_INCOHERENT diff --git a/src/dxb.c b/src/dxb.c index d61290d8..48e815cc 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -154,6 +154,8 @@ __cold int dxb_resize(MDBX_env *const env, const pgno_t used_pgno, const pgno_t unsigned mresize_flags = env->flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_UTTERLY_NOSYNC); if (mode >= impilict_shrink) mresize_flags |= txn_shrink_allowed; + if (fallocate_disabled(env)) + mresize_flags |= MDBX_MRESIZE_NO_FALLOC; if (limit_bytes == env->dxb_mmap.limit && size_bytes == env->dxb_mmap.current && size_bytes == env->dxb_mmap.filesize) goto bailout; @@ -532,7 +534,8 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit if (unlikely(err != MDBX_SUCCESS)) return err; - err = osal_fallocate(env->lazy_fd, env->dxb_mmap.filesize = env->dxb_mmap.current = env->geo_in_bytes.now); + err = (fallocate_disabled(env) ? osal_ftruncate : osal_fallocate)( + env->lazy_fd, env->dxb_mmap.filesize = env->dxb_mmap.current = env->geo_in_bytes.now); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -681,7 +684,10 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit !(env->flags & MDBX_NORDAHEAD) && mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE; err = osal_mmap(env->flags, &env->dxb_mmap, env->geo_in_bytes.now, env->geo_in_bytes.upper, - (lck_rc && env->stuck_meta < 0) ? MMAP_OPTION_SETLENGTH : 0, env->pathname.dxb); + (lck_rc && env->stuck_meta < 0) + ? (fallocate_disabled(env) ? MMAP_OPTION_SETLENGTH | MMAP_OPTION_NOFALLOC : MMAP_OPTION_SETLENGTH) + : 0, + env->pathname.dxb); if (unlikely(err != MDBX_SUCCESS)) return err; diff --git a/src/osal.c b/src/osal.c index 687a05fc..665e6fcb 100644 --- a/src/osal.c +++ b/src/osal.c @@ -2087,7 +2087,7 @@ int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit return err; if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_SETLENGTH) != 0) { - err = osal_fallocate(map->fd, size); + err = ((options & MMAP_OPTION_NOFALLOC) ? osal_ftruncate : osal_fallocate)(map->fd, size); VERBOSE("ftruncate %zu, err %d", size, err); if (err != MDBX_SUCCESS) return err; @@ -2333,7 +2333,7 @@ retry_file_and_section: } if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) { - err = osal_fallocate(map->fd, size); + err = ((flags & MDBX_MRESIZE_NO_FALLOC) ? osal_ftruncate : osal_fallocate)(map->fd, size); if (err == MDBX_SUCCESS) map->filesize = size; /* ignore error, because Windows unable shrink file @@ -2413,7 +2413,7 @@ retry_mapview:; } else { if (map->filesize != size) { if (size > map->filesize) { - rc = osal_fallocate(map->fd, size); + rc = ((flags & MDBX_MRESIZE_NO_FALLOC) ? osal_ftruncate : osal_fallocate)(map->fd, size); VERBOSE("f%s-%s %zu, err %d", "allocate", "extend", size, rc); } else if (flags & txn_shrink_allowed) { rc = osal_ftruncate(map->fd, size); diff --git a/src/osal.h b/src/osal.h index 0e33a698..f440603d 100644 --- a/src/osal.h +++ b/src/osal.h @@ -481,11 +481,14 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait); #define MMAP_OPTION_SETLENGTH 1 #define MMAP_OPTION_SEMAPHORE 2 +#define MMAP_OPTION_NOFALLOC 4 MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options, const pathchar_t *pathname4logging); MDBX_INTERNAL int osal_munmap(osal_mmap_t *map); + #define MDBX_MRESIZE_MAY_MOVE 0x00000100 #define MDBX_MRESIZE_MAY_UNMAP 0x00000200 +#define MDBX_MRESIZE_NO_FALLOC 0x00000400 MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit); #if defined(_WIN32) || defined(_WIN64) typedef struct {