mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b16c2570f0 | ||
|
|
ac8402283f | ||
|
|
945899e4fd | ||
|
|
222150bb28 | ||
|
|
497aabcb2e | ||
|
|
cf6d441e1b | ||
|
|
a6a7a291c7 | ||
|
|
a8ef8d7b72 | ||
|
|
5c40f6983c | ||
|
|
cda8ebe0bd | ||
|
|
f5bbadf3a5 | ||
|
|
58cad2995b | ||
|
|
37217cb199 | ||
|
|
a0b520fa32 | ||
|
|
796b7e4497 | ||
|
|
341a8b8b5c | ||
|
|
ad0b13a544 | ||
|
|
ba42390a56 | ||
|
|
07cfe65ea0 | ||
|
|
75fd4ecf54 | ||
|
|
97b0b0192e | ||
|
|
12e6c631f1 | ||
|
|
458f713c53 | ||
|
|
a5ed725ae3 | ||
|
|
dd9ba2c769 | ||
|
|
d1565fd326 | ||
|
|
e3d4cd5758 | ||
|
|
2d2cec094e | ||
|
|
41ebd6dcf3 | ||
|
|
f40b2fc164 | ||
|
|
8f32f4ac98 | ||
|
|
c1d3afcbe1 | ||
|
|
5721296e16 | ||
|
|
04f1200c3d | ||
|
|
dfcd652e5c | ||
|
|
25089e6491 | ||
|
|
8cc3dba7ae | ||
|
|
4f770999a8 | ||
|
|
93429d3a23 | ||
|
|
3d187abc1b | ||
|
|
4151e0e348 | ||
|
|
c81b007587 | ||
|
|
b415265d16 | ||
|
|
257a534fbe | ||
|
|
33b5aeb768 | ||
|
|
f532e907e9 | ||
|
|
60736dbabb | ||
|
|
24df8073ac | ||
|
|
d504ca1747 | ||
|
|
b7ace5b216 | ||
|
|
2fabac18c0 | ||
|
|
51789f3605 | ||
|
|
6899142872 | ||
|
|
c44c8132e4 | ||
|
|
d376feb7bc | ||
|
|
47851135f3 | ||
|
|
6139443ef1 | ||
|
|
30f292d496 | ||
|
|
d6b47c7bd1 | ||
|
|
8f0c5bc7c7 | ||
|
|
29eab4afdd | ||
|
|
12717aac8c | ||
|
|
e992da9efe | ||
|
|
d7e4cb2e22 | ||
|
|
af1d01ffb3 | ||
|
|
cce052e869 | ||
|
|
094c2f345d | ||
|
|
7b2eee91af | ||
|
|
d863629387 | ||
|
|
1b3b6e4479 | ||
|
|
5dcc0171fa | ||
|
|
425730c2b3 | ||
|
|
471e854551 | ||
|
|
1bd0eb35bc | ||
|
|
6fdae12996 | ||
|
|
2684c89d91 | ||
|
|
7b60363a31 | ||
|
|
290630f118 | ||
|
|
bdcc345455 | ||
|
|
db9e2c6f07 | ||
|
|
50e9e0e561 | ||
|
|
8505203080 | ||
|
|
50ba4bc2f2 | ||
|
|
cf6576984d | ||
|
|
4f3e1a60f1 | ||
|
|
04f60af669 | ||
|
|
c6cd642ff1 |
119
ChangeLog.md
119
ChangeLog.md
@@ -4,6 +4,119 @@ 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.12 "Доллежаль" от 2024-10-27
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
в память о советском ученом-энергетике Николае Антоновиче Доллежаль в день 125-летия со дня его рождения.
|
||||
|
||||
Это последний выпуск куста стабильных версий 0.12.x, спустя более двух
|
||||
лет после выпуска 0.12.1. Последующие выпуски 0.12.x будут формироваться
|
||||
только в случае существенных проблем/ошибок, вероятность чего близка к
|
||||
нулю. Для всех проектов находящихся в стадии активной разраборки
|
||||
рекомендуется использовать ветку `master`.
|
||||
|
||||
```
|
||||
git diff' stat: x commits, y files changed, z insertions(+), zz 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
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
в память об убитых в Крыму девочках 2 и 9 лет.
|
||||
|
||||
Лиза и Соня погибли 23 Июня 2024 на глазах у родителей, в результате
|
||||
удара по общественному городскому пляжу ракетами ATACMS с кассетными
|
||||
боеприпасами. Всего пострадало более 150 граждан России, в том числе 27
|
||||
детей. Ракеты были выпущенными украинскими бандеровцами/фашистами, но
|
||||
полетные задания формировались и загружались военными США, а управление
|
||||
и наведение ATACAMS невозможно без использования орбитальной группировки
|
||||
военных спутников США.
|
||||
|
||||
|
||||
```
|
||||
git diff' stat: 29 commits, 14 files changed, 379 insertions(+), 151 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Значимые исправления:
|
||||
|
||||
- Исправление для ОС Windows нарезки `FILE_SEGMENT_ELEMENT`.
|
||||
Похоже что был потерян коммит входе работы над оптимизацией пути записи
|
||||
на диск в ОС Windows. В текущем понимании, вероятность проявления ошибки
|
||||
достаточно низкая, так как выявлена она была синтетическими тестами в
|
||||
ходе других доработок, а соответствующих сообщений/жалоб не поступало. К
|
||||
повреждению БД ошибка не приводила, так как сбой происходил до записи
|
||||
данных с возвратом `ERROR_INVALID_PARAMETER` из системного вызова, т.е.
|
||||
либо ошибка не проявлялась, либо транзакция не фиксировалась.
|
||||
|
||||
- Устранение вероятности `SIGSEGV` при включении логирования
|
||||
уровня `MDBX_LOG_TRACE` в отладочных сборках.
|
||||
|
||||
- Исправление генерации исключения `key_exists` в C++ API.
|
||||
|
||||
- Исправление опечаток в документации и README.
|
||||
|
||||
- Исправление обработки курсоров, открытых в родительских транзакциях и
|
||||
закрытых до завершения вложенных транзакций. В описанной ситуации
|
||||
закрытые курсоры "воскрешались", что приводило к утечке памяти
|
||||
выделенной под такие курсоры.
|
||||
|
||||
- Костыль для MSVC ARM/ARM64 для предотвращения ICE (Internal Compiler Error).
|
||||
|
||||
- Устранение `MDBX_EINVAL` для случая вызова `mdbx_env_remove(".")`.
|
||||
|
||||
- Исправление инверсии bool-результата `env::remove()` в C++ API.
|
||||
|
||||
- Исправление опечатки `равно`/`неравно` в условии внутри
|
||||
`update_gc()`. Существенных последствий ошибки не было, но в
|
||||
определенных сценариях, сходимость требовала еще одного цикла повтора
|
||||
внутри update_gc().
|
||||
|
||||
Прочие доработки:
|
||||
|
||||
- Проверка совместимости флагов GC/FreeDB на случай их изменения в будущих версиях.
|
||||
- Очистка сообщений `FormatMessageA()` от концевых переводов строк.
|
||||
- Уточнение макроса `__always_inline` для особо яблочных версий CLANG.
|
||||
- Использование `\n` вместо `std::endl` в C++ API для разделения строк в кодировщиках данных.
|
||||
- Проверка дополнительных и пока не используемых полей в meta-страницах.
|
||||
- Отключение ненужной отладки внутри `txn_merge()`.
|
||||
- Исправление условий и привязки к версиям компиляторов при формировании макроса `MDBX_DEPRECATED`.
|
||||
- Больше атрибутов `__cold` для редко-используемых функций (backport).
|
||||
- Добавление методов `buffer::append_bytes()` и `buffer::clear_and_reserve()`.
|
||||
- Отключение установки признака фатальной ошибки для не-активной среды при отличии идентификатора процесса.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.10 "СЭМ" от 2024-03-12
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов
|
||||
@@ -35,7 +148,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
вероятность проявления близка к нулю, а сценарий такого проявления найти не удалось.
|
||||
|
||||
В MDBX ошибка присутствовала с момента отделения проекта от LMDB,
|
||||
где эта ошибка присутствует более 11 лети, по настоящее время.
|
||||
где эта ошибка присутствует более 11 лет, по настоящее время.
|
||||
|
||||
- Исправление ложной ошибки `MDBX_CORRUPTED (-30796)` в сценарии работы
|
||||
в режиме `MDBX_DUPFIXED` и нечетной длиной мульти-значений.
|
||||
@@ -46,7 +159,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
- Доработка `rebalance()` ради уменьшения WAF. Новый функционал, включая
|
||||
контролируемую пользователем опцию `enum MDBX_option_t`, будет доступен
|
||||
в выпусках ветки `0.13.x`, а в этом выпуске доработка сводится к тактике
|
||||
не-вовленичения чистой страницы при нехватке запаса страниц в ходе обновления GC,
|
||||
не-вовлечения чистой страницы при нехватке запаса страниц в ходе обновления GC,
|
||||
за счет ухудшения баланса дерева страниц.
|
||||
|
||||
- Устранение упущения приводящего к нелогичной ситуации
|
||||
@@ -169,7 +282,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
|
||||
- Устранение регресса/ошибки в пути обработки `put(MDBX_MULTIPLE)` при пакетном/оптовом
|
||||
помещении в БД множественных значений одного ключа (aka multi-value или dupsort).
|
||||
Проявление проблемы зависит от компилятора и опций оптимизации/кодогенерации, но с большой вероятностью возвращется
|
||||
Проявление проблемы зависит от компилятора и опций оптимизации/кодогенерации, но с большой вероятностью возвращается
|
||||
ошибка `MDBX_BAD_VALSIZE` (`-30781`), а в отладочных сборках срабатывает проверка `cASSERT(mc, !"Invalid key-size")`.
|
||||
Сценарии приводящие к другим проявлениям на данный момент не известны.
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -2,15 +2,14 @@
|
||||
|
||||
### Время учить Русский
|
||||
|
||||
Начиная с 2021 года наблюдается устойчивые тенденции к распространению
|
||||
недостоверной информации о _libmdbx_ в странах ~~НАТО~~,
|
||||
политизированной критика, а также отказу от использования библиотеки в
|
||||
пользу LMDB, несмотря на явные проблемы с одной стороны и преимущества с
|
||||
другой. Поэтому начиная с 17 марта 2024 года прекращается
|
||||
документирование и сопровождение проекта на английском языке. Новый
|
||||
функционал будет документироваться только на русском языке, однако,
|
||||
целенаправленного переписывания/перевода документации пока не
|
||||
планируется.
|
||||
Начиная с 2021 года наблюдаются устойчивые тенденции к распространению
|
||||
недостоверной информации о _libmdbx_ в странах НАТО, политизированной
|
||||
критики, а также отказу от использования библиотеки в пользу LMDB,
|
||||
несмотря на явные проблемы с одной стороны и преимущества с другой.
|
||||
Поэтому, начиная с 17 марта 2024 года, прекращается документирование и
|
||||
сопровождение проекта на английском языке. Новая функциональность будет
|
||||
документироваться только на русском языке, однако, целенаправленного
|
||||
переписывания/перевода документации пока не планируется.
|
||||
|
||||
### The origin has been migrated to [GitFlic](https://gitflic.ru/project/erthink/libmdbx)
|
||||
Since on 2022-04-15 the Github administration, without any warning
|
||||
|
||||
13
mdbx.h
13
mdbx.h
@@ -343,13 +343,14 @@ typedef mode_t mdbx_mode_t;
|
||||
#ifdef __deprecated
|
||||
#define MDBX_DEPRECATED __deprecated
|
||||
#elif defined(DOXYGEN) || \
|
||||
(defined(__cplusplus) && __cplusplus >= 201603L && \
|
||||
__has_cpp_attribute(maybe_unused) && \
|
||||
__has_cpp_attribute(maybe_unused) >= 201603L) || \
|
||||
(defined(__cplusplus) && __cplusplus >= 201403L && \
|
||||
__has_cpp_attribute(deprecated) && \
|
||||
__has_cpp_attribute(deprecated) >= 201309L) || \
|
||||
(!defined(__cplusplus) && defined(__STDC_VERSION__) && \
|
||||
__STDC_VERSION__ > 202005L)
|
||||
__STDC_VERSION__ >= 202304L)
|
||||
#define MDBX_DEPRECATED [[deprecated]]
|
||||
#elif defined(__GNUC__) || __has_attribute(__deprecated__)
|
||||
#elif (defined(__GNUC__) && __GNUC__ > 5) || \
|
||||
(__has_attribute(__deprecated__) && !defined(__GNUC__))
|
||||
#define MDBX_DEPRECATED __attribute__((__deprecated__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define MDBX_DEPRECATED __declspec(deprecated)
|
||||
@@ -2389,7 +2390,7 @@ enum MDBX_env_delete_mode_t {
|
||||
/** \brief Just delete the environment's files and directory if any.
|
||||
* \note On POSIX systems, processes already working with the database will
|
||||
* continue to work without interference until it close the environment.
|
||||
* \note On Windows, the behavior of `MDB_ENV_JUST_DELETE` is different
|
||||
* \note On Windows, the behavior of `MDBX_ENV_JUST_DELETE` is different
|
||||
* because the system does not support deleting files that are currently
|
||||
* memory mapped. */
|
||||
MDBX_ENV_JUST_DELETE = 0,
|
||||
|
||||
117
mdbx.h++
117
mdbx.h++
@@ -1825,7 +1825,6 @@ private:
|
||||
const size_t old_capacity = bin_.capacity();
|
||||
const size_t new_capacity =
|
||||
bin::advise_capacity(old_capacity, wanna_capacity);
|
||||
assert(new_capacity >= wanna_capacity);
|
||||
if (MDBX_LIKELY(new_capacity == old_capacity))
|
||||
MDBX_CXX20_LIKELY {
|
||||
assert(bin_.is_inplace() ==
|
||||
@@ -1991,7 +1990,13 @@ private:
|
||||
return *this;
|
||||
}
|
||||
|
||||
MDBX_CXX20_CONSTEXPR void clear() { reshape<true>(0, 0, nullptr, 0); }
|
||||
MDBX_CXX20_CONSTEXPR void *clear() {
|
||||
return reshape<true>(0, 0, nullptr, 0);
|
||||
}
|
||||
MDBX_CXX20_CONSTEXPR void *clear_and_reserve(size_t whole_capacity,
|
||||
size_t headroom) {
|
||||
return reshape<false>(whole_capacity, headroom, nullptr, 0);
|
||||
}
|
||||
MDBX_CXX20_CONSTEXPR void resize(size_t capacity, size_t headroom,
|
||||
slice &content) {
|
||||
content.iov_base =
|
||||
@@ -2250,14 +2255,16 @@ public:
|
||||
|
||||
buffer(const char *c_str, bool make_reference,
|
||||
const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(c_str), make_reference, allocator) {}
|
||||
: buffer(::mdbx::slice(c_str), make_reference, allocator){}
|
||||
|
||||
#if defined(DOXYGEN) || \
|
||||
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
|
||||
template <class CHAR, class T>
|
||||
buffer(const ::std::basic_string_view<CHAR, T> &view, bool make_reference,
|
||||
const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(view), make_reference, allocator) {}
|
||||
template <class CHAR, class T>
|
||||
buffer(const ::std::basic_string_view<CHAR, T> &view,
|
||||
bool make_reference,
|
||||
const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(view), make_reference, allocator) {
|
||||
}
|
||||
#endif /* __cpp_lib_string_view >= 201606L */
|
||||
|
||||
MDBX_CXX20_CONSTEXPR
|
||||
@@ -2283,15 +2290,16 @@ public:
|
||||
|
||||
MDBX_CXX20_CONSTEXPR
|
||||
buffer(const char *c_str, const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(c_str), allocator) {}
|
||||
: buffer(::mdbx::slice(c_str), allocator){}
|
||||
|
||||
#if defined(DOXYGEN) || \
|
||||
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
|
||||
template <class CHAR, class T>
|
||||
MDBX_CXX20_CONSTEXPR
|
||||
buffer(const ::std::basic_string_view<CHAR, T> &view,
|
||||
const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(view), allocator) {}
|
||||
template <class CHAR, class T>
|
||||
MDBX_CXX20_CONSTEXPR
|
||||
buffer(const ::std::basic_string_view<CHAR, T> &view,
|
||||
const allocator_type &allocator = allocator_type())
|
||||
: buffer(::mdbx::slice(view), allocator) {
|
||||
}
|
||||
#endif /* __cpp_lib_string_view >= 201606L */
|
||||
|
||||
buffer(size_t head_room, size_t tail_room,
|
||||
@@ -2652,9 +2660,11 @@ public:
|
||||
}
|
||||
|
||||
/// \brief Clears the contents and storage.
|
||||
void clear() noexcept {
|
||||
slice_.clear();
|
||||
silo_.clear();
|
||||
void clear() noexcept { slice_.assign(silo_.clear(), size_t(0)); }
|
||||
|
||||
/// \brief Clears the contents and reserve storage.
|
||||
void clear_and_reserve(size_t whole_capacity, size_t headroom = 0) noexcept {
|
||||
slice_.assign(silo_.clear_and_reserve(whole_capacity, headroom), size_t(0));
|
||||
}
|
||||
|
||||
/// \brief Reduces memory usage by freeing unused storage space.
|
||||
@@ -2742,7 +2752,7 @@ public:
|
||||
buffer &append(const void *src, size_t bytes) {
|
||||
if (MDBX_UNLIKELY(tailroom() < check_length(bytes)))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(bytes);
|
||||
memcpy(slice_.byte_ptr() + size(), src, bytes);
|
||||
memcpy(end_byte_ptr(), src, bytes);
|
||||
slice_.iov_len += bytes;
|
||||
return *this;
|
||||
}
|
||||
@@ -2808,6 +2818,79 @@ public:
|
||||
return append_producer(from_base64(data, ignore_spaces));
|
||||
}
|
||||
|
||||
buffer &append_u8(uint_fast8_t u8) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 1))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(1);
|
||||
*slice_.end_byte_ptr() = uint8_t(u8);
|
||||
slice_.iov_len += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer &append_byte(uint_fast8_t byte) { return append_u8(byte); }
|
||||
|
||||
buffer &append_u16(uint_fast16_t u16) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 2))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(2);
|
||||
const auto ptr = slice_.end_byte_ptr();
|
||||
ptr[0] = uint8_t(u16);
|
||||
ptr[1] = uint8_t(u16 >> 8);
|
||||
slice_.iov_len += 2;
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer &append_u24(uint_fast32_t u24) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 3))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(3);
|
||||
const auto ptr = slice_.end_byte_ptr();
|
||||
ptr[0] = uint8_t(u24);
|
||||
ptr[1] = uint8_t(u24 >> 8);
|
||||
ptr[2] = uint8_t(u24 >> 16);
|
||||
slice_.iov_len += 3;
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer &append_u32(uint_fast32_t u32) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 4))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(4);
|
||||
const auto ptr = slice_.end_byte_ptr();
|
||||
ptr[0] = uint8_t(u32);
|
||||
ptr[1] = uint8_t(u32 >> 8);
|
||||
ptr[2] = uint8_t(u32 >> 16);
|
||||
ptr[3] = uint8_t(u32 >> 24);
|
||||
slice_.iov_len += 4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer &append_u48(uint_fast64_t u48) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 6))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(6);
|
||||
const auto ptr = slice_.end_byte_ptr();
|
||||
ptr[0] = uint8_t(u48);
|
||||
ptr[1] = uint8_t(u48 >> 8);
|
||||
ptr[2] = uint8_t(u48 >> 16);
|
||||
ptr[3] = uint8_t(u48 >> 24);
|
||||
ptr[4] = uint8_t(u48 >> 32);
|
||||
ptr[5] = uint8_t(u48 >> 40);
|
||||
slice_.iov_len += 6;
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer &append_u64(uint_fast64_t u64) {
|
||||
if (MDBX_UNLIKELY(tailroom() < 8))
|
||||
MDBX_CXX20_UNLIKELY reserve_tailroom(8);
|
||||
const auto ptr = slice_.end_byte_ptr();
|
||||
ptr[0] = uint8_t(u64);
|
||||
ptr[1] = uint8_t(u64 >> 8);
|
||||
ptr[2] = uint8_t(u64 >> 16);
|
||||
ptr[3] = uint8_t(u64 >> 24);
|
||||
ptr[4] = uint8_t(u64 >> 32);
|
||||
ptr[5] = uint8_t(u64 >> 40);
|
||||
ptr[6] = uint8_t(u64 >> 48);
|
||||
ptr[7] = uint8_t(u64 >> 56);
|
||||
slice_.iov_len += 8;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
template <size_t SIZE>
|
||||
|
||||
@@ -88,6 +88,10 @@
|
||||
#define __has_extension(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) (0)
|
||||
#endif
|
||||
|
||||
#if __has_feature(thread_sanitizer)
|
||||
#define __SANITIZE_THREAD__ 1
|
||||
#endif
|
||||
@@ -501,7 +505,7 @@ __extern_C key_t ftok(const char *, int);
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-offsetof(type, member)))
|
||||
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||
#endif /* container_of */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@@ -512,7 +516,7 @@ __extern_C key_t ftok(const char *, int);
|
||||
#elif defined(_MSC_VER)
|
||||
#define __always_inline __forceinline
|
||||
#else
|
||||
#define __always_inline
|
||||
#define __always_inline __inline
|
||||
#endif
|
||||
#endif /* __always_inline */
|
||||
|
||||
|
||||
150
src/core.c
150
src/core.c
@@ -428,7 +428,7 @@ node_largedata_pgno(const MDBX_node *const __restrict node) {
|
||||
* max(DATALEN_NO_OVERFLOW, sizeof(MDBX_db));
|
||||
*/
|
||||
|
||||
#define PAGEROOM(pagesize) ((pagesize)-PAGEHDRSZ)
|
||||
#define PAGEROOM(pagesize) ((pagesize) - PAGEHDRSZ)
|
||||
#define EVEN_FLOOR(n) ((n) & ~(size_t)1)
|
||||
#define BRANCH_NODE_MAX(pagesize) \
|
||||
(EVEN_FLOOR((PAGEROOM(pagesize) - sizeof(indx_t) - NODESIZE) / (3 - 1) - \
|
||||
@@ -3187,9 +3187,9 @@ static __always_inline int __must_check_result dpl_append(MDBX_txn *txn,
|
||||
STATIC_ASSERT(sizeof(MDBX_dp) == sizeof(__uint128_t));
|
||||
((__uint128_t *)i)[1] = *(volatile __uint128_t *)i;
|
||||
#else
|
||||
i[1].ptr = i->ptr;
|
||||
i[1].pgno = i->pgno;
|
||||
i[1].npages = i->npages;
|
||||
i[1].ptr = i->ptr;
|
||||
i[1].pgno = i->pgno;
|
||||
i[1].npages = i->npages;
|
||||
#endif
|
||||
--i;
|
||||
}
|
||||
@@ -3485,10 +3485,13 @@ __cold const char *mdbx_strerror_r(int errnum, char *buf, size_t buflen) {
|
||||
const char *msg = mdbx_liberr2str(errnum);
|
||||
if (!msg && buflen > 0 && buflen < INT_MAX) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const DWORD size = FormatMessageA(
|
||||
DWORD size = FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
|
||||
NULL);
|
||||
while (size && buf[size - 1] <= ' ')
|
||||
--size;
|
||||
buf[size] = 0;
|
||||
return size ? buf : "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
|
||||
#elif defined(_GNU_SOURCE) && defined(__GLIBC__)
|
||||
/* GNU-specific */
|
||||
@@ -3539,10 +3542,13 @@ __cold const char *mdbx_strerror(int errnum) {
|
||||
const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf, size_t buflen) {
|
||||
const char *msg = mdbx_liberr2str(errnum);
|
||||
if (!msg && buflen > 0 && buflen < INT_MAX) {
|
||||
const DWORD size = FormatMessageA(
|
||||
DWORD size = FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
|
||||
NULL);
|
||||
while (size && buf[size - 1] <= ' ')
|
||||
--size;
|
||||
buf[size] = 0;
|
||||
if (!size)
|
||||
msg = "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
|
||||
else if (!CharToOemBuffA(buf, buf, size))
|
||||
@@ -3606,19 +3612,26 @@ __cold void debug_log(int level, const char *function, int line,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Dump a key in ascii or hexadecimal. */
|
||||
const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
||||
/* Dump a val in ascii or hexadecimal. */
|
||||
const char *mdbx_dump_val(const MDBX_val *val, char *const buf,
|
||||
const size_t bufsize) {
|
||||
if (!key)
|
||||
if (!val)
|
||||
return "<null>";
|
||||
if (!key->iov_len)
|
||||
if (!val->iov_len)
|
||||
return "<empty>";
|
||||
if (!buf || bufsize < 4)
|
||||
return nullptr;
|
||||
|
||||
if (!val->iov_base) {
|
||||
int len = snprintf(buf, bufsize, "<nullptr.%zu>", val->iov_len);
|
||||
assert(len > 0 && (size_t)len < bufsize);
|
||||
(void)len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool is_ascii = true;
|
||||
const uint8_t *const data = key->iov_base;
|
||||
for (size_t i = 0; i < key->iov_len; i++)
|
||||
const uint8_t *const data = val->iov_base;
|
||||
for (size_t i = 0; i < val->iov_len; i++)
|
||||
if (data[i] < ' ' || data[i] > '~') {
|
||||
is_ascii = false;
|
||||
break;
|
||||
@@ -3627,14 +3640,14 @@ const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
||||
if (is_ascii) {
|
||||
int len =
|
||||
snprintf(buf, bufsize, "%.*s",
|
||||
(key->iov_len > INT_MAX) ? INT_MAX : (int)key->iov_len, data);
|
||||
(val->iov_len > INT_MAX) ? INT_MAX : (int)val->iov_len, data);
|
||||
assert(len > 0 && (size_t)len < bufsize);
|
||||
(void)len;
|
||||
} else {
|
||||
char *const detent = buf + bufsize - 2;
|
||||
char *ptr = buf;
|
||||
*ptr++ = '<';
|
||||
for (size_t i = 0; i < key->iov_len && ptr < detent; i++) {
|
||||
for (size_t i = 0; i < val->iov_len && ptr < detent; i++) {
|
||||
const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
*ptr++ = hex[data[i] >> 4];
|
||||
@@ -3774,7 +3787,9 @@ MDBX_MAYBE_UNUSED static bool cursor_is_tracked(const MDBX_cursor *mc) {
|
||||
} \
|
||||
tracked->mc_next = *tracking_head; \
|
||||
*tracking_head = tracked; \
|
||||
{ act; } \
|
||||
{ \
|
||||
act; \
|
||||
} \
|
||||
*tracking_head = tracked->mc_next; \
|
||||
} while (0)
|
||||
|
||||
@@ -8274,7 +8289,7 @@ static __inline int check_env(const MDBX_env *env, const bool wanna_active) {
|
||||
|
||||
if (wanna_active) {
|
||||
#if MDBX_ENV_CHECKPID
|
||||
if (unlikely(env->me_pid != osal_getpid())) {
|
||||
if (unlikely(env->me_pid != osal_getpid()) && env->me_pid) {
|
||||
((MDBX_env *)env)->me_flags |= MDBX_FATAL_ERROR;
|
||||
return MDBX_PANIC;
|
||||
}
|
||||
@@ -8327,7 +8342,8 @@ static int cursor_shadow(MDBX_txn *parent, MDBX_txn *nested) {
|
||||
MDBX_xcursor *mx = mc->mc_xcursor;
|
||||
if (mx != NULL) {
|
||||
*(MDBX_xcursor *)(bk + 1) = *mx;
|
||||
mx->mx_cursor.mc_txn = nested;
|
||||
mx->mx_cursor.mc_txn = mc->mc_txn;
|
||||
mx->mx_cursor.mc_dbistate = mc->mc_dbistate;
|
||||
}
|
||||
mc->mc_next = nested->mt_cursors[i];
|
||||
nested->mt_cursors[i] = mc;
|
||||
@@ -8364,9 +8380,7 @@ static void cursors_eot(MDBX_txn *txn, const bool merge) {
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(6001);
|
||||
ENSURE(txn->mt_env, bk->mc_signature == MDBX_MC_LIVE);
|
||||
tASSERT(txn, mx == bk->mc_xcursor);
|
||||
if (stage == MDBX_MC_WAIT4EOT /* Cursor was closed by user */)
|
||||
mc->mc_signature = stage /* Promote closed state to parent txn */;
|
||||
else if (merge) {
|
||||
if (merge) {
|
||||
/* Restore pointers to parent txn */
|
||||
mc->mc_next = bk->mc_next;
|
||||
mc->mc_backup = bk->mc_backup;
|
||||
@@ -8374,11 +8388,8 @@ static void cursors_eot(MDBX_txn *txn, const bool merge) {
|
||||
mc->mc_db = bk->mc_db;
|
||||
mc->mc_dbistate = bk->mc_dbistate;
|
||||
if (mx) {
|
||||
if (mx != bk->mc_xcursor) {
|
||||
*bk->mc_xcursor = *mx;
|
||||
mx = bk->mc_xcursor;
|
||||
}
|
||||
mx->mx_cursor.mc_txn = bk->mc_txn;
|
||||
mx->mx_cursor.mc_txn = mc->mc_txn;
|
||||
mx->mx_cursor.mc_dbistate = mc->mc_dbistate;
|
||||
}
|
||||
} else {
|
||||
/* Restore from backup, i.e. rollback/abort nested txn */
|
||||
@@ -8388,6 +8399,8 @@ static void cursors_eot(MDBX_txn *txn, const bool merge) {
|
||||
}
|
||||
bk->mc_signature = 0;
|
||||
osal_free(bk);
|
||||
if (stage == MDBX_MC_WAIT4EOT /* Cursor was closed by user */)
|
||||
mc->mc_signature = stage /* Promote closed state to parent txn */;
|
||||
} else {
|
||||
ENSURE(txn->mt_env, stage == MDBX_MC_LIVE);
|
||||
mc->mc_signature = MDBX_MC_READY4CLOSE /* Cursor may be reused */;
|
||||
@@ -8690,7 +8703,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));
|
||||
@@ -8706,7 +8721,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));
|
||||
@@ -9153,9 +9170,10 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) {
|
||||
}
|
||||
#endif /* Windows */
|
||||
} else {
|
||||
if (unlikely(txn->mt_dbs[FREE_DBI].md_flags != MDBX_INTEGERKEY)) {
|
||||
ERROR("unexpected/invalid db-flags 0x%u for GC/FreeDB",
|
||||
txn->mt_dbs[FREE_DBI].md_flags);
|
||||
if (unlikely((txn->mt_dbs[FREE_DBI].md_flags & DB_PERSISTENT_FLAGS) !=
|
||||
MDBX_INTEGERKEY)) {
|
||||
ERROR("unexpected/invalid db-flags 0x%x for %s",
|
||||
txn->mt_dbs[FREE_DBI].md_flags, "GC/FreeDB");
|
||||
rc = MDBX_INCOMPATIBLE;
|
||||
goto bailout;
|
||||
}
|
||||
@@ -9174,7 +9192,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;
|
||||
}
|
||||
|
||||
@@ -11473,7 +11491,7 @@ static __inline void txn_merge(MDBX_txn *const parent, MDBX_txn *const txn,
|
||||
}
|
||||
++w;
|
||||
}
|
||||
NOTICE("squash to begin for extending-merge %zu -> %zu", d, w - 1);
|
||||
VERBOSE("squash to begin for extending-merge %zu -> %zu", d, w - 1);
|
||||
d = w - 1;
|
||||
continue;
|
||||
}
|
||||
@@ -11515,7 +11533,7 @@ static __inline void txn_merge(MDBX_txn *const parent, MDBX_txn *const txn,
|
||||
}
|
||||
--w;
|
||||
}
|
||||
NOTICE("squash to end for shrinking-merge %zu -> %zu", d, w + 1);
|
||||
VERBOSE("squash to end for shrinking-merge %zu -> %zu", d, w + 1);
|
||||
d = w + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -12232,6 +12250,22 @@ static int validate_meta(MDBX_env *env, MDBX_meta *const meta,
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(meta->mm_extra_flags != 0)) {
|
||||
WARNING("meta[%u] has unsupported %s 0x%x, skip it", meta_number,
|
||||
"extra-flags", meta->mm_extra_flags);
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
if (unlikely(meta->mm_validator_id != 0)) {
|
||||
WARNING("meta[%u] has unsupported %s 0x%x, skip it", meta_number,
|
||||
"validator-id", meta->mm_validator_id);
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
if (unlikely(meta->mm_extra_pagehdr != 0)) {
|
||||
WARNING("meta[%u] has unsupported %s 0x%x, skip it", meta_number,
|
||||
"extra-pageheader", meta->mm_extra_pagehdr);
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
/* LY: check signature as a checksum */
|
||||
if (META_IS_STEADY(meta) &&
|
||||
unlikely(unaligned_peek_u64(4, &meta->mm_sign) != meta_sign(meta))) {
|
||||
@@ -12397,12 +12431,12 @@ static int validate_meta(MDBX_env *env, MDBX_meta *const meta,
|
||||
meta->mm_dbs[FREE_DBI].md_entries ||
|
||||
meta->mm_dbs[FREE_DBI].md_leaf_pages ||
|
||||
meta->mm_dbs[FREE_DBI].md_overflow_pages)) {
|
||||
WARNING("meta[%u] has false-empty %s, skip it", meta_number, "GC");
|
||||
WARNING("meta[%u] has false-empty %s, skip it", meta_number, "GC/FreeDB");
|
||||
return MDBX_CORRUPTED;
|
||||
}
|
||||
} else if (unlikely(meta->mm_dbs[FREE_DBI].md_root >= meta->mm_geo.next)) {
|
||||
WARNING("meta[%u] has invalid %s-root %" PRIaPGNO ", skip it", meta_number,
|
||||
"GC", meta->mm_dbs[FREE_DBI].md_root);
|
||||
"GC/FreeDB", meta->mm_dbs[FREE_DBI].md_root);
|
||||
return MDBX_CORRUPTED;
|
||||
}
|
||||
|
||||
@@ -12424,7 +12458,7 @@ static int validate_meta(MDBX_env *env, MDBX_meta *const meta,
|
||||
|
||||
if (unlikely(meta->mm_dbs[FREE_DBI].md_mod_txnid > txnid)) {
|
||||
WARNING("meta[%u] has wrong md_mod_txnid %" PRIaTXN " for %s, skip it",
|
||||
meta_number, meta->mm_dbs[FREE_DBI].md_mod_txnid, "GC");
|
||||
meta_number, meta->mm_dbs[FREE_DBI].md_mod_txnid, "GC/FreeDB");
|
||||
return MDBX_CORRUPTED;
|
||||
}
|
||||
|
||||
@@ -12434,6 +12468,13 @@ static int validate_meta(MDBX_env *env, MDBX_meta *const meta,
|
||||
return MDBX_CORRUPTED;
|
||||
}
|
||||
|
||||
if (unlikely((meta->mm_dbs[FREE_DBI].md_flags & DB_PERSISTENT_FLAGS) !=
|
||||
MDBX_INTEGERKEY)) {
|
||||
WARNING("meta[%u] has unexpected/invalid db-flags 0x%x for %s", meta_number,
|
||||
meta->mm_dbs[FREE_DBI].md_flags, "GC/FreeDB");
|
||||
return MDBX_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -14865,7 +14906,10 @@ __cold int mdbx_env_deleteW(const wchar_t *pathname,
|
||||
err = MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
if (err == MDBX_SUCCESS && !(dummy_env->me_flags & MDBX_NOSUBDIR)) {
|
||||
if (err == MDBX_SUCCESS && !(dummy_env->me_flags & MDBX_NOSUBDIR) &&
|
||||
(/* pathname != "." */ pathname[0] != '.' || pathname[1] != 0) &&
|
||||
(/* pathname != ".." */ pathname[0] != '.' || pathname[1] != '.' ||
|
||||
pathname[2] != 0)) {
|
||||
err = osal_removedirectory(pathname);
|
||||
if (err == MDBX_SUCCESS)
|
||||
rc = MDBX_SUCCESS;
|
||||
@@ -17323,9 +17367,11 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
||||
int err;
|
||||
DKBUF_DEBUG;
|
||||
MDBX_env *const env = mc->mc_txn->mt_env;
|
||||
if (LOG_ENABLED(MDBX_LOG_DEBUG) && (flags & MDBX_RESERVE))
|
||||
data->iov_base = nullptr;
|
||||
DEBUG("==> put db %d key [%s], size %" PRIuPTR ", data [%s] size %" PRIuPTR,
|
||||
DDBI(mc), DKEY_DEBUG(key), key->iov_len,
|
||||
DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->iov_len);
|
||||
DDBI(mc), DKEY_DEBUG(key), key->iov_len, DVAL_DEBUG(data),
|
||||
data->iov_len);
|
||||
|
||||
if ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) {
|
||||
if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE)))
|
||||
@@ -23088,9 +23134,29 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi 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;
|
||||
|
||||
@@ -90,8 +90,8 @@
|
||||
#endif
|
||||
#if _MSC_VER > 1914
|
||||
#pragma warning( \
|
||||
disable : 5105) /* winbase.h(9531): warning C5105: macro expansion \
|
||||
producing 'defined' has undefined behavior */
|
||||
disable : 5105) /* winbase.h(9531): warning C5105: macro expansion \
|
||||
producing 'defined' has undefined behavior */
|
||||
#endif
|
||||
#if _MSC_VER > 1930
|
||||
#pragma warning(disable : 6235) /* <expression> is always a constant */
|
||||
@@ -120,8 +120,8 @@
|
||||
#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \
|
||||
aggregate initializer */
|
||||
#pragma warning( \
|
||||
disable : 4505) /* unreferenced local function has been removed */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
disable : 4505) /* unreferenced local function has been removed */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 9
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
@@ -684,7 +684,7 @@ typedef struct MDBX_page {
|
||||
#define P_LOOSE 0x4000u /* page was dirtied then freed, can be reused */
|
||||
#define P_FROZEN 0x8000u /* used for retire page with known status */
|
||||
#define P_ILL_BITS \
|
||||
((uint16_t) ~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
|
||||
((uint16_t)~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
|
||||
uint16_t mp_flags;
|
||||
union {
|
||||
uint32_t mp_pages; /* number of overflow pages */
|
||||
@@ -1303,8 +1303,8 @@ struct MDBX_cursor {
|
||||
#define C_SUB 0x04 /* Cursor is a sub-cursor */
|
||||
#define C_DEL 0x08 /* last op was a cursor_del */
|
||||
#define C_UNTRACK 0x10 /* Un-track cursor when closing */
|
||||
#define C_GCU \
|
||||
0x20 /* Происходит подготовка к обновлению GC, поэтому \
|
||||
#define C_GCU \
|
||||
0x20 /* Происходит подготовка к обновлению GC, поэтому \
|
||||
* можно брать страницы из GC даже для FREE_DBI */
|
||||
uint8_t mc_flags;
|
||||
|
||||
|
||||
@@ -691,16 +691,16 @@ __cold MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
if LCK already opened/used inside current process */
|
||||
;
|
||||
|
||||
/* FIXME: Unfortunately, there is no other reliable way but to long testing
|
||||
* on each platform. On the other hand, behavior like FreeBSD is incorrect
|
||||
* and we can expect it to be rare. Moreover, even on FreeBSD without
|
||||
* additional in-process initialization, the probability of an problem
|
||||
* occurring is vanishingly small, and the symptom is a return of EINVAL
|
||||
* while locking a mutex. In other words, in the worst case, the problem
|
||||
* results in an EINVAL error at the start of the transaction, but NOT data
|
||||
* loss, nor database corruption, nor other fatal troubles. Thus, the code
|
||||
* below I am inclined to think the workaround for erroneous platforms (like
|
||||
* FreeBSD), rather than a defect of libmdbx. */
|
||||
/* FIXME: Unfortunately, there is no other reliable way but to long testing
|
||||
* on each platform. On the other hand, behavior like FreeBSD is incorrect
|
||||
* and we can expect it to be rare. Moreover, even on FreeBSD without
|
||||
* additional in-process initialization, the probability of an problem
|
||||
* occurring is vanishingly small, and the symptom is a return of EINVAL
|
||||
* while locking a mutex. In other words, in the worst case, the problem
|
||||
* results in an EINVAL error at the start of the transaction, but NOT data
|
||||
* loss, nor database corruption, nor other fatal troubles. Thus, the code
|
||||
* below I am inclined to think the workaround for erroneous platforms (like
|
||||
* FreeBSD), rather than a defect of libmdbx. */
|
||||
#if defined(__FreeBSD__)
|
||||
/* seems that shared mutexes on FreeBSD required in-process initialization */
|
||||
(void)global_uniqueness_flag;
|
||||
|
||||
96
src/mdbx.c++
96
src/mdbx.c++
@@ -247,6 +247,21 @@ struct temp_buffer {
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifndef MDBX_CXX_ENDL
|
||||
/* Манипулятор std::endl выталкивате буфферизированый вывод, что здесь не
|
||||
* требуется.
|
||||
*
|
||||
* Кроме этого, при сборке libmdbx для символов по-умолчанию выключается
|
||||
* видимость вне DSO, из-за чего обращение к std::endl иногда укачивает
|
||||
* линковщики, если комплятор ошибочно формируют direct access к global weak
|
||||
* symbol, коим является std::endl. */
|
||||
#if 0
|
||||
#define MDBX_CXX_ENDL ::std::endl
|
||||
#else
|
||||
#define MDBX_CXX_ENDL "\n"
|
||||
#endif
|
||||
#endif /* MDBX_CXX_ENDL */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace mdbx {
|
||||
@@ -395,6 +410,7 @@ __cold void error::throw_exception() const {
|
||||
CASE_EXCEPTION(incompatible_operation, MDBX_INCOMPATIBLE);
|
||||
CASE_EXCEPTION(internal_page_full, MDBX_PAGE_FULL);
|
||||
CASE_EXCEPTION(internal_problem, MDBX_PROBLEM);
|
||||
CASE_EXCEPTION(key_exists, MDBX_KEYEXIST);
|
||||
CASE_EXCEPTION(key_mismatch, MDBX_EKEYMISMATCH);
|
||||
CASE_EXCEPTION(max_maps_reached, MDBX_DBS_FULL);
|
||||
CASE_EXCEPTION(max_readers_reached, MDBX_READERS_FULL);
|
||||
@@ -663,7 +679,7 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||
unsigned width = 0;
|
||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||
if (wrap_width && width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
out << MDBX_CXX_ENDL;
|
||||
width = 0;
|
||||
}
|
||||
const int8_t hi = *src >> 4;
|
||||
@@ -858,7 +874,7 @@ char *to_base58::write_bytes(char *__restrict const dest,
|
||||
while (MDBX_LIKELY(begin < end) && *begin == 0) {
|
||||
out.put('1');
|
||||
if (wrap_width && ++width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
out << MDBX_CXX_ENDL;
|
||||
width = 0;
|
||||
}
|
||||
++begin;
|
||||
@@ -872,7 +888,7 @@ char *to_base58::write_bytes(char *__restrict const dest,
|
||||
for (size_t i = 0; i < chunk.length(); ++i) {
|
||||
out.put(chunk.char_ptr()[i]);
|
||||
if (wrap_width && ++width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
out << MDBX_CXX_ENDL;
|
||||
width = 0;
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1065,7 @@ char *to_base64::write_bytes(char *__restrict const dest,
|
||||
src += 3;
|
||||
out.write(&buf.front(), 4);
|
||||
if (wrap_width && (width += 4) >= wrap_width && left) {
|
||||
out << ::std::endl;
|
||||
out << MDBX_CXX_ENDL;
|
||||
width = 0;
|
||||
}
|
||||
continue;
|
||||
@@ -1283,7 +1299,7 @@ bool env::is_pristine() const {
|
||||
|
||||
bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; }
|
||||
|
||||
env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
|
||||
__cold env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
|
||||
error::success_or_throw(
|
||||
::mdbx_env_copy2fd(handle_, fd,
|
||||
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
|
||||
@@ -1292,8 +1308,8 @@ env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
env &env::copy(const char *destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
__cold env &env::copy(const char *destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
error::success_or_throw(
|
||||
::mdbx_env_copy(handle_, destination,
|
||||
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
|
||||
@@ -1302,14 +1318,14 @@ env &env::copy(const char *destination, bool compactify,
|
||||
return *this;
|
||||
}
|
||||
|
||||
env &env::copy(const ::std::string &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
__cold env &env::copy(const ::std::string &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
return copy(destination.c_str(), compactify, force_dynamic_size);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
env &env::copy(const wchar_t *destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
__cold env &env::copy(const wchar_t *destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
error::success_or_throw(
|
||||
::mdbx_env_copyW(handle_, destination,
|
||||
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
|
||||
@@ -1325,13 +1341,13 @@ env &env::copy(const ::std::wstring &destination, bool compactify,
|
||||
#endif /* Windows */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
__cold env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination,
|
||||
bool compactify, bool force_dynamic_size) {
|
||||
return copy(destination.native(), compactify, force_dynamic_size);
|
||||
}
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
|
||||
path env::get_path() const {
|
||||
__cold path env::get_path() const {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const wchar_t *c_wstr;
|
||||
error::success_or_throw(::mdbx_env_get_pathW(handle_, &c_wstr));
|
||||
@@ -1345,29 +1361,30 @@ path env::get_path() const {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool env::remove(const char *pathname, const remove_mode mode) {
|
||||
return error::boolean_or_throw(
|
||||
__cold bool env::remove(const char *pathname, const remove_mode mode) {
|
||||
return !error::boolean_or_throw(
|
||||
::mdbx_env_delete(pathname, MDBX_env_delete_mode_t(mode)));
|
||||
}
|
||||
|
||||
bool env::remove(const ::std::string &pathname, const remove_mode mode) {
|
||||
__cold bool env::remove(const ::std::string &pathname, const remove_mode mode) {
|
||||
return remove(pathname.c_str(), mode);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
bool env::remove(const wchar_t *pathname, const remove_mode mode) {
|
||||
return error::boolean_or_throw(
|
||||
__cold bool env::remove(const wchar_t *pathname, const remove_mode mode) {
|
||||
return !error::boolean_or_throw(
|
||||
::mdbx_env_deleteW(pathname, MDBX_env_delete_mode_t(mode)));
|
||||
}
|
||||
|
||||
bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
|
||||
__cold bool env::remove(const ::std::wstring &pathname,
|
||||
const remove_mode mode) {
|
||||
return remove(pathname.c_str(), mode);
|
||||
}
|
||||
#endif /* Windows */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
const remove_mode mode) {
|
||||
__cold bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
const remove_mode mode) {
|
||||
return remove(pathname.native(), mode);
|
||||
}
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
@@ -1381,13 +1398,13 @@ static inline MDBX_env *create_env() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
env_managed::~env_managed() noexcept {
|
||||
__cold env_managed::~env_managed() noexcept {
|
||||
if (MDBX_UNLIKELY(handle_))
|
||||
MDBX_CXX20_UNLIKELY error::success_or_panic(
|
||||
::mdbx_env_close(handle_), "mdbx::~env()", "mdbx_env_close");
|
||||
}
|
||||
|
||||
void env_managed::close(bool dont_sync) {
|
||||
__cold void env_managed::close(bool dont_sync) {
|
||||
const error rc =
|
||||
static_cast<MDBX_error_t>(::mdbx_env_close_ex(handle_, dont_sync));
|
||||
switch (rc.code()) {
|
||||
@@ -1537,7 +1554,7 @@ void txn_managed::commit(commit_latency *latency) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool txn::drop_map(const char *name, bool throw_if_absent) {
|
||||
__cold bool txn::drop_map(const char *name, bool throw_if_absent) {
|
||||
map_handle map;
|
||||
const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
|
||||
switch (err) {
|
||||
@@ -1554,7 +1571,7 @@ bool txn::drop_map(const char *name, bool throw_if_absent) {
|
||||
}
|
||||
}
|
||||
|
||||
bool txn::clear_map(const char *name, bool throw_if_absent) {
|
||||
__cold bool txn::clear_map(const char *name, bool throw_if_absent) {
|
||||
map_handle map;
|
||||
const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
|
||||
switch (err) {
|
||||
@@ -1630,21 +1647,20 @@ __cold ::std::ostream &operator<<(::std::ostream &out,
|
||||
const char *suffix;
|
||||
} static const scales[] = {
|
||||
#if MDBX_WORDBITS > 32
|
||||
{env_managed::geometry::EiB, "EiB"},
|
||||
{env_managed::geometry::EB, "EB"},
|
||||
{env_managed::geometry::PiB, "PiB"},
|
||||
{env_managed::geometry::PB, "PB"},
|
||||
{env_managed::geometry::TiB, "TiB"},
|
||||
{env_managed::geometry::TB, "TB"},
|
||||
{env_managed::geometry::EiB, "EiB"},
|
||||
{env_managed::geometry::EB, "EB"},
|
||||
{env_managed::geometry::PiB, "PiB"},
|
||||
{env_managed::geometry::PB, "PB"},
|
||||
{env_managed::geometry::TiB, "TiB"},
|
||||
{env_managed::geometry::TB, "TB"},
|
||||
#endif
|
||||
{env_managed::geometry::GiB, "GiB"},
|
||||
{env_managed::geometry::GB, "GB"},
|
||||
{env_managed::geometry::MiB, "MiB"},
|
||||
{env_managed::geometry::MB, "MB"},
|
||||
{env_managed::geometry::KiB, "KiB"},
|
||||
{env_managed::geometry::kB, "kB"},
|
||||
{1, " bytes"}
|
||||
};
|
||||
{env_managed::geometry::GiB, "GiB"},
|
||||
{env_managed::geometry::GB, "GB"},
|
||||
{env_managed::geometry::MiB, "MiB"},
|
||||
{env_managed::geometry::MB, "MB"},
|
||||
{env_managed::geometry::KiB, "KiB"},
|
||||
{env_managed::geometry::kB, "kB"},
|
||||
{1, " bytes"}};
|
||||
|
||||
for (const auto i : scales)
|
||||
if (bytes % i.one == 0)
|
||||
|
||||
23
src/osal.c
23
src/osal.c
@@ -766,11 +766,10 @@ MDBX_INTERNAL_FUNC int osal_ioring_add(osal_ioring_t *ior, const size_t offset,
|
||||
item->sgv[0].Buffer = PtrToPtr64(data);
|
||||
for (size_t i = 1; i < segments; ++i) {
|
||||
data = ptr_disp(data, ior->pagesize);
|
||||
item->sgv[slots_used].Buffer = PtrToPtr64(data);
|
||||
item->sgv[i].Buffer = PtrToPtr64(data);
|
||||
}
|
||||
item->sgv[slots_used].Buffer = 0;
|
||||
item->sgv[slots_used = segments].Buffer = 0;
|
||||
assert((item->single.iov_len & ior_WriteFile_flag) == 0);
|
||||
slots_used = segments;
|
||||
}
|
||||
ior->last_bytes = bytes;
|
||||
ior_last_sgvcnt(ior, item) = slots_used;
|
||||
@@ -3399,16 +3398,15 @@ __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
|
||||
#elif defined(HW_USERMEM) || defined(HW_PHYSMEM64) || defined(HW_MEMSIZE) || \
|
||||
defined(HW_PHYSMEM)
|
||||
size_t ram, len = sizeof(ram);
|
||||
static const int mib[] = {
|
||||
CTL_HW,
|
||||
static const int mib[] = {CTL_HW,
|
||||
#if defined(HW_USERMEM)
|
||||
HW_USERMEM
|
||||
HW_USERMEM
|
||||
#elif defined(HW_PHYSMEM64)
|
||||
HW_PHYSMEM64
|
||||
HW_PHYSMEM64
|
||||
#elif defined(HW_MEMSIZE)
|
||||
HW_MEMSIZE
|
||||
HW_MEMSIZE
|
||||
#else
|
||||
HW_PHYSMEM
|
||||
HW_PHYSMEM
|
||||
#endif
|
||||
};
|
||||
if (sysctl(
|
||||
@@ -3449,12 +3447,11 @@ __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
|
||||
#elif defined(VM_TOTAL) || defined(VM_METER)
|
||||
struct vmtotal info;
|
||||
size_t len = sizeof(info);
|
||||
static const int mib[] = {
|
||||
CTL_VM,
|
||||
static const int mib[] = {CTL_VM,
|
||||
#if defined(VM_TOTAL)
|
||||
VM_TOTAL
|
||||
VM_TOTAL
|
||||
#elif defined(VM_METER)
|
||||
VM_METER
|
||||
VM_METER
|
||||
#endif
|
||||
};
|
||||
if (sysctl(
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -42,7 +42,16 @@ uint32_t us2fractional(uint32_t us) {
|
||||
}
|
||||
|
||||
uint32_t fractional2us(uint32_t fractional) {
|
||||
#if !(defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64))
|
||||
/* Смеяться или плакать, но все существующие на май 2024 компиляторы Microsoft
|
||||
* для ARM/ARM64, уже порядка 10 лет, падают на этом коде из-за внтутренней
|
||||
* ошибке (aka ICE). */
|
||||
return uint32_t((fractional * uint64_t(USEC_PER_SEC)) >> 32);
|
||||
#else
|
||||
static_assert(USEC_PER_SEC % 16 == 0, "WTF?");
|
||||
/* Crutch for MSVC ARM/ARM64 compilers to avoid internal compiler error. */
|
||||
return UInt32x32To64(fractional, USEC_PER_SEC / 16) >> 28;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef MSEC_PER_SEC
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#define IP_PRINTF_ARG_HOST(addr) \
|
||||
(int)((addr) >> 24), (int)((addr) >> 16 & 0xff), (int)((addr) >> 8 & 0xff), \
|
||||
(int)((addr)&0xff)
|
||||
(int)((addr) & 0xff)
|
||||
|
||||
char opt_db_path[PATH_MAX] = "./mdbx_bench2";
|
||||
static MDBX_env *env;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
#if _MSC_FULL_VER < 190024215
|
||||
#pragma message( \
|
||||
"It is recommended to use Visual Studio 2015 (MSC 19.0) or newer.")
|
||||
"It is recommended to use Visual Studio 2015 (MSC 19.0) or newer.")
|
||||
#endif
|
||||
|
||||
#define bswap64(v) _byteswap_uint64(v)
|
||||
|
||||
Reference in New Issue
Block a user