mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-17 05:22:21 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fff1f67d5 | ||
|
|
b000f8c431 | ||
|
|
3baaf70249 | ||
|
|
4447793652 | ||
|
|
a5c5e77c03 | ||
|
|
40a474e9b3 | ||
|
|
cc56710a1d | ||
|
|
ae981c4f9a | ||
|
|
4f3c8423db | ||
|
|
5cbe91a6ab | ||
|
|
d41ebfa399 | ||
|
|
42561e3b8e | ||
|
|
9803259cab | ||
|
|
e754b442a2 | ||
|
|
6cfb2935f6 | ||
|
|
b16c2570f0 | ||
|
|
ac8402283f | ||
|
|
945899e4fd | ||
|
|
222150bb28 | ||
|
|
497aabcb2e | ||
|
|
cf6d441e1b |
106
ChangeLog.md
106
ChangeLog.md
@@ -4,6 +4,107 @@ ChangeLog
|
||||
English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en)
|
||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||
|
||||
## v0.12.13 от 2025-02-28
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов.
|
||||
|
||||
Это последний/консервирующий выпуск куста стабильных версий 0.12.x, спустя более двух
|
||||
лет после выпуска 0.12.1.
|
||||
|
||||
```
|
||||
git diff' stat: 14 commits, 7 files changed, 256 insertions(+), 103 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Значимые исправления:
|
||||
|
||||
- Исправлена обработка `MDBX_GET_MULTIPLE` в специальных случаях и одного значения у ключа в позиции курсора.
|
||||
|
||||
- Устранена ошибка неверной обработки попытки запуска вложенной читающей транзакции.
|
||||
Теперь в таких ситуациях возвращается ошибка `MDBX_EINVAL`, так как вложенность
|
||||
поддерживается только для транзакций чтения-записи.
|
||||
|
||||
Ошибка была внесена при рефакторинге, коммитом `2f2df1ee76ab137ee66d00af69a82a30dc0d6deb`
|
||||
чуть более 5 лет назад и долго оставалось не замеченной.
|
||||
|
||||
- Поддержка получения boot_id при работе внутри LXC-контейнера.
|
||||
|
||||
Из LXC-контейнера не доступен файл хостовой системы `/proc/sys/kernel/random/boot_id`.
|
||||
Вместо него, при каждом старте контейнера, создается и заполняется
|
||||
случайными данными собственный boot_id смонтированный через bind из `tmpfs`.
|
||||
https://github.com/lxc/lxc/issues/3027
|
||||
|
||||
Ранее этот подставной/замещенный boot_id отбраковывался внутри libmdbx,
|
||||
так как файл располагается в `tmpfs`, а не в файловой системе `/proc`.
|
||||
В результате boot_id для проверки целостности БД не был доступен.
|
||||
Теперь при работе внутри LXC-контейнера такой bootid будет использоваться.
|
||||
|
||||
Однако, полноценно работающий контроль по boot_id не возможен, так как при
|
||||
рестарте LXC-контейнера (но не хоста) boot_id будет меняться, хотя
|
||||
данные в unified page cache сохраняются.
|
||||
|
||||
Таким образом, при рестарте LXC-контейнера без рестарта хоста, libmdbx придется
|
||||
откатить состояние БД до крайней точки устойчивой фиксации, что повлечет
|
||||
утрату данных пользователя в случаях когда они могли быть сохранены.
|
||||
Однако, улучшить ситуацию пока не представляется возможным, как минимум
|
||||
до доступности boot_id хостовой системы изнутри LXC-контейнера.
|
||||
|
||||
- Доработан контроль длины ключа внутри `cursor_set()`.
|
||||
|
||||
Ранее проверка внутри `cursor_set()` не позволяла искать ключи длиннее, чем можно поместить в таблицу.
|
||||
Однако, при поиске/позиционировании это не является ошибкой для таблиц с ключами переменного размера.
|
||||
|
||||
- Теперь при попытке запуска вложенных транзакций в режиме `MDBX_WRITEMAP` производится
|
||||
логирование и возврат ошибки `MDBX_INCOMPATIBLE`.
|
||||
|
||||
- Доработано использование `std::experimental::filesystem` для решения проблем со сборкой в старых компиляторах.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.12 "Доллежаль" от 2024-10-27
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
в память о советском ученом-энергетике Николае Антоновиче Доллежаль в день 125-летия со дня его рождения.
|
||||
|
||||
Это последний выпуск куста стабильных версий 0.12.x, спустя более двух
|
||||
лет после выпуска 0.12.1. Последующие выпуски 0.12.x будут формироваться
|
||||
только в случае существенных проблем/ошибок, вероятность чего близка к
|
||||
нулю. Для всех проектов находящихся в стадии активной разраборки
|
||||
рекомендуется использовать ветку `master`.
|
||||
|
||||
```
|
||||
git diff' stat: 6 commits, 5 files changed, 239 insertions(+), 6 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Значимые исправления:
|
||||
|
||||
- Исправление упущенного `TXN_END_EOTDONE` при сбое старта читающей транзакции.
|
||||
Упомянутый флажок отсутствовал в пути разрушения транзакции при ошибке
|
||||
её запуска. Из-за чего делалась попытка разрушить курсоры, что приводило
|
||||
к падению **отладочных сборок**, так как в них соответствующий массив
|
||||
намеренно заполнен некорректными указателями.
|
||||
|
||||
- Устранение возможности `SIGSEGV` внутри `coherency_check()` после
|
||||
изменения геометрии другим процессом с увеличением верхнего размера БД
|
||||
и увеличением БД больше предыдущего лимита.
|
||||
|
||||
- Доработка `mdbx_close_dbi()` для возврата ошибки при попытке закрыть
|
||||
dbi-дескриптор таблицы, созданной и/или измененной в ещё выполняющейся
|
||||
транзакции. Такое преждевременное закрытие дескриптора является неверным
|
||||
использованием API и нарушением контракта/предусловий сформулированных
|
||||
в описании `mdbx_close_dbi()`. Однако, вместо возврата ошибки
|
||||
выполнялось некорректное закрытие дескриптора, что могло приводить к
|
||||
созданию таблицы с пустым именем, утечки страниц БД и/или нарушению
|
||||
структуры b-tree (неверной ссылкой на корень таблицы).
|
||||
Добавлен соответствующий тест `extra/early_close_dbi`.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.11 "Лиза и Соня" от 2024-07-23
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
@@ -71,6 +172,9 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
- Отключение установки признака фатальной ошибки для не-активной среды при отличии идентификатора процесса.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.10 "СЭМ" от 2024-03-12
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов
|
||||
@@ -1894,7 +1998,7 @@ Deprecated functions and flags:
|
||||
- Rework `MADV_DONTNEED` threshold.
|
||||
- Fix `mdbx_chk` utility for don't checking some numbers if walking on the B-tree was disabled.
|
||||
- Use page's mp_txnid for basic integrity checking.
|
||||
- Add `MDBX_FORCE_ASSERTIONS` built-time option.
|
||||
- Add `MDBX_FORCE_ASSERTIONS` build-time option.
|
||||
- Rework `MDBX_DBG_DUMP` to avoid performance degradation.
|
||||
- Rename `MDBX_NOSYNC` to `MDBX_SAFE_NOSYNC` for clarity.
|
||||
- Interpret `ERROR_ACCESS_DENIED` from `OpenProcess()` as 'process exists'.
|
||||
|
||||
7
mdbx.h
7
mdbx.h
@@ -2162,7 +2162,8 @@ enum MDBX_option_t {
|
||||
* spill to disk instead.
|
||||
*
|
||||
* The `MDBX_opt_txn_dp_limit` controls described threshold for the current
|
||||
* process. Default is 65536, it is usually enough for most cases. */
|
||||
* process. Default is 1/42 of the sum of whole and currently available RAM
|
||||
* size, which the same ones are reported by \ref mdbx_get_sysraminfo(). */
|
||||
MDBX_opt_txn_dp_limit,
|
||||
|
||||
/** \brief Controls the in-process initial allocation size for dirty pages
|
||||
@@ -5038,7 +5039,7 @@ LIBMDBX_API int mdbx_cursor_del(MDBX_cursor *cursor, MDBX_put_flags_t flags);
|
||||
* sorted duplicate data items \ref MDBX_DUPSORT.
|
||||
*
|
||||
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
||||
* \param [out] pcount Address where the count will be stored.
|
||||
* \param [out] count Address where the count will be stored.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
@@ -5046,7 +5047,7 @@ LIBMDBX_API int mdbx_cursor_del(MDBX_cursor *cursor, MDBX_put_flags_t flags);
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL Cursor is not initialized, or an invalid parameter
|
||||
* was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_count(const MDBX_cursor *cursor, size_t *pcount);
|
||||
LIBMDBX_API int mdbx_cursor_count(const MDBX_cursor *cursor, size_t *count);
|
||||
|
||||
/** \brief Determines whether the cursor is pointed to a key-value pair or not,
|
||||
* i.e. was not positioned or points to the end of data.
|
||||
|
||||
43
mdbx.h++
43
mdbx.h++
@@ -78,11 +78,34 @@
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
|
||||
#include <filesystem>
|
||||
#ifndef MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM
|
||||
#ifdef INCLUDE_STD_FILESYSTEM_EXPERIMENTAL
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 1
|
||||
#elif defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
|
||||
__cplusplus >= 201703L
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 0
|
||||
#elif (!defined(_MSC_VER) || __cplusplus >= 201403L || \
|
||||
(defined(_MSC_VER) && \
|
||||
defined(_SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING) && \
|
||||
__cplusplus >= 201403L))
|
||||
#if defined(__cpp_lib_experimental_filesystem) && \
|
||||
__cpp_lib_experimental_filesystem >= 201406L
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 1
|
||||
#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \
|
||||
__has_include(<experimental/filesystem>)
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 1
|
||||
#else
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 0
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM 0
|
||||
#endif
|
||||
#endif /* MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM */
|
||||
|
||||
#if MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM
|
||||
#include <experimental/filesystem>
|
||||
#elif defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
@@ -370,13 +393,21 @@ template <class ALLOCATOR = default_allocator>
|
||||
using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
|
||||
|
||||
using filehandle = ::mdbx_filehandle_t;
|
||||
#if defined(DOXYGEN) || \
|
||||
#if MDBX_USING_CXX_EXPERIMETAL_FILESYSTEM
|
||||
#ifdef _MSC_VER
|
||||
namespace filesystem = ::std::experimental::filesystem::v1;
|
||||
#else
|
||||
namespace filesystem = ::std::experimental::filesystem;
|
||||
#endif
|
||||
#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path
|
||||
#elif defined(DOXYGEN) || \
|
||||
(defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
|
||||
defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \
|
||||
(!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \
|
||||
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \
|
||||
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= 130100))
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= 130100)) && \
|
||||
(!defined(_MSC_VER) || __cplusplus >= 201703L)
|
||||
namespace filesystem = ::std::filesystem;
|
||||
/// \brief Defined if `mdbx::filesystem::path` is available.
|
||||
/// \details If defined, it is always `mdbx::filesystem::path`,
|
||||
@@ -385,10 +416,6 @@ namespace filesystem = ::std::filesystem;
|
||||
/// Nonetheless `MDBX_STD_FILESYSTEM_PATH` not defined if the `::mdbx::path`
|
||||
/// is fallbacked to c `std::string` or `std::wstring`.
|
||||
#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path
|
||||
#elif defined(__cpp_lib_experimental_filesystem) && \
|
||||
__cpp_lib_experimental_filesystem >= 201406L
|
||||
namespace filesystem = ::std::experimental::filesystem;
|
||||
#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
From 22732cf074188912caea6da6795c36098efb7eb5 Mon Sep 17 00:00:00 2001
|
||||
From 40efe497b511c322470aa9c084fe4c1759788c57 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?=
|
||||
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
||||
Date: Mon, 23 Oct 2023 18:07:13 +0300
|
||||
Subject: [PATCH] package/libmdbx: new package (library/database).
|
||||
Date: Sun, 27 Oct 2024 22:34:19 +0300
|
||||
Subject: [PATCH 1/1] package/libmdbx: new package (library/database).
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
@@ -15,8 +15,9 @@ This patch adds libmdbx:
|
||||
in terms of reliability, features and performance.
|
||||
- more information at https://gitflic.ru/project/erthink/libmdbx
|
||||
|
||||
The v0.12.10 "SEM" is stable release of _libmdbx_ branch with new superior features,
|
||||
in memory of the Hero of Russia Guard Major Dmitry Semenov with the call sign "SEM".
|
||||
The 0.12.12 "Dollezhal" is stable release of _libmdbx_ branch in memory
|
||||
of the Soviet energy scientist Nikolai Antonovich Dollezhal on the 125th
|
||||
anniversary of his birth.
|
||||
|
||||
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
||||
|
||||
@@ -111,18 +112,18 @@ index 0000000000..a9a4ac45c5
|
||||
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||
new file mode 100644
|
||||
index 0000000000..1dbdef7c69
|
||||
index 0000000000..222e7caf5c
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.hash
|
||||
@@ -0,0 +1,5 @@
|
||||
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
||||
+sha256 4637e06768a9a8fc7577e6e458e045ad1f9a8baee74996a3c88bc0ad64cbcf67 libmdbx-amalgamated-0.12.10.tar.xz
|
||||
+sha256 19c0eb33e1ed43ca2a94dceb06dd31946432d16f30a9751d3701c67efa22eb1a libmdbx-amalgamated-0.12.12.tar.xz
|
||||
+
|
||||
+# Locally calculated
|
||||
+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE
|
||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||
new file mode 100644
|
||||
index 0000000000..36df45b64f
|
||||
index 0000000000..da4a53913f
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.mk
|
||||
@@ -0,0 +1,42 @@
|
||||
@@ -132,7 +133,7 @@ index 0000000000..36df45b64f
|
||||
+#
|
||||
+################################################################################
|
||||
+
|
||||
+LIBMDBX_VERSION = 0.12.10
|
||||
+LIBMDBX_VERSION = 0.12.12
|
||||
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
||||
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
||||
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
@@ -169,5 +170,5 @@ index 0000000000..36df45b64f
|
||||
+
|
||||
+$(eval $(cmake-package))
|
||||
--
|
||||
2.43.2
|
||||
2.47.0
|
||||
|
||||
|
||||
84
src/core.c
84
src/core.c
@@ -2761,12 +2761,11 @@ static __always_inline size_t dpl_size2bytes(ptrdiff_t size) {
|
||||
|
||||
static __always_inline size_t dpl_bytes2size(const ptrdiff_t bytes) {
|
||||
size_t size = (bytes - sizeof(MDBX_dpl)) / sizeof(MDBX_dp);
|
||||
assert(size > CURSOR_STACK + MDBX_DPL_RESERVE_GAP &&
|
||||
size <= MDBX_PGL_LIMIT + MDBX_PNL_GRANULATE);
|
||||
size -= MDBX_DPL_RESERVE_GAP;
|
||||
#if MDBX_DPL_PREALLOC_FOR_RADIXSORT
|
||||
size >>= 1;
|
||||
#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
|
||||
assert(size > CURSOR_STACK && size <= MDBX_PGL_LIMIT + MDBX_PNL_GRANULATE);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -6941,7 +6940,7 @@ __hot static pgno_t relist_get_single(MDBX_txn *txn) {
|
||||
* диском будет более кучным, а у страниц ближе к концу БД будет больше шансов
|
||||
* попасть под авто-компактификацию. Частично эта тактика уже реализована, но
|
||||
* для её эффективности требуется явно приоритезировать выделение страниц:
|
||||
* - поддерживать для relist, для ближних и для дальних страниц;
|
||||
* - поддерживать два relist, для ближних и для дальних страниц;
|
||||
* - использовать страницы из дальнего списка, если первый пуст,
|
||||
* а второй слишком большой, либо при пустой GC.
|
||||
*
|
||||
@@ -6949,11 +6948,11 @@ __hot static pgno_t relist_get_single(MDBX_txn *txn) {
|
||||
* регионы будут линейными, что принципиально ускоряет запись на HDD.
|
||||
* Одновременно, в среднем это не повлияет на чтение, точнее говоря, если
|
||||
* порядок чтения не совпадает с порядком изменения (иначе говоря, если
|
||||
* чтение не коррклирует с обновлениями и/или вставками) то не повлияет, иначе
|
||||
* чтение не коррелирует с обновлениями и/или вставками) то не повлияет, иначе
|
||||
* может ускорить. Однако, последовательности в среднем достаточно редки.
|
||||
* Поэтому для эффективности требуется аккумулировать и поддерживать в ОЗУ
|
||||
* огромные списки страниц, а затем сохранять их обратно в БД. Текущий формат
|
||||
* БД (без битовых карт) для этого крайне не удачен. Поэтому эта тактика не
|
||||
* БД (без сжатых битовых карт) для этого крайне не удачен. Поэтому эта тактика не
|
||||
* имеет шансов быть успешной без смены формата БД (Mithril).
|
||||
*
|
||||
* 3. Стараться экономить последовательности страниц. Это позволяет избегать
|
||||
@@ -6962,7 +6961,7 @@ __hot static pgno_t relist_get_single(MDBX_txn *txn) {
|
||||
* информации от приложения библиотека не может знать насколько
|
||||
* востребованными будут последовательности в ближайшей перспективе, а
|
||||
* экономия последовательностей "на всякий случай" не только затратна
|
||||
* сама-по-себе, но и работает во вред.
|
||||
* сама-по-себе, но и работает во вред (добавляет хаоса).
|
||||
*
|
||||
* Поэтому:
|
||||
* - в TODO добавляется разделение relist на «ближние» и «дальние» страницы,
|
||||
@@ -8703,7 +8702,9 @@ static bool coherency_check(const MDBX_env *env, const txnid_t txnid,
|
||||
: "(wagering meta)");
|
||||
ok = false;
|
||||
}
|
||||
if (likely(freedb_root && freedb_mod_txnid)) {
|
||||
if (likely(freedb_root && freedb_mod_txnid &&
|
||||
(size_t)ptr_dist(env->me_dxb_mmap.base, freedb_root) <
|
||||
env->me_dxb_mmap.limit)) {
|
||||
VALGRIND_MAKE_MEM_DEFINED(freedb_root, sizeof(freedb_root->mp_txnid));
|
||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(freedb_root,
|
||||
sizeof(freedb_root->mp_txnid));
|
||||
@@ -8719,7 +8720,9 @@ static bool coherency_check(const MDBX_env *env, const txnid_t txnid,
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (likely(maindb_root && maindb_mod_txnid)) {
|
||||
if (likely(maindb_root && maindb_mod_txnid &&
|
||||
(size_t)ptr_dist(env->me_dxb_mmap.base, maindb_root) <
|
||||
env->me_dxb_mmap.limit)) {
|
||||
VALGRIND_MAKE_MEM_DEFINED(maindb_root, sizeof(maindb_root->mp_txnid));
|
||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(maindb_root,
|
||||
sizeof(maindb_root->mp_txnid));
|
||||
@@ -9188,7 +9191,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) {
|
||||
}
|
||||
bailout:
|
||||
tASSERT(txn, rc != MDBX_SUCCESS);
|
||||
txn_end(txn, MDBX_END_SLOT | MDBX_END_FAIL_BEGIN);
|
||||
txn_end(txn, MDBX_END_SLOT | MDBX_END_EOTDONE | MDBX_END_FAIL_BEGIN);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -9281,7 +9284,7 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
|
||||
*ret = NULL;
|
||||
|
||||
if (unlikely((flags & ~MDBX_TXN_RW_BEGIN_FLAGS) &&
|
||||
(flags & ~MDBX_TXN_RO_BEGIN_FLAGS)))
|
||||
(parent || (flags & ~MDBX_TXN_RO_BEGIN_FLAGS))))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
int rc = check_env(env, true);
|
||||
@@ -9299,8 +9302,13 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
|
||||
/* Nested transactions: Max 1 child, write txns only, no writemap */
|
||||
rc = check_txn_rw(parent,
|
||||
MDBX_TXN_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
if (rc == MDBX_BAD_TXN && (parent->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)) == 0) {
|
||||
ERROR("%s mode is incompatible with nested transactions", "MDBX_WRITEMAP");
|
||||
rc = MDBX_INCOMPATIBLE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (env->me_options.spill_parent4child_denominator) {
|
||||
/* Spill dirty-pages of parent to provide dirtyroom for child txn */
|
||||
@@ -10811,10 +10819,10 @@ retry:
|
||||
if (unlikely(ctx->rid <= MIN_TXNID)) {
|
||||
if (unlikely(MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed) <=
|
||||
ctx->reused_slot)) {
|
||||
NOTICE("** restart: reserve depleted (reused_gc_slot %zu >= "
|
||||
"lifo_reclaimed %zu" PRIaTXN,
|
||||
ctx->reused_slot,
|
||||
MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed));
|
||||
VERBOSE("** restart: reserve depleted (reused_gc_slot %zu >= "
|
||||
"lifo_reclaimed %zu" PRIaTXN,
|
||||
ctx->reused_slot,
|
||||
MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed));
|
||||
goto retry;
|
||||
}
|
||||
break;
|
||||
@@ -11049,7 +11057,7 @@ retry:
|
||||
tASSERT(txn, ctx->lifo == 0);
|
||||
fill_gc_id = unaligned_peek_u64(4, key.iov_base);
|
||||
if (ctx->filled_slot-- == 0 || fill_gc_id > txn->tw.last_reclaimed) {
|
||||
NOTICE(
|
||||
VERBOSE(
|
||||
"** restart: reserve depleted (filled_slot %zu, fill_id %" PRIaTXN
|
||||
" > last_reclaimed %" PRIaTXN,
|
||||
ctx->filled_slot, fill_gc_id, txn->tw.last_reclaimed);
|
||||
@@ -11058,9 +11066,9 @@ retry:
|
||||
} else {
|
||||
tASSERT(txn, ctx->lifo != 0);
|
||||
if (++ctx->filled_slot > MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed)) {
|
||||
NOTICE("** restart: reserve depleted (filled_gc_slot %zu > "
|
||||
"lifo_reclaimed %zu" PRIaTXN,
|
||||
ctx->filled_slot, MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed));
|
||||
VERBOSE("** restart: reserve depleted (filled_gc_slot %zu > "
|
||||
"lifo_reclaimed %zu" PRIaTXN,
|
||||
ctx->filled_slot, MDBX_PNL_GETSIZE(txn->tw.lifo_reclaimed));
|
||||
goto retry;
|
||||
}
|
||||
fill_gc_id = txn->tw.lifo_reclaimed[ctx->filled_slot];
|
||||
@@ -16517,7 +16525,8 @@ cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op) {
|
||||
struct cursor_set_result ret;
|
||||
ret.exact = false;
|
||||
if (unlikely(key->iov_len < mc->mc_dbx->md_klen_min ||
|
||||
key->iov_len > mc->mc_dbx->md_klen_max)) {
|
||||
(key->iov_len > mc->mc_dbx->md_klen_max &&
|
||||
(mc->mc_dbx->md_klen_min == mc->mc_dbx->md_klen_max || MDBX_DEBUG || MDBX_FORCE_ASSERTIONS)))) {
|
||||
cASSERT(mc, !"Invalid key-size");
|
||||
ret.err = MDBX_BAD_VALSIZE;
|
||||
return ret;
|
||||
@@ -16983,10 +16992,8 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
}
|
||||
rc = MDBX_SUCCESS;
|
||||
if (unlikely(C_INITIALIZED != (mc->mc_xcursor->mx_cursor.mc_flags &
|
||||
(C_INITIALIZED | C_EOF)))) {
|
||||
rc = MDBX_NOTFOUND;
|
||||
(C_INITIALIZED | C_EOF))))
|
||||
break;
|
||||
}
|
||||
goto fetch_multiple;
|
||||
case MDBX_NEXT_MULTIPLE:
|
||||
if (unlikely(!data))
|
||||
@@ -17002,8 +17009,6 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
page_numkeys(mx->mc_pg[mx->mc_top]) * mx->mc_db->md_xsize;
|
||||
data->iov_base = page_data(mx->mc_pg[mx->mc_top]);
|
||||
mx->mc_ki[mx->mc_top] = (indx_t)page_numkeys(mx->mc_pg[mx->mc_top]) - 1;
|
||||
} else {
|
||||
rc = MDBX_NOTFOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -23125,14 +23130,31 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
if (unlikely(dbi >= env->me_maxdbs))
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(dbi < CORE_DBS || dbi >= env->me_maxdbs))
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
rc = osal_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
rc = (dbi < env->me_maxdbs && (env->me_dbflags[dbi] & DB_VALID))
|
||||
? dbi_close_locked(env, dbi)
|
||||
: MDBX_BAD_DBI;
|
||||
retry:
|
||||
rc = MDBX_BAD_DBI;
|
||||
if (dbi < env->me_maxdbs && (env->me_dbflags[dbi] & DB_VALID)) {
|
||||
const MDBX_txn *const hazard = env->me_txn;
|
||||
osal_compiler_barrier();
|
||||
if (env->me_txn0 && (env->me_txn0->mt_flags & MDBX_TXN_FINISHED) == 0) {
|
||||
if (env->me_txn0->mt_dbistate[dbi] & (DBI_DIRTY | DBI_CREAT))
|
||||
goto bailout_dirty_dbi;
|
||||
osal_memory_barrier();
|
||||
if (unlikely(hazard != env->me_txn))
|
||||
goto retry;
|
||||
if (hazard != env->me_txn0 && hazard &&
|
||||
(hazard->mt_flags & MDBX_TXN_FINISHED) == 0 &&
|
||||
hazard->mt_signature == MDBX_MT_SIGNATURE &&
|
||||
(hazard->mt_dbistate[dbi] & (DBI_DIRTY | DBI_CREAT)))
|
||||
goto bailout_dirty_dbi;
|
||||
osal_compiler_barrier();
|
||||
if (unlikely(hazard != env->me_txn))
|
||||
goto retry;
|
||||
}
|
||||
rc = dbi_close_locked(env, dbi);
|
||||
}
|
||||
bailout_dirty_dbi:
|
||||
ENSURE(env, osal_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
#endif /* MinGW */
|
||||
|
||||
/* Workaround for MSVC' header `extern "C"` vs `std::` redefinition bug */
|
||||
#if defined(_MSC_VER) && defined(__SANITIZE_ADDRESS__) && \
|
||||
!defined(_DISABLE_VECTOR_ANNOTATION)
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(__SANITIZE_ADDRESS__) && !defined(_DISABLE_VECTOR_ANNOTATION)
|
||||
#define _DISABLE_VECTOR_ANNOTATION
|
||||
#endif /* _DISABLE_VECTOR_ANNOTATION */
|
||||
#ifndef _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
|
||||
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
|
||||
#endif /* #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include "../mdbx.h++"
|
||||
|
||||
|
||||
168
src/osal.c
168
src/osal.c
@@ -3011,6 +3011,29 @@ __cold static LSTATUS mdbx_RegGetValue(HKEY hKey, LPCSTR lpSubKey,
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t hamming_weight(size_t v) {
|
||||
const size_t m1 = (size_t)UINT64_C(0x5555555555555555);
|
||||
const size_t m2 = (size_t)UINT64_C(0x3333333333333333);
|
||||
const size_t m4 = (size_t)UINT64_C(0x0f0f0f0f0f0f0f0f);
|
||||
const size_t h01 = (size_t)UINT64_C(0x0101010101010101);
|
||||
v -= (v >> 1) & m1;
|
||||
v = (v & m2) + ((v >> 2) & m2);
|
||||
v = (v + (v >> 4)) & m4;
|
||||
return (v * h01) >> (sizeof(v) * 8 - 8);
|
||||
}
|
||||
|
||||
static inline size_t hw64(uint64_t v) {
|
||||
size_t r = hamming_weight((size_t)v);
|
||||
if (sizeof(v) > sizeof(r))
|
||||
r += hamming_weight((size_t)(v >> sizeof(r) * 4 >> sizeof(r) * 4));
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool check_uuid(bin128_t uuid) {
|
||||
size_t hw = hw64(uuid.x) + hw64(uuid.y) + hw64(uuid.x ^ uuid.y);
|
||||
return (hw >> 6) == 1;
|
||||
}
|
||||
|
||||
__cold MDBX_MAYBE_UNUSED static bool
|
||||
bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
|
||||
if (n > 31) {
|
||||
@@ -3044,7 +3067,7 @@ bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
|
||||
s->y += aligned.y;
|
||||
} else
|
||||
bootid_collect(s, p, n);
|
||||
return true;
|
||||
return check_uuid(*s);
|
||||
}
|
||||
|
||||
if (n)
|
||||
@@ -3052,28 +3075,53 @@ bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
bin128_t bin = {{0, 0}};
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
|
||||
__cold static bool is_inside_lxc(void) {
|
||||
bool inside_lxc = false;
|
||||
FILE *mounted = setmntent("/proc/mounts", "r");
|
||||
if (mounted) {
|
||||
const struct mntent *ent;
|
||||
while (nullptr != (ent = getmntent(mounted))) {
|
||||
if (strcmp(ent->mnt_fsname, "lxcfs") == 0 &&
|
||||
strncmp(ent->mnt_dir, "/proc/", 6) == 0) {
|
||||
inside_lxc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
endmntent(mounted);
|
||||
}
|
||||
return inside_lxc;
|
||||
}
|
||||
|
||||
__cold static bool proc_read_uuid(const char *path, bin128_t *target) {
|
||||
const int fd = open(path, O_RDONLY | O_NOFOLLOW);
|
||||
if (fd != -1) {
|
||||
struct statfs fs;
|
||||
char buf[42];
|
||||
const ssize_t len =
|
||||
(fstatfs(fd, &fs) == 0 &&
|
||||
(fs.f_type == /* procfs */ 0x9FA0 ||
|
||||
(fs.f_type == /* tmpfs */ 0x1021994 && is_inside_lxc())))
|
||||
? read(fd, buf, sizeof(buf))
|
||||
: -1;
|
||||
const int err = close(fd);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
if (len > 0)
|
||||
return bootid_parse_uuid(target, buf, len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* Linux */
|
||||
|
||||
__cold bin128_t osal_bootid(void) {
|
||||
bin128_t uuid = {{0, 0}};
|
||||
bool got_machineid = false, got_boottime = false, got_bootseq = false;
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
{
|
||||
const int fd =
|
||||
open("/proc/sys/kernel/random/boot_id", O_RDONLY | O_NOFOLLOW);
|
||||
if (fd != -1) {
|
||||
struct statfs fs;
|
||||
char buf[42];
|
||||
const ssize_t len =
|
||||
(fstatfs(fd, &fs) == 0 && fs.f_type == /* procfs */ 0x9FA0)
|
||||
? read(fd, buf, sizeof(buf))
|
||||
: -1;
|
||||
const int err = close(fd);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
if (len > 0 && bootid_parse_uuid(&bin, buf, len))
|
||||
return bin;
|
||||
}
|
||||
}
|
||||
if (proc_read_uuid("/proc/sys/kernel/random/boot_id", &uuid))
|
||||
return uuid;
|
||||
#endif /* Linux */
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
@@ -3081,16 +3129,15 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
char buf[42];
|
||||
size_t len = sizeof(buf);
|
||||
if (!sysctlbyname("kern.bootsessionuuid", buf, &len, nullptr, 0) &&
|
||||
bootid_parse_uuid(&bin, buf, len))
|
||||
return bin;
|
||||
bootid_parse_uuid(&uuid, buf, len))
|
||||
return uuid;
|
||||
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
|
||||
__MAC_OS_X_VERSION_MIN_REQUIRED > 1050
|
||||
uuid_t uuid;
|
||||
uuid_t hostuuid;
|
||||
struct timespec wait = {0, 1000000000u / 42};
|
||||
if (!gethostuuid(uuid, &wait) &&
|
||||
bootid_parse_uuid(&bin, uuid, sizeof(uuid)))
|
||||
got_machineid = true;
|
||||
if (!gethostuuid(hostuuid, &wait))
|
||||
got_machineid = bootid_parse_uuid(&uuid, hostuuid, sizeof(hostuuid));
|
||||
#endif /* > 10.5 */
|
||||
|
||||
struct timeval boottime;
|
||||
@@ -3128,7 +3175,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
"MachineGuid", &buf.MachineGuid,
|
||||
&len) == ERROR_SUCCESS &&
|
||||
len < sizeof(buf))
|
||||
got_machineid = bootid_parse_uuid(&bin, &buf.MachineGuid, len);
|
||||
got_machineid = bootid_parse_uuid(&uuid, &buf.MachineGuid, len);
|
||||
|
||||
if (!got_machineid) {
|
||||
/* again, Windows is madness */
|
||||
@@ -3146,7 +3193,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
"DigitalProductId", &buf.DigitalProductId,
|
||||
&len) == ERROR_SUCCESS &&
|
||||
len > 42 && len < sizeof(buf)) {
|
||||
bootid_collect(&bin, &buf.DigitalProductId, len);
|
||||
bootid_collect(&uuid, &buf.DigitalProductId, len);
|
||||
got_machineid = true;
|
||||
}
|
||||
len = sizeof(buf);
|
||||
@@ -3154,7 +3201,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
"DigitalProductId", &buf.DigitalProductId,
|
||||
&len) == ERROR_SUCCESS &&
|
||||
len > 42 && len < sizeof(buf)) {
|
||||
bootid_collect(&bin, &buf.DigitalProductId, len);
|
||||
bootid_collect(&uuid, &buf.DigitalProductId, len);
|
||||
got_machineid = true;
|
||||
}
|
||||
len = sizeof(buf);
|
||||
@@ -3162,7 +3209,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
"DigitalProductId", &buf.DigitalProductId,
|
||||
&len) == ERROR_SUCCESS &&
|
||||
len > 42 && len < sizeof(buf)) {
|
||||
bootid_collect(&bin, &buf.DigitalProductId, len);
|
||||
bootid_collect(&uuid, &buf.DigitalProductId, len);
|
||||
got_machineid = true;
|
||||
}
|
||||
}
|
||||
@@ -3174,7 +3221,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BootId",
|
||||
&buf.BootId, &len) == ERROR_SUCCESS &&
|
||||
len > 1 && len < sizeof(buf)) {
|
||||
bootid_collect(&bin, &buf.BootId, len);
|
||||
bootid_collect(&uuid, &buf.BootId, len);
|
||||
got_bootseq = true;
|
||||
}
|
||||
|
||||
@@ -3182,7 +3229,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BaseTime",
|
||||
&buf.BaseTime, &len) == ERROR_SUCCESS &&
|
||||
len >= sizeof(buf.BaseTime) && buf.BaseTime) {
|
||||
bootid_collect(&bin, &buf.BaseTime, len);
|
||||
bootid_collect(&uuid, &buf.BaseTime, len);
|
||||
got_boottime = true;
|
||||
}
|
||||
|
||||
@@ -3198,7 +3245,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
buf.SysTimeOfDayInfoHacked.BootTime.QuadPart -
|
||||
buf.SysTimeOfDayInfoHacked.BootTimeBias;
|
||||
if (UnbiasedBootTime) {
|
||||
bootid_collect(&bin, &UnbiasedBootTime, sizeof(UnbiasedBootTime));
|
||||
bootid_collect(&uuid, &UnbiasedBootTime, sizeof(UnbiasedBootTime));
|
||||
got_boottime = true;
|
||||
}
|
||||
}
|
||||
@@ -3206,7 +3253,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
if (!got_boottime) {
|
||||
uint64_t boottime = windows_bootime();
|
||||
if (boottime) {
|
||||
bootid_collect(&bin, &boottime, sizeof(boottime));
|
||||
bootid_collect(&uuid, &boottime, sizeof(boottime));
|
||||
got_boottime = true;
|
||||
}
|
||||
}
|
||||
@@ -3223,8 +3270,8 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
(int *)
|
||||
#endif
|
||||
mib,
|
||||
ARRAY_LENGTH(mib), &buf, &len, NULL, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&bin, buf, len);
|
||||
ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&uuid, buf, len);
|
||||
}
|
||||
#endif /* CTL_HW && HW_UUID */
|
||||
|
||||
@@ -3238,8 +3285,8 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
(int *)
|
||||
#endif
|
||||
mib,
|
||||
ARRAY_LENGTH(mib), &buf, &len, NULL, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&bin, buf, len);
|
||||
ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&uuid, buf, len);
|
||||
}
|
||||
#endif /* CTL_KERN && KERN_HOSTUUID */
|
||||
|
||||
@@ -3247,16 +3294,33 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
if (!got_machineid) {
|
||||
char buf[42];
|
||||
size_t len = sizeof(buf);
|
||||
if (sysctlbyname("machdep.dmi.system-uuid", buf, &len, NULL, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&bin, buf, len);
|
||||
if (sysctlbyname("machdep.dmi.system-uuid", buf, &len, nullptr, 0) == 0)
|
||||
got_machineid = bootid_parse_uuid(&uuid, buf, len);
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
if (!got_machineid) {
|
||||
int fd = open("/etc/machine-id", O_RDONLY);
|
||||
if (fd == -1)
|
||||
fd = open("/var/lib/dbus/machine-id", O_RDONLY);
|
||||
if (fd != -1) {
|
||||
char buf[42];
|
||||
const ssize_t len = read(fd, buf, sizeof(buf));
|
||||
const int err = close(fd);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
if (len > 0)
|
||||
got_machineid = bootid_parse_uuid(&uuid, buf, len);
|
||||
}
|
||||
}
|
||||
#endif /* !Windows */
|
||||
|
||||
#if _XOPEN_SOURCE_EXTENDED
|
||||
if (!got_machineid) {
|
||||
const int hostid = gethostid();
|
||||
if (hostid > 0) {
|
||||
bootid_collect(&bin, &hostid, sizeof(hostid));
|
||||
const long hostid = gethostid();
|
||||
if (hostid != 0 && hostid != -1) {
|
||||
bootid_collect(&uuid, &hostid, sizeof(hostid));
|
||||
got_machineid = true;
|
||||
}
|
||||
}
|
||||
@@ -3264,8 +3328,8 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
|
||||
if (!got_machineid) {
|
||||
lack:
|
||||
bin.x = bin.y = 0;
|
||||
return bin;
|
||||
uuid.x = uuid.y = 0;
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -3280,9 +3344,9 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
(int *)
|
||||
#endif
|
||||
mib,
|
||||
ARRAY_LENGTH(mib), &boottime, &len, NULL, 0) == 0 &&
|
||||
ARRAY_LENGTH(mib), &boottime, &len, nullptr, 0) == 0 &&
|
||||
len == sizeof(boottime) && boottime.tv_sec) {
|
||||
bootid_collect(&bin, &boottime, len);
|
||||
bootid_collect(&uuid, &boottime, len);
|
||||
got_boottime = true;
|
||||
}
|
||||
}
|
||||
@@ -3299,11 +3363,11 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
switch (kn->data_type) {
|
||||
case KSTAT_DATA_INT32:
|
||||
case KSTAT_DATA_UINT32:
|
||||
bootid_collect(&bin, &kn->value, sizeof(int32_t));
|
||||
bootid_collect(&uuid, &kn->value, sizeof(int32_t));
|
||||
got_boottime = true;
|
||||
case KSTAT_DATA_INT64:
|
||||
case KSTAT_DATA_UINT64:
|
||||
bootid_collect(&bin, &kn->value, sizeof(int64_t));
|
||||
bootid_collect(&uuid, &kn->value, sizeof(int64_t));
|
||||
got_boottime = true;
|
||||
}
|
||||
}
|
||||
@@ -3319,12 +3383,12 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
const struct utmpx id = {.ut_type = BOOT_TIME};
|
||||
const struct utmpx *entry = getutxid(&id);
|
||||
if (entry) {
|
||||
bootid_collect(&bin, entry, sizeof(*entry));
|
||||
bootid_collect(&uuid, entry, sizeof(*entry));
|
||||
got_boottime = true;
|
||||
while (unlikely((entry = getutxid(&id)) != nullptr)) {
|
||||
/* have multiple reboot records, assuming we can distinguish next
|
||||
* bootsession even if RTC is wrong or absent */
|
||||
bootid_collect(&bin, entry, sizeof(*entry));
|
||||
bootid_collect(&uuid, entry, sizeof(*entry));
|
||||
got_bootseq = true;
|
||||
}
|
||||
}
|
||||
@@ -3353,7 +3417,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t osal_bootid(void) {
|
||||
goto lack;
|
||||
}
|
||||
|
||||
return bin;
|
||||
return uuid;
|
||||
}
|
||||
|
||||
__cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
|
||||
|
||||
@@ -91,6 +91,20 @@ if(UNIX AND NOT SUBPROJECT)
|
||||
set_target_properties(test_extra_dupfixed_multiple PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
add_executable(test_extra_dbi extra/dbi.c++)
|
||||
target_include_directories(test_extra_dbi PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_dbi ${TOOL_MDBX_LIB})
|
||||
if(MDBX_CXX_STANDARD)
|
||||
set_target_properties(test_extra_dbi PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
add_executable(test_extra_early_close_dbi extra/early_close_dbi.c++)
|
||||
target_include_directories(test_extra_early_close_dbi PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_early_close_dbi ${TOOL_MDBX_LIB})
|
||||
if(MDBX_CXX_STANDARD)
|
||||
set_target_properties(test_extra_early_close_dbi PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -176,6 +190,7 @@ else()
|
||||
if(MDBX_BUILD_CXX)
|
||||
add_test(NAME extra_maindb_ordinal COMMAND test_extra_maindb_ordinal)
|
||||
add_test(NAME extra_dupfixed_multiple COMMAND test_extra_dupfixed_multiple)
|
||||
add_test(NAME extra_dbi COMMAND test_extra_dbi)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
38
test/extra/dbi.c++
Normal file
38
test/extra/dbi.c++
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "mdbx.h++"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static void logger(MDBX_log_level_t loglevel, const char *function, int line,
|
||||
const char *fmt, va_list args) noexcept {
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u ", function, line);
|
||||
vfprintf(stdout, fmt, args);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
mdbx_setup_debug(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger);
|
||||
|
||||
mdbx::path path = "test-dbi";
|
||||
mdbx::env::remove(path);
|
||||
|
||||
mdbx::env::operate_parameters operateParameters(100, 10);
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
{
|
||||
mdbx::env_managed env2(path, createParameters, operateParameters);
|
||||
mdbx::txn_managed txn2 = env2.start_write(false);
|
||||
/* mdbx::map_handle testHandle2 = */ txn2.create_map(
|
||||
"fap1", mdbx::key_mode::reverse, mdbx::value_mode::single);
|
||||
txn2.commit();
|
||||
}
|
||||
mdbx::env_managed env(path, createParameters, operateParameters);
|
||||
mdbx::txn_managed txn = env.start_write(false);
|
||||
/* mdbx::map_handle testHandle = */ txn.create_map(
|
||||
"fap1", mdbx::key_mode::usual, mdbx::value_mode::single);
|
||||
txn.commit();
|
||||
|
||||
std::cout << "OK\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
110
test/extra/early_close_dbi.c++
Normal file
110
test/extra/early_close_dbi.c++
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "mdbx.h++"
|
||||
#include <cstring>
|
||||
|
||||
static const char *const testkey = "testkey";
|
||||
static uint64_t testval = 11;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
mdbx::path db_filename = "test-early_close_dbi";
|
||||
mdbx::env_managed::remove(db_filename);
|
||||
|
||||
MDBX_env *environment;
|
||||
MDBX_MAYBE_UNUSED int err = mdbx_env_create(&environment);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
err = mdbx_env_set_option(environment, MDBX_opt_max_db, 2);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_env_set_option(environment, MDBX_opt_max_readers, 2);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
// status = mdbx_env_set_option(environment, MDBX_opt_prefault_write_enable,
|
||||
// 1); assert(err == MDBX_SUCCESS);
|
||||
|
||||
intptr_t lowerbound(0), size(0), upperbound(mdbx::env::geometry::GiB / 2);
|
||||
intptr_t step(128 * mdbx::env::geometry::MiB),
|
||||
shrink(256 * mdbx::env::geometry::MiB), pagesize(-1);
|
||||
err =
|
||||
#ifdef _WIN32
|
||||
mdbx_env_set_geometryW
|
||||
#else
|
||||
mdbx_env_set_geometry
|
||||
#endif
|
||||
(environment, lowerbound, size, upperbound, step, shrink, pagesize);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_env_flags_t flags(MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_LIFORECLAIM |
|
||||
MDBX_NORDAHEAD);
|
||||
err = mdbx_env_open(environment, db_filename.c_str(), flags, 0644);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
MDBX_txn *transaction;
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_READWRITE, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_dbi textindex;
|
||||
err = mdbx_dbi_open(transaction, "testdb", MDBX_DB_DEFAULTS, &textindex);
|
||||
assert(err == MDBX_NOTFOUND);
|
||||
err = mdbx_dbi_open(transaction, "testdb", MDBX_CREATE, &textindex);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_val mdbxkey{(void *)testkey, std::strlen(testkey)}, mdbxval{};
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_NOTFOUND);
|
||||
|
||||
unsigned dbi_flags, dbi_state;
|
||||
err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert((dbi_state & (MDBX_DBI_CREAT | MDBX_DBI_DIRTY)) != 0);
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err != MDBX_SUCCESS);
|
||||
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_READWRITE, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_val mdbxput{&testval, sizeof(uint64_t)};
|
||||
err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE);
|
||||
assert(err == MDBX_KEYEXIST);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert((dbi_state & MDBX_DBI_DIRTY) != 0);
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err != MDBX_SUCCESS);
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_RDONLY, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_env_close_ex(environment, true);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user