mirror of
https://github.com/isar/libmdbx.git
synced 2024-12-29 09:18:50 +08:00
mdbx: Merge branch 'master' into devel.
Change-Id: Ic130cd181097332aa2f49019d75403e18d8cba0d
This commit is contained in:
commit
860aa017db
@ -187,11 +187,11 @@ if(SUBPROJECT)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" OFF)
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independed (PIC)" ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
|
||||
endif()
|
||||
else()
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independed (PIC)" ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
|
||||
if (CC_HAS_ARCH_NATIVE)
|
||||
option(BUILD_FOR_NATIVE_CPU "Generate code for the compiling machine CPU" OFF)
|
||||
endif()
|
||||
|
@ -6,7 +6,7 @@ libmdbx
|
||||
> Please refer to the online [documentation](https://erthink.github.io/libmdbx/)
|
||||
> with [`C` API description](https://erthink.github.io/libmdbx/group__c__api.html)
|
||||
> and pay attention to the preliminary [`C++` API](https://github.com/erthink/libmdbx/blob/c%2B%2B/mdbx.h%2B%2B).
|
||||
> Questions, feedback and suggestions are welcome to the [Telergam' group](https://t.me/libmdbx).
|
||||
> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx).
|
||||
|
||||
<!-- section-begin overview -->
|
||||
_libmdbx_ is an extremely fast, compact, powerful, embedded,
|
||||
@ -224,7 +224,7 @@ the user's point of view.
|
||||
> _libmdbx_ database format depends only on the [endianness](https://en.wikipedia.org/wiki/Endianness) but not on the [bitness](https://en.wiktionary.org/wiki/bitness).
|
||||
|
||||
6. LIFO policy for Garbage Collection recycling. This can significantly increase write performance due write-back disk cache up to several times in a best case scenario.
|
||||
> LIFO means that for reuse will be taken the latest becames unused pages.
|
||||
> LIFO means that for reuse will be taken the latest becomes unused pages.
|
||||
> Therefore the loop of database pages circulation becomes as short as possible.
|
||||
> In other words, the set of pages, that are (over)written in memory and on disk during a series of write transactions, will be as small as possible.
|
||||
> Thus creates ideal conditions for the battery-backed or flash-backed disk cache efficiency.
|
||||
|
@ -231,7 +231,7 @@ else()
|
||||
check_compiler_flag("-ggdb" CC_HAS_GGDB)
|
||||
check_compiler_flag("-fvisibility=hidden" CC_HAS_VISIBILITY)
|
||||
check_compiler_flag("-march=native" CC_HAS_ARCH_NATIVE)
|
||||
check_compiler_flag("-Og" CC_HAS_DEBUG_FRENDLY_OPTIMIZATION)
|
||||
check_compiler_flag("-Og" CC_HAS_DEBUG_FRIENDLY_OPTIMIZATION)
|
||||
check_compiler_flag("-Wall" CC_HAS_WALL)
|
||||
check_compiler_flag("-Ominimal" CC_HAS_OMINIMAL)
|
||||
check_compiler_flag("-ffunction-sections -fdata-sections" CC_HAS_SECTIONS)
|
||||
|
@ -155,7 +155,7 @@ macro(fetch_version name source_root_directory parent_scope)
|
||||
|
||||
if(NOT ${name}_GIT_VERSION OR NOT ${name}_GIT_TIMESTAMP OR ${name}_GIT_REVISION STREQUAL "")
|
||||
if(GIT AND EXISTS "${source_root_directory}/.git")
|
||||
message(WARNING "Unable to retrive ${name} version from git.")
|
||||
message(WARNING "Unable to retrieve ${name} version from git.")
|
||||
endif()
|
||||
set(${name}_GIT_VERSION "0;0;0;0")
|
||||
set(${name}_GIT_TIMESTAMP "")
|
||||
@ -168,7 +168,7 @@ macro(fetch_version name source_root_directory parent_scope)
|
||||
endif()
|
||||
|
||||
if(NOT ${name}_VERSION)
|
||||
message(WARNING "Unable to retrive ${name} version from \"${version_file}\" file.")
|
||||
message(WARNING "Unable to retrieve ${name} version from \"${version_file}\" file.")
|
||||
set(${name}_VERSION_LIST ${${name}_GIT_VERSION})
|
||||
string(REPLACE ";" "." ${name}_VERSION "${${name}_GIT_VERSION}")
|
||||
else()
|
||||
|
@ -29,7 +29,7 @@ In addition to those listed for some functions.
|
||||
\note Workaround: Check for stale readers periodically, using the
|
||||
`mdbx_reader_check()` function or the mdbx_stat tool.
|
||||
|
||||
3. Stale writers will be cleared automatically by MDBX on supprted
|
||||
3. Stale writers will be cleared automatically by MDBX on supported
|
||||
platforms. But this is platform-specific, especially of
|
||||
implementation of shared POSIX-mutexes and support for robust
|
||||
mutexes. For instance there are no known issues on Linux, OSX,
|
||||
@ -108,7 +108,7 @@ vulnerable to corruption from other processes.
|
||||
|
||||
For compatibility with LMDB which allows multi-opening, MDBX can be
|
||||
configured at runtime by `mdbx_setup_debug(MDBX_DBG_LEGACY_MULTIOPEN, ...)`
|
||||
prior to calling other MDBX funcitons. In this way MDBX will track
|
||||
prior to calling other MDBX functions. In this way MDBX will track
|
||||
databases opening, detect multi-opening cases and then recover POSIX file
|
||||
locks as necessary. However, lock recovery can cause unexpected pauses,
|
||||
such as when another process opened the database in exclusive mode before
|
||||
@ -157,7 +157,7 @@ The "next" version of libmdbx (MithrilDB) will completely solve this.
|
||||
|
||||
The "next" version of libmdbx (MithrilDB) will solve this issue.
|
||||
|
||||
- Avoid aborting a process with an active read-only transaction in scenaries
|
||||
- Avoid aborting a process with an active read-only transaction in scenarios
|
||||
with high rate of write transactions. The transaction becomes "long-lived"
|
||||
as above until a check for stale readers is performed or the LCK-file is
|
||||
reset, since the process may not remove it from the lockfile. This does
|
||||
|
@ -99,7 +99,7 @@ opened the file across all threads. The reason for this is:
|
||||
vulnerable to corruption from other processes.
|
||||
+ For compatibility with LMDB which allows multi-opening, MDBX can be
|
||||
configured at runtime by \ref mdbx_setup_debug() with \ref MDBX_DBG_LEGACY_MULTIOPEN` option
|
||||
prior to calling other MDBX funcitons. In this way MDBX will track
|
||||
prior to calling other MDBX functions. In this way MDBX will track
|
||||
databases opening, detect multi-opening cases and then recover POSIX file
|
||||
locks as necessary. However, lock recovery can cause unexpected pauses,
|
||||
such as when another process opened the database in exclusive mode before
|
||||
@ -108,7 +108,7 @@ opened the file across all threads. The reason for this is:
|
||||
|
||||
Do not use opened MDBX environment(s) after `fork()` in a child process(es),
|
||||
MDBX will check and prevent this at critical points. Instead, ensure there is
|
||||
no open MDBX-instance(s) during fork(), or atleast close it immediately after
|
||||
no open MDBX-instance(s) during fork(), or at least close it immediately after
|
||||
`fork()` in the child process and reopen if required - for instance by using
|
||||
`pthread_atfork()`. The reason for this is:
|
||||
- For competitive consistent reading, MDBX assigns a slot in the shared
|
||||
@ -123,7 +123,7 @@ no open MDBX-instance(s) during fork(), or atleast close it immediately after
|
||||
threads could run in critical and/or intermediate sections of MDBX code
|
||||
with interaction and/or racing conditions with threads from other
|
||||
process(es). For instance: shrinking a database or copying it to a pipe,
|
||||
opening or closing environment, begining or finishing a transaction,
|
||||
opening or closing environment, beginning or finishing a transaction,
|
||||
and so on.
|
||||
= Therefore, any solution other than simply close database (and reopen if
|
||||
necessary) in a child process would be both extreme complicated and so
|
||||
@ -234,7 +234,7 @@ The full \ref c_api documentation lists further details below, like how to:
|
||||
- Reduce (temporarily) robustness to gain even more speed: \ref sync_modes.
|
||||
- Gather statistics about the database: \ref c_statinfo.
|
||||
- Sstimate size of range query result: \ref c_rqest.
|
||||
- Double perfomance by LIFO reclaiming on storages with write-back: \ref MDBX_LIFORECLAIM.
|
||||
- Double performance by LIFO reclaiming on storages with write-back: \ref MDBX_LIFORECLAIM.
|
||||
- Use sequences and canary markers: \ref mdbx_dbi_sequence(), \ref MDBX_canary.
|
||||
- Use lack-of-space callback (aka OOM-KICK): \ref mdbx_env_set_oomfunc().
|
||||
- Use exclusive mode: \ref MDBX_EXCLUSIVE.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* MDBX usage examle
|
||||
/* MDBX usage example
|
||||
*
|
||||
* Do a line-by-line comparison of this and sample-bdb.txt
|
||||
*/
|
||||
|
48
mdbx.h
48
mdbx.h
@ -188,7 +188,7 @@ typedef DWORD mdbx_tid_t;
|
||||
#include <errno.h> /* for error codes */
|
||||
#include <pthread.h> /* for pthread_t */
|
||||
#include <sys/types.h> /* for pid_t */
|
||||
#include <sys/uio.h> /* for truct iovec */
|
||||
#include <sys/uio.h> /* for struct iovec */
|
||||
#define HAVE_STRUCT_IOVEC 1
|
||||
typedef int mdbx_filehandle_t;
|
||||
typedef pid_t mdbx_pid_t;
|
||||
@ -644,7 +644,7 @@ struct iovec {
|
||||
|
||||
#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
|
||||
/* The `iov_len` is signed on Sun/Solaris.
|
||||
* So define custom MDBX_val to avoid a lot of warings. */
|
||||
* So define custom MDBX_val to avoid a lot of warnings. */
|
||||
struct MDBX_val {
|
||||
void *iov_base; /**< pointer to some data */
|
||||
size_t iov_len; /**< the length of data in bytes */
|
||||
@ -869,7 +869,7 @@ enum MDBX_env_flags_t {
|
||||
* `MDBX_EXCLUSIVE` flag can be used as a replacement for `MDB_NOLOCK`,
|
||||
* which don't supported by MDBX.
|
||||
* In this way, you can get the minimal overhead, but with the correct
|
||||
* multi-process and mutli-thread locking.
|
||||
* multi-process and multi-thread locking.
|
||||
*
|
||||
* - with `MDBX_EXCLUSIVE` = open environment in exclusive/monopolistic mode
|
||||
* or return \ref MDBX_BUSY if environment already used by other process.
|
||||
@ -1155,7 +1155,7 @@ enum MDBX_env_flags_t {
|
||||
* \ref mdbx_env_sync() as alternatively for batch committing or nested
|
||||
* transaction (in some cases). As well, auto-sync feature exposed by
|
||||
* \ref mdbx_env_set_syncbytes() and \ref mdbx_env_set_syncperiod() functions
|
||||
* could be very usefull with `MDBX_SAFE_NOSYNC` flag.
|
||||
* could be very useful with `MDBX_SAFE_NOSYNC` flag.
|
||||
*
|
||||
* The number and volume of of disk IOPs with MDBX_SAFE_NOSYNC flag will
|
||||
* exactly the as without any no-sync flags. However, you should expect a
|
||||
@ -1202,7 +1202,7 @@ enum MDBX_env_flags_t {
|
||||
* - a system crash immediately after commit the write transaction
|
||||
* high likely lead to database corruption.
|
||||
* - successful completion of mdbx_env_sync(force = true) after one or
|
||||
* more commited transactions guarantees consystency and durability.
|
||||
* more commited transactions guarantees consistency and durability.
|
||||
* - BUT by committing two or more transactions you back database into
|
||||
* a weak state, in which a system crash may lead to database corruption!
|
||||
* In case single transaction after mdbx_env_sync, you may lose transaction
|
||||
@ -2059,8 +2059,10 @@ LIBMDBX_API int mdbx_env_sync_poll(MDBX_env *env);
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold);
|
||||
|
||||
/** \brief Sets relative period since the last unsteay commit to force flush the
|
||||
* data buffers to disk, even of \ref MDBX_SAFE_NOSYNC flag in the environment.
|
||||
/** \brief Sets relative period since the last unsteady commit to force flush
|
||||
* the data buffers to disk, even of \ref MDBX_SAFE_NOSYNC flag in the
|
||||
* environment.
|
||||
*
|
||||
* \ingroup c_settings
|
||||
*
|
||||
* The relative period value affects all processes which operates with given
|
||||
@ -2084,7 +2086,7 @@ LIBMDBX_API int mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold);
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
* \param [in] seconds_16dot16 The period in 1/65536 of second when
|
||||
* a synchronous flush would be made since
|
||||
* the last unsteay commit.
|
||||
* the last unsteady commit.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_env_set_syncperiod(MDBX_env *env,
|
||||
@ -2187,7 +2189,7 @@ LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest);
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
* \note All MDBX file descriptors have `FD_CLOEXEC` and
|
||||
* could't be used after exec() and or `fork()`.
|
||||
* couldn't be used after exec() and or `fork()`.
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
* \param [out] fd Address of a int to contain the descriptor.
|
||||
@ -2216,7 +2218,7 @@ LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);
|
||||
* - In case \ref mdbx_env_info_ex() or legacy \ref mdbx_env_info() was called
|
||||
* BEFORE \ref mdbx_env_open(), i.e. for closed environment, then the
|
||||
* specified parameters will be used for new database creation, or will be
|
||||
* appliend during openeing if database exists and no other process using it.
|
||||
* applied during opening if database exists and no other process using it.
|
||||
*
|
||||
* If the database is already exist, opened with \ref MDBX_EXCLUSIVE or not
|
||||
* used by any other process, and parameters specified by
|
||||
@ -2231,7 +2233,7 @@ LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);
|
||||
*
|
||||
* - In case \ref mdbx_env_info_ex() or legacy \ref mdbx_env_info() was called
|
||||
* after \ref mdbx_env_open() WITHIN the write transaction running by current
|
||||
* thread, then specified parameters will be appliad as a part of write
|
||||
* thread, then specified parameters will be applied as a part of write
|
||||
* transaction, i.e. will not be visible to any others processes until the
|
||||
* current write transaction has been committed by the current process.
|
||||
* However, if transaction will be aborted, then the database file will be
|
||||
@ -2242,7 +2244,7 @@ LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);
|
||||
* after \ref mdbx_env_open() but OUTSIDE a write transaction, then MDBX will
|
||||
* execute internal pseudo-transaction to apply new parameters (but only if
|
||||
* anything has been changed), and changes be visible to any others processes
|
||||
* immediatelly after succesfull competeion of function.
|
||||
* immediately after succesful completion of function.
|
||||
*
|
||||
* Essentially a concept of "automatic size management" is simple and useful:
|
||||
* - There are the lower and upper bound of the database file size;
|
||||
@ -2635,7 +2637,7 @@ struct MDBX_txn_info {
|
||||
/** For READ-ONLY transaction: the lag from a recent MVCC-snapshot, i.e. the
|
||||
number of committed transaction since read transaction started. For WRITE
|
||||
transaction (provided if `scan_rlt=true`): the lag of the oldest reader
|
||||
from current transaction (i.e. atleast 1 if any reader running). */
|
||||
from current transaction (i.e. at least 1 if any reader running). */
|
||||
uint64_t txn_reader_lag;
|
||||
|
||||
/** Used space by this transaction, i.e. corresponding to the last used
|
||||
@ -2646,7 +2648,7 @@ struct MDBX_txn_info {
|
||||
uint64_t txn_space_limit_soft;
|
||||
|
||||
/** Upper bound for size the database file, i.e. the value `size_upper`
|
||||
argument of the approriate call of \ref mdbx_env_set_geometry(). */
|
||||
argument of the appropriate call of \ref mdbx_env_set_geometry(). */
|
||||
uint64_t txn_space_limit_hard;
|
||||
|
||||
/** For READ-ONLY transaction: The total size of the database pages that were
|
||||
@ -2750,7 +2752,7 @@ mdbx_txn_id(const MDBX_txn *txn);
|
||||
* be aborted due to previous errors.
|
||||
* \retval MDBX_PANIC A fatal error occurred earlier
|
||||
* and the environment must be shut down.
|
||||
* \retval MDBX_BAD_TXN Transaction is already fihished or never began.
|
||||
* \retval MDBX_BAD_TXN Transaction is already finished or never began.
|
||||
* \retval MDBX_EBADSIGN Transaction object has invalid signature,
|
||||
* e.g. transaction was already terminated
|
||||
* or memory was corrupted.
|
||||
@ -2788,7 +2790,7 @@ LIBMDBX_API int mdbx_txn_commit(MDBX_txn *txn);
|
||||
* some possible errors are:
|
||||
* \retval MDBX_PANIC A fatal error occurred earlier and
|
||||
* the environment must be shut down.
|
||||
* \retval MDBX_BAD_TXN Transaction is already fihished or never began.
|
||||
* \retval MDBX_BAD_TXN Transaction is already finished or never began.
|
||||
* \retval MDBX_EBADSIGN Transaction object has invalid signature,
|
||||
* e.g. transaction was already terminated
|
||||
* or memory was corrupted.
|
||||
@ -2835,7 +2837,7 @@ LIBMDBX_API int mdbx_txn_break(MDBX_txn *txn);
|
||||
* some possible errors are:
|
||||
* \retval MDBX_PANIC A fatal error occurred earlier and
|
||||
* the environment must be shut down.
|
||||
* \retval MDBX_BAD_TXN Transaction is already fihished or never began.
|
||||
* \retval MDBX_BAD_TXN Transaction is already finished or never began.
|
||||
* \retval MDBX_EBADSIGN Transaction object has invalid signature,
|
||||
* e.g. transaction was already terminated
|
||||
* or memory was corrupted.
|
||||
@ -2857,7 +2859,7 @@ LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);
|
||||
* some possible errors are:
|
||||
* \retval MDBX_PANIC A fatal error occurred earlier and
|
||||
* the environment must be shut down.
|
||||
* \retval MDBX_BAD_TXN Transaction is already fihished or never began.
|
||||
* \retval MDBX_BAD_TXN Transaction is already finished or never began.
|
||||
* \retval MDBX_EBADSIGN Transaction object has invalid signature,
|
||||
* e.g. transaction was already terminated
|
||||
* or memory was corrupted.
|
||||
@ -3230,7 +3232,8 @@ LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
MDBX_val *data);
|
||||
|
||||
/** \brief Get items from a database
|
||||
* and optionaly number of data items for a given key.
|
||||
* and optionally number of data items for a given key.
|
||||
*
|
||||
* \ingroup c_crud
|
||||
*
|
||||
* Briefly this function does the same as \ref mdbx_get() with a few
|
||||
@ -4010,7 +4013,7 @@ mdbx_get_datacmp(MDBX_db_flags_t flags);
|
||||
* starting from 1.
|
||||
* \param [in] slot The reader lock table slot number.
|
||||
* \param [in] txnid The ID of the transaction being read,
|
||||
* i.e. the MVCC-snaphot number.
|
||||
* i.e. the MVCC-snapshot number.
|
||||
* \param [in] lag The lag from a recent MVCC-snapshot,
|
||||
* i.e. the number of committed write transactions
|
||||
* since the current read transaction started.
|
||||
@ -4032,7 +4035,8 @@ typedef int(MDBX_reader_list_func)(void *ctx, int num, int slot, mdbx_pid_t pid,
|
||||
uint64_t lag, size_t bytes_used,
|
||||
size_t bytes_retained) MDBX_CXX17_NOEXCEPT;
|
||||
|
||||
/** \brief Enumarete the entries in the reader lock table.
|
||||
/** \brief Enumerate the entries in the reader lock table.
|
||||
*
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
@ -4102,7 +4106,7 @@ LIBMDBX_API int mdbx_thread_register(const MDBX_env *env);
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success, or
|
||||
* \ref MDBX_RESULT_TRUE if thread is not registered or already undegistered. */
|
||||
* \ref MDBX_RESULT_TRUE if thread is not registered or already unregistered. */
|
||||
LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env);
|
||||
|
||||
/** \brief A lack-of-space callback function to resolve issues with a laggard
|
||||
|
59
src/core.c
59
src/core.c
@ -319,7 +319,7 @@ node_largedata_pgno(const MDBX_node *const __restrict node) {
|
||||
* leaf-page, since dupsort value couldn't be placed on a large/overflow
|
||||
* page.
|
||||
*
|
||||
* - So, the simpliest solution is to use half of branch.maxkey as
|
||||
* - So, the simplest solution is to use half of branch.maxkey as
|
||||
* a common maxkey value. Nevertheless, the actual values of maxkey are:
|
||||
* nondupsort.maxkey = even_floor(pageroom / 3)
|
||||
* - sizeof(indx_t) - node_hdr_len;
|
||||
@ -415,7 +415,8 @@ MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
|
||||
leaf_size(const MDBX_env *env, const MDBX_val *key, const MDBX_val *data) {
|
||||
size_t node_bytes = node_size(key, data);
|
||||
/* NOTE: The actual limit is LEAF_NODEMAX(env->me_psize), but it reasonable to
|
||||
* use env->me_branch_nodemax (which is 3 times less) as the treshold because:
|
||||
* use env->me_branch_nodemax (which is 3 times less) as the threshold
|
||||
* because:
|
||||
* - Large threshold implies that any insertion/update could result split
|
||||
* a single leaf page to THREE, which requires TWO insertion into parent
|
||||
* branch page, then could leads to split parent page and so on up to
|
||||
@ -1016,7 +1017,7 @@ static void __cold workaround_glibc_bug21031(void) {
|
||||
/* Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=21031
|
||||
*
|
||||
* Due race between pthread_key_delete() and __nptl_deallocate_tsd()
|
||||
* The destructor(s) of thread-local-storate object(s) may be running
|
||||
* The destructor(s) of thread-local-storage object(s) may be running
|
||||
* in another thread(s) and be blocked or not finished yet.
|
||||
* In such case we get a SEGFAULT after unload this library DSO.
|
||||
*
|
||||
@ -1084,11 +1085,11 @@ static void thread_rthc_set(mdbx_thread_key_t key, const void *value) {
|
||||
mdbx_ensure(nullptr, TlsSetValue(key, (void *)value));
|
||||
#else
|
||||
#define MDBX_THREAD_RTHC_ZERO 0
|
||||
#define MDBX_THREAD_RTHC_REGISTERD 1
|
||||
#define MDBX_THREAD_RTHC_REGISTERED 1
|
||||
#define MDBX_THREAD_RTHC_COUNTED 2
|
||||
static __thread uint32_t thread_registration_state;
|
||||
if (value && unlikely(thread_registration_state == MDBX_THREAD_RTHC_ZERO)) {
|
||||
thread_registration_state = MDBX_THREAD_RTHC_REGISTERD;
|
||||
thread_registration_state = MDBX_THREAD_RTHC_REGISTERED;
|
||||
mdbx_trace("thread registered 0x%" PRIxPTR, mdbx_thread_self());
|
||||
if (&__cxa_thread_atexit_impl == nullptr ||
|
||||
__cxa_thread_atexit_impl(mdbx_rthc_thread_dtor,
|
||||
@ -4315,10 +4316,10 @@ static __always_inline bool meta_bootid_match(const MDBX_meta *meta) {
|
||||
}
|
||||
|
||||
static bool meta_weak_acceptable(const MDBX_env *env, const MDBX_meta *meta,
|
||||
const int lck_exlusive) {
|
||||
return lck_exlusive ? /* exclusive lock */ meta_bootid_match(meta)
|
||||
: /* db already opened */ env->me_lck &&
|
||||
(env->me_lck->mti_envmode & MDBX_RDONLY) == 0;
|
||||
const int lck_exclusive) {
|
||||
return lck_exclusive ? /* exclusive lock */ meta_bootid_match(meta)
|
||||
: /* db already opened */ env->me_lck &&
|
||||
(env->me_lck->mti_envmode & MDBX_RDONLY) == 0;
|
||||
}
|
||||
|
||||
#define METAPAGE(env, n) page_meta(pgno2page(env, n))
|
||||
@ -4731,7 +4732,7 @@ static __cold int mdbx_mapresize(MDBX_env *env, const pgno_t used_pgno,
|
||||
goto bailout;
|
||||
|
||||
/* 1) Windows allows only extending a read-write section, but not a
|
||||
* corresponing mapped view. Therefore in other cases we must suspend
|
||||
* corresponding mapped view. Therefore in other cases we must suspend
|
||||
* the local threads for safe remap.
|
||||
* 2) At least on Windows 10 1803 the entire mapped section is unavailable
|
||||
* for short time during NtExtendSection() or VirtualAlloc() execution.
|
||||
@ -5348,7 +5349,7 @@ skip_cache:
|
||||
((autosync_threshold | autosync_period) == 0 ||
|
||||
next >= steady->mm_geo.now)) {
|
||||
/* wipe steady checkpoint in MDBX_UTTERLY_NOSYNC mode
|
||||
* without any auto-sync treshold(s). */
|
||||
* without any auto-sync threshold(s). */
|
||||
rc = mdbx_wipe_steady(env, oldest);
|
||||
mdbx_debug("gc-wipe-steady, rc %d", rc);
|
||||
mdbx_assert(env, steady != mdbx_meta_steady(env));
|
||||
@ -6523,7 +6524,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
|
||||
MDBX_PNL_SIZEOF(parent->tw.reclaimed_pglist));
|
||||
mdbx_assert(env, mdbx_pnl_check4assert(
|
||||
txn->tw.reclaimed_pglist,
|
||||
(txn->mt_next_pgno /* LY: intentional assigment here,
|
||||
(txn->mt_next_pgno /* LY: intentional assignment here,
|
||||
only for assertion */
|
||||
= parent->mt_next_pgno)));
|
||||
|
||||
@ -7394,7 +7395,7 @@ retry_noaccount:
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle reclaimed and loost pages - merge and store both into gc */
|
||||
/* handle reclaimed and lost pages - merge and store both into gc */
|
||||
mdbx_tassert(txn, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
|
||||
txn->mt_next_pgno));
|
||||
mdbx_tassert(txn, txn->tw.loose_count == 0);
|
||||
@ -8685,7 +8686,7 @@ static MDBX_page *__cold mdbx_meta_model(const MDBX_env *env, MDBX_page *model,
|
||||
}
|
||||
|
||||
/* Fill in most of the zeroed meta-pages for an empty database environment.
|
||||
* Return pointer to recenly (head) meta-page. */
|
||||
* Return pointer to recently (head) meta-page. */
|
||||
static MDBX_meta *__cold mdbx_init_metas(const MDBX_env *env, void *buffer) {
|
||||
MDBX_page *page0 = (MDBX_page *)buffer;
|
||||
MDBX_page *page1 = mdbx_meta_model(env, page0, 0);
|
||||
@ -8742,20 +8743,20 @@ static int mdbx_sync_locked(MDBX_env *env, unsigned flags,
|
||||
#if defined(MADV_DONTNEED)
|
||||
const size_t largest_bytes = pgno2bytes(env, largest_pgno);
|
||||
/* threshold to avoid unreasonable frequent madvise() calls */
|
||||
const size_t madvise_treshold = (largest_bytes < 65536 * 256)
|
||||
? 65536
|
||||
: (largest_bytes > MEGABYTE * 4 * 256)
|
||||
? MEGABYTE * 4
|
||||
: largest_bytes >> 10;
|
||||
const size_t madvise_threshold = (largest_bytes < 65536 * 256)
|
||||
? 65536
|
||||
: (largest_bytes > MEGABYTE * 4 * 256)
|
||||
? MEGABYTE * 4
|
||||
: largest_bytes >> 10;
|
||||
const size_t discard_edge_bytes = bytes_align2os_bytes(
|
||||
env, ((MDBX_RDONLY &
|
||||
(env->me_lck ? env->me_lck->mti_envmode : env->me_flags))
|
||||
? largest_bytes
|
||||
: largest_bytes + madvise_treshold));
|
||||
: largest_bytes + madvise_threshold));
|
||||
const pgno_t discard_edge_pgno = bytes2pgno(env, discard_edge_bytes);
|
||||
const pgno_t prev_discarded_pgno = *env->me_discarded_tail;
|
||||
if (prev_discarded_pgno >=
|
||||
discard_edge_pgno + bytes2pgno(env, madvise_treshold)) {
|
||||
discard_edge_pgno + bytes2pgno(env, madvise_threshold)) {
|
||||
mdbx_notice("open-MADV_%s %u..%u", "DONTNEED", *env->me_discarded_tail,
|
||||
largest_pgno);
|
||||
*env->me_discarded_tail = discard_edge_pgno;
|
||||
@ -9806,7 +9807,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) {
|
||||
}
|
||||
|
||||
if (!env->me_lck) {
|
||||
/* LY: without-lck (read-only) mode, so it is imposible that other
|
||||
/* LY: without-lck (read-only) mode, so it is impossible that other
|
||||
* process made weak checkpoint. */
|
||||
mdbx_error("%s", "without-lck, unable recovery/rollback");
|
||||
return MDBX_WANNA_RECOVERY;
|
||||
@ -10077,7 +10078,7 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
|
||||
|
||||
struct MDBX_lockinfo *const lck = env->me_lck;
|
||||
if (lck_seize_rc == MDBX_RESULT_TRUE) {
|
||||
/* LY: exlcusive mode, check and reset lck content */
|
||||
/* LY: exclusive mode, check and reset lck content */
|
||||
memset(lck, 0, (size_t)size);
|
||||
mdbx_jitter4testing(false);
|
||||
lck->mti_magic_and_version = MDBX_LOCK_MAGIC;
|
||||
@ -10608,7 +10609,7 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
sizeof(unsigned) + 1);
|
||||
rc = mdbx_memalign_alloc(
|
||||
env->me_os_psize,
|
||||
env->me_psize * (1 /* page buffer */ + 1 /* page killer bufer */),
|
||||
env->me_psize * (1 /* page buffer */ + 1 /* page killer buffer */),
|
||||
&env->me_pbuf);
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
memset(env->me_pbuf, -1, env->me_psize * 2);
|
||||
@ -16227,7 +16228,7 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
if (flags & MDBX_CP_FORCE_DYNAMIC_SIZE)
|
||||
make_sizeable(meta);
|
||||
|
||||
/* copy canary sequenses if present */
|
||||
/* copy canary sequences if present */
|
||||
if (read_txn->mt_canary.v) {
|
||||
meta->mm_canary = read_txn->mt_canary;
|
||||
meta->mm_canary.v = mdbx_meta_txnid_stable(env, meta);
|
||||
@ -16341,7 +16342,7 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
for (size_t offset = used_size; offset < whole_size;) {
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < whole_size - offset) ? MDBX_WBUF : whole_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
/* copy to avoid EFAULT in case swapped-out */
|
||||
int rc = mdbx_write(fd, data_buffer, chunk);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
@ -16376,7 +16377,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
|
||||
/* Make a snapshot of meta-pages,
|
||||
* but writing ones after the data was flushed */
|
||||
memcpy(buffer, env->me_map, meta_bytes);
|
||||
MDBX_meta *const headcopy = /* LY: get pointer to the spanshot copy */
|
||||
MDBX_meta *const headcopy = /* LY: get pointer to the snapshot copy */
|
||||
(MDBX_meta *)(buffer + ((uint8_t *)mdbx_meta_head(env) - env->me_map));
|
||||
mdbx_txn_unlock(env);
|
||||
|
||||
@ -16433,7 +16434,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
|
||||
/* fallback to portable */
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < used_size - offset) ? MDBX_WBUF : used_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
/* copy to avoid EFAULT in case swapped-out */
|
||||
memcpy(data_buffer, env->me_map + offset, chunk);
|
||||
rc = mdbx_write(fd, data_buffer, chunk);
|
||||
offset += chunk;
|
||||
@ -16449,7 +16450,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
|
||||
rc == MDBX_SUCCESS && offset < whole_size;) {
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < whole_size - offset) ? MDBX_WBUF : whole_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
/* copy to avoid EFAULT in case swapped-out */
|
||||
rc = mdbx_write(fd, data_buffer, chunk);
|
||||
offset += chunk;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@
|
||||
#pragma warning(disable : 4127) /* conditional expression is constant */
|
||||
#pragma warning(disable : 4324) /* 'xyz': structure was padded due to alignment specifier */
|
||||
#pragma warning(disable : 4310) /* cast truncates constant value */
|
||||
#pragma warning(disable : 4820) /* bytes padding added after data member for aligment */
|
||||
#pragma warning(disable : 4820) /* bytes padding added after data member for alignment */
|
||||
#pragma warning(disable : 4548) /* expression before comma has no effect; expected expression with side - effect */
|
||||
#pragma warning(disable : 4366) /* the result of the unary '&' operator may be unaligned */
|
||||
#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized array in struct/union */
|
||||
@ -101,7 +101,7 @@
|
||||
#include "defs.h"
|
||||
|
||||
#if defined(__GNUC__) && !__GNUC_PREREQ(4,2)
|
||||
/* Actualy libmdbx was not tested with compilers older than GCC from RHEL6.
|
||||
/* Actually libmdbx was not tested with compilers older than GCC from RHEL6.
|
||||
* But you could remove this #error and try to continue at your own risk.
|
||||
* In such case please don't rise up an issues related ONLY to old compilers.
|
||||
*/
|
||||
@ -109,7 +109,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) && !__CLANG_PREREQ(3,8)
|
||||
/* Actualy libmdbx was not tested with CLANG older than 3.8.
|
||||
/* Actually libmdbx was not tested with CLANG older than 3.8.
|
||||
* But you could remove this #error and try to continue at your own risk.
|
||||
* In such case please don't rise up an issues related ONLY to old compilers.
|
||||
*/
|
||||
@ -117,7 +117,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) && !__GLIBC_PREREQ(2,12)
|
||||
/* Actualy libmdbx was not tested with something older than glibc 2.12 (from RHEL6).
|
||||
/* Actually libmdbx was not tested with something older than glibc 2.12 (from RHEL6).
|
||||
* But you could remove this #error and try to continue at your own risk.
|
||||
* In such case please don't rise up an issues related ONLY to old systems.
|
||||
*/
|
||||
@ -536,7 +536,7 @@ typedef struct MDBX_lockinfo {
|
||||
|
||||
alignas(MDBX_CACHELINE_SIZE) /* cacheline ---------------------------------*/
|
||||
|
||||
/* Write transation lock. */
|
||||
/* Write transaction lock. */
|
||||
#if MDBX_LOCKING > 0
|
||||
mdbx_ipclock_t mti_wlock;
|
||||
#endif /* MDBX_LOCKING > 0 */
|
||||
@ -884,7 +884,7 @@ struct MDBX_cursor {
|
||||
#define C_RECLAIMING 0x20 /* GC lookup is prohibited */
|
||||
#define C_GCFREEZE 0x40 /* reclaimed_pglist must not be updated */
|
||||
|
||||
/* Cursor checing flags. */
|
||||
/* Cursor checking flags. */
|
||||
#define C_COPYING 0x100 /* skip key-value length check (copying simplify) */
|
||||
#define C_UPDATING 0x200 /* update/rebalance pending */
|
||||
#define C_RETIRING 0x400 /* refs to child pages may be invalid */
|
||||
|
@ -183,7 +183,8 @@ MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env) {
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE)
|
||||
return MDBX_SUCCESS; /* readonly database in readonly filesystem */
|
||||
|
||||
/* transite from S-? (used) to S-E (locked), e.g. exclusive lock upper-part */
|
||||
/* transition from S-? (used) to S-E (locked),
|
||||
* e.g. exclusive lock upper-part */
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) ||
|
||||
flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER))
|
||||
return MDBX_SUCCESS;
|
||||
@ -195,7 +196,7 @@ MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env) {
|
||||
|
||||
MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE) {
|
||||
/* transite from S-E (locked) to S-? (used), e.g. unlock upper-part */
|
||||
/* transition from S-E (locked) to S-? (used), e.g. unlock upper-part */
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) == 0 &&
|
||||
!funlock(env->me_lfd, LCK_UPPER))
|
||||
mdbx_panic("%s failed: err %u", __func__, GetLastError());
|
||||
@ -277,7 +278,7 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
}
|
||||
} else {
|
||||
/* Without LCK (i.e. read-only mode).
|
||||
* Walk thougth a snapshot of all running threads */
|
||||
* Walk through a snapshot of all running threads */
|
||||
mdbx_assert(env,
|
||||
env->me_txn0 == NULL || (env->me_flags & MDBX_EXCLUSIVE) != 0);
|
||||
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
@ -336,7 +337,7 @@ mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
/* global `initial` lock for lockfile initialization,
|
||||
* exclusive/shared locking first cacheline */
|
||||
|
||||
/* Briefly descritpion of locking schema/algorithm:
|
||||
/* Briefly description of locking schema/algorithm:
|
||||
* - Windows does not support upgrading or downgrading for file locking.
|
||||
* - Therefore upgrading/downgrading is emulated by shared and exclusive
|
||||
* locking of upper and lower halves.
|
||||
@ -411,7 +412,7 @@ static void lck_unlock(MDBX_env *env) {
|
||||
|
||||
/* Seize state as 'exclusive-write' (E-E and returns MDBX_RESULT_TRUE)
|
||||
* or as 'used' (S-? and returns MDBX_RESULT_FALSE).
|
||||
* Oherwise returns an error. */
|
||||
* Otherwise returns an error. */
|
||||
static int internal_seize_lck(HANDLE lfd) {
|
||||
int rc;
|
||||
assert(lfd != INVALID_HANDLE_VALUE);
|
||||
@ -450,7 +451,7 @@ static int internal_seize_lck(HANDLE lfd) {
|
||||
mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
|
||||
/* 8) now on S-E (locked) or still on ?-E (middle),
|
||||
* transite to S-? (used) or ?-? (free) */
|
||||
* transition to S-? (used) or ?-? (free) */
|
||||
if (!funlock(lfd, LCK_UPPER))
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"X-E(locked/middle) >> X-?(used/free)", GetLastError());
|
||||
@ -512,12 +513,12 @@ MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
|
||||
;
|
||||
/* 1) now at E-E (exclusive-write), transite to ?_E (middle) */
|
||||
/* 1) now at E-E (exclusive-write), transition to ?_E (middle) */
|
||||
if (!funlock(env->me_lfd, LCK_LOWER))
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"E-E(exclusive-write) >> ?-E(middle)", GetLastError());
|
||||
|
||||
/* 2) now at ?-E (middle), transite to S-E (locked) */
|
||||
/* 2) now at ?-E (middle), transition to S-E (locked) */
|
||||
if (!flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER)) {
|
||||
int rc = GetLastError() /* 3) something went wrong, give up */;
|
||||
mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
@ -549,7 +550,7 @@ MDBX_INTERNAL_FUNC int mdbx_lck_upgrade(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3) now on S-E (locked), transite to ?-E (middle) */
|
||||
/* 3) now on S-E (locked), transition to ?-E (middle) */
|
||||
if (!funlock(env->me_lfd, LCK_LOWER))
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> ?-E(middle)",
|
||||
GetLastError());
|
||||
@ -666,7 +667,7 @@ static void WINAPI stub_srwlock_AcquireShared(MDBX_srwlock *srwl) {
|
||||
// Add to the readers list
|
||||
_InterlockedIncrement(&srwl->readerCount);
|
||||
|
||||
// Check for writers again (we may have been pre-empted). If
|
||||
// Check for writers again (we may have been preempted). If
|
||||
// there are no writers writing or waiting, then we're done.
|
||||
if (srwl->writerCount == 0)
|
||||
break;
|
||||
|
@ -478,7 +478,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
(number + 1) * sizeof(pgno_t), data->iov_len);
|
||||
number = data->iov_len / sizeof(pgno_t) - 1;
|
||||
} else if (data->iov_len - (number + 1) * sizeof(pgno_t) >=
|
||||
/* LY: allow gap upto one page. it is ok
|
||||
/* LY: allow gap up to one page. it is ok
|
||||
* and better than shink-and-retry inside mdbx_update_gc() */
|
||||
envstat.ms_psize)
|
||||
problem_add("entry", txnid, "extra idl space",
|
||||
@ -1318,7 +1318,7 @@ int main(int argc, char *argv[]) {
|
||||
alloc_pages = backed_pages;
|
||||
}
|
||||
} else {
|
||||
/* LY: DB may be shrinked by writer downto the allocated pages. */
|
||||
/* LY: DB may be shrinked by writer down to the allocated pages. */
|
||||
if (alloc_pages > backed_pages) {
|
||||
print(" ! alloc-pages %" PRIu64 " > backed-pages %" PRIu64 "\n",
|
||||
alloc_pages, backed_pages);
|
||||
|
@ -224,7 +224,7 @@ static void usage(void) {
|
||||
" -a\t\tdump main DB and all subDBs,\n"
|
||||
" \t\tby default dump only the main DB\n"
|
||||
" -s\t\tdump only the named subDB\n"
|
||||
" -r\t\trescure mode (ignore errors to dump corrupted DB)\n",
|
||||
" -r\t\trescue mode (ignore errors to dump corrupted DB)\n",
|
||||
prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ static void usage(void) {
|
||||
" -s name\tload into named subDB\n"
|
||||
" -N\t\tuse NOOVERWRITE on puts\n"
|
||||
" -T\t\tread plaintext\n"
|
||||
" -r\t\trescure mode (ignore errors to load corrupted DB dump)\n",
|
||||
" -r\t\trescue mode (ignore errors to load corrupted DB dump)\n",
|
||||
prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@
|
||||
/** Controls checking PID against reuse DB environment after the fork() */
|
||||
#ifndef MDBX_ENV_CHECKPID
|
||||
#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
|
||||
/* PID check could be ommited:
|
||||
/* PID check could be omitted:
|
||||
* - on Linux when madvise(MADV_DONTFORK) is available. i.e. after the fork()
|
||||
* mapped pages will not be available for child process.
|
||||
* - in Windows where fork() not available. */
|
||||
|
@ -1387,7 +1387,7 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
|
||||
MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) {
|
||||
VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
|
||||
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
|
||||
* when this memory will re-used by malloc or another mmaping.
|
||||
* when this memory will re-used by malloc or another mmapping.
|
||||
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203 */
|
||||
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@ -1673,7 +1673,7 @@ retry_mapview:;
|
||||
if (unlikely(ptr == MAP_FAILED)) {
|
||||
VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
|
||||
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
|
||||
* when this memory will re-used by malloc or another mmaping.
|
||||
* when this memory will re-used by malloc or another mmapping.
|
||||
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203
|
||||
*/
|
||||
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
|
||||
@ -1691,7 +1691,7 @@ retry_mapview:;
|
||||
if (map->address != ptr) {
|
||||
VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
|
||||
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
|
||||
* when this memory will re-used by malloc or another mmaping.
|
||||
* when this memory will re-used by malloc or another mmapping.
|
||||
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203
|
||||
*/
|
||||
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
|
||||
|
@ -741,12 +741,12 @@ MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
|
||||
|
||||
/// \brief Downgrades the level of initially acquired lock to
|
||||
/// operational level specified by agrument. The reson for such downgrade:
|
||||
/// operational level specified by argument. The reson for such downgrade:
|
||||
/// - unblocking of other processes that are waiting for access, i.e.
|
||||
/// if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
|
||||
/// should be made aware that access is unavailable rather than
|
||||
/// wait for it.
|
||||
/// - freeing locks that interfere file operation (expecially for Windows)
|
||||
/// - freeing locks that interfere file operation (especially for Windows)
|
||||
/// (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
|
||||
/// (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
|
||||
/// operational lock.
|
||||
|
@ -103,7 +103,7 @@ time now_realtime() {
|
||||
#endif
|
||||
}
|
||||
|
||||
time now_motonic() {
|
||||
time now_monotonic() {
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
||||
static uint64_t reciprocal;
|
||||
static LARGE_INTEGER Frequency;
|
||||
|
@ -94,6 +94,6 @@ inline time from_timeval(const struct timeval &tv) {
|
||||
#endif /* HAVE_TIMEVAL_TV_USEC */
|
||||
|
||||
time now_realtime();
|
||||
time now_motonic();
|
||||
time now_monotonic();
|
||||
|
||||
} /* namespace chrono */
|
||||
|
@ -31,7 +31,7 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
if (!value) {
|
||||
if (current[optlen + 2] == '=')
|
||||
failure("Option '--%s' doen't accept any value\n", option);
|
||||
failure("Option '--%s' doesn't accept any value\n", option);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
*value = argv[narg + 1];
|
||||
if (strcmp(*value, "default") == 0) {
|
||||
if (!default_value)
|
||||
failure("Option '--%s' doen't accept default value\n", option);
|
||||
failure("Option '--%s' doesn't accept default value\n", option);
|
||||
*value = default_value;
|
||||
}
|
||||
++narg;
|
||||
@ -74,7 +74,7 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
return false;
|
||||
|
||||
if (!allow_empty && strlen(value_cstr) == 0)
|
||||
failure("Value for option '--%s' could't be empty\n", option);
|
||||
failure("Value for option '--%s' couldn't be empty\n", option);
|
||||
|
||||
value = value_cstr;
|
||||
return true;
|
||||
@ -157,34 +157,34 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
failure("Option '--%s' expects a numeric value (%s)\n", option,
|
||||
test_strerror(errno));
|
||||
|
||||
uint64_t multipler = 1;
|
||||
uint64_t multiplier = 1;
|
||||
if (suffix && *suffix) {
|
||||
if (scale == no_scale)
|
||||
failure("Option '--%s' doen't accepts suffixes, so '%s' is unexpected\n",
|
||||
failure("Option '--%s' doesn't accepts suffixes, so '%s' is unexpected\n",
|
||||
option, suffix);
|
||||
if (strcmp(suffix, "K") == 0 || strcasecmp(suffix, "Kilo") == 0)
|
||||
multipler = (scale == decimal) ? UINT64_C(1000) : UINT64_C(1024);
|
||||
multiplier = (scale == decimal) ? UINT64_C(1000) : UINT64_C(1024);
|
||||
else if (strcmp(suffix, "M") == 0 || strcasecmp(suffix, "Mega") == 0)
|
||||
multipler =
|
||||
multiplier =
|
||||
(scale == decimal) ? UINT64_C(1000) * 1000 : UINT64_C(1024) * 1024;
|
||||
else if (strcmp(suffix, "G") == 0 || strcasecmp(suffix, "Giga") == 0)
|
||||
multipler = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000
|
||||
: UINT64_C(1024) * 1024 * 1024;
|
||||
multiplier = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000
|
||||
: UINT64_C(1024) * 1024 * 1024;
|
||||
else if (strcmp(suffix, "T") == 0 || strcasecmp(suffix, "Tera") == 0)
|
||||
multipler = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 * 1000
|
||||
: UINT64_C(1024) * 1024 * 1024 * 1024;
|
||||
multiplier = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 * 1000
|
||||
: UINT64_C(1024) * 1024 * 1024 * 1024;
|
||||
else if (scale == duration &&
|
||||
(strcmp(suffix, "s") == 0 || strcasecmp(suffix, "Seconds") == 0))
|
||||
multipler = 1;
|
||||
multiplier = 1;
|
||||
else if (scale == duration &&
|
||||
(strcmp(suffix, "m") == 0 || strcasecmp(suffix, "Minutes") == 0))
|
||||
multipler = 60;
|
||||
multiplier = 60;
|
||||
else if (scale == duration &&
|
||||
(strcmp(suffix, "h") == 0 || strcasecmp(suffix, "Hours") == 0))
|
||||
multipler = 3600;
|
||||
multiplier = 3600;
|
||||
else if (scale == duration &&
|
||||
(strcmp(suffix, "d") == 0 || strcasecmp(suffix, "Days") == 0))
|
||||
multipler = 3600 * 24;
|
||||
multiplier = 3600 * 24;
|
||||
else
|
||||
failure(
|
||||
"Option '--%s' expects a numeric value with Kilo/Mega/Giga/Tera %s"
|
||||
@ -193,10 +193,10 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
suffix);
|
||||
}
|
||||
|
||||
if (raw >= UINT64_MAX / multipler)
|
||||
if (raw >= UINT64_MAX / multiplier)
|
||||
failure("The value for option '--%s' is too huge\n", option);
|
||||
|
||||
value = raw * multipler;
|
||||
value = raw * multiplier;
|
||||
if (maxval && value > maxval)
|
||||
failure("The maximal value for option '--%s' is %" PRIu64 "\n", option,
|
||||
maxval);
|
||||
|
@ -240,7 +240,7 @@ local_suffix::~local_suffix() { suffix.erase(trim_pos); }
|
||||
|
||||
void progress_canary(bool active) {
|
||||
static chrono::time progress_timestamp;
|
||||
chrono::time now = chrono::now_motonic();
|
||||
chrono::time now = chrono::now_monotonic();
|
||||
|
||||
if (now.fixedpoint - progress_timestamp.fixedpoint <
|
||||
chrono::from_ms(42).fixedpoint)
|
||||
|
26
test/main.cc
26
test/main.cc
@ -26,7 +26,7 @@ MDBX_NORETURN void usage(void) {
|
||||
"Common parameters:\n"
|
||||
" --pathname=... Path and/or name of database files\n"
|
||||
" --repeat=N Set repeat counter\n"
|
||||
" --threads=N Number of thread (unsunpported for now)\n"
|
||||
" --threads=N Number of thread (unsupported for now)\n"
|
||||
" --timeout=N[s|m|h|d] Set timeout in seconds/minutes/hours/days\n"
|
||||
" --failfast[=YES/no] Lill all actors on first failure/error\n"
|
||||
" --max-readers=N See mdbx_env_set_maxreaders() description\n"
|
||||
@ -43,7 +43,7 @@ MDBX_NORETURN void usage(void) {
|
||||
" --size Initial size in Kb/Mb/Gb/Tb\n"
|
||||
" --shrink-threshold Shrink threshold in Kb/Mb/Gb/Tb\n"
|
||||
" --growth-step Grow step in Kb/Mb/Gb/Tb\n"
|
||||
"Predefined complext scenarios/cases:\n"
|
||||
"Predefined complex scenarios/cases:\n"
|
||||
" --case=... Only `basic` scenario implemented for now\n"
|
||||
" basic == Simultaneous multi-process execution\n"
|
||||
" of test-actors: nested,hill,ttl,copy,append,jitter,try\n"
|
||||
@ -186,8 +186,8 @@ std::unordered_map<unsigned, actor_config *> events;
|
||||
std::unordered_map<mdbx_pid_t, actor_config *> pid2actor;
|
||||
std::set<std::string> databases;
|
||||
unsigned nactors;
|
||||
chrono::time start_motonic;
|
||||
chrono::time deadline_motonic;
|
||||
chrono::time start_monotonic;
|
||||
chrono::time deadline_monotonic;
|
||||
bool singlemode;
|
||||
|
||||
namespace config {
|
||||
@ -504,11 +504,11 @@ int main(int argc, char *const argv[]) {
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
global::start_motonic = chrono::now_motonic();
|
||||
global::deadline_motonic.fixedpoint =
|
||||
global::start_monotonic = chrono::now_monotonic();
|
||||
global::deadline_monotonic.fixedpoint =
|
||||
(global::config::timeout_duration_seconds == 0)
|
||||
? chrono::infinite().fixedpoint
|
||||
: global::start_motonic.fixedpoint +
|
||||
: global::start_monotonic.fixedpoint +
|
||||
chrono::from_seconds(global::config::timeout_duration_seconds)
|
||||
.fixedpoint;
|
||||
|
||||
@ -557,14 +557,14 @@ int main(int argc, char *const argv[]) {
|
||||
log_trace("=== polling...");
|
||||
while (left > 0) {
|
||||
unsigned timeout_seconds_left = INT_MAX;
|
||||
chrono::time now_motonic = chrono::now_motonic();
|
||||
if (now_motonic.fixedpoint >= global::deadline_motonic.fixedpoint)
|
||||
chrono::time now_monotonic = chrono::now_monotonic();
|
||||
if (now_monotonic.fixedpoint >= global::deadline_monotonic.fixedpoint)
|
||||
timeout_seconds_left = 0;
|
||||
else {
|
||||
chrono::time left_motonic;
|
||||
left_motonic.fixedpoint =
|
||||
global::deadline_motonic.fixedpoint - now_motonic.fixedpoint;
|
||||
timeout_seconds_left = left_motonic.seconds();
|
||||
chrono::time left_monotonic;
|
||||
left_monotonic.fixedpoint =
|
||||
global::deadline_monotonic.fixedpoint - now_monotonic.fixedpoint;
|
||||
timeout_seconds_left = left_monotonic.seconds();
|
||||
}
|
||||
|
||||
mdbx_pid_t pid;
|
||||
|
@ -336,7 +336,7 @@ bool osal_progress_push(bool active) {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static std::unordered_map<pid_t, actor_status> childs;
|
||||
static std::unordered_map<pid_t, actor_status> children;
|
||||
|
||||
static std::atomic_int sigalarm_head;
|
||||
static void handler_SIGCHLD(int signum) {
|
||||
@ -349,7 +349,7 @@ mdbx_pid_t osal_getpid(void) { return getpid(); }
|
||||
int osal_delay(unsigned seconds) { return sleep(seconds) ? errno : 0; }
|
||||
|
||||
int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
if (childs.empty()) {
|
||||
if (children.empty()) {
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = handler_SIGCHLD;
|
||||
@ -380,14 +380,14 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
|
||||
log_trace("osal_actor_start: fork pid %ld for %u", (long)pid,
|
||||
config.actor_id);
|
||||
childs[pid] = as_running;
|
||||
children[pid] = as_running;
|
||||
return 0;
|
||||
}
|
||||
|
||||
actor_status osal_actor_info(const mdbx_pid_t pid) { return childs.at(pid); }
|
||||
actor_status osal_actor_info(const mdbx_pid_t pid) { return children.at(pid); }
|
||||
|
||||
void osal_killall_actors(void) {
|
||||
for (auto &pair : childs) {
|
||||
for (auto &pair : children) {
|
||||
kill(pair.first, SIGKILL);
|
||||
pair.second = as_killed;
|
||||
}
|
||||
@ -417,16 +417,16 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
|
||||
if (pid > 0) {
|
||||
if (WIFEXITED(status))
|
||||
childs[pid] =
|
||||
children[pid] =
|
||||
(WEXITSTATUS(status) == EXIT_SUCCESS) ? as_successful : as_failed;
|
||||
else if (WCOREDUMP(status))
|
||||
childs[pid] = as_coredump;
|
||||
children[pid] = as_coredump;
|
||||
else if (WIFSIGNALED(status))
|
||||
childs[pid] = as_killed;
|
||||
children[pid] = as_killed;
|
||||
else if (WIFSTOPPED(status))
|
||||
childs[pid] = as_debugging;
|
||||
children[pid] = as_debugging;
|
||||
else if (WIFCONTINUED(status))
|
||||
childs[pid] = as_running;
|
||||
children[pid] = as_running;
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
@ -463,7 +463,7 @@ void osal_yield(void) {
|
||||
}
|
||||
|
||||
void osal_udelay(unsigned us) {
|
||||
chrono::time until, now = chrono::now_motonic();
|
||||
chrono::time until, now = chrono::now_monotonic();
|
||||
until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint;
|
||||
struct timespec ts;
|
||||
|
||||
@ -506,7 +506,7 @@ void osal_udelay(unsigned us) {
|
||||
}
|
||||
cpu_relax();
|
||||
|
||||
now = chrono::now_motonic();
|
||||
now = chrono::now_monotonic();
|
||||
} while (until.fixedpoint > now.fixedpoint);
|
||||
}
|
||||
|
||||
|
@ -186,10 +186,10 @@ bool actor_config::osal_deserialize(const char *str, const char *end,
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef std::pair<HANDLE, actor_status> child;
|
||||
static std::unordered_map<mdbx_pid_t, child> childs;
|
||||
static std::unordered_map<mdbx_pid_t, child> children;
|
||||
|
||||
bool osal_progress_push(bool active) {
|
||||
if (!childs.empty()) {
|
||||
if (!children.empty()) {
|
||||
if (!SetEvent(active ? hProgressActiveEvent : hProgressPassiveEvent))
|
||||
failure_perror("osal_progress_push: SetEvent(overlord.progress)",
|
||||
GetLastError());
|
||||
@ -284,8 +284,8 @@ Environment:
|
||||
}
|
||||
|
||||
int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
if (childs.size() == MAXIMUM_WAIT_OBJECTS)
|
||||
failure("Could't manage more that %u actors on Windows\n",
|
||||
if (children.size() == MAXIMUM_WAIT_OBJECTS)
|
||||
failure("Couldn't manage more that %u actors on Windows\n",
|
||||
MAXIMUM_WAIT_OBJECTS);
|
||||
|
||||
_flushall();
|
||||
@ -324,17 +324,17 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
|
||||
CloseHandle(ProcessInformation.hThread);
|
||||
pid = ProcessInformation.dwProcessId;
|
||||
childs[pid] = std::make_pair(ProcessInformation.hProcess, as_running);
|
||||
children[pid] = std::make_pair(ProcessInformation.hProcess, as_running);
|
||||
return 0;
|
||||
}
|
||||
|
||||
actor_status osal_actor_info(const mdbx_pid_t pid) {
|
||||
actor_status status = childs.at(pid).second;
|
||||
actor_status status = children.at(pid).second;
|
||||
if (status > as_running)
|
||||
return status;
|
||||
|
||||
DWORD ExitCode;
|
||||
if (!GetExitCodeProcess(childs.at(pid).first, &ExitCode))
|
||||
if (!GetExitCodeProcess(children.at(pid).first, &ExitCode))
|
||||
failure_perror("GetExitCodeProcess()", GetLastError());
|
||||
|
||||
switch (ExitCode) {
|
||||
@ -364,21 +364,21 @@ actor_status osal_actor_info(const mdbx_pid_t pid) {
|
||||
break;
|
||||
}
|
||||
|
||||
childs.at(pid).second = status;
|
||||
children.at(pid).second = status;
|
||||
return status;
|
||||
}
|
||||
|
||||
void osal_killall_actors(void) {
|
||||
for (auto &pair : childs)
|
||||
for (auto &pair : children)
|
||||
TerminateProcess(pair.second.first, STATUS_CONTROL_C_EXIT);
|
||||
}
|
||||
|
||||
int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
std::vector<HANDLE> handles;
|
||||
handles.reserve(childs.size() + 2);
|
||||
handles.reserve(children.size() + 2);
|
||||
handles.push_back(hProgressActiveEvent);
|
||||
handles.push_back(hProgressPassiveEvent);
|
||||
for (const auto &pair : childs)
|
||||
for (const auto &pair : children)
|
||||
if (pair.second.second <= as_running)
|
||||
handles.push_back(pair.second.first);
|
||||
|
||||
@ -399,7 +399,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
|
||||
if (rc >= WAIT_OBJECT_0 + 2 && rc < WAIT_OBJECT_0 + handles.size()) {
|
||||
pid = 0;
|
||||
for (const auto &pair : childs)
|
||||
for (const auto &pair : children)
|
||||
if (pair.second.first == handles[rc - WAIT_OBJECT_0]) {
|
||||
pid = pair.first;
|
||||
break;
|
||||
@ -419,7 +419,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
void osal_yield(void) { SwitchToThread(); }
|
||||
|
||||
void osal_udelay(unsigned us) {
|
||||
chrono::time until, now = chrono::now_motonic();
|
||||
chrono::time until, now = chrono::now_monotonic();
|
||||
until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint;
|
||||
|
||||
static unsigned threshold_us;
|
||||
@ -440,7 +440,7 @@ void osal_udelay(unsigned us) {
|
||||
}
|
||||
|
||||
YieldProcessor();
|
||||
now = chrono::now_motonic();
|
||||
now = chrono::now_monotonic();
|
||||
} while (now.fixedpoint < until.fixedpoint);
|
||||
}
|
||||
|
||||
|
@ -376,7 +376,7 @@ bool testcase::setup() {
|
||||
if (!wait4start())
|
||||
return false;
|
||||
|
||||
start_timestamp = chrono::now_motonic();
|
||||
start_timestamp = chrono::now_monotonic();
|
||||
nops_completed = 0;
|
||||
return true;
|
||||
}
|
||||
@ -395,7 +395,7 @@ bool testcase::should_continue(bool check_timeout_only) const {
|
||||
if (config.params.test_duration) {
|
||||
chrono::time since;
|
||||
since.fixedpoint =
|
||||
chrono::now_motonic().fixedpoint - start_timestamp.fixedpoint;
|
||||
chrono::now_monotonic().fixedpoint - start_timestamp.fixedpoint;
|
||||
if (since.seconds() >= config.params.test_duration)
|
||||
result = false;
|
||||
}
|
||||
|
@ -56,8 +56,8 @@ extern std::unordered_map<unsigned, actor_config *> events;
|
||||
extern std::unordered_map<mdbx_pid_t, actor_config *> pid2actor;
|
||||
extern std::set<std::string> databases;
|
||||
extern unsigned nactors;
|
||||
extern chrono::time start_motonic;
|
||||
extern chrono::time deadline_motonic;
|
||||
extern chrono::time start_monotonic;
|
||||
extern chrono::time deadline_monotonic;
|
||||
extern bool singlemode;
|
||||
|
||||
namespace config {
|
||||
|
Loading…
x
Reference in New Issue
Block a user