Compare commits

...

11 Commits

Author SHA1 Message Date
Леонид Юрьев (Leonid Yuriev)
1fff1f67d5 mdbx: выпуск 0.12.13
Завершающий выпуск архивной ветки с исправлением обнаруженных ошибок и устранением недочетов.

`git diff' stat: 14 commits, 7 files changed, 256 insertions(+), 103 deletions(-)`

Это последний/консервирующий выпуск куста стабильных версий 0.12.x, спустя более двух лет после выпуска 0.12.1.

Значимые исправления:
---------------------

 - Исправлена обработка `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` для решения проблем со сборкой в старых компиляторах.

Более подробная информация и история предыдущих выпусков доступна в [ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html).

Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2025-02-28 23:34:52 +03:00
Леонид Юрьев (Leonid Yuriev)
b000f8c431 mdbx++: доработка использования std::experimental::filesystem. 2025-02-28 23:23:34 +03:00
Леонид Юрьев (Leonid Yuriev)
3baaf70249 mdbx: доработка osal_bootid() для LXC (backport).
Из LXC-контейнера не доступен файл хостовой системы "/proc/sys/kernel/random/boot_id".
Вместо него, при каждом старте контейнера, создается и заполняется
случайными данными собственный boot_id смонтированный через bind из tmpfs.
https://github.com/lxc/lxc/issues/3027

Поэтому полноценный контроль по boot_id не возможен, так как при
рестарте LXC-контейнера (но не хоста) boot_id будет меняться, хотя
данные в unified page cache сохраняются.

Таким образом, при рестарте LXC-контейнера, libmdbx будет производить
откат БД до крайней точки устойчивой фиксации, что может приводить к
утрате данных пользователя в случаях когда они могли быть сохранены.
Однако, улучшить ситуацию пока не представляется возможным, как минимум
до доступности boot_id хостовой системы изнутри LXC-контейнера.

Этот коммит частично улучшает ситуацию тем, что позволяет использовать
фейковый/замещенный boot_id размещенный в файловой системе с типом tmpfs
при работе внутри LXC-контейнера.
2025-02-28 22:38:43 +03:00
Леонид Юрьев (Leonid Yuriev)
4447793652 mdbx: логирование и возврат MDBX_INCOMPATIBLE при попытке запуска вложенных транзакций в режиме MDBX_WRITEMAP (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
a5c5e77c03 mdbx: доработка контроля длины ключа внутри cursor_set() (backport).
Ранее проверка внутри cursor_set() не позволяла искать ключи длиннее чем можно поместить в таблицу,
что при поиске/позиционировании не является ошибкой для ключей переменного размера.
2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
40a474e9b3 mdbx: исправление несогласованности MDBX_DPL_PREALLOC_FOR_RADIXSORT и assert-проверки внутри dpl_bytes2size() (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
cc56710a1d mdbx: понижение уровня логирования "reserve depleted" при обновлении GC (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
ae981c4f9a mdbx-doc: исправление орфографии/опечатки в ChangeLog (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
4f3c8423db mdbx-doc: корректировка описания значения по-умолчанию MDBX_opt_txn_dp_limit (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
5cbe91a6ab mdbx: опечатки в комментариях (backport). 2025-02-28 22:38:40 +03:00
Леонид Юрьев (Leonid Yuriev)
d41ebfa399 mdbx: корректировка doxygen-комментариев (backport). 2025-02-28 22:38:40 +03:00
6 changed files with 243 additions and 84 deletions

View File

@@ -4,6 +4,65 @@ 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
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
@@ -16,7 +75,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic
рекомендуется использовать ветку `master`.
```
git diff' stat: x commits, y files changed, z insertions(+), zz deletions(-)
git diff' stat: 6 commits, 5 files changed, 239 insertions(+), 6 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
```
@@ -43,7 +102,6 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
Добавлен соответствующий тест `extra/early_close_dbi`.
--------------------------------------------------------------------------------
@@ -1940,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
View File

@@ -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.

View File

@@ -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

View File

@@ -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 на «ближние» и «дальние» страницы,
@@ -9303,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 */
@@ -10815,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;
@@ -11053,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);
@@ -11062,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];
@@ -16521,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;

View File

@@ -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++"

View File

@@ -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,