summaryrefslogtreecommitdiff
path: root/libs/libmdbx/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libmdbx/src')
-rw-r--r--libs/libmdbx/src/COPYRIGHT2
-rw-r--r--libs/libmdbx/src/README-RU.md91
-rw-r--r--libs/libmdbx/src/README.md88
-rw-r--r--libs/libmdbx/src/dll.vcxproj1
-rw-r--r--libs/libmdbx/src/libmdbx.files1
-rw-r--r--libs/libmdbx/src/mdbx.h55
-rw-r--r--libs/libmdbx/src/src/bits.h8
-rw-r--r--libs/libmdbx/src/src/defs.h2
-rw-r--r--libs/libmdbx/src/src/lck-posix.c6
-rw-r--r--libs/libmdbx/src/src/lck-windows.c2
-rw-r--r--libs/libmdbx/src/src/mdbx.c424
-rw-r--r--libs/libmdbx/src/src/osal.c49
-rw-r--r--libs/libmdbx/src/src/osal.h2
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_chk.c38
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_chk.vcxproj1
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_copy.12
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_copy.c2
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_copy.vcxproj1
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_dump.12
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_dump.c2
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_dump.vcxproj1
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_load.19
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_load.c70
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_load.vcxproj1
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_stat.12
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_stat.c2
-rw-r--r--libs/libmdbx/src/src/tools/mdbx_stat.vcxproj1
-rw-r--r--libs/libmdbx/src/test/CMakeLists.txt1
-rw-r--r--libs/libmdbx/src/test/append.cc132
-rw-r--r--libs/libmdbx/src/test/base.h2
-rw-r--r--libs/libmdbx/src/test/cases.cc3
-rw-r--r--libs/libmdbx/src/test/chrono.cc2
-rw-r--r--libs/libmdbx/src/test/chrono.h2
-rw-r--r--libs/libmdbx/src/test/config.cc2
-rw-r--r--libs/libmdbx/src/test/config.h5
-rw-r--r--libs/libmdbx/src/test/dead.cc2
-rw-r--r--libs/libmdbx/src/test/hill.cc2
-rw-r--r--libs/libmdbx/src/test/jitter.cc2
-rw-r--r--libs/libmdbx/src/test/keygen.cc11
-rw-r--r--libs/libmdbx/src/test/keygen.h4
-rw-r--r--libs/libmdbx/src/test/log.cc2
-rw-r--r--libs/libmdbx/src/test/log.h2
-rw-r--r--libs/libmdbx/src/test/main.cc6
-rw-r--r--libs/libmdbx/src/test/osal-unix.cc2
-rw-r--r--libs/libmdbx/src/test/osal-windows.cc2
-rw-r--r--libs/libmdbx/src/test/osal.h2
-rw-r--r--libs/libmdbx/src/test/test.cc33
-rw-r--r--libs/libmdbx/src/test/test.h11
-rw-r--r--libs/libmdbx/src/test/test.vcxproj2
-rw-r--r--libs/libmdbx/src/test/utils.cc2
-rw-r--r--libs/libmdbx/src/test/utils.h11
-rw-r--r--libs/libmdbx/src/tutorial/sample-bdb.txt2
-rw-r--r--libs/libmdbx/src/tutorial/sample-mdbx.c2
53 files changed, 898 insertions, 216 deletions
diff --git a/libs/libmdbx/src/COPYRIGHT b/libs/libmdbx/src/COPYRIGHT
index 7c2fd24c78..46e0961046 100644
--- a/libs/libmdbx/src/COPYRIGHT
+++ b/libs/libmdbx/src/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
Copyright 2011-2015 Howard Chu, Symas Corp.
Copyright 2015,2016 Peter-Service R&D LLC.
All rights reserved.
diff --git a/libs/libmdbx/src/README-RU.md b/libs/libmdbx/src/README-RU.md
index 5dd062c1a6..97888cbf88 100644
--- a/libs/libmdbx/src/README-RU.md
+++ b/libs/libmdbx/src/README-RU.md
@@ -12,7 +12,7 @@ and [by Yandex](https://translate.yandex.ru/translate?url=https%3A%2F%2Fgithub.c
### Project Status
-**Сейчас MDBX _активно перерабатывается_** и к середине 2018 ожидается
+**Сейчас MDBX _активно перерабатывается_** предстоит
большое изменение как API, так и формата базы данных. К сожалению,
обновление приведет к потере совместимости с предыдущими версиями.
@@ -171,31 +171,18 @@ Amplification Factor) и RAF (Read Amplification Factor) также Olog(N).
Доработки и усовершенствования относительно LMDB
================================================
-1. Утилита `mdbx_chk` для проверки целостности структуры БД.
-
-2. Автоматическое динамическое управление размером БД согласно
+1. Автоматическое динамическое управление размером БД согласно
параметрам задаваемым функцией `mdbx_env_set_geometry()`, включая шаг
приращения и порог уменьшения размера БД, а также выбор размера
страницы. Соответственно, это позволяет снизить фрагментированность
файла БД на диске и освободить место, в том числе в **Windows**.
-3. Автоматическая без-затратная компактификация БД путем возврата
+2. Автоматическая без-затратная компактификация БД путем возврата
освобождающихся страниц в область нераспределенного резерва в конце
файла данных. При этом уменьшается количество страниц находящихся в
памяти и участвующих в в обмене с диском.
-4. Поддержка ключей и значений нулевой длины, включая сортированные
-дубликаты.
-
-5. Возможность связать с каждой завершаемой транзакцией до 3
-дополнительных маркеров посредством `mdbx_canary_put()`, и прочитать их
-в транзакции чтения посредством `mdbx_canary_get()`.
-
-6. Возможность посредством `mdbx_replace()` обновить или удалить запись
-с получением предыдущего значения данных, а также адресно изменить
-конкретное multi-значение.
-
-7. Режим `LIFO RECLAIM`.
+3. Режим `LIFO RECLAIM`.
Для повторного использования выбираются не самые старые, а
самые новые страницы из доступных. За счет этого цикл
@@ -209,9 +196,27 @@ Amplification Factor) и RAF (Read Amplification Factor) также Olog(N).
многократное увеличение производительности по записи
(обновлению данных).
-8. Генерация последовательностей посредством `mdbx_dbi_sequence()`.
+4. Быстрая оценка количества элементов попадающих в запрашиваемый
+диапазон значений ключа посредством функций `mdbx_estimate_range()`,
+`mdbx_estimate_move()` и `mdbx_estimate_distance()` для выбора
+оптимального плана выполнения запроса.
+
+5. Утилита `mdbx_chk` для проверки целостности структуры БД.
+
+6. Поддержка ключей и значений нулевой длины, включая сортированные
+дубликаты.
+
+7. Возможность связать с каждой завершаемой транзакцией до 3
+дополнительных маркеров посредством `mdbx_canary_put()`, и прочитать их
+в транзакции чтения посредством `mdbx_canary_get()`.
+
+8. Возможность посредством `mdbx_replace()` обновить или удалить запись
+с получением предыдущего значения данных, а также адресно изменить
+конкретное multi-значение.
+
+9. Генерация последовательностей посредством `mdbx_dbi_sequence()`.
-9. Обработчик `OOM-KICK`.
+10. Обработчик `OOM-KICK`.
Посредством `mdbx_env_set_oomfunc()` может быть установлен
внешний обработчик (callback), который будет вызван при
@@ -232,83 +237,83 @@ Amplification Factor) и RAF (Read Amplification Factor) также Olog(N).
* прервать текущую операцию изменения данных с возвратом кода
ошибки.
-10. Возможность открыть БД в эксклюзивном режиме посредством флага
-`MDBX_EXCLUSIVE`.
+11. Возможность открыть БД в эксклюзивном режиме посредством флага
+ `MDBX_EXCLUSIVE`, в том числе на сетевом носителе.
-11. Возможность получить отставание текущей транзакции чтения от
+12. Возможность получить отставание текущей транзакции чтения от
последней версии данных в БД посредством `mdbx_txn_straggler()`.
-12. Возможность явно запросить обновление существующей записи, без
+13. Возможность явно запросить обновление существующей записи, без
создания новой посредством флажка `MDBX_CURRENT` для `mdbx_put()`.
-13. Исправленный вариант `mdbx_cursor_count()`, возвращающий корректное
+14. Исправленный вариант `mdbx_cursor_count()`, возвращающий корректное
количество дубликатов для всех типов таблиц и любого положения курсора.
-14. Возможность получить посредством `mdbx_env_info()` дополнительную
+15. Возможность получить посредством `mdbx_env_info()` дополнительную
информацию, включая номер самой старой версии БД (снимка данных),
который используется одним из читателей.
-15. Функция `mdbx_del()` не игнорирует дополнительный (уточняющий)
+16. Функция `mdbx_del()` не игнорирует дополнительный (уточняющий)
аргумент `data` для таблиц без дубликатов (без флажка `MDBX_DUPSORT`), а
при его ненулевом значении всегда использует его для сверки с удаляемой
записью.
-16. Возможность открыть dbi-таблицу, одновременно с установкой
+17. Возможность открыть dbi-таблицу, одновременно с установкой
компараторов для ключей и данных, посредством `mdbx_dbi_open_ex()`.
-17. Возможность посредством `mdbx_is_dirty()` определить находятся ли
+18. Возможность посредством `mdbx_is_dirty()` определить находятся ли
некоторый ключ или данные в "грязной" странице БД. Таким образом,
избегая лишнего копирования данных перед выполнением модифицирующих
операций (значения, размещенные в "грязных" страницах, могут быть
перезаписаны при изменениях, иначе они будут неизменны).
-18. Корректное обновление текущей записи, в том числе сортированного
+19. Корректное обновление текущей записи, в том числе сортированного
дубликата, при использовании режима `MDBX_CURRENT` в
`mdbx_cursor_put()`.
-19. Возможность узнать есть ли за текущей позицией курсора строка данных
+20. Возможность узнать есть ли за текущей позицией курсора строка данных
посредством `mdbx_cursor_eof()`.
-20. Дополнительный код ошибки `MDBX_EMULTIVAL`, который возвращается из
+21. Дополнительный код ошибки `MDBX_EMULTIVAL`, который возвращается из
`mdbx_put()` и `mdbx_replace()` при попытке выполнить неоднозначное
обновление или удаления одного из нескольких значений с одним ключом.
-21. Возможность посредством `mdbx_get_ex()` получить значение по
+22. Возможность посредством `mdbx_get_ex()` получить значение по
заданному ключу, одновременно с количеством дубликатов.
-22. Наличие функций `mdbx_cursor_on_first()` и `mdbx_cursor_on_last()`,
+23. Наличие функций `mdbx_cursor_on_first()` и `mdbx_cursor_on_last()`,
которые позволяют быстро выяснить стоит ли курсор на первой/последней
позиции.
-23. Возможность автоматического формирования контрольных точек (сброса
+24. Возможность автоматического формирования контрольных точек (сброса
данных на диск) при накоплении заданного объёма изменений,
устанавливаемого функцией `mdbx_env_set_syncbytes()`.
-24. Управление отладкой и получение отладочных сообщений посредством
+25. Управление отладкой и получение отладочных сообщений посредством
`mdbx_setup_debug()`.
-25. Функция `mdbx_env_pgwalk()` для обхода всех страниц БД.
+26. Функция `mdbx_env_pgwalk()` для обхода всех страниц БД.
-26. Три мета-страницы вместо двух, что позволяет гарантированно
+27. Три мета-страницы вместо двух, что позволяет гарантированно
консистентно обновлять слабые контрольные точки фиксации без риска
повредить крайнюю сильную точку фиксации.
-27. Гарантия сохранности БД в режиме `WRITEMAP+MAPSYNC`.
+28. Гарантия сохранности БД в режиме `WRITEMAP+MAPSYNC`.
> В текущей версии _libmdbx_ вам предоставляется выбор между безопасным
> режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC`
> когда при системной аварии есть шанс полного разрушения БД как в LMDB.
> Для подробностей смотрите раздел
> [Сохранность данных в режиме асинхронной фиксации](#Сохранность-данных-в-режиме-асинхронной-фиксации).
-28. Возможность закрыть БД в "грязном" состоянии (без сброса данных и
+29. Возможность закрыть БД в "грязном" состоянии (без сброса данных и
формирования сильной точки фиксации) посредством `mdbx_env_close_ex()`.
-29. При завершении читающих транзакций, открытые в них DBI-хендлы не
+30. При завершении читающих транзакций, открытые в них DBI-хендлы не
закрываются и не теряются при завершении таких транзакций посредством
`mdbx_txn_abort()` или `mdbx_txn_reset()`. Что позволяет избавится от ряда
сложно обнаруживаемых ошибок.
-30. Все курсоры, как в транзакциях только для чтения, так и в пишущих,
+31. Все курсоры, как в транзакциях только для чтения, так и в пишущих,
могут быть переиспользованы посредством `mdbx_cursor_renew()` и ДОЛЖНЫ
ОСВОБОЖДАТЬСЯ ЯВНО.
>
@@ -682,11 +687,11 @@ $ objdump -f -h -j .text libmdbx.so
libmdbx.so: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
-start address 0x000030e0
+start address 0x0000000000003870
Sections:
Idx Name Size VMA LMA File off Algn
- 11 .text 00014d84 00000000000030e0 00000000000030e0 000030e0 2**4
+ 11 .text 000173d4 0000000000003870 0000000000003870 00003870 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
```
diff --git a/libs/libmdbx/src/README.md b/libs/libmdbx/src/README.md
index a2a6ab7ac3..78cc906763 100644
--- a/libs/libmdbx/src/README.md
+++ b/libs/libmdbx/src/README.md
@@ -170,30 +170,18 @@ regular maintenance. Backups can be made on the fly on working DB
Improvements over LMDB
======================
-1. `mdbx_chk` tool for DB integrity check.
-
-2. Automatic dynamic DB size management according to the parameters
-specified by `mdbx_env_set_geometry()` function. Including including
+1. Automatic dynamic DB size management according to the parameters
+specified by `mdbx_env_set_geometry()` function. Including
growth step and truncation threshold, as well as the choice of page
size.
-3. Automatic returning of freed pages into unallocated space at the end
-of database file with optionally automatic shrinking it. This reduces
+2. Automatic returning of freed pages into unallocated space at the end
+of database file, with optionally automatic shrinking it. This reduces
amount of pages resides in RAM and circulated in disk I/O. In fact
_libmdbx_ constantly performs DB compactification, without spending
additional resources for that.
-4. Support for keys and values of zero length, including sorted
-duplicates.
-
-5. Ability to assign up to 3 markers to commiting transaction with
-`mdbx_canary_put()` and then get them in read transaction by
-`mdbx_canary_get()`.
-
-6. Ability to update or delete record and get previous value via
-`mdbx_replace()` Also can update specific multi-value.
-
-7. `LIFO RECLAIM` mode:
+3. `LIFO RECLAIM` mode:
The newest pages are picked for reuse instead of the oldest. This allows
to minimize reclaim loop and make it execution time independent of total
@@ -204,9 +192,25 @@ duplicates.
[BBWC](https://en.wikipedia.org/wiki/Disk_buffer#Write_acceleration)
this may greatly improve write performance.
-8. Sequence generation via `mdbx_dbi_sequence()`.
+4. Fast estimation of range query result size via functions `mdbx_estimate_range()`,
+`mdbx_estimate_move()` and `mdbx_estimate_distance()`. E.g. for selection the
+optimal query execution plan.
+
+5. `mdbx_chk` tool for DB integrity check.
+
+6. Support for keys and values of zero length, including sorted
+duplicates.
+
+7. Ability to assign up to 3 markers to commiting transaction with
+`mdbx_canary_put()` and then get them in read transaction by
+`mdbx_canary_get()`.
+
+8. Ability to update or delete record and get previous value via
+`mdbx_replace()`. Also can update specific multi-value.
+
+9. Sequence generation via `mdbx_dbi_sequence()`.
-9. `OOM-KICK` callback.
+10. `OOM-KICK` callback.
`mdbx_env_set_oomfunc()` allows to set a callback, which will be called
in the event of DB space exhausting during long-time read transaction in
@@ -224,75 +228,75 @@ duplicates.
* abort current write transaction with returning error code.
-10. Ability to open DB in exclusive mode with `MDBX_EXCLUSIVE` flag.
+11. Ability to open DB in exclusive mode with `MDBX_EXCLUSIVE` flag.
-11. Ability to get how far current read-only snapshot is from latest
+12. Ability to get how far current read-only snapshot is from latest
version of the DB by `mdbx_txn_straggler()`.
-12. Ability to explicitly request update of present record without
+13. Ability to explicitly request update of present record without
creating new record. Implemented as `MDBX_CURRENT` flag for
`mdbx_put()`.
-13. Fixed `mdbx_cursor_count()`, which returns correct count of
+14. Fixed `mdbx_cursor_count()`, which returns correct count of
duplicated for all table types and any cursor position.
-14. `mdbx_env_info()` to getting additional info, including number of
+15. `mdbx_env_info()` to getting additional info, including number of
the oldest snapshot of DB, which is used by one of the readers.
-15. `mdbx_del()` doesn't ignore additional argument (specifier) `data`
+16. `mdbx_del()` doesn't ignore additional argument (specifier) `data`
for tables without duplicates (without flag `MDBX_DUPSORT`), if `data`
is not null then always uses it to verify record, which is being
deleted.
-16. Ability to open dbi-table with simultaneous setup of comparators for
+17. Ability to open dbi-table with simultaneous setup of comparators for
keys and values, via `mdbx_dbi_open_ex()`.
-17. `mdbx_is_dirty()`to find out if key or value is on dirty page, that
+18. `mdbx_is_dirty()`to find out if key or value is on dirty page, that
useful to avoid copy-out before updates.
-18. Correct update of current record in `MDBX_CURRENT` mode of
+19. Correct update of current record in `MDBX_CURRENT` mode of
`mdbx_cursor_put()`, including sorted duplicated.
-19. Check if there is a row with data after current cursor position via
+20. Check if there is a row with data after current cursor position via
`mdbx_cursor_eof()`.
-20. Additional error code `MDBX_EMULTIVAL`, which is returned by
+21. Additional error code `MDBX_EMULTIVAL`, which is returned by
`mdbx_put()` and `mdbx_replace()` in case is ambiguous update or delete.
-21. Ability to get value by key and duplicates count by `mdbx_get_ex()`.
+22. Ability to get value by key and duplicates count by `mdbx_get_ex()`.
-22. Functions `mdbx_cursor_on_first()` and `mdbx_cursor_on_last()`,
+23. Functions `mdbx_cursor_on_first()` and `mdbx_cursor_on_last()`,
which allows to know if cursor is currently on first or last position
respectively.
-23. Automatic creation of synchronization points (flush changes to
+24. Automatic creation of synchronization points (flush changes to
persistent storage) when changes reach set threshold (threshold can be
set by `mdbx_env_set_syncbytes()`).
-24. Control over debugging and receiving of debugging messages via
+25. Control over debugging and receiving of debugging messages via
`mdbx_setup_debug()`.
-25. Function `mdbx_env_pgwalk()` for page-walking all pages in DB.
+26. Function `mdbx_env_pgwalk()` for page-walking all pages in DB.
-26. Three meta-pages instead of two, this allows to guarantee
+27. Three meta-pages instead of two, this allows to guarantee
consistently update weak sync-points without risking to corrupt last
steady sync-point.
-27. Guarantee of DB integrity in `WRITEMAP+MAPSYNC` mode:
+28. Guarantee of DB integrity in `WRITEMAP+MAPSYNC` mode:
> Current _libmdbx_ gives a choice of safe async-write mode (default)
> and `UTTERLY_NOSYNC` mode which may result in full
> DB corruption during system crash as with LMDB. For details see
> [Data safety in async-write mode](#data-safety-in-async-write-mode).
-28. Ability to close DB in "dirty" state (without data flush and
+29. Ability to close DB in "dirty" state (without data flush and
creation of steady synchronization point) via `mdbx_env_close_ex()`.
-29. If read transaction is aborted via `mdbx_txn_abort()` or
+30. If read transaction is aborted via `mdbx_txn_abort()` or
`mdbx_txn_reset()` then DBI-handles, which were opened in it, aren't
closed or deleted. This allows to avoid several types of hard-to-debug
errors.
-30. All cursors in all read and write transactions can be reused by
+31. All cursors in all read and write transactions can be reused by
`mdbx_cursor_renew()` and MUST be freed explicitly.
> ## Caution, please pay attention!
>
@@ -594,11 +598,11 @@ $ objdump -f -h -j .text libmdbx.so
libmdbx.so: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
-start address 0x000030e0
+start address 0x0000000000003870
Sections:
Idx Name Size VMA LMA File off Algn
- 11 .text 00014d84 00000000000030e0 00000000000030e0 000030e0 2**4
+ 11 .text 000173d4 0000000000003870 0000000000003870 00003870 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
```
diff --git a/libs/libmdbx/src/dll.vcxproj b/libs/libmdbx/src/dll.vcxproj
index 63a1c766d6..c0743890ce 100644
--- a/libs/libmdbx/src/dll.vcxproj
+++ b/libs/libmdbx/src/dll.vcxproj
@@ -21,6 +21,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{6D19209B-ECE7-4B9C-941C-0AA2B484F199}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/libmdbx.files b/libs/libmdbx/src/libmdbx.files
index 653b03970e..76ea29fb5a 100644
--- a/libs/libmdbx/src/libmdbx.files
+++ b/libs/libmdbx/src/libmdbx.files
@@ -3,6 +3,7 @@ README-RU.md
pcrf_test/CMakeLists.txt
src/tools/CMakeLists.txt
test/CMakeLists.txt
+test/append.cc
test/copy.cc
tutorial/CMakeLists.txt
tutorial/sample-mdbx.c
diff --git a/libs/libmdbx/src/mdbx.h b/libs/libmdbx/src/mdbx.h
index c42f62aafa..3b76bacc7d 100644
--- a/libs/libmdbx/src/mdbx.h
+++ b/libs/libmdbx/src/mdbx.h
@@ -1,6 +1,6 @@
/* LICENSE AND COPYRUSTING *****************************************************
*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -60,8 +60,8 @@
/* IMPENDING CHANGES WARNING ***************************************************
*
- * MDBX is under active development, database format and API aren't stable
- * at least until 2018Q2. New version won't be backwards compatible. Main focus
+ * MDBX is under active non-public development, database format and API
+ * will be refined. New version won't be backwards compatible. Main focus
* of the rework is to provide clear and robust API and new features.
*
******************************************************************************/
@@ -615,7 +615,7 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
* - MDBX_NOTLS
* Don't use Thread-Local Storage. Tie reader locktable slots to
* MDBX_txn objects instead of to threads. I.e. mdbx_txn_reset() keeps
- * the slot reseved for the MDBX_txn object. A thread may use parallel
+ * the slot reserved for the MDBX_txn object. A thread may use parallel
* read-only transactions. A read-only transaction may span threads if
* the user synchronizes its use. Applications that multiplex many
* user threads over individual OS threads need this option. Such an
@@ -1700,6 +1700,53 @@ LIBMDBX_API int mdbx_cursor_on_first(MDBX_cursor *mc);
/* Returns: MDBX_RESULT_TRUE, MDBX_RESULT_FALSE or Error code. */
LIBMDBX_API int mdbx_cursor_on_last(MDBX_cursor *mc);
+/* Estimates the distance between cursors as the number of elements.
+ * Both cursors must be initialized for the same DBI.
+ *
+ * [in] cursor_a The first cursor for estimation.
+ * [in] cursor_b The second cursor for estimation.
+ * [out] distance_items A pointer to store estimated distance value,
+ * i.e. *distance_items = distance(a - b).
+ *
+ * Returns A non-zero error value on failure and 0 on success. */
+LIBMDBX_API int mdbx_estimate_distance(const MDBX_cursor *first,
+ const MDBX_cursor *last,
+ ptrdiff_t *distance_items);
+
+/* Estimates the move distance, i.e. between the current cursor position and
+ * next position after the specified move-operation with given key and data.
+ * Current cursor position and state are preserved.
+ *
+ * [in] cursor Cursor for estimation.
+ * [in,out] key The key for a retrieved item.
+ * [in,out] data The data of a retrieved item.
+ * [in] op A cursor operation MDBX_cursor_op.
+ * [out] distance_items A pointer to store estimated move distance
+ * as the number of elements.
+ *
+ * Returns A non-zero error value on failure and 0 on success. */
+LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key,
+ MDBX_val *data, MDBX_cursor_op move_op,
+ ptrdiff_t *distance_items);
+
+/* Estimates the size of a range in the number of elements.
+ *
+ * [in] txn A transaction handle returned by mdbx_txn_begin().
+ * [in] dbi A database handle returned by mdbx_dbi_open().
+ * [in] begin_key The key of range beginning or NULL for explicit FIRST.
+ * [in] begin_data Optional additional data to seeking among sorted
+ * duplicates. Only for MDBX_DUPSORT, NULL otherwise.
+ * [in] end_key The key of range ending or NULL for explicit LAST.
+ * [in] end_data Optional additional data to seeking among sorted
+ * duplicates. Only for MDBX_DUPSORT, NULL otherwise.
+ * [out] distance_items A pointer to store range estimation result.
+ *
+ * Returns A non-zero error value on failure and 0 on success. */
+LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
+ MDBX_val *begin_key, MDBX_val *begin_data,
+ MDBX_val *end_key, MDBX_val *end_data,
+ ptrdiff_t *size_items);
+
LIBMDBX_API int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
MDBX_val *new_data, MDBX_val *old_data,
unsigned flags);
diff --git a/libs/libmdbx/src/src/bits.h b/libs/libmdbx/src/src/bits.h
index 3d3e392180..3325c327ae 100644
--- a/libs/libmdbx/src/src/bits.h
+++ b/libs/libmdbx/src/src/bits.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -29,6 +29,12 @@
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 500
+#endif
#ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
#endif
diff --git a/libs/libmdbx/src/src/defs.h b/libs/libmdbx/src/src/defs.h
index fb60b310ef..024322a1f2 100644
--- a/libs/libmdbx/src/src/defs.h
+++ b/libs/libmdbx/src/src/defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/lck-posix.c b/libs/libmdbx/src/src/lck-posix.c
index 2633d44791..e8d4539a1b 100644
--- a/libs/libmdbx/src/src/lck-posix.c
+++ b/libs/libmdbx/src/src/lck-posix.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -20,8 +20,8 @@
#ifndef MDBX_USE_ROBUST
/* Howard Chu: Android currently lacks Robust Mutex support */
#if defined(EOWNERDEAD) && \
- !defined(ANDROID) /* LY: glibc before 2.10 has a troubles with Robust \
- Mutex too. */ \
+ !defined(__ANDROID__) /* LY: glibc before 2.10 has a troubles \
+ with Robust Mutex too. */ \
&& __GLIBC_PREREQ(2, 10)
#define MDBX_USE_ROBUST 1
#else
diff --git a/libs/libmdbx/src/src/lck-windows.c b/libs/libmdbx/src/src/lck-windows.c
index 24fa09965c..822ba9c293 100644
--- a/libs/libmdbx/src/src/lck-windows.c
+++ b/libs/libmdbx/src/src/lck-windows.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/mdbx.c b/libs/libmdbx/src/src/mdbx.c
index 3203d30a30..84b2c1b125 100644
--- a/libs/libmdbx/src/src/mdbx.c
+++ b/libs/libmdbx/src/src/mdbx.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -406,7 +406,7 @@ __cold void mdbx_rthc_global_init(void) {
}
/* dtor called for thread, i.e. for all mdbx's environment objects */
-void mdbx_rthc_thread_dtor(void *ptr) {
+__cold void mdbx_rthc_thread_dtor(void *ptr) {
mdbx_rthc_lock();
mdbx_trace(">> pid %d, thread 0x%" PRIxPTR ", rthc %p", mdbx_getpid(),
(uintptr_t)mdbx_thread_self(), ptr);
@@ -2214,8 +2214,8 @@ static int __must_check_result mdbx_page_dirty(MDBX_txn *txn, MDBX_page *mp) {
return MDBX_SUCCESS;
}
-static int mdbx_mapresize(MDBX_env *env, const pgno_t size_pgno,
- const pgno_t limit_pgno) {
+__cold static int mdbx_mapresize(MDBX_env *env, const pgno_t size_pgno,
+ const pgno_t limit_pgno) {
#ifdef USE_VALGRIND
const size_t prev_mapsize = env->me_mapsize;
void *const prev_mapaddr = env->me_map;
@@ -2770,7 +2770,8 @@ done:
* [in] dst page to copy into
* [in] src page to copy from
* [in] psize size of a page */
-static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src, unsigned psize) {
+__hot static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src,
+ unsigned psize) {
STATIC_ASSERT(UINT16_MAX > MAX_PAGESIZE - PAGEHDRSZ);
STATIC_ASSERT(MIN_PAGESIZE > PAGEHDRSZ + NODESIZE * 42);
enum { Align = sizeof(pgno_t) };
@@ -2797,8 +2798,9 @@ static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src, unsigned psize) {
* [in] mp the page being referenced. It must not be dirty.
* [out] ret the writable page, if any.
* ret is unchanged if mp wasn't spilled. */
-static int __must_check_result mdbx_page_unspill(MDBX_txn *txn, MDBX_page *mp,
- MDBX_page **ret) {
+__hot static int __must_check_result mdbx_page_unspill(MDBX_txn *txn,
+ MDBX_page *mp,
+ MDBX_page **ret) {
MDBX_env *env = txn->mt_env;
const MDBX_txn *tx2;
unsigned x;
@@ -2856,7 +2858,7 @@ static int __must_check_result mdbx_page_unspill(MDBX_txn *txn, MDBX_page *mp,
* [in] mc cursor pointing to the page to be touched
*
* Returns 0 on success, non-zero on failure. */
-static int mdbx_page_touch(MDBX_cursor *mc) {
+__hot static int mdbx_page_touch(MDBX_cursor *mc) {
MDBX_page *mp = mc->mc_pg[mc->mc_top], *np;
MDBX_txn *txn = mc->mc_txn;
MDBX_cursor *m2, *m3;
@@ -2963,7 +2965,7 @@ fail:
return rc;
}
-static int mdbx_env_sync_ex(MDBX_env *env, int force, int nonblock) {
+__cold static int mdbx_env_sync_ex(MDBX_env *env, int force, int nonblock) {
if (unlikely(!env))
return MDBX_EINVAL;
@@ -3034,7 +3036,7 @@ static int mdbx_env_sync_ex(MDBX_env *env, int force, int nonblock) {
return MDBX_SUCCESS;
}
-int mdbx_env_sync(MDBX_env *env, int force) {
+__cold int mdbx_env_sync(MDBX_env *env, int force) {
return mdbx_env_sync_ex(env, force, false);
}
@@ -5127,7 +5129,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta,
/* LY: check and silently put mm_geo.now into [geo.lower...geo.upper].
*
- * Copy-with-compaction by previous version of libmfbx could produce DB-file
+ * Copy-with-compaction by previous version of libmdbx could produce DB-file
* less than meta.geo.lower bound, in case actual filling is low or no data
* at all. This is not a problem as there is no damage or loss of data.
* Therefore it is better not to consider such situation as an error, but
@@ -5643,11 +5645,10 @@ static int __cold mdbx_env_map(MDBX_env *env, size_t usedsize) {
return MDBX_SUCCESS;
}
-LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
- intptr_t size_now, intptr_t size_upper,
- intptr_t growth_step,
- intptr_t shrink_threshold,
- intptr_t pagesize) {
+__cold LIBMDBX_API int
+mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
+ intptr_t size_upper, intptr_t growth_step,
+ intptr_t shrink_threshold, intptr_t pagesize) {
if (unlikely(!env))
return MDBX_EINVAL;
@@ -5723,25 +5724,32 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
}
}
+ if (pagesize == 0)
+ pagesize = MIN_PAGESIZE;
+ else if (pagesize == INTPTR_MAX)
+ pagesize = MAX_PAGESIZE;
+
if (pagesize < (intptr_t)MIN_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
!mdbx_is_power2(pagesize)) {
rc = MDBX_EINVAL;
goto bailout;
}
- if (size_lower < 0) {
+ if (size_lower <= 0) {
size_lower = MIN_MAPSIZE;
if (MIN_MAPSIZE / pagesize < MIN_PAGENO)
size_lower = MIN_PAGENO * pagesize;
}
- if (size_now < 0) {
+ if (size_now <= 0) {
size_now = DEFAULT_MAPSIZE;
if (size_now < size_lower)
size_now = size_lower;
+ if (size_upper >= size_lower && size_now > size_upper)
+ size_now = size_upper;
}
- if (size_upper < 0) {
+ if (size_upper <= 0) {
if ((size_t)size_now >= MAX_MAPSIZE / 2)
size_upper = MAX_MAPSIZE;
else if (MAX_MAPSIZE != MAX_MAPSIZE32 &&
@@ -6489,8 +6497,10 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
int oflags;
if (F_ISSET(flags, MDBX_RDONLY))
oflags = O_RDONLY;
- else
+ else if (mode != 0)
oflags = O_RDWR | O_CREAT;
+ else
+ oflags = O_RDWR;
rc = mdbx_openfile(dxb_pathname, oflags, mode, &env->me_fd,
(env->me_flags & MDBX_EXCLUSIVE) ? true : false);
@@ -6711,7 +6721,9 @@ int __cold mdbx_env_close_ex(MDBX_env *env, int dont_sync) {
return rc;
}
-int mdbx_env_close(MDBX_env *env) { return mdbx_env_close_ex(env, false); }
+__cold int mdbx_env_close(MDBX_env *env) {
+ return mdbx_env_close_ex(env, false);
+}
/* Compare two items pointing at aligned unsigned int's. */
static int __hot mdbx_cmp_int_ai(const MDBX_val *a, const MDBX_val *b) {
@@ -6993,8 +7005,8 @@ static int mdbx_cursor_push(MDBX_cursor *mc, MDBX_page *mp) {
* 0=mapped page.
*
* Returns 0 on success, non-zero on failure. */
-static int mdbx_page_get(MDBX_cursor *mc, pgno_t pgno, MDBX_page **ret,
- int *lvl) {
+__hot static int mdbx_page_get(MDBX_cursor *mc, pgno_t pgno, MDBX_page **ret,
+ int *lvl) {
MDBX_txn *txn = mc->mc_txn;
MDBX_env *env = txn->mt_env;
MDBX_page *p = NULL;
@@ -7062,7 +7074,8 @@ done:
/* Finish mdbx_page_search() / mdbx_page_search_lowest().
* The cursor is at the root page, set up the rest of it. */
-static int mdbx_page_search_root(MDBX_cursor *mc, MDBX_val *key, int flags) {
+__hot static int mdbx_page_search_root(MDBX_cursor *mc, MDBX_val *key,
+ int flags) {
MDBX_page *mp = mc->mc_pg[mc->mc_top];
int rc;
DKBUF;
@@ -7145,7 +7158,7 @@ static int mdbx_page_search_root(MDBX_cursor *mc, MDBX_val *key, int flags) {
* before calling mdbx_page_search_root(), because the callers
* are all in situations where the current page is known to
* be underfilled. */
-static int mdbx_page_search_lowest(MDBX_cursor *mc) {
+__hot static int mdbx_page_search_lowest(MDBX_cursor *mc) {
MDBX_page *mp = mc->mc_pg[mc->mc_top];
mdbx_cassert(mc, IS_BRANCH(mp));
MDBX_node *node = NODEPTR(mp, 0);
@@ -7174,7 +7187,7 @@ static int mdbx_page_search_lowest(MDBX_cursor *mc) {
* lookups.
*
* Returns 0 on success, non-zero on failure. */
-static int mdbx_page_search(MDBX_cursor *mc, MDBX_val *key, int flags) {
+__hot static int mdbx_page_search(MDBX_cursor *mc, MDBX_val *key, int flags) {
int rc;
pgno_t root;
@@ -7689,8 +7702,8 @@ static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
}
/* Set the cursor on a specific data item. */
-static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
- MDBX_cursor_op op, int *exactp) {
+__hot static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
+ MDBX_cursor_op op, int *exactp) {
int rc;
MDBX_page *mp;
MDBX_node *leaf = NULL;
@@ -8300,7 +8313,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
if (rc > 0) {
rc = MDBX_NOTFOUND;
mc->mc_ki[mc->mc_top]++;
- } else {
+ } else if (unlikely(rc < 0 || (flags & MDBX_APPENDDUP) == 0)) {
/* new key is <= last key */
rc = MDBX_EKEYMISMATCH;
}
@@ -10882,7 +10895,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *newkey,
* This yields better packing during sequential inserts.
*/
int dir;
- if (nkeys < 20 || nsize > pmax / 16 || newindx >= nkeys) {
+ if (nkeys < 32 || nsize > pmax / 16 || newindx >= nkeys) {
/* Find split point */
psize = 0;
if (newindx <= split_indx || newindx >= nkeys) {
@@ -13159,11 +13172,362 @@ int mdbx_cursor_eof(MDBX_cursor *mc) {
return MDBX_RESULT_FALSE;
}
+//------------------------------------------------------------------------------
+
+struct diff_result {
+ ptrdiff_t diff;
+ int level;
+ int root_nkeys;
+};
+
+/* calculates: r = x - y */
+__hot static int cursor_diff(const MDBX_cursor *const __restrict x,
+ const MDBX_cursor *const __restrict y,
+ struct diff_result *const __restrict r) {
+ r->diff = 0;
+ r->level = 0;
+ r->root_nkeys = 0;
+
+ if (unlikely(y->mc_signature != MDBX_MC_SIGNATURE ||
+ x->mc_signature != MDBX_MC_SIGNATURE))
+ return MDBX_EBADSIGN;
+
+ if (unlikely(y->mc_dbi != x->mc_dbi))
+ return MDBX_EINVAL;
+
+ if (unlikely(!(y->mc_flags & x->mc_flags & C_INITIALIZED)))
+ return MDBX_ENODATA;
+
+ while (likely(r->level < y->mc_snum && r->level < x->mc_snum)) {
+ if (unlikely(y->mc_pg[r->level] != x->mc_pg[r->level]))
+ return MDBX_PROBLEM;
+
+ int nkeys = NUMKEYS(y->mc_pg[r->level]);
+ assert(nkeys > 0);
+ if (r->level == 0)
+ r->root_nkeys = nkeys;
+
+ const int limit_ki = nkeys - 1;
+ const int x_ki = x->mc_ki[r->level];
+ const int y_ki = y->mc_ki[r->level];
+ r->diff = ((x_ki < limit_ki) ? x_ki : limit_ki) -
+ ((y_ki < limit_ki) ? y_ki : limit_ki);
+ if (r->diff == 0) {
+ r->level += 1;
+ continue;
+ }
+
+ while (unlikely(r->diff == 1) &&
+ likely(r->level + 1 < y->mc_snum && r->level + 1 < x->mc_snum)) {
+ r->level += 1;
+ /* DB'PAGEs: 0------------------>MAX
+ *
+ * CURSORs: y < x
+ * STACK[i ]: |
+ * STACK[+1]: ...y++N|0++x...
+ */
+ nkeys = NUMKEYS(y->mc_pg[r->level]);
+ r->diff = (nkeys - y->mc_ki[r->level]) + x->mc_ki[r->level];
+ assert(r->diff > 0);
+ }
+
+ while (unlikely(r->diff == -1) &&
+ likely(r->level + 1 < y->mc_snum && r->level + 1 < x->mc_snum)) {
+ r->level += 1;
+ /* DB'PAGEs: 0------------------>MAX
+ *
+ * CURSORs: x < y
+ * STACK[i ]: |
+ * STACK[+1]: ...x--N|0--y...
+ */
+ nkeys = NUMKEYS(x->mc_pg[r->level]);
+ r->diff = -(nkeys - x->mc_ki[r->level]) - y->mc_ki[r->level];
+ assert(r->diff < 0);
+ }
+
+ return MDBX_SUCCESS;
+ }
+
+ r->diff = mdbx_cmp2int(x->mc_flags & C_EOF, y->mc_flags & C_EOF);
+ return MDBX_SUCCESS;
+}
+
+__hot static ptrdiff_t estimate(const MDBX_db *db,
+ struct diff_result *const __restrict dr) {
+ /* root: branch-page => scale = leaf-factor * branch-factor^(N-1)
+ * level-1: branch-page(s) => scale = leaf-factor * branch-factor^2
+ * level-2: branch-page(s) => scale = leaf-factor * branch-factor
+ * level-N: branch-page(s) => scale = leaf-factor
+ * last-level: leaf-page(s) => scale = 1
+ */
+ ptrdiff_t btree_power = db->md_depth - 2 - dr->level;
+ if (btree_power < 0)
+ return dr->diff;
+
+ ptrdiff_t estimated =
+ (ptrdiff_t)db->md_entries * dr->diff / (ptrdiff_t)db->md_leaf_pages;
+ if (btree_power == 0)
+ return estimated;
+
+ if (db->md_depth < 4) {
+ assert(dr->level == 0 && btree_power == 1);
+ return (ptrdiff_t)db->md_entries * dr->diff / (ptrdiff_t)dr->root_nkeys;
+ }
+
+ /* average_branchpage_fillfactor = total(branch_entries) / branch_pages
+ total(branch_entries) = leaf_pages + branch_pages - 1 (root page) */
+ const size_t log2_fixedpoint = sizeof(size_t) - 1;
+ const size_t half = UINT64_C(1) << (log2_fixedpoint - 1);
+ const size_t factor =
+ ((db->md_leaf_pages + db->md_branch_pages - 1) << log2_fixedpoint) /
+ db->md_branch_pages;
+ while (1) {
+ switch ((size_t)btree_power) {
+ default: {
+ const size_t square = (factor * factor + half) >> log2_fixedpoint;
+ const size_t quad = (square * square + half) >> log2_fixedpoint;
+ do {
+ estimated = estimated * quad + half;
+ estimated >>= log2_fixedpoint;
+ btree_power -= 4;
+ } while (btree_power >= 4);
+ continue;
+ }
+ case 3:
+ estimated = estimated * factor + half;
+ estimated >>= log2_fixedpoint;
+ __fallthrough /* fall through */;
+ case 2:
+ estimated = estimated * factor + half;
+ estimated >>= log2_fixedpoint;
+ __fallthrough /* fall through */;
+ case 1:
+ estimated = estimated * factor + half;
+ estimated >>= log2_fixedpoint;
+ __fallthrough /* fall through */;
+ case 0:
+ if (unlikely(estimated > (ptrdiff_t)db->md_entries))
+ return (ptrdiff_t)db->md_entries;
+ if (unlikely(estimated < -(ptrdiff_t)db->md_entries))
+ return -(ptrdiff_t)db->md_entries;
+ return estimated;
+ }
+ }
+}
+
+__hot int mdbx_estimate_distance(const MDBX_cursor *first,
+ const MDBX_cursor *last,
+ ptrdiff_t *distance_items) {
+ if (unlikely(first == NULL || last == NULL || distance_items == NULL))
+ return MDBX_EINVAL;
+
+ *distance_items = 0;
+ struct diff_result dr;
+ int rc = cursor_diff(last, first, &dr);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+
+ if (unlikely(dr.diff == 0) &&
+ F_ISSET(first->mc_db->md_flags & first->mc_db->md_flags,
+ MDBX_DUPSORT | C_INITIALIZED)) {
+ first = &first->mc_xcursor->mx_cursor;
+ last = &last->mc_xcursor->mx_cursor;
+ rc = cursor_diff(first, last, &dr);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+ }
+
+ if (likely(dr.diff != 0))
+ *distance_items = estimate(first->mc_db, &dr);
+
+ return MDBX_SUCCESS;
+}
+
+int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
+ MDBX_cursor_op move_op, ptrdiff_t *distance_items) {
+ if (unlikely(cursor == NULL || distance_items == NULL ||
+ move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE))
+ return MDBX_EINVAL;
+
+ if (unlikely(cursor->mc_signature != MDBX_MC_SIGNATURE))
+ return MDBX_EBADSIGN;
+
+ if (!(cursor->mc_flags & C_INITIALIZED))
+ return MDBX_ENODATA;
+
+ MDBX_cursor_couple next;
+ mdbx_cursor_copy(cursor, &next.outer);
+ next.outer.mc_xcursor = NULL;
+ if (cursor->mc_db->md_flags & MDBX_DUPSORT) {
+ next.outer.mc_xcursor = &next.inner;
+ int rc = mdbx_xcursor_init0(&next.outer);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+ MDBX_xcursor *mx = &container_of(cursor, MDBX_cursor_couple, outer)->inner;
+ mdbx_cursor_copy(&mx->mx_cursor, &next.inner.mx_cursor);
+ }
+
+ MDBX_val stub = {0, 0};
+ if (data == NULL) {
+ const unsigned mask =
+ 1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE | 1 << MDBX_SET_KEY;
+ if (unlikely(mask & (1 << move_op)))
+ return MDBX_EINVAL;
+ data = &stub;
+ }
+
+ if (key == NULL) {
+ const unsigned mask = 1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE |
+ 1 << MDBX_SET_KEY | 1 << MDBX_SET |
+ 1 << MDBX_SET_RANGE;
+ if (unlikely(mask & (1 << move_op)))
+ return MDBX_EINVAL;
+ key = &stub;
+ }
+
+ int rc = mdbx_cursor_get(&next.outer, key, data, move_op);
+ if (unlikely(rc != MDBX_SUCCESS &&
+ (rc != MDBX_NOTFOUND || !(next.outer.mc_flags & C_INITIALIZED))))
+ return rc;
+
+ return mdbx_estimate_distance(cursor, &next.outer, distance_items);
+}
+
static int mdbx_is_samedata(const MDBX_val *a, const MDBX_val *b) {
return a->iov_len == b->iov_len &&
memcmp(a->iov_base, b->iov_base, a->iov_len) == 0;
}
+int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
+ MDBX_val *begin_data, MDBX_val *end_key,
+ MDBX_val *end_data, ptrdiff_t *size_items) {
+
+ if (unlikely(!txn || !size_items))
+ return MDBX_EINVAL;
+
+ if (unlikely(!begin_key && begin_data))
+ return MDBX_EINVAL;
+
+ if (unlikely(!end_key && end_data))
+ return MDBX_EINVAL;
+
+ if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
+ return MDBX_EBADSIGN;
+
+ if (unlikely(txn->mt_owner != mdbx_thread_self()))
+ return MDBX_THREAD_MISMATCH;
+
+ if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
+ return MDBX_EINVAL;
+
+ if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
+ return MDBX_BAD_TXN;
+
+ MDBX_cursor_couple begin;
+ /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */
+ int rc = mdbx_cursor_init(&begin.outer, txn, dbi);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+
+ if (unlikely(begin.outer.mc_db->md_entries == 0)) {
+ *size_items = 0;
+ return MDBX_SUCCESS;
+ }
+
+ if (!begin_key) {
+ if (unlikely(!end_key)) {
+ /* LY: FIRST..LAST case */
+ *size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
+ return MDBX_SUCCESS;
+ }
+ MDBX_val stub = {0, 0};
+ rc = mdbx_cursor_first(&begin.outer, &stub, &stub);
+ } else if (end_key && !begin_data && !end_data &&
+ (begin_key == end_key || mdbx_is_samedata(begin_key, end_key))) {
+ /* LY: single key case */
+ int exact = 0;
+ rc = mdbx_cursor_set(&begin.outer, begin_key, NULL, MDBX_SET, &exact);
+ if (unlikely(rc != MDBX_SUCCESS)) {
+ *size_items = 0;
+ return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
+ }
+ *size_items = 1;
+ if (begin.outer.mc_xcursor != NULL) {
+ MDBX_node *leaf = NODEPTR(begin.outer.mc_pg[begin.outer.mc_top],
+ begin.outer.mc_ki[begin.outer.mc_top]);
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ /* LY: return the number of duplicates for given key */
+ mdbx_tassert(txn, begin.outer.mc_xcursor == &begin.inner &&
+ (begin.inner.mx_cursor.mc_flags & C_INITIALIZED));
+ *size_items =
+ (sizeof(*size_items) >= sizeof(begin.inner.mx_db.md_entries) ||
+ begin.inner.mx_db.md_entries <= SIZE_MAX)
+ ? (size_t)begin.inner.mx_db.md_entries
+ : SIZE_MAX;
+ }
+ }
+ return MDBX_SUCCESS;
+ } else {
+ rc = mdbx_cursor_set(&begin.outer, begin_key, begin_data,
+ begin_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE,
+ NULL);
+ }
+
+ if (unlikely(rc != MDBX_SUCCESS)) {
+ if (rc != MDBX_NOTFOUND || !(begin.outer.mc_flags & C_INITIALIZED))
+ return rc;
+ }
+
+ MDBX_cursor_couple end;
+ rc = mdbx_cursor_init(&end.outer, txn, dbi);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+ if (!end_key) {
+ MDBX_val stub = {0, 0};
+ rc = mdbx_cursor_last(&end.outer, &stub, &stub);
+ } else {
+ rc = mdbx_cursor_set(&end.outer, end_key, end_data,
+ end_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE, NULL);
+ }
+ if (unlikely(rc != MDBX_SUCCESS)) {
+ if (rc != MDBX_NOTFOUND || !(end.outer.mc_flags & C_INITIALIZED))
+ return rc;
+ }
+
+ rc = mdbx_estimate_distance(&begin.outer, &end.outer, size_items);
+ if (unlikely(rc != MDBX_SUCCESS))
+ return rc;
+ assert(*size_items >= -(ptrdiff_t)begin.outer.mc_db->md_entries &&
+ *size_items <= (ptrdiff_t)begin.outer.mc_db->md_entries);
+
+#if 0 /* LY: Was decided to returns as-is (i.e. negative) the estimation \
+ * results for an inverted ranges. */
+
+ /* Commit 8ddfd1f34ad7cf7a3c4aa75d2e248ca7e639ed63
+ Change-Id: If59eccf7311123ab6384c4b93f9b1fed5a0a10d1 */
+
+ if (*size_items < 0) {
+ /* LY: inverted range case */
+ *size_items += (ptrdiff_t)begin.outer.mc_db->md_entries;
+ } else if (*size_items == 0 && begin_key && end_key) {
+ int cmp = begin.outer.mc_dbx->md_cmp(&origin_begin_key, &origin_end_key);
+ if (cmp == 0 && (begin.inner.mx_cursor.mc_flags & C_INITIALIZED) &&
+ begin_data && end_data)
+ cmp = begin.outer.mc_dbx->md_dcmp(&origin_begin_data, &origin_end_data);
+ if (cmp > 0) {
+ /* LY: inverted range case with empty scope */
+ *size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
+ }
+ }
+ assert(*size_items >= 0 &&
+ *size_items <= (ptrdiff_t)begin.outer.mc_db->md_entries);
+#endif
+
+ return MDBX_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+
/* Позволяет обновить или удалить существующую запись с получением
* в old_data предыдущего значения данных. При этом если new_data равен
* нулю, то выполняется удаление, иначе обновление/вставка.
diff --git a/libs/libmdbx/src/src/osal.c b/libs/libmdbx/src/src/osal.c
index 4650519348..e3997e2a45 100644
--- a/libs/libmdbx/src/src/osal.c
+++ b/libs/libmdbx/src/src/osal.c
@@ -1,7 +1,7 @@
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -153,8 +153,10 @@ typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 {
/*----------------------------------------------------------------------------*/
-#ifndef _MSC_VER
-/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 3.1 */
+#if !defined(_MSC_VER) && \
+ /* workaround for avoid musl libc wrong prototype */ ( \
+ defined(__GLIBC__) || defined(__GNU_LIBRARY__))
+/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 1.x-3.x */
__nothrow __noreturn void __assert_fail(const char *assertion, const char *file,
unsigned line, const char *function);
#endif /* _MSC_VER */
@@ -673,34 +675,27 @@ int mdbx_filesync(mdbx_filehandle_t fd, bool filesize_changed) {
#if defined(_WIN32) || defined(_WIN64)
(void)filesize_changed;
return FlushFileBuffers(fd) ? MDBX_SUCCESS : GetLastError();
-#elif __GLIBC_PREREQ(2, 16) || _BSD_SOURCE || _XOPEN_SOURCE || \
- (__GLIBC_PREREQ(2, 8) && _POSIX_C_SOURCE >= 200112L)
- for (;;) {
-/* LY: It is no reason to use fdatasync() here, even in case
- * no such bug in a kernel. Because "no-bug" mean that a kernel
- * internally do nearly the same, e.g. fdatasync() == fsync()
- * when no-kernel-bug and file size was changed.
- *
- * So, this code is always safe and without appreciable
- * performance degradation.
- *
- * For more info about of a corresponding fdatasync() bug
- * see http://www.spinics.net/lists/linux-ext4/msg33714.html */
-#if _POSIX_C_SOURCE >= 199309L || _XOPEN_SOURCE >= 500 || \
- defined(_POSIX_SYNCHRONIZED_IO)
- if (!filesize_changed && fdatasync(fd) == 0)
- return MDBX_SUCCESS;
+#else
+ int rc;
+ do {
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+ /* LY: This code is always safe and without appreciable performance
+ * degradation, even on a kernel with fdatasync's bug.
+ *
+ * For more info about of a corresponding fdatasync() bug
+ * see http://www.spinics.net/lists/linux-ext4/msg33714.html */
+ if (!filesize_changed) {
+ if (fdatasync(fd) == 0)
+ return MDBX_SUCCESS;
+ } else
#else
(void)filesize_changed;
#endif
- if (fsync(fd) == 0)
+ if (fsync(fd) == 0)
return MDBX_SUCCESS;
- int rc = errno;
- if (rc != EINTR)
- return rc;
- }
-#else
-#error FIXME
+ rc = errno;
+ } while (rc == EINTR);
+ return rc;
#endif
}
diff --git a/libs/libmdbx/src/src/osal.h b/libs/libmdbx/src/src/osal.h
index 101605be05..0208a52254 100644
--- a/libs/libmdbx/src/src/osal.h
+++ b/libs/libmdbx/src/src/osal.h
@@ -1,7 +1,7 @@
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/tools/mdbx_chk.c b/libs/libmdbx/src/src/tools/mdbx_chk.c
index 31119ba66e..64349cd392 100644
--- a/libs/libmdbx/src/src/tools/mdbx_chk.c
+++ b/libs/libmdbx/src/src/tools/mdbx_chk.c
@@ -1,7 +1,7 @@
/* mdbx_chk.c - memory-mapped database check tool */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -92,7 +92,8 @@ MDBX_envinfo envinfo;
MDBX_stat envstat;
size_t maxkeysize, userdb_count, skipped_subdb;
uint64_t reclaimable_pages, gc_pages, lastpgno, unused_pages;
-unsigned verbose, quiet;
+unsigned verbose;
+char ignore_wrong_order, quiet;
const char *only_subdb;
struct problem {
@@ -615,6 +616,8 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
saved_list = problems_push();
prev_key.iov_base = NULL;
+ prev_key.iov_len = 0;
+ prev_data.iov_base = NULL;
prev_data.iov_len = 0;
rc = mdbx_cursor_get(mc, &key, &data, MDBX_FIRST);
while (rc == MDBX_SUCCESS) {
@@ -648,18 +651,25 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
}
int cmp = mdbx_cmp(txn, dbi_handle, &prev_key, &key);
- if (cmp > 0) {
- problem_add("entry", record_count, "broken ordering of entries", NULL);
- } else if (cmp == 0) {
+ if (cmp == 0) {
++dups;
- if (!(flags & MDBX_DUPSORT))
+ if ((flags & MDBX_DUPSORT) == 0) {
problem_add("entry", record_count, "duplicated entries", NULL);
- else if (flags & MDBX_INTEGERDUP) {
+ if (data.iov_len == prev_data.iov_len &&
+ memcmp(data.iov_base, prev_data.iov_base, data.iov_len) == 0) {
+ problem_add("entry", record_count, "complete duplicate", NULL);
+ }
+ } else {
cmp = mdbx_dcmp(txn, dbi_handle, &prev_data, &data);
- if (cmp > 0)
- problem_add("entry", record_count,
- "broken ordering of multi-values", NULL);
+ if (cmp == 0) {
+ problem_add("entry", record_count, "complete duplicate", NULL);
+ } else if (cmp > 0 && !ignore_wrong_order) {
+ problem_add("entry", record_count, "wrong order of multi-values",
+ NULL);
+ }
}
+ } else if (cmp > 0 && !ignore_wrong_order) {
+ problem_add("entry", record_count, "wrong order of entries", NULL);
}
} else if (verbose) {
if (flags & MDBX_INTEGERKEY)
@@ -714,7 +724,8 @@ static void usage(char *prog) {
" -w\t\tlock DB for writing while checking\n"
" -d\t\tdisable page-by-page traversal of b-tree\n"
" -s subdb\tprocess a specific subdatabase only\n"
- " -c\t\tforce cooperative mode (don't try exclusive)\n",
+ " -c\t\tforce cooperative mode (don't try exclusive)\n"
+ " -i\t\tignore wrong order errors (for custom comparators case)\n",
prog);
exit(EXIT_INTERRUPTED);
}
@@ -898,7 +909,7 @@ int main(int argc, char *argv[]) {
usage(prog);
}
- for (int i; (i = getopt(argc, argv, "Vvqnwcds:")) != EOF;) {
+ for (int i; (i = getopt(argc, argv, "Vvqnwcdsi:")) != EOF;) {
switch (i) {
case 'V':
printf("%s (%s, build %s)\n", mdbx_version.git.describe,
@@ -928,6 +939,9 @@ int main(int argc, char *argv[]) {
usage(prog);
only_subdb = optarg;
break;
+ case 'i':
+ ignore_wrong_order = 1;
+ break;
default:
usage(prog);
}
diff --git a/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj b/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj
index f87c687526..e6c2686286 100644
--- a/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj
+++ b/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj
@@ -22,6 +22,7 @@
<ProjectGuid>{15030120-5F7F-48F9-ABE5-DFC814F2A4BE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbx_chk</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/src/tools/mdbx_copy.1 b/libs/libmdbx/src/src/tools/mdbx_copy.1
index db6c453abd..74d94b6b98 100644
--- a/libs/libmdbx/src/src/tools/mdbx_copy.1
+++ b/libs/libmdbx/src/src/tools/mdbx_copy.1
@@ -1,4 +1,4 @@
-.\" Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+.\" Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
diff --git a/libs/libmdbx/src/src/tools/mdbx_copy.c b/libs/libmdbx/src/src/tools/mdbx_copy.c
index ee3f739d4d..9b0c833a37 100644
--- a/libs/libmdbx/src/src/tools/mdbx_copy.c
+++ b/libs/libmdbx/src/src/tools/mdbx_copy.c
@@ -1,7 +1,7 @@
/* mdbx_copy.c - memory-mapped database backup tool */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj b/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj
index 09bdc78fe7..d47513c204 100644
--- a/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj
+++ b/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj
@@ -22,6 +22,7 @@
<ProjectGuid>{15030120-5F7F-48F9-ABE5-DFC814F2A4BD}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbx_copy</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/src/tools/mdbx_dump.1 b/libs/libmdbx/src/src/tools/mdbx_dump.1
index ccfcc0c9da..93d29a7cf3 100644
--- a/libs/libmdbx/src/src/tools/mdbx_dump.1
+++ b/libs/libmdbx/src/src/tools/mdbx_dump.1
@@ -1,4 +1,4 @@
-.\" Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+.\" Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
diff --git a/libs/libmdbx/src/src/tools/mdbx_dump.c b/libs/libmdbx/src/src/tools/mdbx_dump.c
index d16215622e..07951548dd 100644
--- a/libs/libmdbx/src/src/tools/mdbx_dump.c
+++ b/libs/libmdbx/src/src/tools/mdbx_dump.c
@@ -1,7 +1,7 @@
/* mdbx_dump.c - memory-mapped database dump tool */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj b/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj
index 1e2ff8450f..6978a2c22d 100644
--- a/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj
+++ b/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj
@@ -22,6 +22,7 @@
<ProjectGuid>{15030120-5F7F-48F9-ABE5-DFC814F2A4BC}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbx_dump</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/src/tools/mdbx_load.1 b/libs/libmdbx/src/src/tools/mdbx_load.1
index 7a18a6c018..e23ec78eee 100644
--- a/libs/libmdbx/src/src/tools/mdbx_load.1
+++ b/libs/libmdbx/src/src/tools/mdbx_load.1
@@ -1,4 +1,4 @@
-.\" Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+.\" Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
@@ -39,6 +39,13 @@ option below.
.BR \-V
Write the library version number to the standard output, and exit.
.TP
+.BR \-a
+Append all records in the order they appear in the input. The input is assumed to already be
+in correctly sorted order and no sorting or checking for redundant values will be performed.
+This option must be used to reload data that was produced by running
+.B mdbx_dump
+on a database that uses custom compare functions.
+.TP
.BR \-f \ file
Read from the specified file instead of from the standard input.
.TP
diff --git a/libs/libmdbx/src/src/tools/mdbx_load.c b/libs/libmdbx/src/src/tools/mdbx_load.c
index 697e3e166f..9789e83a62 100644
--- a/libs/libmdbx/src/src/tools/mdbx_load.c
+++ b/libs/libmdbx/src/src/tools/mdbx_load.c
@@ -1,7 +1,7 @@
-/* mdbx_load.c - memory-mapped database load tool */
+/* mdbx_load.c - memory-mapped database load tool */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -57,6 +57,7 @@ static int Eof;
static MDBX_envinfo envinfo;
static MDBX_val kbuf, dbuf;
+static MDBX_val k0buf;
#define STRLENOF(s) (sizeof(s) - 1)
@@ -304,11 +305,18 @@ static int readline(MDBX_val *out, MDBX_val *buf) {
}
static void usage(void) {
- fprintf(stderr, "usage: %s [-V] [-f input] [-n] [-s name] [-N] [-T] dbpath\n",
+ fprintf(stderr,
+ "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n",
prog);
exit(EXIT_FAILURE);
}
+static int anyway_greater(const MDBX_val *a, const MDBX_val *b) {
+ (void)a;
+ (void)b;
+ return 1;
+}
+
int main(int argc, char *argv[]) {
int i, rc;
MDBX_env *env = NULL;
@@ -316,28 +324,32 @@ int main(int argc, char *argv[]) {
MDBX_cursor *mc = NULL;
MDBX_dbi dbi;
char *envname = NULL;
- int envflags = 0, putflags = 0;
+ int envflags = MDBX_UTTERLY_NOSYNC, putflags = 0;
+ int append = 0;
+ MDBX_val prevk;
prog = argv[0];
-
- if (argc < 2) {
+ if (argc < 2)
usage();
- }
- /* -f: load file instead of stdin
+ /* -a: append records in input order
+ * -f: load file instead of stdin
* -n: use NOSUBDIR flag on env_open
* -s: load into named subDB
* -N: use NOOVERWRITE on puts
* -T: read plaintext
* -V: print version and exit
*/
- while ((i = getopt(argc, argv, "f:ns:NTV")) != EOF) {
+ while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) {
switch (i) {
case 'V':
printf("%s (%s, build %s)\n", mdbx_version.git.describe,
mdbx_version.git.datetime, mdbx_build.datetime);
exit(EXIT_SUCCESS);
break;
+ case 'a':
+ append = 1;
+ break;
case 'f':
if (freopen(optarg, "r", stdin) == NULL) {
fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg,
@@ -381,6 +393,7 @@ int main(int argc, char *argv[]) {
dbuf.iov_len = 4096;
dbuf.iov_base = mdbx_malloc(dbuf.iov_len);
+ /* read first header for mapsize= */
if (!(mode & NOHDR))
readhdr();
@@ -418,8 +431,17 @@ int main(int argc, char *argv[]) {
goto env_close;
}
- kbuf.iov_len = mdbx_env_get_maxkeysize(env) * 2 + 2;
- kbuf.iov_base = mdbx_malloc(kbuf.iov_len);
+ kbuf.iov_len = mdbx_env_get_maxkeysize(env);
+ if (kbuf.iov_len >= SIZE_MAX / 4) {
+ fprintf(stderr, "mdbx_env_get_maxkeysize failed, returns %zu\n",
+ kbuf.iov_len);
+ goto env_close;
+ }
+ kbuf.iov_len = (kbuf.iov_len + 1) * 2;
+ kbuf.iov_base = malloc(kbuf.iov_len * 2);
+ k0buf.iov_len = kbuf.iov_len;
+ k0buf.iov_base = (char *)kbuf.iov_base + kbuf.iov_len;
+ prevk.iov_base = k0buf.iov_base;
while (!Eof) {
if (user_break) {
@@ -427,9 +449,6 @@ int main(int argc, char *argv[]) {
break;
}
- MDBX_val key, data;
- int batch = 0;
-
rc = mdbx_txn_begin(env, NULL, 0, &txn);
if (rc) {
fprintf(stderr, "mdbx_txn_begin failed, error %d %s\n", rc,
@@ -437,7 +456,9 @@ int main(int argc, char *argv[]) {
goto env_close;
}
- rc = mdbx_dbi_open(txn, subname, dbi_flags | MDBX_CREATE, &dbi);
+ rc = mdbx_dbi_open_ex(txn, subname, dbi_flags | MDBX_CREATE, &dbi,
+ append ? anyway_greater : NULL,
+ append ? anyway_greater : NULL);
if (rc) {
fprintf(stderr, "mdbx_open failed, error %d %s\n", rc, mdbx_strerror(rc));
goto txn_abort;
@@ -450,11 +471,15 @@ int main(int argc, char *argv[]) {
goto txn_abort;
}
+ int batch = 0;
+ prevk.iov_len = 0;
while (1) {
+ MDBX_val key;
rc = readline(&key, &kbuf);
if (rc) /* rc == EOF */
break;
+ MDBX_val data;
rc = readline(&data, &dbuf);
if (rc) {
fprintf(stderr, "%s: line %" PRIiSIZE ": failed to read key value\n",
@@ -462,7 +487,18 @@ int main(int argc, char *argv[]) {
goto txn_abort;
}
- rc = mdbx_cursor_put(mc, &key, &data, putflags);
+ int appflag = 0;
+ if (append) {
+ appflag = MDBX_APPEND;
+ if (dbi_flags & MDBX_DUPSORT) {
+ if (prevk.iov_len == key.iov_len &&
+ memcmp(prevk.iov_base, key.iov_base, key.iov_len) == 0)
+ appflag = MDBX_APPEND | MDBX_APPENDDUP;
+ else
+ memcpy(prevk.iov_base, key.iov_base, prevk.iov_len = key.iov_len);
+ }
+ }
+ rc = mdbx_cursor_put(mc, &key, &data, putflags | appflag);
if (rc == MDBX_KEYEXIST && putflags)
continue;
if (rc) {
@@ -501,6 +537,8 @@ int main(int argc, char *argv[]) {
goto env_close;
}
mdbx_dbi_close(env, dbi);
+
+ /* try read next header */
if (!(mode & NOHDR))
readhdr();
}
diff --git a/libs/libmdbx/src/src/tools/mdbx_load.vcxproj b/libs/libmdbx/src/src/tools/mdbx_load.vcxproj
index 483d9b6104..05a100fc64 100644
--- a/libs/libmdbx/src/src/tools/mdbx_load.vcxproj
+++ b/libs/libmdbx/src/src/tools/mdbx_load.vcxproj
@@ -22,6 +22,7 @@
<ProjectGuid>{15030120-5F7F-48F9-ABE5-DFC814F2A4BB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbx_load</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/src/tools/mdbx_stat.1 b/libs/libmdbx/src/src/tools/mdbx_stat.1
index ca427f7a66..50a30b4f97 100644
--- a/libs/libmdbx/src/src/tools/mdbx_stat.1
+++ b/libs/libmdbx/src/src/tools/mdbx_stat.1
@@ -1,4 +1,4 @@
-.\" Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+.\" Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
diff --git a/libs/libmdbx/src/src/tools/mdbx_stat.c b/libs/libmdbx/src/src/tools/mdbx_stat.c
index 95a6cdd23c..e459121d76 100644
--- a/libs/libmdbx/src/src/tools/mdbx_stat.c
+++ b/libs/libmdbx/src/src/tools/mdbx_stat.c
@@ -1,7 +1,7 @@
/* mdbx_stat.c - memory-mapped database status tool */
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj b/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj
index 53f649bfd9..4027491d39 100644
--- a/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj
+++ b/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj
@@ -22,6 +22,7 @@
<ProjectGuid>{15030120-5F7F-48F9-ABE5-DFC814F2A4BF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbx_stat</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/libs/libmdbx/src/test/CMakeLists.txt b/libs/libmdbx/src/test/CMakeLists.txt
index ca7dd794cd..88fd09e01b 100644
--- a/libs/libmdbx/src/test/CMakeLists.txt
+++ b/libs/libmdbx/src/test/CMakeLists.txt
@@ -27,6 +27,7 @@ add_executable(${TARGET}
try.cc
utils.cc
utils.h
+ append.cc
)
target_link_libraries(${TARGET}
diff --git a/libs/libmdbx/src/test/append.cc b/libs/libmdbx/src/test/append.cc
new file mode 100644
index 0000000000..3ce53eb292
--- /dev/null
+++ b/libs/libmdbx/src/test/append.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
+ * and other libmdbx authors: please see AUTHORS file.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "test.h"
+
+bool testcase_append::run() {
+ db_open();
+
+ txn_begin(false);
+ MDBX_dbi dbi = db_table_open(true);
+ int rc = mdbx_drop(txn_guard.get(), dbi, false);
+ if (unlikely(rc != MDBX_SUCCESS))
+ failure_perror("mdbx_drop(delete=false)", rc);
+
+ keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
+ /* LY: тест наполнения таблиц в append-режиме,
+ * при котором записи добавляются строго в конец (в порядке сортировки) */
+ const unsigned flags = (config.params.table_flags & MDBX_DUPSORT)
+ ? MDBX_APPEND | MDBX_APPENDDUP
+ : MDBX_APPEND;
+ keyvalue_maker.make_ordered();
+
+ key = keygen::alloc(config.params.keylen_max);
+ data = keygen::alloc(config.params.datalen_max);
+ keygen::buffer last_key = keygen::alloc(config.params.keylen_max);
+ keygen::buffer last_data = keygen::alloc(config.params.datalen_max);
+ last_key->value.iov_base = last_key->bytes;
+ last_key->value.iov_len = 0;
+ last_data->value.iov_base = last_data->bytes;
+ last_data->value.iov_len = 0;
+
+ simple_checksum inserted_checksum;
+ uint64_t inserted_number = 0;
+ uint64_t serial_count = 0;
+ unsigned txn_nops = 0;
+ while (should_continue()) {
+ const keygen::serial_t serial = serial_count;
+ if (!keyvalue_maker.increment(serial_count, 1)) {
+ // дошли до границы пространства ключей
+ break;
+ }
+
+ log_trace("append: append-a %" PRIu64, serial);
+ generate_pair(serial, key, data);
+ int cmp = inserted_number ? mdbx_cmp(txn_guard.get(), dbi, &key->value,
+ &last_key->value)
+ : 1;
+ if (cmp == 0 && (config.params.table_flags & MDBX_DUPSORT))
+ cmp = mdbx_dcmp(txn_guard.get(), dbi, &data->value, &last_data->value);
+
+ rc = mdbx_put(txn_guard.get(), dbi, &key->value, &data->value, flags);
+ if (cmp > 0) {
+ if (unlikely(rc != MDBX_SUCCESS))
+ failure_perror("mdbx_put(appenda-a)", rc);
+ memcpy(last_key->value.iov_base, key->value.iov_base,
+ last_key->value.iov_len = key->value.iov_len);
+ memcpy(last_data->value.iov_base, data->value.iov_base,
+ last_data->value.iov_len = data->value.iov_len);
+ ++inserted_number;
+ inserted_checksum.push((uint32_t)inserted_number, key->value);
+ inserted_checksum.push(10639, data->value);
+ } else {
+ if (unlikely(rc != MDBX_EKEYMISMATCH))
+ failure_perror("mdbx_put(appenda-a) != MDBX_EKEYMISMATCH", rc);
+ }
+
+ if (++txn_nops >= config.params.batch_write) {
+ txn_restart(false, false);
+ txn_nops = 0;
+ }
+
+ report(1);
+ }
+
+ txn_restart(false, true);
+ //----------------------------------------------------------------------------
+ cursor_open(dbi);
+
+ MDBX_val check_key, check_data;
+ rc = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_FIRST);
+ if (unlikely(rc != MDBX_SUCCESS))
+ failure_perror("mdbx_cursor_get(MDBX_FIRST)", rc);
+
+ simple_checksum read_checksum;
+ uint64_t read_count = 0;
+ while (rc == MDBX_SUCCESS) {
+ ++read_count;
+ read_checksum.push((uint32_t)read_count, check_key);
+ read_checksum.push(10639, check_data);
+
+ rc =
+ mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_NEXT);
+ }
+
+ if (unlikely(rc != MDBX_NOTFOUND))
+ failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", rc);
+
+ if (unlikely(read_count != inserted_number))
+ failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")",
+ read_count, inserted_number);
+
+ if (unlikely(read_checksum.value != inserted_checksum.value))
+ failure("read_checksum(0x%016" PRIu64 ") "
+ "!= inserted_checksum(0x%016" PRIu64 ")",
+ read_checksum.value, inserted_checksum.value);
+
+ cursor_close();
+ //----------------------------------------------------------------------------
+ if (txn_guard)
+ txn_end(false);
+
+ if (dbi) {
+ if (config.params.drop_table && !mode_readonly()) {
+ txn_begin(false);
+ db_table_drop(dbi);
+ txn_end(false);
+ } else
+ db_table_close(dbi);
+ }
+ return true;
+}
diff --git a/libs/libmdbx/src/test/base.h b/libs/libmdbx/src/test/base.h
index b23f776aa3..0b4d26e51b 100644
--- a/libs/libmdbx/src/test/base.h
+++ b/libs/libmdbx/src/test/base.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/cases.cc b/libs/libmdbx/src/test/cases.cc
index 13d475763a..1d41efc82b 100644
--- a/libs/libmdbx/src/test/cases.cc
+++ b/libs/libmdbx/src/test/cases.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -69,6 +69,7 @@ void testcase_setup(const char *casename, actor_params &params,
configure_actor(last_space_id, ac_hill, nullptr, params);
configure_actor(last_space_id, ac_try, nullptr, params);
configure_actor(last_space_id, ac_copy, nullptr, params);
+ configure_actor(last_space_id, ac_append, nullptr, params);
log_notice("<<< testcase_setup(%s): done", casename);
} else {
failure("unknown testcase `%s`", casename);
diff --git a/libs/libmdbx/src/test/chrono.cc b/libs/libmdbx/src/test/chrono.cc
index f734668628..38cb321a81 100644
--- a/libs/libmdbx/src/test/chrono.cc
+++ b/libs/libmdbx/src/test/chrono.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/chrono.h b/libs/libmdbx/src/test/chrono.h
index c2bd5627a6..11675195ac 100644
--- a/libs/libmdbx/src/test/chrono.h
+++ b/libs/libmdbx/src/test/chrono.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/config.cc b/libs/libmdbx/src/test/config.cc
index 619bd35727..bfae5c14df 100644
--- a/libs/libmdbx/src/test/config.cc
+++ b/libs/libmdbx/src/test/config.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/config.h b/libs/libmdbx/src/test/config.h
index 1886a8ea57..d6eaea2e54 100644
--- a/libs/libmdbx/src/test/config.h
+++ b/libs/libmdbx/src/test/config.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -27,7 +27,8 @@ enum actor_testcase {
ac_deadwrite,
ac_jitter,
ac_try,
- ac_copy
+ ac_copy,
+ ac_append
};
enum actor_status {
diff --git a/libs/libmdbx/src/test/dead.cc b/libs/libmdbx/src/test/dead.cc
index 3dd1ee7b24..a1a8b5f9de 100644
--- a/libs/libmdbx/src/test/dead.cc
+++ b/libs/libmdbx/src/test/dead.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/hill.cc b/libs/libmdbx/src/test/hill.cc
index 856aeb9356..5b083e1fcc 100644
--- a/libs/libmdbx/src/test/hill.cc
+++ b/libs/libmdbx/src/test/hill.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/jitter.cc b/libs/libmdbx/src/test/jitter.cc
index 48f9bd998e..82d1d764ff 100644
--- a/libs/libmdbx/src/test/jitter.cc
+++ b/libs/libmdbx/src/test/jitter.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/keygen.cc b/libs/libmdbx/src/test/keygen.cc
index c7a706065f..5876fd8cec 100644
--- a/libs/libmdbx/src/test/keygen.cc
+++ b/libs/libmdbx/src/test/keygen.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -167,6 +167,15 @@ void maker::setup(const config::actor_params_pod &actor, unsigned actor_id,
base = 0;
}
+void maker::make_ordered() {
+ mapping.mesh = 0;
+ mapping.rotate = 0;
+}
+
+bool maker::is_unordered() const {
+ return (mapping.mesh >= serial_minwith || mapping.rotate) != 0;
+}
+
bool maker::increment(serial_t &serial, int delta) {
if (serial > mask(mapping.width)) {
log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial,
diff --git a/libs/libmdbx/src/test/keygen.h b/libs/libmdbx/src/test/keygen.h
index bbd97b29d1..890397b8ca 100644
--- a/libs/libmdbx/src/test/keygen.h
+++ b/libs/libmdbx/src/test/keygen.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -121,6 +121,8 @@ public:
serial_t value_age);
void setup(const config::actor_params_pod &actor, unsigned actor_id,
unsigned thread_number);
+ void make_ordered();
+ bool is_unordered() const;
bool increment(serial_t &serial, int delta);
};
diff --git a/libs/libmdbx/src/test/log.cc b/libs/libmdbx/src/test/log.cc
index 0e325e3add..79544e11bb 100644
--- a/libs/libmdbx/src/test/log.cc
+++ b/libs/libmdbx/src/test/log.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/log.h b/libs/libmdbx/src/test/log.h
index ecdd91bf88..7d6b4012f1 100644
--- a/libs/libmdbx/src/test/log.h
+++ b/libs/libmdbx/src/test/log.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/main.cc b/libs/libmdbx/src/test/main.cc
index 749d48f07d..f3ee76b62f 100644
--- a/libs/libmdbx/src/test/main.cc
+++ b/libs/libmdbx/src/test/main.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -341,6 +341,10 @@ int main(int argc, char *const argv[]) {
configure_actor(last_space_id, ac_copy, value, params);
continue;
}
+ if (config::parse_option(argc, argv, narg, "append", nullptr)) {
+ configure_actor(last_space_id, ac_append, value, params);
+ continue;
+ }
if (config::parse_option(argc, argv, narg, "failfast",
global::config::failfast))
continue;
diff --git a/libs/libmdbx/src/test/osal-unix.cc b/libs/libmdbx/src/test/osal-unix.cc
index 6e6d7a1c5c..fd691e354f 100644
--- a/libs/libmdbx/src/test/osal-unix.cc
+++ b/libs/libmdbx/src/test/osal-unix.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/osal-windows.cc b/libs/libmdbx/src/test/osal-windows.cc
index f7f1de56e0..5858e89530 100644
--- a/libs/libmdbx/src/test/osal-windows.cc
+++ b/libs/libmdbx/src/test/osal-windows.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/osal.h b/libs/libmdbx/src/test/osal.h
index 3ccc7bbec1..5acf7ad094 100644
--- a/libs/libmdbx/src/test/osal.h
+++ b/libs/libmdbx/src/test/osal.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/test.cc b/libs/libmdbx/src/test/test.cc
index 6bba425a67..e34bd7f0e8 100644
--- a/libs/libmdbx/src/test/test.cc
+++ b/libs/libmdbx/src/test/test.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -33,6 +33,8 @@ const char *testcase2str(const actor_testcase testcase) {
return "try";
case ac_copy:
return "copy";
+ case ac_append:
+ return "append";
}
}
@@ -185,9 +187,33 @@ void testcase::txn_end(bool abort) {
log_trace("<< txn_end(%s)", abort ? "abort" : "commit");
}
+void testcase::cursor_open(unsigned dbi) {
+ log_trace(">> cursor_open(%u)", dbi);
+ assert(!cursor_guard);
+ assert(txn_guard);
+
+ MDBX_cursor *cursor = nullptr;
+ int rc = mdbx_cursor_open(txn_guard.get(), dbi, &cursor);
+ if (unlikely(rc != MDBX_SUCCESS))
+ failure_perror("mdbx_cursor_open()", rc);
+ cursor_guard.reset(cursor);
+
+ log_trace("<< cursor_open(%u)", dbi);
+}
+
+void testcase::cursor_close() {
+ log_trace(">> cursor_close()");
+ assert(cursor_guard);
+ MDBX_cursor *cursor = cursor_guard.release();
+ mdbx_cursor_close(cursor);
+ log_trace("<< cursor_close()");
+}
+
void testcase::txn_restart(bool abort, bool readonly, unsigned flags) {
if (txn_guard)
txn_end(abort);
+ if (cursor_guard)
+ cursor_close();
txn_begin(readonly, flags);
}
@@ -396,7 +422,7 @@ void testcase::db_table_drop(MDBX_dbi handle) {
if (config.params.drop_table) {
int rc = mdbx_drop(txn_guard.get(), handle, true);
if (unlikely(rc != MDBX_SUCCESS))
- failure_perror("mdbx_drop()", rc);
+ failure_perror("mdbx_drop(delete=true)", rc);
log_trace("<< testcase::db_table_drop");
} else {
log_trace("<< testcase::db_table_drop: not needed");
@@ -458,6 +484,9 @@ bool test_execute(const actor_config &config) {
case ac_copy:
test.reset(new testcase_copy(config, pid));
break;
+ case ac_append:
+ test.reset(new testcase_append(config, pid));
+ break;
default:
test.reset(new testcase(config, pid));
break;
diff --git a/libs/libmdbx/src/test/test.h b/libs/libmdbx/src/test/test.h
index d145ec2e38..e726023279 100644
--- a/libs/libmdbx/src/test/test.h
+++ b/libs/libmdbx/src/test/test.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -107,6 +107,8 @@ protected:
void txn_begin(bool readonly, unsigned flags = 0);
void txn_end(bool abort);
void txn_restart(bool abort, bool readonly, unsigned flags = 0);
+ void cursor_open(unsigned dbi);
+ void cursor_close();
void txn_inject_writefault(void);
void txn_inject_writefault(MDBX_txn *txn);
void fetch_canary();
@@ -158,6 +160,13 @@ public:
bool run();
};
+class testcase_append : public testcase {
+public:
+ testcase_append(const actor_config &config, const mdbx_pid_t pid)
+ : testcase(config, pid) {}
+ bool run();
+};
+
class testcase_deadread : public testcase {
public:
testcase_deadread(const actor_config &config, const mdbx_pid_t pid)
diff --git a/libs/libmdbx/src/test/test.vcxproj b/libs/libmdbx/src/test/test.vcxproj
index ad647f3874..9eb62cdcf5 100644
--- a/libs/libmdbx/src/test/test.vcxproj
+++ b/libs/libmdbx/src/test/test.vcxproj
@@ -27,6 +27,7 @@
<ProjectGuid>{30E29CE6-E6FC-4D32-AA07-46A55FAF3A31}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mdbxtest</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -180,6 +181,7 @@
<ClInclude Include="utils.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="append.cc" />
<ClCompile Include="cases.cc" />
<ClCompile Include="chrono.cc" />
<ClCompile Include="config.cc" />
diff --git a/libs/libmdbx/src/test/utils.cc b/libs/libmdbx/src/test/utils.cc
index 622c4d09bd..326455a693 100644
--- a/libs/libmdbx/src/test/utils.cc
+++ b/libs/libmdbx/src/test/utils.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
diff --git a/libs/libmdbx/src/test/utils.h b/libs/libmdbx/src/test/utils.h
index 42d497e86e..7bf3abd305 100644
--- a/libs/libmdbx/src/test/utils.h
+++ b/libs/libmdbx/src/test/utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2018 Leonid Yuriev <leo@yuriev.ru>
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
@@ -288,6 +288,7 @@ struct simple_checksum {
void push(uint32_t data) {
value += data * UINT64_C(9386433910765580089) + 1;
value ^= value >> 41;
+ value *= UINT64_C(0xBD9CACC22C6E9571);
}
void push(uint64_t data) {
@@ -304,11 +305,15 @@ struct simple_checksum {
}
void push(const double &data) { push(&data, sizeof(double)); }
-
void push(const char *cstr) { push(cstr, strlen(cstr)); }
-
void push(const std::string &str) { push(str.data(), str.size()); }
+ void push(unsigned salt, const MDBX_val &val) {
+ push(val.iov_len);
+ push(salt);
+ push(val.iov_base, val.iov_len);
+ }
+
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
void push(const HANDLE &handle) { push(&handle, sizeof(handle)); }
#endif /* _WINDOWS */
diff --git a/libs/libmdbx/src/tutorial/sample-bdb.txt b/libs/libmdbx/src/tutorial/sample-bdb.txt
index 1015d06460..440efddb57 100644
--- a/libs/libmdbx/src/tutorial/sample-bdb.txt
+++ b/libs/libmdbx/src/tutorial/sample-bdb.txt
@@ -4,7 +4,7 @@
*/
/*
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
* Copyright 2012-2015 Howard Chu, Symas Corp.
* Copyright 2015,2016 Peter-Service R&D LLC.
* All rights reserved.
diff --git a/libs/libmdbx/src/tutorial/sample-mdbx.c b/libs/libmdbx/src/tutorial/sample-mdbx.c
index aaafbc31cf..991ab69806 100644
--- a/libs/libmdbx/src/tutorial/sample-mdbx.c
+++ b/libs/libmdbx/src/tutorial/sample-mdbx.c
@@ -5,7 +5,7 @@
/*
* Copyright 2017 Ilya Shipitsin <chipitsine@gmail.com>.
- * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru>.
+ * Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
* Copyright 2012-2015 Howard Chu, Symas Corp.
* All rights reserved.
*