mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-20 05:38:20 +08:00
mdbx: merge branch master
into stable
.
This commit is contained in:
commit
4f770999a8
54
ChangeLog.md
54
ChangeLog.md
@ -5,9 +5,53 @@ English version [by Google](https://gitflic-ru.translate.goog/project/erthink/li
|
|||||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||||
|
|
||||||
|
|
||||||
## v0.12.8 (сопровождение и подготовка к релизу)
|
## v0.12.9 "Ясень-4" от 2023-12-11
|
||||||
|
|
||||||
Поддержка стабильной ветки.
|
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением недочетов.
|
||||||
|
|
||||||
|
```
|
||||||
|
git diff' stat: 32 commits, 8 files changed, 667 insertions(+), 401 deletions(-)
|
||||||
|
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||||
|
```
|
||||||
|
|
||||||
|
Исправления и доработки:
|
||||||
|
|
||||||
|
- Ликвидация зависимости от ранее удаленной опции `MDBX_ENABLE_PREFAULT`, из-за
|
||||||
|
чего опция `MDBX_ENABLE_MINCORE` не включалась автоматически, что приводило
|
||||||
|
к не-активации соответствующего улучшения и не-достижению декларируемого уровня
|
||||||
|
производительности в сценариях использования в режиме `MDBX_WRITEMAP`.
|
||||||
|
|
||||||
|
- Исправление авто-установки `MDBX_ENV_CHECKPID` при отключении использования
|
||||||
|
функционала `madvise()` посредством опции сборки `MDBX_ENABLE_MADVISE=0`.
|
||||||
|
Из-за чего при поддержке системой `madvise(MADV_DONTFORK)` не включался контроль pid.
|
||||||
|
|
||||||
|
- Добавлена проверка переданного ключа на `NULL` при обработке `MDBX_GET_MULTIPLE`.
|
||||||
|
|
||||||
|
- Добавлена проверка номеров корневых страниц в `coherency_check()`.
|
||||||
|
|
||||||
|
- Обеспечен `const` для начала и конца диапазона в аргументах `mdbx_estimate_range()`.
|
||||||
|
|
||||||
|
- Из разрабатываемой версии перенесены не-нарушающие совместимости доработки C++ API:
|
||||||
|
|
||||||
|
- добавлен тип `mdbx::cursor::estimation_result`, а поведение методов
|
||||||
|
`cursor::estimate()` унифицировано с `cursor::move()`;
|
||||||
|
- для предотвращения незаметного неверного использования API, для инициализации
|
||||||
|
возвращаемых по ссылке срезов, вместо пустых срезов задействован `slice::invalid()`;
|
||||||
|
- добавлены дополнительные C++ операторы преобразования к типам C API;
|
||||||
|
- для совместимости со старыми стандартами C++ и старыми версиями STL перенесены
|
||||||
|
в public классы `buffer::move_assign_alloc` и `buffer::copy_assign_alloc`;
|
||||||
|
- добавлен тип `mdbx::default_buffer`;
|
||||||
|
- для срезов и буферов добавлены методы `hex_decode()`, `base64_decode()`, `base58_decode()`;
|
||||||
|
- добавлен тип `mdbx::comparator` и функций `mdbx::default_comparator()`;
|
||||||
|
- добавлены статические методы `buffer::hex()`, `base64()`, `base58()`;
|
||||||
|
- для транзакций и курсоров добавлены методы `get_/set_context`;
|
||||||
|
- добавлен метод `cursor::clone()`;
|
||||||
|
|
||||||
|
- Поддержка base58 приведена в соответствии с черновиком RFC.
|
||||||
|
|
||||||
|
- Переработка/исправление `to_hex()` и `from_hex()`.
|
||||||
|
|
||||||
|
- Уменьшение `MDBX_opt_rp_augment_limit` по умолчанию до 1/3 от текущего количества страниц в БД.
|
||||||
|
|
||||||
Мелочи:
|
Мелочи:
|
||||||
|
|
||||||
@ -15,6 +59,12 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic
|
|||||||
- Корректировка определения `MDBX_LAST_ADDED_ERRCODE`.
|
- Корректировка определения `MDBX_LAST_ADDED_ERRCODE`.
|
||||||
- Добавление в C++ API забытого исключения `mdbx::duplicated_lck_file`.
|
- Добавление в C++ API забытого исключения `mdbx::duplicated_lck_file`.
|
||||||
- Обновление патча для старых версий buildroot.
|
- Обновление патча для старых версий buildroot.
|
||||||
|
- Использование в API `const MDBX_txn` где это возможно.
|
||||||
|
- Удаление устаревшего упоминания `MDBX_EAGAIN`.
|
||||||
|
- Проверка pid процесса только в функциях API требующих активной среды/env.
|
||||||
|
- Исправление опечаток в комментариях, в том числе в doxygen-описании.
|
||||||
|
- В тестах для совместимости с проблемными версиями glibc и glibc++
|
||||||
|
устранено использование `std::stoull()`.
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
36
mdbx.h
36
mdbx.h
@ -2119,7 +2119,8 @@ enum MDBX_option_t {
|
|||||||
* growth, or/and to the inability of put long values.
|
* growth, or/and to the inability of put long values.
|
||||||
*
|
*
|
||||||
* The `MDBX_opt_rp_augment_limit` controls described limit for the current
|
* The `MDBX_opt_rp_augment_limit` controls described limit for the current
|
||||||
* process. Default is 262144, it is usually enough for most cases. */
|
* process. By default this limit adjusted dynamically to 1/3 of current
|
||||||
|
* quantity of DB pages, which is usually enough for most cases. */
|
||||||
MDBX_opt_rp_augment_limit,
|
MDBX_opt_rp_augment_limit,
|
||||||
|
|
||||||
/** \brief Controls the in-process limit to grow a cache of dirty
|
/** \brief Controls the in-process limit to grow a cache of dirty
|
||||||
@ -2352,7 +2353,6 @@ LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env,
|
|||||||
* doesn't exist.
|
* doesn't exist.
|
||||||
* \retval MDBX_EACCES The user didn't have permission to access
|
* \retval MDBX_EACCES The user didn't have permission to access
|
||||||
* the environment files.
|
* the environment files.
|
||||||
* \retval MDBX_EAGAIN The environment was locked by another process.
|
|
||||||
* \retval MDBX_BUSY The \ref MDBX_EXCLUSIVE flag was specified and the
|
* \retval MDBX_BUSY The \ref MDBX_EXCLUSIVE flag was specified and the
|
||||||
* environment is in use by another process,
|
* environment is in use by another process,
|
||||||
* or the current process tries to open environment
|
* or the current process tries to open environment
|
||||||
@ -4293,8 +4293,8 @@ mdbx_int64_from_key(const MDBX_val);
|
|||||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
|
LIBMDBX_API int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
size_t bytes);
|
MDBX_stat *stat, size_t bytes);
|
||||||
|
|
||||||
/** \brief Retrieve depth (bitmask) information of nested dupsort (multi-value)
|
/** \brief Retrieve depth (bitmask) information of nested dupsort (multi-value)
|
||||||
* B+trees for given database.
|
* B+trees for given database.
|
||||||
@ -4311,7 +4311,7 @@ LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
|
|||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified.
|
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||||
* \retval MDBX_RESULT_TRUE The dbi isn't a dupsort (multi-value) database. */
|
* \retval MDBX_RESULT_TRUE The dbi isn't a dupsort (multi-value) database. */
|
||||||
LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
LIBMDBX_API int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
uint32_t *mask);
|
uint32_t *mask);
|
||||||
|
|
||||||
/** \brief DBI state bits returted by \ref mdbx_dbi_flags_ex()
|
/** \brief DBI state bits returted by \ref mdbx_dbi_flags_ex()
|
||||||
@ -4343,13 +4343,13 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state_t)
|
|||||||
* \param [out] state Address where the state will be returned.
|
* \param [out] state Address where the state will be returned.
|
||||||
*
|
*
|
||||||
* \returns A non-zero error value on failure and 0 on success. */
|
* \returns A non-zero error value on failure and 0 on success. */
|
||||||
LIBMDBX_API int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
LIBMDBX_API int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
unsigned *state);
|
unsigned *flags, unsigned *state);
|
||||||
/** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL`
|
/** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL`
|
||||||
* for discarding it result.
|
* for discarding it result.
|
||||||
* \ingroup c_statinfo */
|
* \ingroup c_statinfo */
|
||||||
LIBMDBX_INLINE_API(int, mdbx_dbi_flags,
|
LIBMDBX_INLINE_API(int, mdbx_dbi_flags,
|
||||||
(MDBX_txn * txn, MDBX_dbi dbi, unsigned *flags)) {
|
(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags)) {
|
||||||
unsigned state;
|
unsigned state;
|
||||||
return mdbx_dbi_flags_ex(txn, dbi, flags, &state);
|
return mdbx_dbi_flags_ex(txn, dbi, flags, &state);
|
||||||
}
|
}
|
||||||
@ -4425,7 +4425,7 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del);
|
|||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
LIBMDBX_API int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||||
MDBX_val *data);
|
MDBX_val *data);
|
||||||
|
|
||||||
/** \brief Get items from a database
|
/** \brief Get items from a database
|
||||||
@ -4458,7 +4458,7 @@ LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
|||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
LIBMDBX_API int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||||
MDBX_val *data, size_t *values_count);
|
MDBX_val *data, size_t *values_count);
|
||||||
|
|
||||||
/** \brief Get equal or great item from a database.
|
/** \brief Get equal or great item from a database.
|
||||||
@ -4489,7 +4489,7 @@ LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi,
|
LIBMDBX_API int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
MDBX_val *key, MDBX_val *data);
|
MDBX_val *key, MDBX_val *data);
|
||||||
|
|
||||||
/** \brief Store items into a database.
|
/** \brief Store items into a database.
|
||||||
@ -4731,7 +4731,7 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
|
|||||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
|
LIBMDBX_API int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *cursor,
|
||||||
MDBX_dbi dbi);
|
MDBX_dbi dbi);
|
||||||
|
|
||||||
/** \brief Create a cursor handle for the specified transaction and DBI handle.
|
/** \brief Create a cursor handle for the specified transaction and DBI handle.
|
||||||
@ -4764,7 +4764,7 @@ LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
|
|||||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||||
LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
|
LIBMDBX_API int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
MDBX_cursor **cursor);
|
MDBX_cursor **cursor);
|
||||||
|
|
||||||
/** \brief Close a cursor handle.
|
/** \brief Close a cursor handle.
|
||||||
@ -4807,7 +4807,7 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
|||||||
* \retval MDBX_EINVAL An invalid parameter was specified.
|
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||||
* \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle
|
* \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle
|
||||||
* or such a handle became invalid. */
|
* or such a handle became invalid. */
|
||||||
LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
|
LIBMDBX_API int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *cursor);
|
||||||
|
|
||||||
/** \brief Return the cursor's transaction handle.
|
/** \brief Return the cursor's transaction handle.
|
||||||
* \ingroup c_cursors
|
* \ingroup c_cursors
|
||||||
@ -5186,9 +5186,11 @@ LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key,
|
|||||||
* \param [out] distance_items A pointer to store range estimation result.
|
* \param [out] distance_items A pointer to store range estimation result.
|
||||||
*
|
*
|
||||||
* \returns A non-zero error value on failure and 0 on success. */
|
* \returns A non-zero error value on failure and 0 on success. */
|
||||||
LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
|
LIBMDBX_API int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
MDBX_val *begin_key, MDBX_val *begin_data,
|
const MDBX_val *begin_key,
|
||||||
MDBX_val *end_key, MDBX_val *end_data,
|
const MDBX_val *begin_data,
|
||||||
|
const MDBX_val *end_key,
|
||||||
|
const MDBX_val *end_data,
|
||||||
ptrdiff_t *distance_items);
|
ptrdiff_t *distance_items);
|
||||||
|
|
||||||
/** \brief The EPSILON value for mdbx_estimate_range()
|
/** \brief The EPSILON value for mdbx_estimate_range()
|
||||||
|
302
mdbx.h++
302
mdbx.h++
@ -362,8 +362,11 @@ using default_allocator = polymorphic_allocator;
|
|||||||
using default_allocator = legacy_allocator;
|
using default_allocator = legacy_allocator;
|
||||||
#endif /* __cpp_lib_memory_resource >= 201603L */
|
#endif /* __cpp_lib_memory_resource >= 201603L */
|
||||||
|
|
||||||
/// \brief Default singe-byte string.
|
/// \brief Default buffer.
|
||||||
template <class ALLOCATOR = legacy_allocator>
|
using default_buffer = buffer<default_allocator, default_capacity_policy>;
|
||||||
|
|
||||||
|
/// \brief Default single-byte string.
|
||||||
|
template <class ALLOCATOR = default_allocator>
|
||||||
using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
|
using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
|
||||||
|
|
||||||
using filehandle = ::mdbx_filehandle_t;
|
using filehandle = ::mdbx_filehandle_t;
|
||||||
@ -733,6 +736,8 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
|
|||||||
slice &operator=(const slice &) noexcept = default;
|
slice &operator=(const slice &) noexcept = default;
|
||||||
inline slice &operator=(slice &&src) noexcept;
|
inline slice &operator=(slice &&src) noexcept;
|
||||||
inline slice &operator=(::MDBX_val &&src);
|
inline slice &operator=(::MDBX_val &&src);
|
||||||
|
operator MDBX_val *() noexcept { return this; }
|
||||||
|
operator const MDBX_val *() const noexcept { return this; }
|
||||||
|
|
||||||
#if defined(DOXYGEN) || \
|
#if defined(DOXYGEN) || \
|
||||||
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
|
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
|
||||||
@ -1322,8 +1327,7 @@ struct LIBMDBX_API to_base58 {
|
|||||||
/// \brief Returns the buffer size in bytes needed for
|
/// \brief Returns the buffer size in bytes needed for
|
||||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice.
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice.
|
||||||
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
||||||
const size_t bytes =
|
const size_t bytes = (source.length() * 11 + 7) / 8;
|
||||||
source.length() / 8 * 11 + (source.length() % 8 * 43 + 31) / 32;
|
|
||||||
return wrap_width ? bytes + bytes / wrap_width : bytes;
|
return wrap_width ? bytes + bytes / wrap_width : bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1488,7 +1492,7 @@ struct LIBMDBX_API from_base58 {
|
|||||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to
|
||||||
/// decoded data.
|
/// decoded data.
|
||||||
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
||||||
return source.length() / 11 * 8 + source.length() % 11 * 32 / 43;
|
return source.length() /* могут быть все нули кодируемые один-к-одному */;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Fills the destination with data decoded from
|
/// \brief Fills the destination with data decoded from
|
||||||
@ -1576,10 +1580,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class txn;
|
friend class txn;
|
||||||
struct silo;
|
struct silo;
|
||||||
using move_assign_alloc =
|
|
||||||
allocation_aware_details::move_assign_alloc<silo, allocator_type>;
|
|
||||||
using copy_assign_alloc =
|
|
||||||
allocation_aware_details::copy_assign_alloc<silo, allocator_type>;
|
|
||||||
using swap_alloc = allocation_aware_details::swap_alloc<silo, allocator_type>;
|
using swap_alloc = allocation_aware_details::swap_alloc<silo, allocator_type>;
|
||||||
struct silo /* Empty Base Class Optimization */ : public allocator_type {
|
struct silo /* Empty Base Class Optimization */ : public allocator_type {
|
||||||
MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept {
|
MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept {
|
||||||
@ -2071,6 +2071,11 @@ public:
|
|||||||
/// \todo buffer& operator>>(buffer&, ...) for reading (delegated to slice)
|
/// \todo buffer& operator>>(buffer&, ...) for reading (delegated to slice)
|
||||||
/// \todo template<class X> key(X) for encoding keys while writing
|
/// \todo template<class X> key(X) for encoding keys while writing
|
||||||
|
|
||||||
|
using move_assign_alloc =
|
||||||
|
allocation_aware_details::move_assign_alloc<silo, allocator_type>;
|
||||||
|
using copy_assign_alloc =
|
||||||
|
allocation_aware_details::copy_assign_alloc<silo, allocator_type>;
|
||||||
|
|
||||||
/// \brief Returns the associated allocator.
|
/// \brief Returns the associated allocator.
|
||||||
MDBX_CXX20_CONSTEXPR allocator_type get_allocator() const {
|
MDBX_CXX20_CONSTEXPR allocator_type get_allocator() const {
|
||||||
return silo_.get_allocator();
|
return silo_.get_allocator();
|
||||||
@ -2339,6 +2344,126 @@ public:
|
|||||||
return slice_.as_pod<POD>();
|
return slice_.as_pod<POD>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a hexadecimal dump of the slice content.
|
||||||
|
static buffer hex(const ::mdbx::slice &source, bool uppercase = false,
|
||||||
|
unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template encode_hex<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
uppercase, wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
|
||||||
|
static buffer base58(const ::mdbx::slice &source, unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template encode_base58<ALLOCATOR, CAPACITY_POLICY>(wrap_width,
|
||||||
|
allocator);
|
||||||
|
}
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
|
||||||
|
static buffer base64(const ::mdbx::slice &source, unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template encode_base64<ALLOCATOR, CAPACITY_POLICY>(wrap_width,
|
||||||
|
allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a hexadecimal dump of the given pod.
|
||||||
|
template <typename POD>
|
||||||
|
static buffer hex(const POD &pod, bool uppercase = false,
|
||||||
|
unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return hex(mdbx::slice::wrap(pod), uppercase, wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the given pod.
|
||||||
|
template <typename POD>
|
||||||
|
static buffer base58(const POD &pod, unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return base58(mdbx::slice::wrap(pod), wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the given pod.
|
||||||
|
template <typename POD>
|
||||||
|
static buffer base64(const POD &pod, unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return base64(mdbx::slice::wrap(pod), wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a hexadecimal dump of the slice content.
|
||||||
|
buffer encode_hex(bool uppercase = false, unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return slice().template encode_hex<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
uppercase, wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
|
||||||
|
buffer
|
||||||
|
encode_base58(unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return slice().template encode_base58<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
wrap_width, allocator);
|
||||||
|
}
|
||||||
|
/// \brief Returns a new buffer with a
|
||||||
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
|
||||||
|
buffer
|
||||||
|
encode_base64(unsigned wrap_width = 0,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return slice().template encode_base64<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
wrap_width, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes hexadecimal dump from the slice content to returned buffer.
|
||||||
|
static buffer hex_decode(const ::mdbx::slice &source,
|
||||||
|
bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template hex_decode<ALLOCATOR, CAPACITY_POLICY>(ignore_spaces,
|
||||||
|
allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump
|
||||||
|
/// from the slice content to returned buffer.
|
||||||
|
static buffer
|
||||||
|
base58_decode(const ::mdbx::slice &source, bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template base58_decode<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
ignore_spaces, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump
|
||||||
|
/// from the slice content to returned buffer.
|
||||||
|
static buffer
|
||||||
|
base64_decode(const ::mdbx::slice &source, bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) {
|
||||||
|
return source.template base64_decode<ALLOCATOR, CAPACITY_POLICY>(
|
||||||
|
ignore_spaces, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes hexadecimal dump
|
||||||
|
/// from the buffer content to new returned buffer.
|
||||||
|
buffer hex_decode(bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return hex_decode(slice(), ignore_spaces, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump
|
||||||
|
/// from the buffer content to new returned buffer.
|
||||||
|
buffer
|
||||||
|
base58_decode(bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return base58_decode(slice(), ignore_spaces, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump
|
||||||
|
/// from the buffer content to new returned buffer.
|
||||||
|
buffer
|
||||||
|
base64_decode(bool ignore_spaces = false,
|
||||||
|
const allocator_type &allocator = allocator_type()) const {
|
||||||
|
return base64_decode(slice(), ignore_spaces, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Reserves storage space.
|
/// \brief Reserves storage space.
|
||||||
void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
|
void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
|
||||||
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
|
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
|
||||||
@ -2983,6 +3108,7 @@ struct LIBMDBX_API_TYPE map_handle {
|
|||||||
map_handle(const map_handle &) noexcept = default;
|
map_handle(const map_handle &) noexcept = default;
|
||||||
map_handle &operator=(const map_handle &) noexcept = default;
|
map_handle &operator=(const map_handle &) noexcept = default;
|
||||||
operator bool() const noexcept { return dbi != 0; }
|
operator bool() const noexcept { return dbi != 0; }
|
||||||
|
operator MDBX_dbi() const { return dbi; }
|
||||||
|
|
||||||
using flags = ::MDBX_db_flags_t;
|
using flags = ::MDBX_db_flags_t;
|
||||||
using state = ::MDBX_dbi_state_t;
|
using state = ::MDBX_dbi_state_t;
|
||||||
@ -3008,6 +3134,14 @@ struct LIBMDBX_API_TYPE map_handle {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using comparator = ::MDBX_cmp_func *;
|
||||||
|
inline comparator default_comparator(key_mode mode) noexcept {
|
||||||
|
return ::mdbx_get_keycmp(static_cast<MDBX_db_flags_t>(mode));
|
||||||
|
}
|
||||||
|
inline comparator default_comparator(value_mode mode) noexcept {
|
||||||
|
return ::mdbx_get_keycmp(static_cast<MDBX_db_flags_t>(mode));
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Key-value pairs put mode.
|
/// \brief Key-value pairs put mode.
|
||||||
enum put_mode {
|
enum put_mode {
|
||||||
insert_unique = MDBX_NOOVERWRITE, ///< Insert only unique keys.
|
insert_unique = MDBX_NOOVERWRITE, ///< Insert only unique keys.
|
||||||
@ -3445,7 +3579,7 @@ public:
|
|||||||
inline void *get_context() const noexcept;
|
inline void *get_context() const noexcept;
|
||||||
|
|
||||||
/// \brief Sets the application context associated with the environment.
|
/// \brief Sets the application context associated with the environment.
|
||||||
inline env &set_context(void *);
|
inline env &set_context(void *your_context);
|
||||||
|
|
||||||
/// \brief Sets threshold to force flush the data buffers to disk, for
|
/// \brief Sets threshold to force flush the data buffers to disk, for
|
||||||
/// non-sync durability modes.
|
/// non-sync durability modes.
|
||||||
@ -3803,6 +3937,12 @@ public:
|
|||||||
/// \brief Return the transaction's ID.
|
/// \brief Return the transaction's ID.
|
||||||
inline uint64_t id() const;
|
inline uint64_t id() const;
|
||||||
|
|
||||||
|
/// \brief Returns the application context associated with the transaction.
|
||||||
|
inline void *get_context() const noexcept;
|
||||||
|
|
||||||
|
/// \brief Sets the application context associated with the transaction.
|
||||||
|
inline txn &set_context(void *your_context);
|
||||||
|
|
||||||
/// \brief Checks whether the given data is on a dirty page.
|
/// \brief Checks whether the given data is on a dirty page.
|
||||||
inline bool is_dirty(const void *ptr) const;
|
inline bool is_dirty(const void *ptr) const;
|
||||||
|
|
||||||
@ -3839,7 +3979,7 @@ public:
|
|||||||
txn_managed start_nested();
|
txn_managed start_nested();
|
||||||
|
|
||||||
/// \brief Opens cursor for specified key-value map handle.
|
/// \brief Opens cursor for specified key-value map handle.
|
||||||
inline cursor_managed open_cursor(map_handle map);
|
inline cursor_managed open_cursor(map_handle map) const;
|
||||||
|
|
||||||
/// \brief Open existing key-value map.
|
/// \brief Open existing key-value map.
|
||||||
inline map_handle open_map(
|
inline map_handle open_map(
|
||||||
@ -4038,10 +4178,12 @@ public:
|
|||||||
put_multiple(map, key, vector.data(), vector.size(), mode);
|
put_multiple(map, key, vector.data(), vector.size(), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t estimate(map_handle map, pair from, pair to) const;
|
inline ptrdiff_t estimate(map_handle map, const pair &from,
|
||||||
inline ptrdiff_t estimate(map_handle map, slice from, slice to) const;
|
const pair &to) const;
|
||||||
inline ptrdiff_t estimate_from_first(map_handle map, slice to) const;
|
inline ptrdiff_t estimate(map_handle map, const slice &from,
|
||||||
inline ptrdiff_t estimate_to_last(map_handle map, slice from) const;
|
const slice &to) const;
|
||||||
|
inline ptrdiff_t estimate_from_first(map_handle map, const slice &to) const;
|
||||||
|
inline ptrdiff_t estimate_to_last(map_handle map, const slice &from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Managed database transaction.
|
/// \brief Managed database transaction.
|
||||||
@ -4122,6 +4264,7 @@ public:
|
|||||||
inline cursor &operator=(cursor &&other) noexcept;
|
inline cursor &operator=(cursor &&other) noexcept;
|
||||||
inline cursor(cursor &&other) noexcept;
|
inline cursor(cursor &&other) noexcept;
|
||||||
inline ~cursor() noexcept;
|
inline ~cursor() noexcept;
|
||||||
|
inline cursor_managed clone(void *your_context = nullptr) const;
|
||||||
MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
|
MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
|
||||||
MDBX_CXX14_CONSTEXPR operator const MDBX_cursor *() const;
|
MDBX_CXX14_CONSTEXPR operator const MDBX_cursor *() const;
|
||||||
MDBX_CXX14_CONSTEXPR operator MDBX_cursor *();
|
MDBX_CXX14_CONSTEXPR operator MDBX_cursor *();
|
||||||
@ -4130,6 +4273,12 @@ public:
|
|||||||
friend MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
|
friend MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
|
||||||
const cursor &b) noexcept;
|
const cursor &b) noexcept;
|
||||||
|
|
||||||
|
/// \brief Returns the application context associated with the cursor.
|
||||||
|
inline void *get_context() const noexcept;
|
||||||
|
|
||||||
|
/// \brief Sets the application context associated with the cursor.
|
||||||
|
inline cursor &set_context(void *your_context);
|
||||||
|
|
||||||
enum move_operation {
|
enum move_operation {
|
||||||
first = MDBX_FIRST,
|
first = MDBX_FIRST,
|
||||||
last = MDBX_LAST,
|
last = MDBX_LAST,
|
||||||
@ -4154,10 +4303,13 @@ public:
|
|||||||
|
|
||||||
struct move_result : public pair_result {
|
struct move_result : public pair_result {
|
||||||
inline move_result(const cursor &cursor, bool throw_notfound);
|
inline move_result(const cursor &cursor, bool throw_notfound);
|
||||||
inline move_result(cursor &cursor, move_operation operation,
|
move_result(cursor &cursor, move_operation operation, bool throw_notfound)
|
||||||
bool throw_notfound);
|
: move_result(cursor, operation, slice::invalid(), slice::invalid(),
|
||||||
inline move_result(cursor &cursor, move_operation operation,
|
throw_notfound) {}
|
||||||
const slice &key, bool throw_notfound);
|
move_result(cursor &cursor, move_operation operation, const slice &key,
|
||||||
|
bool throw_notfound)
|
||||||
|
: move_result(cursor, operation, key, slice::invalid(),
|
||||||
|
throw_notfound) {}
|
||||||
inline move_result(cursor &cursor, move_operation operation,
|
inline move_result(cursor &cursor, move_operation operation,
|
||||||
const slice &key, const slice &value,
|
const slice &key, const slice &value,
|
||||||
bool throw_notfound);
|
bool throw_notfound);
|
||||||
@ -4165,6 +4317,20 @@ public:
|
|||||||
move_result &operator=(const move_result &) noexcept = default;
|
move_result &operator=(const move_result &) noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct estimate_result : public pair {
|
||||||
|
ptrdiff_t approximate_quantity;
|
||||||
|
estimate_result(const cursor &cursor, move_operation operation)
|
||||||
|
: estimate_result(cursor, operation, slice::invalid(),
|
||||||
|
slice::invalid()) {}
|
||||||
|
estimate_result(const cursor &cursor, move_operation operation,
|
||||||
|
const slice &key)
|
||||||
|
: estimate_result(cursor, operation, key, slice::invalid()) {}
|
||||||
|
inline estimate_result(const cursor &cursor, move_operation operation,
|
||||||
|
const slice &key, const slice &value);
|
||||||
|
estimate_result(const estimate_result &) noexcept = default;
|
||||||
|
estimate_result &operator=(const estimate_result &) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline bool move(move_operation operation, MDBX_val *key, MDBX_val *value,
|
inline bool move(move_operation operation, MDBX_val *key, MDBX_val *value,
|
||||||
bool throw_notfound) const
|
bool throw_notfound) const
|
||||||
@ -4209,19 +4375,20 @@ public:
|
|||||||
inline bool eof() const;
|
inline bool eof() const;
|
||||||
inline bool on_first() const;
|
inline bool on_first() const;
|
||||||
inline bool on_last() const;
|
inline bool on_last() const;
|
||||||
inline ptrdiff_t estimate(slice key, slice value) const;
|
inline estimate_result estimate(const slice &key, const slice &value) const;
|
||||||
inline ptrdiff_t estimate(slice key) const;
|
inline estimate_result estimate(const slice &key) const;
|
||||||
inline ptrdiff_t estimate(move_operation operation) const;
|
inline estimate_result estimate(move_operation operation) const;
|
||||||
|
inline estimate_result estimate(move_operation operation, slice &key) const;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// \brief Renew/bind a cursor with a new transaction and previously used
|
/// \brief Renew/bind a cursor with a new transaction and previously used
|
||||||
/// key-value map handle.
|
/// key-value map handle.
|
||||||
inline void renew(::mdbx::txn &txn);
|
inline void renew(const ::mdbx::txn &txn);
|
||||||
|
|
||||||
/// \brief Bind/renew a cursor with a new transaction and specified key-value
|
/// \brief Bind/renew a cursor with a new transaction and specified key-value
|
||||||
/// map handle.
|
/// map handle.
|
||||||
inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle);
|
inline void bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle);
|
||||||
|
|
||||||
/// \brief Returns the cursor's transaction.
|
/// \brief Returns the cursor's transaction.
|
||||||
inline ::mdbx::txn txn() const;
|
inline ::mdbx::txn txn() const;
|
||||||
@ -4275,7 +4442,8 @@ class LIBMDBX_API_TYPE cursor_managed : public cursor {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief Creates a new managed cursor with underlying object.
|
/// \brief Creates a new managed cursor with underlying object.
|
||||||
cursor_managed() : cursor_managed(::mdbx_cursor_create(nullptr)) {
|
cursor_managed(void *your_context = nullptr)
|
||||||
|
: cursor_managed(::mdbx_cursor_create(your_context)) {
|
||||||
if (MDBX_UNLIKELY(!handle_))
|
if (MDBX_UNLIKELY(!handle_))
|
||||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_ENOMEM);
|
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_ENOMEM);
|
||||||
}
|
}
|
||||||
@ -5417,6 +5585,15 @@ MDBX_CXX11_CONSTEXPR bool operator!=(const txn &a, const txn &b) noexcept {
|
|||||||
return a.handle_ != b.handle_;
|
return a.handle_ != b.handle_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void *txn::get_context() const noexcept {
|
||||||
|
return mdbx_txn_get_userctx(handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline txn &txn::set_context(void *ptr) {
|
||||||
|
error::success_or_throw(::mdbx_txn_set_userctx(handle_, ptr));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool txn::is_dirty(const void *ptr) const {
|
inline bool txn::is_dirty(const void *ptr) const {
|
||||||
int err = ::mdbx_is_dirty(handle_, ptr);
|
int err = ::mdbx_is_dirty(handle_, ptr);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
@ -5457,7 +5634,7 @@ inline txn::info txn::get_info(bool scan_reader_lock_table) const {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline cursor_managed txn::open_cursor(map_handle map) {
|
inline cursor_managed txn::open_cursor(map_handle map) const {
|
||||||
MDBX_cursor *ptr;
|
MDBX_cursor *ptr;
|
||||||
error::success_or_throw(::mdbx_cursor_open(handle_, map.dbi, &ptr));
|
error::success_or_throw(::mdbx_cursor_open(handle_, map.dbi, &ptr));
|
||||||
return cursor_managed(ptr);
|
return cursor_managed(ptr);
|
||||||
@ -5855,28 +6032,32 @@ inline size_t txn::put_multiple(map_handle map, const slice &key,
|
|||||||
return args[1].iov_len /* done item count */;
|
return args[1].iov_len /* done item count */;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t txn::estimate(map_handle map, pair from, pair to) const {
|
inline ptrdiff_t txn::estimate(map_handle map, const pair &from,
|
||||||
|
const pair &to) const {
|
||||||
ptrdiff_t result;
|
ptrdiff_t result;
|
||||||
error::success_or_throw(mdbx_estimate_range(
|
error::success_or_throw(mdbx_estimate_range(
|
||||||
handle_, map.dbi, &from.key, &from.value, &to.key, &to.value, &result));
|
handle_, map.dbi, &from.key, &from.value, &to.key, &to.value, &result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t txn::estimate(map_handle map, slice from, slice to) const {
|
inline ptrdiff_t txn::estimate(map_handle map, const slice &from,
|
||||||
|
const slice &to) const {
|
||||||
ptrdiff_t result;
|
ptrdiff_t result;
|
||||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
||||||
&to, nullptr, &result));
|
&to, nullptr, &result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t txn::estimate_from_first(map_handle map, slice to) const {
|
inline ptrdiff_t txn::estimate_from_first(map_handle map,
|
||||||
|
const slice &to) const {
|
||||||
ptrdiff_t result;
|
ptrdiff_t result;
|
||||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, nullptr,
|
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, nullptr,
|
||||||
nullptr, &to, nullptr, &result));
|
nullptr, &to, nullptr, &result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t txn::estimate_to_last(map_handle map, slice from) const {
|
inline ptrdiff_t txn::estimate_to_last(map_handle map,
|
||||||
|
const slice &from) const {
|
||||||
ptrdiff_t result;
|
ptrdiff_t result;
|
||||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
||||||
nullptr, nullptr, &result));
|
nullptr, nullptr, &result));
|
||||||
@ -5887,6 +6068,21 @@ inline ptrdiff_t txn::estimate_to_last(map_handle map, slice from) const {
|
|||||||
|
|
||||||
MDBX_CXX11_CONSTEXPR cursor::cursor(MDBX_cursor *ptr) noexcept : handle_(ptr) {}
|
MDBX_CXX11_CONSTEXPR cursor::cursor(MDBX_cursor *ptr) noexcept : handle_(ptr) {}
|
||||||
|
|
||||||
|
inline cursor_managed cursor::clone(void *your_context) const {
|
||||||
|
cursor_managed clone(your_context);
|
||||||
|
error::success_or_throw(::mdbx_cursor_copy(handle_, clone.handle_));
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *cursor::get_context() const noexcept {
|
||||||
|
return mdbx_cursor_get_userctx(handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cursor &cursor::set_context(void *ptr) {
|
||||||
|
error::success_or_throw(::mdbx_cursor_set_userctx(handle_, ptr));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline cursor &cursor::operator=(cursor &&other) noexcept {
|
inline cursor &cursor::operator=(cursor &&other) noexcept {
|
||||||
handle_ = other.handle_;
|
handle_ = other.handle_;
|
||||||
other.handle_ = nullptr;
|
other.handle_ = nullptr;
|
||||||
@ -5925,22 +6121,8 @@ MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
|
|||||||
|
|
||||||
inline cursor::move_result::move_result(const cursor &cursor,
|
inline cursor::move_result::move_result(const cursor &cursor,
|
||||||
bool throw_notfound)
|
bool throw_notfound)
|
||||||
: pair_result(key, value, false) {
|
: pair_result(slice(), slice(), false) {
|
||||||
done = cursor.move(get_current, &key, &value, throw_notfound);
|
done = cursor.move(get_current, &this->key, &this->value, throw_notfound);
|
||||||
}
|
|
||||||
|
|
||||||
inline cursor::move_result::move_result(cursor &cursor,
|
|
||||||
move_operation operation,
|
|
||||||
bool throw_notfound)
|
|
||||||
: pair_result(key, value, false) {
|
|
||||||
done = cursor.move(operation, &key, &value, throw_notfound);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline cursor::move_result::move_result(cursor &cursor,
|
|
||||||
move_operation operation,
|
|
||||||
const slice &key, bool throw_notfound)
|
|
||||||
: pair_result(key, slice(), false) {
|
|
||||||
this->done = cursor.move(operation, &this->key, &this->value, throw_notfound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline cursor::move_result::move_result(cursor &cursor,
|
inline cursor::move_result::move_result(cursor &cursor,
|
||||||
@ -5967,6 +6149,14 @@ inline bool cursor::move(move_operation operation, MDBX_val *key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline cursor::estimate_result::estimate_result(const cursor &cursor,
|
||||||
|
move_operation operation,
|
||||||
|
const slice &key,
|
||||||
|
const slice &value)
|
||||||
|
: pair(key, value), approximate_quantity(PTRDIFF_MIN) {
|
||||||
|
approximate_quantity = cursor.estimate(operation, &this->key, &this->value);
|
||||||
|
}
|
||||||
|
|
||||||
inline ptrdiff_t cursor::estimate(move_operation operation, MDBX_val *key,
|
inline ptrdiff_t cursor::estimate(move_operation operation, MDBX_val *key,
|
||||||
MDBX_val *value) const {
|
MDBX_val *value) const {
|
||||||
ptrdiff_t result;
|
ptrdiff_t result;
|
||||||
@ -6089,24 +6279,26 @@ inline bool cursor::on_last() const {
|
|||||||
return error::boolean_or_throw(::mdbx_cursor_on_last(*this));
|
return error::boolean_or_throw(::mdbx_cursor_on_last(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t cursor::estimate(slice key, slice value) const {
|
inline cursor::estimate_result cursor::estimate(const slice &key,
|
||||||
return estimate(multi_exactkey_lowerboundvalue, &key, &value);
|
const slice &value) const {
|
||||||
|
return estimate_result(*this, multi_exactkey_lowerboundvalue, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t cursor::estimate(slice key) const {
|
inline cursor::estimate_result cursor::estimate(const slice &key) const {
|
||||||
return estimate(key_lowerbound, &key, nullptr);
|
return estimate_result(*this, key_lowerbound, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t cursor::estimate(move_operation operation) const {
|
inline cursor::estimate_result
|
||||||
slice unused_key;
|
cursor::estimate(move_operation operation) const {
|
||||||
return estimate(operation, &unused_key, nullptr);
|
return estimate_result(*this, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void cursor::renew(::mdbx::txn &txn) {
|
inline void cursor::renew(const ::mdbx::txn &txn) {
|
||||||
error::success_or_throw(::mdbx_cursor_renew(txn, handle_));
|
error::success_or_throw(::mdbx_cursor_renew(txn, handle_));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) {
|
inline void cursor::bind(const ::mdbx::txn &txn,
|
||||||
|
::mdbx::map_handle map_handle) {
|
||||||
error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi));
|
error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
157
src/core.c
157
src/core.c
@ -3386,7 +3386,7 @@ static int __must_check_result cursor_first(MDBX_cursor *mc, MDBX_val *key,
|
|||||||
static int __must_check_result cursor_last(MDBX_cursor *mc, MDBX_val *key,
|
static int __must_check_result cursor_last(MDBX_cursor *mc, MDBX_val *key,
|
||||||
MDBX_val *data);
|
MDBX_val *data);
|
||||||
|
|
||||||
static int __must_check_result cursor_init(MDBX_cursor *mc, MDBX_txn *txn,
|
static int __must_check_result cursor_init(MDBX_cursor *mc, const MDBX_txn *txn,
|
||||||
size_t dbi);
|
size_t dbi);
|
||||||
static int __must_check_result cursor_xinit0(MDBX_cursor *mc);
|
static int __must_check_result cursor_xinit0(MDBX_cursor *mc);
|
||||||
static int __must_check_result cursor_xinit1(MDBX_cursor *mc, MDBX_node *node,
|
static int __must_check_result cursor_xinit1(MDBX_cursor *mc, MDBX_node *node,
|
||||||
@ -5979,8 +5979,8 @@ __cold static void munlock_all(const MDBX_env *env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__cold static unsigned default_rp_augment_limit(const MDBX_env *env) {
|
__cold static unsigned default_rp_augment_limit(const MDBX_env *env) {
|
||||||
/* default rp_augment_limit = ceil(npages / gold_ratio) */
|
/* default rp_augment_limit = npages / 3 */
|
||||||
const size_t augment = (env->me_dbgeo.now >> (env->me_psize2log + 10)) * 633u;
|
const size_t augment = env->me_dbgeo.now / 3 >> env->me_psize2log;
|
||||||
eASSERT(env, augment < MDBX_PGL_LIMIT);
|
eASSERT(env, augment < MDBX_PGL_LIMIT);
|
||||||
return pnl_bytes2size(pnl_size2bytes(
|
return pnl_bytes2size(pnl_size2bytes(
|
||||||
(augment > MDBX_PNL_INITIAL) ? augment : MDBX_PNL_INITIAL));
|
(augment > MDBX_PNL_INITIAL) ? augment : MDBX_PNL_INITIAL));
|
||||||
@ -7315,7 +7315,7 @@ static pgr_t page_alloc_slowpath(const MDBX_cursor *const mc, const size_t num,
|
|||||||
* простейших случаях (тривиальный бенчмарк) интегральная производительность
|
* простейших случаях (тривиальный бенчмарк) интегральная производительность
|
||||||
* становится вдвое меньше. А на платформах без mincore() и с проблемной
|
* становится вдвое меньше. А на платформах без mincore() и с проблемной
|
||||||
* подсистемой виртуальной памяти ситуация может быть многократно хуже.
|
* подсистемой виртуальной памяти ситуация может быть многократно хуже.
|
||||||
* Поэтому избегаем затрат в ситуациях когда prefaukt-write скорее всего не
|
* Поэтому избегаем затрат в ситуациях когда prefault-write скорее всего не
|
||||||
* нужна. */
|
* нужна. */
|
||||||
const bool readahead_enabled = env->me_lck->mti_readahead_anchor & 1;
|
const bool readahead_enabled = env->me_lck->mti_readahead_anchor & 1;
|
||||||
const pgno_t readahead_edge = env->me_lck->mti_readahead_anchor >> 1;
|
const pgno_t readahead_edge = env->me_lck->mti_readahead_anchor >> 1;
|
||||||
@ -8258,17 +8258,16 @@ static __inline int check_env(const MDBX_env *env, const bool wanna_active) {
|
|||||||
if (unlikely(env->me_signature.weak != MDBX_ME_SIGNATURE))
|
if (unlikely(env->me_signature.weak != MDBX_ME_SIGNATURE))
|
||||||
return MDBX_EBADSIGN;
|
return MDBX_EBADSIGN;
|
||||||
|
|
||||||
#if MDBX_ENV_CHECKPID
|
|
||||||
if (unlikely(env->me_pid != osal_getpid())) {
|
|
||||||
((MDBX_env *)env)->me_flags |= MDBX_FATAL_ERROR;
|
|
||||||
return MDBX_PANIC;
|
|
||||||
}
|
|
||||||
#endif /* MDBX_ENV_CHECKPID */
|
|
||||||
|
|
||||||
if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
|
if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
|
||||||
return MDBX_PANIC;
|
return MDBX_PANIC;
|
||||||
|
|
||||||
if (wanna_active) {
|
if (wanna_active) {
|
||||||
|
#if MDBX_ENV_CHECKPID
|
||||||
|
if (unlikely(env->me_pid != osal_getpid())) {
|
||||||
|
((MDBX_env *)env)->me_flags |= MDBX_FATAL_ERROR;
|
||||||
|
return MDBX_PANIC;
|
||||||
|
}
|
||||||
|
#endif /* MDBX_ENV_CHECKPID */
|
||||||
if (unlikely((env->me_flags & MDBX_ENV_ACTIVE) == 0))
|
if (unlikely((env->me_flags & MDBX_ENV_ACTIVE) == 0))
|
||||||
return MDBX_EPERM;
|
return MDBX_EPERM;
|
||||||
eASSERT(env, env->me_map != nullptr);
|
eASSERT(env, env->me_map != nullptr);
|
||||||
@ -8615,20 +8614,45 @@ static bool coherency_check(const MDBX_env *env, const txnid_t txnid,
|
|||||||
const volatile MDBX_meta *meta, bool report) {
|
const volatile MDBX_meta *meta, bool report) {
|
||||||
const txnid_t freedb_mod_txnid = dbs[FREE_DBI].md_mod_txnid;
|
const txnid_t freedb_mod_txnid = dbs[FREE_DBI].md_mod_txnid;
|
||||||
const txnid_t maindb_mod_txnid = dbs[MAIN_DBI].md_mod_txnid;
|
const txnid_t maindb_mod_txnid = dbs[MAIN_DBI].md_mod_txnid;
|
||||||
|
const pgno_t last_pgno = meta->mm_geo.now;
|
||||||
|
|
||||||
const pgno_t freedb_root_pgno = dbs[FREE_DBI].md_root;
|
const pgno_t freedb_root_pgno = dbs[FREE_DBI].md_root;
|
||||||
const MDBX_page *freedb_root = (env->me_map && freedb_root_pgno != P_INVALID)
|
const MDBX_page *freedb_root = (env->me_map && freedb_root_pgno < last_pgno)
|
||||||
? pgno2page(env, freedb_root_pgno)
|
? pgno2page(env, freedb_root_pgno)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
const pgno_t maindb_root_pgno = dbs[MAIN_DBI].md_root;
|
const pgno_t maindb_root_pgno = dbs[MAIN_DBI].md_root;
|
||||||
const MDBX_page *maindb_root = (env->me_map && maindb_root_pgno != P_INVALID)
|
const MDBX_page *maindb_root = (env->me_map && maindb_root_pgno < last_pgno)
|
||||||
? pgno2page(env, maindb_root_pgno)
|
? pgno2page(env, maindb_root_pgno)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const uint64_t magic_and_version =
|
const uint64_t magic_and_version =
|
||||||
unaligned_peek_u64_volatile(4, &meta->mm_magic_and_version);
|
unaligned_peek_u64_volatile(4, &meta->mm_magic_and_version);
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
if (freedb_root_pgno != P_INVALID &&
|
||||||
|
unlikely(freedb_root_pgno >= last_pgno)) {
|
||||||
|
if (report)
|
||||||
|
WARNING(
|
||||||
|
"catch invalid %sdb root %" PRIaPGNO " for meta_txnid %" PRIaTXN
|
||||||
|
" %s",
|
||||||
|
"free", freedb_root_pgno, txnid,
|
||||||
|
(env->me_stuck_meta < 0)
|
||||||
|
? "(workaround for incoherent flaw of unified page/buffer cache)"
|
||||||
|
: "(wagering meta)");
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
if (maindb_root_pgno != P_INVALID &&
|
||||||
|
unlikely(maindb_root_pgno >= last_pgno)) {
|
||||||
|
if (report)
|
||||||
|
WARNING(
|
||||||
|
"catch invalid %sdb root %" PRIaPGNO " for meta_txnid %" PRIaTXN
|
||||||
|
" %s",
|
||||||
|
"main", maindb_root_pgno, txnid,
|
||||||
|
(env->me_stuck_meta < 0)
|
||||||
|
? "(workaround for incoherent flaw of unified page/buffer cache)"
|
||||||
|
: "(wagering meta)");
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
if (unlikely(txnid < freedb_mod_txnid ||
|
if (unlikely(txnid < freedb_mod_txnid ||
|
||||||
(!freedb_mod_txnid && freedb_root &&
|
(!freedb_mod_txnid && freedb_root &&
|
||||||
likely(magic_and_version == MDBX_DATA_MAGIC)))) {
|
likely(magic_and_version == MDBX_DATA_MAGIC)))) {
|
||||||
@ -9579,7 +9603,7 @@ int mdbx_txn_flags(const MDBX_txn *txn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check for misused dbi handles */
|
/* Check for misused dbi handles */
|
||||||
static __inline bool dbi_changed(MDBX_txn *txn, size_t dbi) {
|
static __inline bool dbi_changed(const MDBX_txn *txn, size_t dbi) {
|
||||||
if (txn->mt_dbiseqs == txn->mt_env->me_dbiseqs)
|
if (txn->mt_dbiseqs == txn->mt_env->me_dbiseqs)
|
||||||
return false;
|
return false;
|
||||||
if (likely(
|
if (likely(
|
||||||
@ -11170,7 +11194,7 @@ static int txn_write(MDBX_txn *txn, iov_ctx_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check txn and dbi arguments to a function */
|
/* Check txn and dbi arguments to a function */
|
||||||
static __always_inline bool check_dbi(MDBX_txn *txn, MDBX_dbi dbi,
|
static __always_inline bool check_dbi(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
unsigned validity) {
|
unsigned validity) {
|
||||||
if (likely(dbi < txn->mt_numdbs)) {
|
if (likely(dbi < txn->mt_numdbs)) {
|
||||||
if (likely(!dbi_changed(txn, dbi))) {
|
if (likely(!dbi_changed(txn, dbi))) {
|
||||||
@ -11181,7 +11205,7 @@ static __always_inline bool check_dbi(MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dbi_import(txn, dbi);
|
return dbi_import((MDBX_txn *)txn, dbi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Merge child txn into parent */
|
/* Merge child txn into parent */
|
||||||
@ -16078,7 +16102,8 @@ static __always_inline int node_read(MDBX_cursor *mc, const MDBX_node *node,
|
|||||||
return node_read_bigdata(mc, node, data, mp);
|
return node_read_bigdata(mc, node, data, mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
|
int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||||
|
MDBX_val *data) {
|
||||||
DKBUF_DEBUG;
|
DKBUF_DEBUG;
|
||||||
DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
|
DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
|
||||||
|
|
||||||
@ -16100,7 +16125,7 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
|
|||||||
return cursor_set(&cx.outer, (MDBX_val *)key, data, MDBX_SET).err;
|
return cursor_set(&cx.outer, (MDBX_val *)key, data, MDBX_SET).err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||||
MDBX_val *data) {
|
MDBX_val *data) {
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
@ -16123,8 +16148,8 @@ int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
return cursor_get(&cx.outer, key, data, MDBX_SET_LOWERBOUND);
|
return cursor_get(&cx.outer, key, data, MDBX_SET_LOWERBOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||||
size_t *values_count) {
|
MDBX_val *data, size_t *values_count) {
|
||||||
DKBUF_DEBUG;
|
DKBUF_DEBUG;
|
||||||
DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
|
DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
|
||||||
|
|
||||||
@ -16883,24 +16908,30 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
|||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0))
|
if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0))
|
||||||
return MDBX_INCOMPATIBLE;
|
return MDBX_INCOMPATIBLE;
|
||||||
rc = (mc->mc_flags & C_INITIALIZED)
|
if ((mc->mc_flags & C_INITIALIZED) == 0) {
|
||||||
? MDBX_SUCCESS
|
if (unlikely(!key))
|
||||||
: cursor_set(mc, key, data, MDBX_SET).err;
|
return MDBX_EINVAL;
|
||||||
if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) !=
|
rc = cursor_set(mc, key, data, MDBX_SET).err;
|
||||||
C_INITIALIZED)
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rc = MDBX_SUCCESS;
|
||||||
|
if (unlikely(C_INITIALIZED != (mc->mc_xcursor->mx_cursor.mc_flags &
|
||||||
|
(C_INITIALIZED | C_EOF)))) {
|
||||||
|
rc = MDBX_NOTFOUND;
|
||||||
break;
|
break;
|
||||||
goto fetchm;
|
}
|
||||||
|
goto fetch_multiple;
|
||||||
case MDBX_NEXT_MULTIPLE:
|
case MDBX_NEXT_MULTIPLE:
|
||||||
if (unlikely(data == NULL))
|
if (unlikely(!data))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED)))
|
if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED)))
|
||||||
return MDBX_INCOMPATIBLE;
|
return MDBX_INCOMPATIBLE;
|
||||||
rc = cursor_next(mc, key, data, MDBX_NEXT_DUP);
|
rc = cursor_next(mc, key, data, MDBX_NEXT_DUP);
|
||||||
if (rc == MDBX_SUCCESS) {
|
if (rc == MDBX_SUCCESS) {
|
||||||
if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
|
if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
|
||||||
MDBX_cursor *mx;
|
fetch_multiple:;
|
||||||
fetchm:
|
MDBX_cursor *mx = &mc->mc_xcursor->mx_cursor;
|
||||||
mx = &mc->mc_xcursor->mx_cursor;
|
|
||||||
data->iov_len =
|
data->iov_len =
|
||||||
page_numkeys(mx->mc_pg[mx->mc_top]) * mx->mc_db->md_xsize;
|
page_numkeys(mx->mc_pg[mx->mc_top]) * mx->mc_db->md_xsize;
|
||||||
data->iov_base = page_data(mx->mc_pg[mx->mc_top]);
|
data->iov_base = page_data(mx->mc_pg[mx->mc_top]);
|
||||||
@ -16911,21 +16942,20 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MDBX_PREV_MULTIPLE:
|
case MDBX_PREV_MULTIPLE:
|
||||||
if (data == NULL)
|
if (unlikely(!data))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
if (!(mc->mc_db->md_flags & MDBX_DUPFIXED))
|
if (!(mc->mc_db->md_flags & MDBX_DUPFIXED))
|
||||||
return MDBX_INCOMPATIBLE;
|
return MDBX_INCOMPATIBLE;
|
||||||
rc = MDBX_SUCCESS;
|
rc = MDBX_SUCCESS;
|
||||||
if (!(mc->mc_flags & C_INITIALIZED))
|
if ((mc->mc_flags & C_INITIALIZED) == 0)
|
||||||
rc = cursor_last(mc, key, data);
|
rc = cursor_last(mc, key, data);
|
||||||
if (rc == MDBX_SUCCESS) {
|
if (rc == MDBX_SUCCESS) {
|
||||||
MDBX_cursor *mx = &mc->mc_xcursor->mx_cursor;
|
MDBX_cursor *mx = &mc->mc_xcursor->mx_cursor;
|
||||||
|
rc = MDBX_NOTFOUND;
|
||||||
if (mx->mc_flags & C_INITIALIZED) {
|
if (mx->mc_flags & C_INITIALIZED) {
|
||||||
rc = cursor_sibling(mx, SIBLING_LEFT);
|
rc = cursor_sibling(mx, SIBLING_LEFT);
|
||||||
if (rc == MDBX_SUCCESS)
|
if (rc == MDBX_SUCCESS)
|
||||||
goto fetchm;
|
goto fetch_multiple;
|
||||||
} else {
|
|
||||||
rc = MDBX_NOTFOUND;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -18754,13 +18784,13 @@ static int cursor_xinit2(MDBX_cursor *mc, MDBX_xcursor *src_mx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static __inline int couple_init(MDBX_cursor_couple *couple, const size_t dbi,
|
static __inline int couple_init(MDBX_cursor_couple *couple, const size_t dbi,
|
||||||
MDBX_txn *const txn, MDBX_db *const db,
|
const MDBX_txn *const txn, MDBX_db *const db,
|
||||||
MDBX_dbx *const dbx, uint8_t *const dbstate) {
|
MDBX_dbx *const dbx, uint8_t *const dbstate) {
|
||||||
couple->outer.mc_signature = MDBX_MC_LIVE;
|
couple->outer.mc_signature = MDBX_MC_LIVE;
|
||||||
couple->outer.mc_next = NULL;
|
couple->outer.mc_next = NULL;
|
||||||
couple->outer.mc_backup = NULL;
|
couple->outer.mc_backup = NULL;
|
||||||
couple->outer.mc_dbi = (MDBX_dbi)dbi;
|
couple->outer.mc_dbi = (MDBX_dbi)dbi;
|
||||||
couple->outer.mc_txn = txn;
|
couple->outer.mc_txn = (MDBX_txn *)txn;
|
||||||
couple->outer.mc_db = db;
|
couple->outer.mc_db = db;
|
||||||
couple->outer.mc_dbx = dbx;
|
couple->outer.mc_dbx = dbx;
|
||||||
couple->outer.mc_dbistate = dbstate;
|
couple->outer.mc_dbistate = dbstate;
|
||||||
@ -18798,7 +18828,7 @@ static __inline int couple_init(MDBX_cursor_couple *couple, const size_t dbi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize a cursor for a given transaction and database. */
|
/* Initialize a cursor for a given transaction and database. */
|
||||||
static int cursor_init(MDBX_cursor *mc, MDBX_txn *txn, size_t dbi) {
|
static int cursor_init(MDBX_cursor *mc, const MDBX_txn *txn, size_t dbi) {
|
||||||
STATIC_ASSERT(offsetof(MDBX_cursor_couple, outer) == 0);
|
STATIC_ASSERT(offsetof(MDBX_cursor_couple, outer) == 0);
|
||||||
return couple_init(container_of(mc, MDBX_cursor_couple, outer), dbi, txn,
|
return couple_init(container_of(mc, MDBX_cursor_couple, outer), dbi, txn,
|
||||||
&txn->mt_dbs[dbi], &txn->mt_dbxs[dbi],
|
&txn->mt_dbs[dbi], &txn->mt_dbxs[dbi],
|
||||||
@ -18841,7 +18871,7 @@ void *mdbx_cursor_get_userctx(const MDBX_cursor *mc) {
|
|||||||
return couple->mc_userctx;
|
return couple->mc_userctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
|
int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
|
||||||
if (unlikely(!mc))
|
if (unlikely(!mc))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
@ -18913,7 +18943,7 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||||
if (unlikely(!ret))
|
if (unlikely(!ret))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
*ret = NULL;
|
*ret = NULL;
|
||||||
@ -18932,7 +18962,7 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
|
int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *mc) {
|
||||||
return likely(mc) ? mdbx_cursor_bind(txn, mc, mc->mc_dbi) : MDBX_EINVAL;
|
return likely(mc) ? mdbx_cursor_bind(txn, mc, mc->mc_dbi) : MDBX_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22199,7 +22229,7 @@ __cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
__cold int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
__cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
uint32_t *mask) {
|
uint32_t *mask) {
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
@ -22817,7 +22847,7 @@ int mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name,
|
|||||||
return dbi_open(txn, name, flags, dbi, keycmp, datacmp);
|
return dbi_open(txn, name, flags, dbi, keycmp, datacmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
__cold int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
|
__cold int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
|
||||||
size_t bytes) {
|
size_t bytes) {
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
@ -22837,7 +22867,7 @@ __cold int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
|
|||||||
return MDBX_BAD_TXN;
|
return MDBX_BAD_TXN;
|
||||||
|
|
||||||
if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
|
if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
|
||||||
rc = fetch_sdb(txn, dbi);
|
rc = fetch_sdb((MDBX_txn *)txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -22898,7 +22928,7 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
||||||
unsigned *state) {
|
unsigned *state) {
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
|
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
@ -24069,9 +24099,10 @@ int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
|
|||||||
return mdbx_estimate_distance(cursor, &next.outer, distance_items);
|
return mdbx_estimate_distance(cursor, &next.outer, distance_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
MDBX_val *begin_data, MDBX_val *end_key,
|
const MDBX_val *begin_key, const MDBX_val *begin_data,
|
||||||
MDBX_val *end_data, ptrdiff_t *size_items) {
|
const MDBX_val *end_key, const MDBX_val *end_data,
|
||||||
|
ptrdiff_t *size_items) {
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
@ -24102,13 +24133,13 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDBX_val stub;
|
||||||
if (!begin_key) {
|
if (!begin_key) {
|
||||||
if (unlikely(!end_key)) {
|
if (unlikely(!end_key)) {
|
||||||
/* LY: FIRST..LAST case */
|
/* LY: FIRST..LAST case */
|
||||||
*size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
|
*size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
MDBX_val stub = {0, 0};
|
|
||||||
rc = cursor_first(&begin.outer, &stub, &stub);
|
rc = cursor_first(&begin.outer, &stub, &stub);
|
||||||
if (unlikely(end_key == MDBX_EPSILON)) {
|
if (unlikely(end_key == MDBX_EPSILON)) {
|
||||||
/* LY: FIRST..+epsilon case */
|
/* LY: FIRST..+epsilon case */
|
||||||
@ -24120,7 +24151,6 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
|||||||
if (unlikely(begin_key == MDBX_EPSILON)) {
|
if (unlikely(begin_key == MDBX_EPSILON)) {
|
||||||
if (end_key == NULL) {
|
if (end_key == NULL) {
|
||||||
/* LY: -epsilon..LAST case */
|
/* LY: -epsilon..LAST case */
|
||||||
MDBX_val stub = {0, 0};
|
|
||||||
rc = cursor_last(&begin.outer, &stub, &stub);
|
rc = cursor_last(&begin.outer, &stub, &stub);
|
||||||
return (rc == MDBX_SUCCESS)
|
return (rc == MDBX_SUCCESS)
|
||||||
? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
|
? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
|
||||||
@ -24138,7 +24168,7 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
|||||||
(begin_key == end_key ||
|
(begin_key == end_key ||
|
||||||
begin.outer.mc_dbx->md_cmp(begin_key, end_key) == 0)) {
|
begin.outer.mc_dbx->md_cmp(begin_key, end_key) == 0)) {
|
||||||
/* LY: single key case */
|
/* LY: single key case */
|
||||||
rc = cursor_set(&begin.outer, begin_key, NULL, MDBX_SET).err;
|
rc = cursor_set(&begin.outer, (MDBX_val *)begin_key, NULL, MDBX_SET).err;
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
*size_items = 0;
|
*size_items = 0;
|
||||||
return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
|
return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
|
||||||
@ -24159,10 +24189,14 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
} else {
|
} else if (begin_data) {
|
||||||
rc = cursor_set(&begin.outer, begin_key, begin_data,
|
stub = *begin_data;
|
||||||
begin_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE)
|
rc = cursor_set(&begin.outer, (MDBX_val *)begin_key, &stub,
|
||||||
|
MDBX_GET_BOTH_RANGE)
|
||||||
.err;
|
.err;
|
||||||
|
} else {
|
||||||
|
stub = *begin_key;
|
||||||
|
rc = cursor_set(&begin.outer, &stub, nullptr, MDBX_SET_RANGE).err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24175,13 +24209,15 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
|||||||
rc = cursor_init(&end.outer, txn, dbi);
|
rc = cursor_init(&end.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
if (!end_key) {
|
if (!end_key)
|
||||||
MDBX_val stub = {0, 0};
|
|
||||||
rc = cursor_last(&end.outer, &stub, &stub);
|
rc = cursor_last(&end.outer, &stub, &stub);
|
||||||
} else {
|
else if (end_data) {
|
||||||
rc = cursor_set(&end.outer, end_key, end_data,
|
stub = *end_data;
|
||||||
end_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE)
|
rc = cursor_set(&end.outer, (MDBX_val *)end_key, &stub, MDBX_GET_BOTH_RANGE)
|
||||||
.err;
|
.err;
|
||||||
|
} else {
|
||||||
|
stub = *end_key;
|
||||||
|
rc = cursor_set(&end.outer, &stub, nullptr, MDBX_SET_RANGE).err;
|
||||||
}
|
}
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
if (rc != MDBX_NOTFOUND || !(end.outer.mc_flags & C_INITIALIZED))
|
if (rc != MDBX_NOTFOUND || !(end.outer.mc_flags & C_INITIALIZED))
|
||||||
@ -25411,7 +25447,8 @@ LIBMDBX_API __cold int mdbx_env_info(const MDBX_env *env, MDBX_envinfo *info,
|
|||||||
return __inline_mdbx_env_info(env, info, bytes);
|
return __inline_mdbx_env_info(env, info, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBMDBX_API int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) {
|
LIBMDBX_API int mdbx_dbi_flags(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||||
|
unsigned *flags) {
|
||||||
return __inline_mdbx_dbi_flags(txn, dbi, flags);
|
return __inline_mdbx_dbi_flags(txn, dbi, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
432
src/mdbx.c++
432
src/mdbx.c++
@ -207,6 +207,44 @@ __cold bug::~bug() noexcept {}
|
|||||||
|
|
||||||
#endif /* Unused*/
|
#endif /* Unused*/
|
||||||
|
|
||||||
|
struct line_wrapper {
|
||||||
|
char *line, *ptr;
|
||||||
|
line_wrapper(char *buf) noexcept : line(buf), ptr(buf) {}
|
||||||
|
void put(char c, size_t wrap_width) noexcept {
|
||||||
|
*ptr++ = c;
|
||||||
|
if (wrap_width && ptr >= wrap_width + line) {
|
||||||
|
*ptr++ = '\n';
|
||||||
|
line = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void put(const ::mdbx::slice &chunk, size_t wrap_width) noexcept {
|
||||||
|
if (!wrap_width || wrap_width > (ptr - line) + chunk.length()) {
|
||||||
|
memcpy(ptr, chunk.data(), chunk.length());
|
||||||
|
ptr += chunk.length();
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < chunk.length(); ++i)
|
||||||
|
put(chunk.char_ptr()[i], wrap_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TYPE, unsigned INPLACE_BYTES = unsigned(sizeof(void *) * 64)>
|
||||||
|
struct temp_buffer {
|
||||||
|
TYPE inplace[(INPLACE_BYTES + sizeof(TYPE) - 1) / sizeof(TYPE)];
|
||||||
|
const size_t size;
|
||||||
|
TYPE *const area;
|
||||||
|
temp_buffer(size_t bytes)
|
||||||
|
: size((bytes + sizeof(TYPE) - 1) / sizeof(TYPE)),
|
||||||
|
area((bytes > sizeof(inplace)) ? new TYPE[size] : inplace) {
|
||||||
|
memset(area, 0, sizeof(TYPE) * size);
|
||||||
|
}
|
||||||
|
~temp_buffer() {
|
||||||
|
if (area != inplace)
|
||||||
|
delete[] area;
|
||||||
|
}
|
||||||
|
TYPE *end() const { return area + size; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -599,7 +637,7 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
|||||||
|
|
||||||
auto ptr = dest;
|
auto ptr = dest;
|
||||||
auto src = source.byte_ptr();
|
auto src = source.byte_ptr();
|
||||||
const char alphabase = (uppercase ? 'A' : 'a') - 10;
|
const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
|
||||||
auto line = ptr;
|
auto line = ptr;
|
||||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||||
if (wrap_width && size_t(ptr - line) >= wrap_width) {
|
if (wrap_width && size_t(ptr - line) >= wrap_width) {
|
||||||
@ -608,8 +646,8 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
|||||||
}
|
}
|
||||||
const int8_t hi = *src >> 4;
|
const int8_t hi = *src >> 4;
|
||||||
const int8_t lo = *src & 15;
|
const int8_t lo = *src & 15;
|
||||||
ptr[0] = char(alphabase + hi + (((hi - 10) >> 7) & -7));
|
ptr[0] = char('0' + hi + (((9 - hi) >> 7) & alpha_shift));
|
||||||
ptr[1] = char(alphabase + lo + (((lo - 10) >> 7) & -7));
|
ptr[1] = char('0' + lo + (((9 - lo) >> 7) & alpha_shift));
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
assert(ptr <= dest + dest_size);
|
assert(ptr <= dest + dest_size);
|
||||||
}
|
}
|
||||||
@ -621,7 +659,7 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
|||||||
MDBX_CXX20_LIKELY {
|
MDBX_CXX20_LIKELY {
|
||||||
::std::ostream::sentry sentry(out);
|
::std::ostream::sentry sentry(out);
|
||||||
auto src = source.byte_ptr();
|
auto src = source.byte_ptr();
|
||||||
const char alphabase = (uppercase ? 'A' : 'a') - 10;
|
const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||||
if (wrap_width && width >= wrap_width) {
|
if (wrap_width && width >= wrap_width) {
|
||||||
@ -630,8 +668,8 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
|||||||
}
|
}
|
||||||
const int8_t hi = *src >> 4;
|
const int8_t hi = *src >> 4;
|
||||||
const int8_t lo = *src & 15;
|
const int8_t lo = *src & 15;
|
||||||
out.put(char(alphabase + hi + (((hi - 10) >> 7) & -7)));
|
out.put(char('0' + hi + (((9 - hi) >> 7) & alpha_shift)));
|
||||||
out.put(char(alphabase + lo + (((lo - 10) >> 7) & -7)));
|
out.put(char('0' + lo + (((9 - lo) >> 7) & alpha_shift)));
|
||||||
width += 2;
|
width += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,11 +700,11 @@ char *from_hex::write_bytes(char *__restrict const dest,
|
|||||||
|
|
||||||
int8_t hi = src[0];
|
int8_t hi = src[0];
|
||||||
hi = (hi | 0x20) - 'a';
|
hi = (hi | 0x20) - 'a';
|
||||||
hi += 10 + ((hi >> 7) & 7);
|
hi += 10 + ((hi >> 7) & 39);
|
||||||
|
|
||||||
int8_t lo = src[1];
|
int8_t lo = src[1];
|
||||||
lo = (lo | 0x20) - 'a';
|
lo = (lo | 0x20) - 'a';
|
||||||
lo += 10 + ((lo >> 7) & 7);
|
lo += 10 + ((lo >> 7) & 39);
|
||||||
|
|
||||||
*ptr++ = hi << 4 | lo;
|
*ptr++ = hi << 4 | lo;
|
||||||
src += 2;
|
src += 2;
|
||||||
@ -709,156 +747,135 @@ enum : signed char {
|
|||||||
IL /* invalid */ = -1
|
IL /* invalid */ = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
static const byte b58_alphabet[58] = {
|
#if MDBX_WORDBITS > 32
|
||||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
using b58_uint = uint_fast64_t;
|
||||||
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
|
||||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
|
|
||||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
|
||||||
|
|
||||||
#ifndef bswap64
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
static inline uint64_t bswap64(uint64_t v) noexcept {
|
|
||||||
#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \
|
|
||||||
__has_builtin(__builtin_bswap64)
|
|
||||||
return __builtin_bswap64(v);
|
|
||||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
|
||||||
return _byteswap_uint64(v);
|
|
||||||
#elif defined(__bswap_64)
|
|
||||||
return __bswap_64(v);
|
|
||||||
#elif defined(bswap_64)
|
|
||||||
return bswap_64(v);
|
|
||||||
#else
|
#else
|
||||||
return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) |
|
using b58_uint = uint_fast32_t;
|
||||||
((v << 24) & UINT64_C(0x0000ff0000000000)) |
|
|
||||||
((v << 8) & UINT64_C(0x000000ff00000000)) |
|
|
||||||
((v >> 8) & UINT64_C(0x00000000ff000000)) |
|
|
||||||
((v >> 24) & UINT64_C(0x0000000000ff0000)) |
|
|
||||||
((v >> 40) & UINT64_C(0x000000000000ff00));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
#endif /* __BYTE_ORDER__ */
|
|
||||||
#endif /* ifndef bswap64 */
|
|
||||||
|
|
||||||
static inline char b58_8to11(uint64_t &v) noexcept {
|
struct b58_buffer : public temp_buffer<b58_uint> {
|
||||||
const unsigned i = unsigned(v % 58);
|
b58_buffer(size_t bytes, size_t estimation_ratio_numerator,
|
||||||
|
size_t estimation_ratio_denominator, size_t extra = 0)
|
||||||
|
: temp_buffer((/* пересчитываем по указанной пропорции */
|
||||||
|
bytes = (bytes * estimation_ratio_numerator +
|
||||||
|
estimation_ratio_denominator - 1) /
|
||||||
|
estimation_ratio_denominator,
|
||||||
|
/* учитываем резервный старший байт в каждом слове */
|
||||||
|
((bytes + sizeof(b58_uint) - 2) / (sizeof(b58_uint) - 1) *
|
||||||
|
sizeof(b58_uint) +
|
||||||
|
extra) *
|
||||||
|
sizeof(b58_uint))) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte b58_8to11(b58_uint &v) noexcept {
|
||||||
|
static const char b58_alphabet[58] = {
|
||||||
|
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||||
|
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||||
|
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
|
||||||
|
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||||
|
|
||||||
|
const auto i = size_t(v % 58);
|
||||||
v /= 58;
|
v /= 58;
|
||||||
return b58_alphabet[i];
|
return b58_alphabet[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static slice b58_encode(b58_buffer &buf, const byte *begin, const byte *end) {
|
||||||
|
auto high = buf.end();
|
||||||
|
const auto modulo =
|
||||||
|
b58_uint((sizeof(b58_uint) > 4) ? UINT64_C(0x1A636A90B07A00) /* 58^9 */
|
||||||
|
: UINT32_C(0xACAD10) /* 58^4 */);
|
||||||
|
static_assert(sizeof(modulo) == 4 || sizeof(modulo) == 8, "WTF?");
|
||||||
|
while (begin < end) {
|
||||||
|
b58_uint carry = *begin++;
|
||||||
|
auto ptr = buf.end();
|
||||||
|
do {
|
||||||
|
assert(ptr > buf.area);
|
||||||
|
carry += *--ptr << CHAR_BIT;
|
||||||
|
*ptr = carry % modulo;
|
||||||
|
carry /= modulo;
|
||||||
|
} while (carry || ptr > high);
|
||||||
|
high = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
|
||||||
|
auto ptr = output;
|
||||||
|
for (auto porous = high; porous < buf.end();) {
|
||||||
|
auto chunk = *porous++;
|
||||||
|
static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
|
||||||
|
assert(chunk < modulo);
|
||||||
|
if (sizeof(chunk) > 4) {
|
||||||
|
ptr[8] = b58_8to11(chunk);
|
||||||
|
ptr[7] = b58_8to11(chunk);
|
||||||
|
ptr[6] = b58_8to11(chunk);
|
||||||
|
ptr[5] = b58_8to11(chunk);
|
||||||
|
ptr[4] = b58_8to11(chunk);
|
||||||
|
ptr[3] = b58_8to11(chunk);
|
||||||
|
ptr[2] = b58_8to11(chunk);
|
||||||
|
ptr[1] = b58_8to11(chunk);
|
||||||
|
ptr[0] = b58_8to11(chunk);
|
||||||
|
ptr += 9;
|
||||||
|
} else {
|
||||||
|
ptr[3] = b58_8to11(chunk);
|
||||||
|
ptr[2] = b58_8to11(chunk);
|
||||||
|
ptr[1] = b58_8to11(chunk);
|
||||||
|
ptr[0] = b58_8to11(chunk);
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
assert(static_cast<void *>(ptr) < static_cast<void *>(porous));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (output < ptr && *output == '1')
|
||||||
|
++output;
|
||||||
|
return slice(output, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
char *to_base58::write_bytes(char *__restrict const dest,
|
char *to_base58::write_bytes(char *__restrict const dest,
|
||||||
size_t dest_size) const {
|
size_t dest_size) const {
|
||||||
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
|
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
|
||||||
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
||||||
|
|
||||||
auto ptr = dest;
|
auto begin = source.byte_ptr();
|
||||||
auto src = source.byte_ptr();
|
auto end = source.end_byte_ptr();
|
||||||
size_t left = source.length();
|
line_wrapper wrapper(dest);
|
||||||
auto line = ptr;
|
while (MDBX_LIKELY(begin < end) && *begin == 0) {
|
||||||
while (MDBX_LIKELY(left > 7)) {
|
wrapper.put('1', wrap_width);
|
||||||
uint64_t v;
|
assert(wrapper.ptr <= dest + dest_size);
|
||||||
std::memcpy(&v, src, 8);
|
++begin;
|
||||||
src += 8;
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
v = bswap64(v);
|
|
||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
||||||
#else
|
|
||||||
#error "FIXME: Unsupported byte order"
|
|
||||||
#endif /* __BYTE_ORDER__ */
|
|
||||||
ptr[10] = b58_8to11(v);
|
|
||||||
ptr[9] = b58_8to11(v);
|
|
||||||
ptr[8] = b58_8to11(v);
|
|
||||||
ptr[7] = b58_8to11(v);
|
|
||||||
ptr[6] = b58_8to11(v);
|
|
||||||
ptr[5] = b58_8to11(v);
|
|
||||||
ptr[4] = b58_8to11(v);
|
|
||||||
ptr[3] = b58_8to11(v);
|
|
||||||
ptr[2] = b58_8to11(v);
|
|
||||||
ptr[1] = b58_8to11(v);
|
|
||||||
ptr[0] = b58_8to11(v);
|
|
||||||
assert(v == 0);
|
|
||||||
ptr += 11;
|
|
||||||
left -= 8;
|
|
||||||
if (wrap_width && size_t(ptr - line) >= wrap_width && left) {
|
|
||||||
*ptr = '\n';
|
|
||||||
line = ++ptr;
|
|
||||||
}
|
|
||||||
assert(ptr <= dest + dest_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left) {
|
b58_buffer buf(end - begin, 11, 8);
|
||||||
uint64_t v = 0;
|
wrapper.put(b58_encode(buf, begin, end), wrap_width);
|
||||||
unsigned parrots = 31;
|
return wrapper.ptr;
|
||||||
do {
|
|
||||||
v = (v << 8) + *src++;
|
|
||||||
parrots += 43;
|
|
||||||
} while (--left);
|
|
||||||
|
|
||||||
auto tail = ptr += parrots >> 5;
|
|
||||||
assert(ptr <= dest + dest_size);
|
|
||||||
do {
|
|
||||||
*--tail = b58_8to11(v);
|
|
||||||
parrots -= 32;
|
|
||||||
} while (parrots > 31);
|
|
||||||
assert(v == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::std::ostream &to_base58::output(::std::ostream &out) const {
|
::std::ostream &to_base58::output(::std::ostream &out) const {
|
||||||
if (MDBX_LIKELY(!is_empty()))
|
if (MDBX_LIKELY(!is_empty()))
|
||||||
MDBX_CXX20_LIKELY {
|
MDBX_CXX20_LIKELY {
|
||||||
::std::ostream::sentry sentry(out);
|
::std::ostream::sentry sentry(out);
|
||||||
auto src = source.byte_ptr();
|
auto begin = source.byte_ptr();
|
||||||
size_t left = source.length();
|
auto end = source.end_byte_ptr();
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
std::array<char, 11> buf;
|
while (MDBX_LIKELY(begin < end) && *begin == 0) {
|
||||||
|
out.put('1');
|
||||||
while (MDBX_LIKELY(left > 7)) {
|
if (wrap_width && ++width >= wrap_width) {
|
||||||
uint64_t v;
|
|
||||||
std::memcpy(&v, src, 8);
|
|
||||||
src += 8;
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
v = bswap64(v);
|
|
||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
||||||
#else
|
|
||||||
#error "FIXME: Unsupported byte order"
|
|
||||||
#endif /* __BYTE_ORDER__ */
|
|
||||||
buf[10] = b58_8to11(v);
|
|
||||||
buf[9] = b58_8to11(v);
|
|
||||||
buf[8] = b58_8to11(v);
|
|
||||||
buf[7] = b58_8to11(v);
|
|
||||||
buf[6] = b58_8to11(v);
|
|
||||||
buf[5] = b58_8to11(v);
|
|
||||||
buf[4] = b58_8to11(v);
|
|
||||||
buf[3] = b58_8to11(v);
|
|
||||||
buf[2] = b58_8to11(v);
|
|
||||||
buf[1] = b58_8to11(v);
|
|
||||||
buf[0] = b58_8to11(v);
|
|
||||||
assert(v == 0);
|
|
||||||
out.write(&buf.front(), 11);
|
|
||||||
left -= 8;
|
|
||||||
if (wrap_width && (width += 11) >= wrap_width && left) {
|
|
||||||
out << ::std::endl;
|
out << ::std::endl;
|
||||||
width = 0;
|
width = 0;
|
||||||
}
|
}
|
||||||
|
++begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left) {
|
b58_buffer buf(end - begin, 11, 8);
|
||||||
uint64_t v = 0;
|
const auto chunk = b58_encode(buf, begin, end);
|
||||||
unsigned parrots = 31;
|
if (!wrap_width || wrap_width > width + chunk.length())
|
||||||
do {
|
out.write(chunk.char_ptr(), chunk.length());
|
||||||
v = (v << 8) + *src++;
|
else {
|
||||||
parrots += 43;
|
for (size_t i = 0; i < chunk.length(); ++i) {
|
||||||
} while (--left);
|
out.put(chunk.char_ptr()[i]);
|
||||||
|
if (wrap_width && ++width >= wrap_width) {
|
||||||
auto ptr = buf.end();
|
out << ::std::endl;
|
||||||
do {
|
width = 0;
|
||||||
*--ptr = b58_8to11(v);
|
}
|
||||||
parrots -= 32;
|
}
|
||||||
} while (parrots > 31);
|
|
||||||
assert(v == 0);
|
|
||||||
out.write(&*ptr, buf.end() - ptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@ -884,10 +901,46 @@ const signed char b58_map[256] = {
|
|||||||
IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL // f0
|
IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL // f0
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline signed char b58_11to8(uint64_t &v, const byte c) noexcept {
|
static slice b58_decode(b58_buffer &buf, const byte *begin, const byte *end,
|
||||||
const signed char m = b58_map[c];
|
bool ignore_spaces) {
|
||||||
v = v * 58 + m;
|
auto high = buf.end();
|
||||||
return m;
|
while (begin < end) {
|
||||||
|
const auto c = b58_map[*begin++];
|
||||||
|
if (MDBX_LIKELY(c >= 0)) {
|
||||||
|
b58_uint carry = c;
|
||||||
|
auto ptr = buf.end();
|
||||||
|
do {
|
||||||
|
assert(ptr > buf.area);
|
||||||
|
carry += *--ptr * 58;
|
||||||
|
*ptr = carry & (~b58_uint(0) >> CHAR_BIT);
|
||||||
|
carry >>= CHAR_BIT * (sizeof(carry) - 1);
|
||||||
|
} while (carry || ptr > high);
|
||||||
|
high = ptr;
|
||||||
|
} else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(begin[-1])))
|
||||||
|
MDBX_CXX20_UNLIKELY
|
||||||
|
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
|
||||||
|
auto ptr = output;
|
||||||
|
for (auto porous = high; porous < buf.end(); ++porous) {
|
||||||
|
auto chunk = *porous;
|
||||||
|
static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
|
||||||
|
assert(chunk <= (~b58_uint(0) >> CHAR_BIT));
|
||||||
|
if (sizeof(chunk) > 4) {
|
||||||
|
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 6);
|
||||||
|
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 5);
|
||||||
|
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 4);
|
||||||
|
*ptr++ = byte(chunk >> CHAR_BIT * 3);
|
||||||
|
}
|
||||||
|
*ptr++ = byte(chunk >> CHAR_BIT * 2);
|
||||||
|
*ptr++ = byte(chunk >> CHAR_BIT * 1);
|
||||||
|
*ptr++ = byte(chunk >> CHAR_BIT * 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (output < ptr && *output == 0)
|
||||||
|
++output;
|
||||||
|
return slice(output, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *from_base58::write_bytes(char *__restrict const dest,
|
char *from_base58::write_bytes(char *__restrict const dest,
|
||||||
@ -896,98 +949,33 @@ char *from_base58::write_bytes(char *__restrict const dest,
|
|||||||
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
||||||
|
|
||||||
auto ptr = dest;
|
auto ptr = dest;
|
||||||
auto src = source.byte_ptr();
|
auto begin = source.byte_ptr();
|
||||||
for (auto left = source.length(); left > 0;) {
|
auto const end = source.end_byte_ptr();
|
||||||
if (MDBX_UNLIKELY(isspace(*src)) && ignore_spaces) {
|
while (begin < end && *begin <= '1') {
|
||||||
++src;
|
if (MDBX_LIKELY(*begin == '1'))
|
||||||
--left;
|
MDBX_CXX20_LIKELY *ptr++ = 0;
|
||||||
continue;
|
else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(*begin)))
|
||||||
}
|
MDBX_CXX20_UNLIKELY
|
||||||
|
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
||||||
if (MDBX_LIKELY(left > 10)) {
|
++begin;
|
||||||
uint64_t v = 0;
|
|
||||||
if (MDBX_UNLIKELY((b58_11to8(v, src[0]) | b58_11to8(v, src[1]) |
|
|
||||||
b58_11to8(v, src[2]) | b58_11to8(v, src[3]) |
|
|
||||||
b58_11to8(v, src[4]) | b58_11to8(v, src[5]) |
|
|
||||||
b58_11to8(v, src[6]) | b58_11to8(v, src[7]) |
|
|
||||||
b58_11to8(v, src[8]) | b58_11to8(v, src[9]) |
|
|
||||||
b58_11to8(v, src[10])) < 0))
|
|
||||||
MDBX_CXX20_UNLIKELY goto bailout;
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
v = bswap64(v);
|
|
||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
||||||
#else
|
|
||||||
#error "FIXME: Unsupported byte order"
|
|
||||||
#endif /* __BYTE_ORDER__ */
|
|
||||||
std::memcpy(ptr, &v, 8);
|
|
||||||
ptr += 8;
|
|
||||||
src += 11;
|
|
||||||
left -= 11;
|
|
||||||
assert(ptr <= dest + dest_size);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
|
|
||||||
if (MDBX_UNLIKELY(invalid_length_mask & (1 << left)))
|
|
||||||
MDBX_CXX20_UNLIKELY goto bailout;
|
|
||||||
|
|
||||||
uint64_t v = 1;
|
|
||||||
unsigned parrots = 0;
|
|
||||||
do {
|
|
||||||
if (MDBX_UNLIKELY(b58_11to8(v, *src++) < 0))
|
|
||||||
MDBX_CXX20_UNLIKELY goto bailout;
|
|
||||||
parrots += 32;
|
|
||||||
} while (--left);
|
|
||||||
|
|
||||||
auto tail = ptr += parrots / 43;
|
|
||||||
assert(ptr <= dest + dest_size);
|
|
||||||
do {
|
|
||||||
*--tail = byte(v);
|
|
||||||
v >>= 8;
|
|
||||||
} while (v > 255);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return ptr;
|
|
||||||
|
|
||||||
bailout:
|
b58_buffer buf(end - begin, 47, 64);
|
||||||
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
auto slice = b58_decode(buf, begin, end, ignore_spaces);
|
||||||
|
memcpy(ptr, slice.data(), slice.length());
|
||||||
|
return ptr + slice.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool from_base58::is_erroneous() const noexcept {
|
bool from_base58::is_erroneous() const noexcept {
|
||||||
bool got = false;
|
auto begin = source.byte_ptr();
|
||||||
auto src = source.byte_ptr();
|
auto const end = source.end_byte_ptr();
|
||||||
for (auto left = source.length(); left > 0;) {
|
while (begin < end) {
|
||||||
if (MDBX_UNLIKELY(*src <= ' ') &&
|
if (MDBX_UNLIKELY(b58_map[*begin] < 0 &&
|
||||||
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
|
!(ignore_spaces && isspace(*begin))))
|
||||||
++src;
|
return true;
|
||||||
--left;
|
++begin;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MDBX_LIKELY(left > 10)) {
|
|
||||||
if (MDBX_UNLIKELY((b58_map[src[0]] | b58_map[src[1]] | b58_map[src[2]] |
|
|
||||||
b58_map[src[3]] | b58_map[src[4]] | b58_map[src[5]] |
|
|
||||||
b58_map[src[6]] | b58_map[src[7]] | b58_map[src[8]] |
|
|
||||||
b58_map[src[9]] | b58_map[src[10]]) < 0))
|
|
||||||
MDBX_CXX20_UNLIKELY return true;
|
|
||||||
src += 11;
|
|
||||||
left -= 11;
|
|
||||||
got = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
|
|
||||||
if (invalid_length_mask & (1 << left))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
do
|
|
||||||
if (MDBX_UNLIKELY(b58_map[*src++] < 0))
|
|
||||||
MDBX_CXX20_UNLIKELY return true;
|
|
||||||
while (--left);
|
|
||||||
got = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return !got;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -28,9 +28,17 @@
|
|||||||
#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
|
#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
|
||||||
#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
|
#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
|
||||||
|
|
||||||
|
/** Controls using of POSIX' madvise() and/or similar hints. */
|
||||||
|
#ifndef MDBX_ENABLE_MADVISE
|
||||||
|
#define MDBX_ENABLE_MADVISE 1
|
||||||
|
#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
|
||||||
|
#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
|
||||||
|
#endif /* MDBX_ENABLE_MADVISE */
|
||||||
|
|
||||||
/** Controls checking PID against reuse DB environment after the fork() */
|
/** Controls checking PID against reuse DB environment after the fork() */
|
||||||
#ifndef MDBX_ENV_CHECKPID
|
#ifndef MDBX_ENV_CHECKPID
|
||||||
#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
|
#if (defined(MADV_DONTFORK) && MDBX_ENABLE_MADVISE) || defined(_WIN32) || \
|
||||||
|
defined(_WIN64)
|
||||||
/* PID check could be omitted:
|
/* PID check could be omitted:
|
||||||
* - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
|
* - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
|
||||||
* mapped pages will not be available for child process.
|
* mapped pages will not be available for child process.
|
||||||
@ -96,8 +104,7 @@
|
|||||||
/** Controls using Unix' mincore() to determine whether DB-pages
|
/** Controls using Unix' mincore() to determine whether DB-pages
|
||||||
* are resident in memory. */
|
* are resident in memory. */
|
||||||
#ifndef MDBX_ENABLE_MINCORE
|
#ifndef MDBX_ENABLE_MINCORE
|
||||||
#if MDBX_ENABLE_PREFAULT && \
|
#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))
|
||||||
(defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)))
|
|
||||||
#define MDBX_ENABLE_MINCORE 1
|
#define MDBX_ENABLE_MINCORE 1
|
||||||
#else
|
#else
|
||||||
#define MDBX_ENABLE_MINCORE 0
|
#define MDBX_ENABLE_MINCORE 0
|
||||||
@ -118,13 +125,6 @@
|
|||||||
#error MDBX_ENABLE_BIGFOOT must be defined as 0 or 1
|
#error MDBX_ENABLE_BIGFOOT must be defined as 0 or 1
|
||||||
#endif /* MDBX_ENABLE_BIGFOOT */
|
#endif /* MDBX_ENABLE_BIGFOOT */
|
||||||
|
|
||||||
/** Controls using of POSIX' madvise() and/or similar hints. */
|
|
||||||
#ifndef MDBX_ENABLE_MADVISE
|
|
||||||
#define MDBX_ENABLE_MADVISE 1
|
|
||||||
#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
|
|
||||||
#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
|
|
||||||
#endif /* MDBX_ENABLE_MADVISE */
|
|
||||||
|
|
||||||
/** Disable some checks to reduce an overhead and detection probability of
|
/** Disable some checks to reduce an overhead and detection probability of
|
||||||
* database corruption to a values closer to the LMDB. */
|
* database corruption to a values closer to the LMDB. */
|
||||||
#ifndef MDBX_DISABLE_VALIDATION
|
#ifndef MDBX_DISABLE_VALIDATION
|
||||||
|
@ -667,7 +667,10 @@ bool actor_config::deserialize(const char *str, actor_config &config) {
|
|||||||
}
|
}
|
||||||
str = slash + 1;
|
str = slash + 1;
|
||||||
|
|
||||||
uint64_t verify = std::stoull(std::string(str));
|
uint64_t verify = 0;
|
||||||
|
while (*str >= '0' && *str <= '9')
|
||||||
|
verify = verify * 10 + *str++ - '0';
|
||||||
|
|
||||||
if (checksum.value != verify) {
|
if (checksum.value != verify) {
|
||||||
TRACE("<< actor_config::deserialize: checksum mismatch\n");
|
TRACE("<< actor_config::deserialize: checksum mismatch\n");
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user