25 February 2020
Леонид Юрьев (Leonid Yuriev) created group «libmdbx» with members Леонид Юрьев (Leonid Yuriev) and CZ
Леонид Юрьев (Leonid Yuriev) converted this group to a supergroup
libmdbx converted a basic group to this supergroup «libmdbx»
3 March 2020
Л(
13:41
Леонид Юрьев (Leonid Yuriev)
This is the public bilingual group for discussing topics related to libmdbx.
ETH: 0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A.
Это публичная двуязычная группа для обсуждения тем связанных c libmdbx.

Основной репозиторий проекта перемещен на https://gitflic.ru/project/erthink/libmdbx, так как 15 апреля 2022 администрация Github без предупреждения и без объяснения причин удалила libmdbx вместе с массой других проектов, одновременно заблокировав доступ многим разработчикам. По той же причине Github навсегда занесен в черный список.

На случай если это была случайность или ошибка мы ждали 5 суток (три рабочих дня), но чуда не случилось. Github умер, как и многие декларируемые либеральные ценности (свобода слова, презумпция невиновности и право на суд, неприкосновенность личности и частной собственности и т.д.).

---

The origin repository of the project has been moved to https://gitflic.ru/project/erthink/libmdbx since on April 15, 2022, the Github administration, without warning and without explanation, deleted libmdbx along with a lot of other projects, simultaneously blocking access to many developers. For the same reason Github is blacklisted forever.

In case it was an accident or a mistake, we waited 5 days (three working days), but no miracle happened. So Github is died, as well as many declared liberal values (freedom of speech, presumption of innocence and right to trial, inviolability of the person and private property, etc).

https://gitflic.ru/project/erthink/libmdbx/commit/1a471ed04b12d90514d37d95af3316a59503d943
👍
E
S
КА
Леонид Юрьев (Leonid Yuriev) pinned this message
C
6 March 2020
Arthur Goncharuk invited Arthur Goncharuk
7 March 2020
Л(
16:00
Леонид Юрьев (Leonid Yuriev)
libmdbx v0.7.0 will be released soon.
Roman Sergeev invited Roman Sergeev
Roman invited Roman
13 March 2020
Aleksei🐈 invited Aleksei🐈
18 March 2020
Л(
20:33
Леонид Юрьев (Leonid Yuriev)
20:34
MDBX version 0.7.0, released 2020-03-18
Notable fixes, improvements and changes since v0.4.0:

1. Workarounds for Wine.
2. MDBX_MAP_RESIZED renamed to MDBX_UNABLE_EXTEND_MAPSIZE.
3. Clarify API description & comments, fix typos.
4. Speedup runtime checks in debug/checked builds.
5. Added checking for read/write transactions overlapping for the same thread, added MDBX_TXN_OVERLAPPING error and MDBX_DBG_LEGACY_OVERLAP option.
6. Added mdbx_key_from_jsonInteger(), mdbx_key_from_double(), mdbx_key_from_float(), mdbx_key_from_int64() and mdbx_key_from_int32() functions. See mdbx.h for description.
7. Fix mdbx_load utility for custom comparators.
8. Fix checks related to MDBX_APPEND flag inside mdbx_cursor_put().
9. Fix mdbx_env_set_geometry() for large page size.
10. Fix false-positive ASAN issue.
11. Fix assertion for MDBX_NOTLS option.
12. Fix mdbx_chk utility for don't checking some numbers if walking of B-tree was disabled.
13. Added install section to CMakeLists.txt.
14. Rework MDBX_DBG_DUMP option to avoid disk I/O performance degradation.
15. Interpret ERROR_ACCESS_DENIED from OpenProcess() as 'process exists'.
20:41
Изменения и доработки запланированные в v0.8.x:
1. Использование RadixSort для очень больших транзакций (5К грязных страниц и более).
2. Минимальный интерфейс C++ (набор классов для RAII).
+3. Опционально/Дополнительно: Привязка к питону (если найдется заинтересованный квалифицированный пользователь).
19 March 2020
Georgiy Komarov invited Georgiy Komarov
AG
10:18
Arthur Goncharuk
привет) слушай, а можно пример использования функций mdbx_key_from?
насколько я понимаю, число нужно перевернуть в big-endian чтобы лексикографическое сравнение таких ключей работало правильно
Л(
16:50
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не переворачивать, а использовать MDBX_INTEGERKEY.
AG
17:06
Arthur Goncharuk
да, я вспомнил об этом
Л(
21:10
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
20 March 2020
AG
01:14
Arthur Goncharuk
@erthink
В своё время я активно использовал Berkeley DB, в которой есть очень классный флаг DB_RECNUM. Он включает нумерацию записей для b-tree, позволяя эффективно смещать курсор в произвольную позицию, что делает возможным быструю пагинацию, получение случайных записей, получение количества записей для диапазона ключей.
https://docs.oracle.com/cd/E17276_01/html/api_reference/C/dbset_flags.html#dbset_flags_DB_RECNUM

Что-то подобное планируется в будущих релизах или в Mithril DB? Может, у тебя есть мысли как вручную реализовать эффективное смещение курсора поверх существующих функций MDBХ?
Л(
01:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
А чем не подходит вариант использования в качестве ключей значений получаемых посредством mdbx_dbi_sequence()?
01:58
Если же нужны вторичные индексы, то стоит посмотреть на libfpta.
AG
02:29
Arthur Goncharuk
Нет, это не так работает. Флаг DB_RECNUM включает механизм, когда каждая запись имеет логический номер в точности как индекс в массиве. Если удаляется запись из середины базы, то номера всех следующих за ней записей "съезжают" влево.

Например:
1 'abc': 'xxx',
2 'def': 'xxx',
3 'ghi': 'xxx'

// удалили 'def'
1 'abc': 'xxx'
2 'ghi': 'xxx'

Технически, беркли реализует это через подсчет ключей на уровне страниц (снизу вверх до корня).
02:31
Вручную это можно реализовать "в лоб" ассоциировав с каждым ключем его порядковый номер в другой бд, смещая все номера при вставках/удалениях. Крайне медленно
Л(
02:45
Леонид Юрьев (Leonid Yuriev)
А, теперь понял о чем вы.
В MDBX такого точно не будет, ибо требует смены формата БД (добавить счетчик записей в элементах branch-страниц).
А насчет Mithril нужно подумать.
Понятно что такая фича будет полезна в каких-то сценариях, но одновременно усложняет код...
AG
02:48
Arthur Goncharuk
Да, вдобавок это требует блокировать не стрницу, а всю бд на запись (но MDBX и так делает это). Такая фича крайне полезна при диапазонных/префиксных выборках из b-tree, поскольку смещение курсора не вносит линейную деградацию скорости при росте N
02:49
Но в любом случае, фича может быть опциональной. Просто подумай об этом как-нибудь)
3 April 2020
Gleb K. invited Gleb K.
Л(
16:29
Леонид Юрьев (Leonid Yuriev)
GK
16:38
Gleb K.
In reply to this message
Приветствую! Попрошу своих поредактить
Л(
16:39
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
6 April 2020
GK
08:41
Gleb K.
mdbx:8431: mdbx_sync_locked: Assertion `prev_discarded_bytes > discard_edge_bytes' failed.
а почему теоретически может возникать?
GK
09:55
Gleb K.
версия 0.7.0, UTTERLY_NOSYNC, один write тред, периодически зову mdbx_env_sync
Л(
10:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Видимо лишений assert. Заведите issue на github. Посмотрю.
GK
10:38
Gleb K.
ок, спасибо
👹 LA invited 👹 LA
?
15:30
👹 LA
Леонид, доброго времени.
Сразу извиняюсь за крайне нубский вопрос.
Использую LMDB в PHP (через модуль dba: https://www.php.net/manual/ru/book.dba.php , причём для использования lmdb нужно собирать php самому: https://www.php.net/manual/ru/dba.installation.php).

Могу ли я взять код, который осуществляет работу с LMDB в PHP: https://github.com/php/php-src/blob/PHP-7.3/ext/dba/dba_lmdb.c
поменять везде "mdb_*" на "mdbx_*" и ожидать что всё заведётся с пол тычка?

Хочется попробовать libmdbx, но скиллзов по C - нет.
Л(
16:00
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Приветствую.
Только заменой не обойтись, скорее всего потребуются другие (но незначительные) изменения.
?
16:03
👹 LA
Связано с deprecated методами или схема взаимодействия изменилась сильно уже (не вникал в разницу от lmdb)?
16:09
Сейчас просто много сайтов поднято с LMDB в режиме работы read-only для посетителей (контент только администраторы добавляют). Никакой нагрузки на CPU/RAM, все данные по ключу берутся, тысячи баз (сайтов) на дешевых VPS.
Хочется добавить интерактивности, чтоб не было однопоточной блокируемой записи в базу (надеюсь, правильно выразился). Вроде бы libmdbx как раз позволит сделать много асинхронных writers, которые будут что-то добавлять в базу.
Л(
16:12
Леонид Юрьев (Leonid Yuriev)
In reply to this message
См пункты 2 и 3 из https://github.com/erthink/libmdbx#other-fixes-and-specifics

На всякий - переходить на MDBX стоит если вам нужны какие-то добавленные фичи (управление размеров и т.п.), либо есть проблемы при использовании LMDB.
?
16:12
👹 LA
Вот как раз перейти хочется только из-за того, что в LMDB (вроде бы) нельзя асинхронно (многопоточно скорее даже) писать в базу, где-то читал что могут быть проблемы
Л(
16:15
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нет, вы что-то неверно поняли.
В MDBX ровно точно также сериализуются все пишущие транзакции.
Асинхронная запись на диск возможна, но "не бесплатна":
- в режиме MDBX_UTTERLY_NOSYNC вы можете потерять всю базу при системной аварии (точно такте как в режиме LMDB_NOSYNC в LMDB).
- в режиме MDBX_SAFE_NOSYNC трафика на диск будет больше.
16:18
In reply to this message
Вам нужно внимательно прочесть https://github.com/erthink/libmdbx/blob/master/mdbx.h#L1120-L1295
А уже после задавать вопросы.
Если вы будете делать что-то без полного понимания, то это кончится потерей данных.
?
16:20
👹 LA
Хм, понял. Спасибо. Я и вправду "с наскока" пытаюсь пробовать)

И возможно тогда я неправильно инструмент выбираю, может быть у вас есть совет что можно попробовать для моего кейса?

В худшем случае каждый посетитель при открытии страницы - добавляет в базу какие-то новые данные, а следующий за ним - может получить их. И всё это в многопоточном режиме до сотен посетителей в секунду (на один сайт, а сайтов - много, поэтому под каждый своя база нужна ещё).

PS: ушли от mysql / pgsql из-за того, что они не выдерживают нагрузки. А нам и нужно то всего от базы банальные CRUD (key-value) без возможностей SQL
AG
16:22
Arthur Goncharuk
И lmdb, и mdbx при записи блокируют остальных писателей (но не трогают читателей). При этом скорость записи все равно остается огромной, даже несмотря на то, что она не параллельна. Главное не выполнять никакого лишнего кода в пишущих транзакциях.
?
16:23
👹 LA
In reply to this message
Спасибо. Почему-то казалось (не знаю откуда я это взял) - что в mdbx как раз ушли каким-то образом от этой блокировки писателей.
AG
16:27
Arthur Goncharuk
К слову, мне не удалось повредить базу lmdb флагом MDB_NOSYNC, если грязно прибивать интенсивно пишущий процесс
Л(
16:29
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Есть примерно три варианта как это сделать:

1) В LMDB/MDBX вам нужно "собирать" все обновления из всех клиентских запросов приходящих в течение 10-100 миллисекунд, но не возвращать "ОК" до фиксации транзакции.
Затем коммитить эту одну транзакцию со всеми накопленными изменениями и после возвращать "ОК" во все клиентские запросы.
Есть несколько технических способов как это делать, это отдельная тема.

2) Использовать Tarantool. Описанный выше "алгоритм" там реализуется автоматически при записи WAL на диск.

3) Использовать что-то другое.
Например кассандру или другую распределенную БД (т.е. нужен кластер, который будет гарантировать низкую вероятность потери данных)
16:37
In reply to this message
1. Убийство процесса - это не системная авария.
При убийстве процесса все закоммиченные транзакции будут сохранены.
Если же выключить питание, нажать reset, спровоцировать kernel oops/panic, убить процесс гипервизор - тогда результат может быть другим.

2. В режиме MDB_NOSYNC (важно чтобы без MDB_WRITEMAP и MDB_MAPASYNC), даже при системной аварии, БД может не повреждаться если файловая система обеспечивает/сохраняет порядок записи для пользовательских данных (иногда это так).

3. В MDBX при использовании MDBX_SAFE_NOSYNC порядок записи обеспечивается "исcкуственно", но ценой увеличения объема.

4. В MDBX при использовании MDBX_UTTERLY_NOSYNC без MDBX_WRITEMAP и без MDBX_LIFO_RECLAIM сохранность БД также зависит от ordered write для пользовательских данных в файловой системе.
?
16:39
👹 LA
Спасибо за наводку, при беглом изучении кажется что у тарантула и кассандры куча оверхеда и они не очень-то задизайнены под простую key-value работу БЕЗ выгрузки значительной части данных в память (не хочется ставить отдельный мощный сервер для них). Возможно, конечно, я ошибаюсь, но LMDB подкупила простотой и скоростью чтения данных, которые не нужно вгружать в RAM при каждом чихе, а это позволило очень сильно сократить бюджет на количество железок)
Понимаю, что везде есть свои ограничения, но кажется что я недостаточно рисерчил и где-то ещё есть такая же забытая и уникальная разработка вроде LMDB
Л(
16:49
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не хочу вас излишне критиковать, но видимо вы "ресерчили" не с той стороны.
Упрощенно:
- по структуре хранения на диск БД можно разделить на LSM и b-tree = вам нужно понимать плюсы/минусы обоих вариантов для вашего случая.
- по методу фиксации на диск БД можно разделить на "c WAL" и "без WAL" = вам также нужно понимать плюсы/минусы обоих вариантов.
- в распределенных БД часть есть возможность снизить риск потери данных без немедленной записи на диски за счет тиражирования изменений на несколько машин (т.е. если одно умрет, то данные останутся в памяти остальных).
?
16:51
👹 LA
Критика уместна, я не разбирался в этих особенностях и просто на глаз пытаюсь примерить сценарии различных баз на себя 🙂
Спасибо за разъяснения!
RattenKong 🦧🐀🦍️ invited RattenKong 🦧🐀🦍️
R
16:53
RattenKong 🦧🐀🦍️
Привет! Пытаюсь собрать mdbx под ios при помощи cmake, и после сборки получаю только шелл-скрипт. Аккаунт не девелоперский, если что
Л(
16:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это не то чтобы "особенности". Это достаточно важные знания, которые позволят вам не заправить дизель бензином и наоборот ;)
?
16:54
👹 LA
In reply to this message
😅👍
Л(
16:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
покажите вывод команд cmake && cmake -build .
R
16:57
RattenKong 🦧🐀🦍️
In reply to this message
а можно файлом прислать?
Л(
16:58
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да
R
16:58
RattenKong 🦧🐀🦍️
хотя на пастебин скину
Л(
17:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Пока не пойму в чем дело.
Варианты такие:
1. Посмотреть каким будет поведение при сборке в отдельном каталоге, т.е. mkdir BUILD && cd BUILD && cmake .. && cmake -build .
2. Посмотреть как будет работать сборке без cmake, т.е. просто выполнить make (предварительно установив gmake).
3. Заглянуть внутрь скрипта /Users/macbookpro/Downloads/mdbx/libmdbx.build/MinSizeRel-iphoneos/ALL_BUILD.build/Script-5EC7E29288A04AA7A9694553.sh и понять почему он "молчит".
AG
17:12
Arthur Goncharuk
In reply to this message
Мне не удавалась повредить базу в том числе через выдергивание шнура питания. Файловая система ext4. Если я все правильно понял, ext4 по умолчанию сохраняет такой порядок https://www.kernel.org/doc/Documentation/filesystems/ext4.txt (см. data=ordered). Но могу ошибаться, конечно.
Л(
17:37
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Если вы намерены докопаться до сути, то всё несколько сложнее.
Файловая система просто выталкивает запросы в очередь IO-шедулера, который может выполнять их переупорядочивание.
При этом для обеспечения порядка записи ФС генерирует барьеры - условные границы, через которые шедулер не должен переносить запросы при переупорядочивании.
Такие барьеры генерируются после записи в журнал и выполнении sync(), fdata_sync().
Поэтому получается примерно так:
- в режиме data=writeback только по запросу приложения.
- в режиме data=order при изменении метаданных, но не при записи пользовательских данных.
- в режиме data=journal при каждой операции записи.

К этому добавляется варианты обработки очереди контроллерами дисков с NCQ и тонкости обработки flush-запросов (некоторые "не-серверные" диски их игнорируют ради скорости).
17:38
In reply to this message
Есть успехи?
R
17:59
RattenKong 🦧🐀🦍️
In reply to this message
в шел скрипте запускается другой скрипт(зависящий от типа сборки), в котором полезной работы нет. Через мейк пока не получается, сорцы не православно отвязали от гита....
Л(
18:01
Леонид Юрьев (Leonid Yuriev)
In reply to this message
У меня OSX только в виртуалке и сейчас не рядом, т.е. проверить не могу.
R
18:03
RattenKong 🦧🐀🦍️
In reply to this message
Это печально, даже проект хкодовский только симейк содержит. На остальных платформах(андроид, мингв, линукс) все собиралось в динамический объектник без таких причуд
Л(
18:05
Леонид Юрьев (Leonid Yuriev)
Это "православно" отлученные от гита исходники (make dist).
18:09
In reply to this message
Кроме тарбола с корректными исхониками пока ничем помочь не могу.
По факту проблем с CMake под OSX заводите issue на github и сразу прикладывайте архив со сборочной директорией.
Вероятно завтра смогу посмотреть в чем дело.
R
18:14
RattenKong 🦧🐀🦍️
In reply to this message
Тут еще дело в том, что без аккаунта разработчика можно только статическую библиотеку собрать, но какие-то команды вроде try_compile требуют подписи, из-за чего без хаков вроде set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) не собирается сборка. Сейчас попробовал с исходниками из архива собраться, но получил ошибку с которой до этого боролся:
CMake Error at /usr/local/Cellar/cmake/3.17.0_1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:164 (message):
Could NOT find Threads (missing: Threads_FOUND)
Call Stack (most recent call first):
/usr/local/Cellar/cmake/3.17.0_1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:445 (_FPHSA_FAILURE_MESSAGE)
/usr/local/Cellar/cmake/3.17.0_1/share/cmake/Modules/FindThreads.cmake:234 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
CMakeLists.txt:70 (find_package)

И с этой ишью до сих пор люди из китваре не разобрались: https://gitlab.kitware.com/cmake/cmake/issues/18993
Л(
18:15
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Кстати, сейчас make dist должен отрабатывать на OSX (на днях был добавлен костыль для не-gnu tar).
Т.е. git clone и make dist должно быть достаточно для получение "отлученных" от гита исходников.
18:18
In reply to this message
У меня в виртуалке тоже нет никакого особого "девелоперского аккаунта", только какая-то пробная версия (деталей не помню).
Как вариант - смотрите как собирается и тестируется libmdbx на travis-ci = https://travis-ci.org/github/erthink/libmdbx/jobs/671190289?utm_medium=notification&utm_source=github_status
R
18:23
RattenKong 🦧🐀🦍️
под osx все собирается без аккаунтов, да. Вот под мобильную платформу(ios) уже нужен аккаунт
18:27
и проблема в сборке под ios, а не osx, да
GK
18:30
Gleb K.
ну вообще очень редкий проект может похвастаться работающей сборкой под иос, обычно все просто мануально инклудят файлы исходников в xcode, в mdbx тем более файлов не очень много
Л(
18:40
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Теоретически не должно быть ничего особо сложного.
Нужно "просто" понять с какими флагами вызывать clang и lld.
Затем вызвать CC=path-to-clang CFLAGS="clang-flags" LD=path-to-lld LDFLAGS="lld-flags".
7 April 2020
Л(
02:51
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Возможно я нашел ошибку в коде - могло случаться на 64-битных системах при работе с БД размером около 4 Гб (32 бита).
GK
02:53
Gleb K.
о да именно при 4гб и проявлялось!
02:54
но так же на 8 гигабайтах видел
Л(
02:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ага, на каждой границе кратной 4Гб.
Скоро будет исправление.
GK
02:54
Gleb K.
пока починилось просто увеличением минимального размера базы
02:55
ок, спасибо большое!
Л(
02:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не за что.
Но мне нужно посмотреть/подумать что эта ошибка могла затрагивать...
Л(
04:13
Леонид Юрьев (Leonid Yuriev)
In reply to this message
https://github.com/erthink/libmdbx/issues/91

Подтвердите устранение проблемы и тогда я волью правки в master-ветку.
GK
15:35
Gleb K.
Ок! позапускаю тесты, попозже отпишусь
R
16:24
RattenKong 🦧🐀🦍️
In reply to this message
Симейк отработал, теперь во время сборки ошибка компиляции: `fatal error: 'sys/vmmeter.h' file not found
#include <sys/vmmeter.h>
`
Этот заголовочник точно есть под мобильный иос?
Л(
16:28
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Он входит в состав darwin-xnu, см. https://github.com/apple/darwin-xnu/blob/master/bsd/sys/vmmeter.h
16:37
In reply to this message
Я не мастер разработки под iOS, к тому же у Apple всё "для яблочных людей" сделано.
Попробуйте такой рецепт https://github.com/WooKeyWallet/monero-ios-lib#xcode
Л(
17:53
Леонид Юрьев (Leonid Yuriev)
In reply to this message
R
18:04
RattenKong 🦧🐀🦍️
In reply to this message
да, информация по ссылке помогла, спасибо! Но вернулась исходная проблема с пустым шелл скриптом 🙁
18:06
буду варить тогда сборочную директорию
Л(
18:07
Леонид Юрьев (Leonid Yuriev)
Тогда я не пойму как у вас до этого cmake отработал и почему
R
20:08
RattenKong 🦧🐀🦍️
In reply to this message
я в симейк докинул политику CMP0006 OLD, try_compile на статически библиотеках делать и запретил подписывать бинари
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")

Без этого не собиралось под ios. В предыдущем эксперименте только указал делать try_compile на статических либах
Л(
20:27
Леонид Юрьев (Leonid Yuriev)
Со CMAKE_TRY_COMPILE_TARGET_TYPE более-менее понятно, добавлю это для случаев кросс-компиляции и iOS.
20:29
C CMP0006 не понятно как лучше.
Возможно нужно добавить опцию для включения/выключения сборки утилит и по-умолчанию на iOS не собирать и устанавливать их, тем самым убрав проблему bundle/не-bundle.
20:31
А вот добавлять CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED я пока не хочу.
Более логичным выглядит определение этой опции в командной строке CMake или в родительском CMake-проекте.
20:38
In reply to this message
R
22:29
RattenKong 🦧🐀🦍️
In reply to this message
Неа, попробую, завтра отпишусь
Л(
23:44
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Берите devel-ветку, там ряд правок для iOS.
R
23:45
RattenKong 🦧🐀🦍️
In reply to this message
хорошо!
8 April 2020
Л(
20:45
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ну и как, работает?
R
21:07
RattenKong 🦧🐀🦍️
In reply to this message
Собралось по крайней мере. С тулчейном сторонним. Причем в «форке» моем с тем тулчейном те же шелл скрипты, что и без него. Наверное все таки дело в «форке»
Л(
21:09
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Про "форк" ничего не понял.
Какой форк и чего? С какими изменениями?
R
21:10
RattenKong 🦧🐀🦍️
In reply to this message
Этот «форк» произошел где то месяц-два назад, там неправильно код от гита отвязали и слегка симейк поправили
Л(
21:13
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Тогда делайте PR с правками, либо дальше разбирайтесь сами.
R
21:29
RattenKong 🦧🐀🦍️
In reply to this message
да вот для нормального ПРа надо каждый вызов try_compile и подобных оборачивать во выключение/включение обязательного подписывания бинарей
21:29
но не знаю, заработает ли это у меня, и нужно ли это вам
Л(
21:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Вообще-то в ветке devel это сейчас так и сделано.
Точнее говоря у меня были намерения так сделать, но неплохо-бы проверить что работает как задуманно.
R
21:46
RattenKong 🦧🐀🦍️
In reply to this message
могу проверить собираемость и способность слинковаться, но работоспособность в рабочих сценариях -- нет
Л(
22:07
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Как минимум мне бы хотелось, чтобы вы проверили собираемость ветки devel на iOS.
Как максимум - чтобы вы попробовали перейти на mainstream-версию libmdbx, с вливанием необходимых правок.
Всё это желательно с использованием https://github.com/leetal/ios-cmake
22:08
Последние правки для iOS сделаны только-что
9 April 2020
R
20:52
RattenKong 🦧🐀🦍️
In reply to this message
Да, все собирается без правок с моей стороны с тулчейном от leetal. Спасибо!
Л(
20:53
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
13 April 2020
R
16:18
RattenKong 🦧🐀🦍️
Привет! Собираюсь под андроид с девел ветки с коммитом 19454f26e6a258b4ec7306dcb94a3483538cbf72 и получаю ошибки:
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:7744:9: warning: implicit declaration of function 'sync_file_range' is invalid in C99 [-Wimplicit-function-declaration]
if (sync_file_range(env->me_lazy_fd, 0, pgno2bytes(env, NUM_METAS),
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:7745:25: error: use of undeclared identifier 'SYNC_FILE_RANGE_WRITE'
SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER))
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:7745:49: error: use of undeclared identifier 'SYNC_FILE_RANGE_WAIT_AFTER'
SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER))
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:21435:5: warning: implicit declaration of function '__assert_fail' is invalid in C99 [-Wimplicit-function-declaration]
__assert_fail(msg, "mdbx", line, func);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:21464:3: warning: implicit declaration of function '__assert_fail' is invalid in C99 [-Wimplicit-function-declaration]
__assert_fail(const_message, "mdbx", 0, "panic");
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:21983:15: warning: implicit declaration of function 'pwritev' is invalid in C99 [-Wimplicit-function-declaration]
written = pwritev(fd, iov, iovcnt, offset);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:22386:50: error: extraneous ')' after condition, expected a statement
while (nullptr != (ent = getmntent(mounted))))
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24832:8: warning: implicit declaration of function 'pthread_mutexattr_setrobust' is invalid in C99 [-Wimplicit-function-declaration]
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24832:41: error: use of undeclared identifier 'PTHREAD_MUTEX_ROBUST'
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24897:20: warning: implicit declaration of function 'pthread_mutex_consistent' is invalid in C99 [-Wimplicit-function-declaration]
int mreco_rc = pthread_mutex_consistent(ipc);
16:18
на ведре нет PTHREAD_MUTEX_ROBUST, см https://github.com/snipsco/tensorflow-build/issues/21#issuecomment-434459893
Ошибка с SYNC_FILE_RANGE_* лечится поднятием поддерживаемого андроида, но нам бы такого не хотелось. При этом при поднятии уровня андроида все равно остаются ошибки
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:21435:5: warning: implicit declaration of function '__assert_fail' is invalid in C99 [-Wimplicit-function-declaration]
__assert_fail(msg, "mdbx", line, func);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:21464:3: warning: implicit declaration of function '__assert_fail' is invalid in C99 [-Wimplicit-function-declaration]
__assert_fail(const_message, "mdbx", 0, "panic");
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:22386:50: error: extraneous ')' after condition, expected a statement
while (nullptr != (ent = getmntent(mounted))))
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24832:8: warning: implicit declaration of function 'pthread_mutexattr_setrobust' is invalid in C99 [-Wimplicit-function-declaration]
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24832:41: error: use of undeclared identifier 'PTHREAD_MUTEX_ROBUST'
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
^
/Users/macbookpro/Downloads/test_mdbx/libmdbx/dist/mdbx.c:24897:20: warning: implicit declaration of function 'pthread_mutex_consistent' is invalid in C99 [-Wimplicit-function-declaration]
int mreco_rc = pthread_mutex_consistent(ipc);
Л(
16:26
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это хорошо, значить сейчас всё поправим.
С PTHREAD_MUTEX_ROBUST и SYNC_FILE_RANGE - всё понятно.
А вот с остальным нужно разбираться.
Для начала - можете глянуть и подсказать прототип для аналога __assert_fail?
Л(
23:41
Леонид Юрьев (Leonid Yuriev)
In reply to this message
14 April 2020
R
00:06
RattenKong 🦧🐀🦍️
In reply to this message
собралось, спасибо! С поведением в рантайме все еще не могу отписаться 🙁
Л(
00:07
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не понял, что не так в рантайме?
R
00:08
RattenKong 🦧🐀🦍️
In reply to this message
Ой, не тот смысл видите. Я про то, что пока нет возможности отрепортовать о поведении mdbx во время работы с ней, только компиляция кода
Л(
00:14
Леонид Юрьев (Leonid Yuriev)
Понял.
На всякий случай - лучший способ проверить это собрать и запустить тест.
Достаточно собрать посредством cmake с опцией -ВMDBX_ENABLE_TESTS=ON и запусить полученный исполнимый модуль
./mdbx_test --repeat=42 --pathname=$(TEST_DB) basic
R
00:17
RattenKong 🦧🐀🦍️
понял-принял, надо будет как-то это сделать на мобильных платформах
C
00:32
CZ
я думаю под андроидом нельзя просто взять и запустить "./mdbx_test --repeat=42 --pathname=$(TEST_DB) basic”, придется засунуть это все в библиотеку и от туда организовать вызов.
00:33
мы кстати тоже за интересованы в мобильной версии mdbx, если это все будет надежно работать мы бы тоже интегрировали в наше мобильное приложение.
00:33
так что если кто-то сможет запустить тесты - будет суппер.
00:37
Для супер-мега тестирования следует запускать скрипт https://github.com/erthink/libmdbx/blob/master/test/long_stochastic.sh
Вероятно его потребуется немного поправить.
00:39
Аналогично для iOS
C
00:40
CZ
интересно, после того как этот тест изнасилует сторадж мобильного устройства, оно не сойдет сума, для мобильных устройств вроде бы не характерны такие нагрузки.
Л(
00:43
Леонид Юрьев (Leonid Yuriev)
Ну это слишком, в полном объеме (до остановки) этот тест может работать 2-3 месяца, а то и больше...
Поэтому достаточно запустить минут на 10, чтобы он перебрал все режимы работы БД.
00:45
При этот нет особого смысла запускать тест с размещением тестовой БД на флешке, обычно достаточно tmpfs/ramfs/ramdisk.
19 April 2020
C
21:50
CZ
кто-то протестил под android/iphone?
Л(
21:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не думаю, все ждут халявы (как обычно).
Рекомендую наладить CI в собственном форке и потом сделать PR.
20 May 2020
Vassilis invited Vassilis
V
20:28
Vassilis
Hello. Is there an English speaking room for mdbx? Здравствуйте, есть ли англоязычная комната для mdbx?
Л(
20:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
No, but this chat-room is bi-lingual.
V
20:33
Vassilis
Thank you Leonid and thank you for your software. Are there by any chance any plans to support mdbx as an nginx module? If not, is someone interested in a paid engagement to help me with it?
Л(
20:40
Леонид Юрьев (Leonid Yuriev)
Perhaps there are two important points here:
1. I don't understand what API such module should provide for NGINX.
2. In may, I plan to release a C++ interface for libmdbx, which will make it much easier to make such solutions.
V
20:42
Vassilis
My goal is to have an http interface to do get and put of data. Maybe use openresty/Lua and use the libmdbx via ffi to perform the get/set
20:42
Openresty is nginx + Lua
Л(
20:46
Леонид Юрьев (Leonid Yuriev)
In other words, you need bindings to lua, which could be used in NGINX.
V
20:46
Vassilis
Yes, that would be the best
Л(
21:05
Леонид Юрьев (Leonid Yuriev)
Ok. In general it is possible, but there is potential issue in write-intensive workloads:

NGINX internally uses event-loop and prefers avoid waiting on a mutexes.
In contrast, libmdbx explicitly uses a mutex to serialize all writing transactions (reads are executed without waiting).
So, NGINX will not be able to process more than one request with write-to-database transactions, i.e. you will get a bottleneck.
However, read requests will be processed with cosmic speed.

Therefore, if you have a very heavy load of writing to the database, I strongly recommend that you look at Tarantool.
V
21:08
Vassilis
Yes I read about single write. How many writes per second you think is possible? I will not have many write operations but many read.
21:08
I would rather not use tarantool, to be honest.
Л(
21:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
This depends linearly on disk performance and inversely on the Log(data size).
For a rough estimate: random-write IOPS of HDD/SSD divided by 10.
21:20
IOarena (https://github.com/pmwkaa/ioarena) may be useful to estimate performance on the particular hardware.
V
21:23
Vassilis
Sounds good and fast, to be honest. So would it be possible to sponsor such functionality for the libmdbx to be used via Lua / openresty? I think would be a nice feature for the community
Л(
21:34
Леонид Юрьев (Leonid Yuriev)
In reply to this message
I'm pretty busy, so I don't want to make any promises.
I think you should fill two issues (one into libmdbx, the second into NGINX) and link ones.
It is likely that there will be an interested developer.

In the meantime, for my part, I can promise that I will soon add support for C++, will always be happy to give advice and answer questions.
V
21:35
Vassilis
Thank you very much!
V
22:16
Vassilis
ioarena gives me 4.500k RPS for write with sync (avg 221 us). That's on my laptop. Is that good?
?
22:17
👹 LA
can you post full log of all dbs tests?
Л(
22:18
Леонид Юрьев (Leonid Yuriev)
Hmm, that's too good.
The total number of entries corresponds to what you will have in production?
V
22:18
Vassilis
No. I just did a random test based on the defaults of ioarena. I'm using a VM so perhaps it really writes to my macbook's RAM instead of disk
22:19
is that 4.5 million RPS?
22:20
In reply to this message
I only compiled mdbx. This is in my VM so I have to use pastebin or so
22:30
vedisdb was 186.815k and 709ns on the same (SET) test. I think vedisdb does not do fsync on disk. I have the sync option but I'm not sure it honors it
22:31
sqlite at 1.700k and 588us
22:32
May I safely assume I'm doing something wrong? Please advise
Л(
22:39
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Seems your VM caches writes in RAM, i.e. at least NOT every fdatasync() inside VM actually flushes data to disk.
There is an example of a real performance measurement, e.g. https://github.com/erthink/libmdbx#sync-write-mode
V
22:39
Vassilis
I'm installing and compiling now in a normal LXC container under bare metal
22 May 2020
Л(
16:53
Леонид Юрьев (Leonid Yuriev)
Vote (and briefly describe your project) to extended support of true security by Kaspersky OS.
https://github.com/erthink/libmdbx/issues/106
C
20:18
CZ
KasperskyOS lol?
20:22
now russian intelligence agency offers OS, hope they won’t force apple too preinstall it into iphones 🙂
Л(
22:41
Леонид Юрьев (Leonid Yuriev)
In reply to this message
This is a pretty stupid joke.
I don't think you would write such nonsense if you had any idea what it was about.
C
22:43
CZ
i have pretty good idea of what is Kaspersky, been workin in antimalware industry for 8 years, and have a lot of friends working in Kaspersky.
Л(
23:02
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Then you should know how much I work in this field and how many people I know personally.
C
23:04
CZ
how it’s related?
23:05
i just know that Kaspesky well connected with russian intelligence agency, don’t you agree with that?
23:09
i have feeling that i’ll be kicked from this chat in few moments 🙂
Л(
23:34
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Hmm, why do you think I have fewer connections?

However, all this has nothing to do with the theoretical basis of the design and a properties of KasperskyOS.
So, please don't flood here by off-topic.
C
23:44
CZ
As you wish 🙂
31 May 2020
A
19:20
Aleksei🐈
Если кому-нибудь вдруг интересно, статья про наш проект, в котором мы использовали lmdbx
Л(
19:21
Леонид Юрьев (Leonid Yuriev)
👍
A
19:23
Aleksei🐈
Полностью под андроид тесты мы не делали, но в рамках нашего приложения все работает
1 June 2020
C
2 June 2020
Л(
00:01
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Какие-либо проблемы исключительно под Андроид крайне маловероятны, ибо это фактически linux с немного сокращенным API.
Т.е. если собралось, то регресс может быть только "возле" соответствующих ifdef-ов.
Но этот код был проверен локально, и у вас.
A
18:06
Aleksei🐈
In reply to this message
Ну собственно да, у нас особо сомнений и не было :)
18:08
Пожалуй получается лучшая kv библиотека для мобильных устройств по компактности скорости эффнктивности
18:09
У меня были мысли когда-то lmdb портировать под Android, но случайно вот нашли уже готовый порт ещё и прокаченный
Л(
18:49
Леонид Юрьев (Leonid Yuriev)
In reply to this message
LMDB вроде-бы давно собирается под Android, но я не пробовал.
5 June 2020
Л(
03:15
Леонид Юрьев (Leonid Yuriev)
Л(
14:45
Леонид Юрьев (Leonid Yuriev)
Разработчики Mail.ru написали статью об LMDB и немного про MDBX, в которой неплохо описаны основные концепции MDBX/LMDB и рассмотрены некоторые вопросы использования.
https://habr.com/ru/company/mailru/blog/480850/
A
14:59
Aleksei🐈
In reply to this message
На самом деле самый интересный момент в lmdb это выделение свободных страниц, так как напрямую влияет на скорость write commit
15:05
Если выделять последовательный набор страниц, то возможно сократить фрагментацию и добиться скорости записи сравнимой с wal, но поиск диапазона подходящего размера непростая задача. Насколько я помню в lmdb свободные страницы хранились просто в виде массива отсортировнных номеров страниц
15:05
Как с этим в lmdbx?
Л(
15:09
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не в "lmdbx", а в libmdbx либо в MDBX.
Кстати неплохо-бы поправить в вашей статье (а то никакой поиск не находит).

В libmdx с этим ровно также, и уже не будет меняться, ибо требует изменения формата БД.
Что-либо новое будет только в MithrilDB.
A
15:10
Aleksei🐈
In reply to this message
Ок, поправим
Л(
15:15
Леонид Юрьев (Leonid Yuriev)
В libmdbx реализовано переиспользование страниц в LIFO-режиме, что существенно увеличивает производительность при налиции write-back кеща (с батарейной) или гибридной системы хранения flash/SSD+HDD.

Но в LMDB (и в MDBX) есть проблема "распухания" БД при апдейтах на фоне долгих читающих транзакций.
Эта проблема будет решена в Mithril (иначе нет смысла релизить), но с первого захода не получилось сделать это достаточно эффективно.
13 June 2020
Л(
03:13
Леонид Юрьев (Leonid Yuriev)
19 June 2020
Л(
17:32
Леонид Юрьев (Leonid Yuriev)
25 June 2020
?
20:19
👹 LA
Леонид, доброго времени. А что вы можете сказать про mdbm (https://github.com/yahoo/mdbm)?
Сравнивали libmdbx/lmdb с ней?
Л(
20:37
Леонид Юрьев (Leonid Yuriev)
In reply to this message
?
20:44
👹 LA
проще говоря - или не сравнить, или будет хуже в некоторых кейсах?
Л(
20:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В MDBM:
- "ручная" блокировка для доступа к данным.
- нет транзакций.
- нет гарантий целостности при сбоях.
- ключи не упорядоченны (хеш-таблицы).

Поэтому MDBM подходит если достаточно read-only доступа к хеш-таблицам.
Например, к каким-то справочникам, которые перестраиваются целиком и НЕ часто.

Причем уже лет 10-15 замена MDBM легко "велосипедится" посредством https://theboostcpplibraries.com/boost.interprocess (STL-подобные контейнеры в разделяемой памяти). При этом вы получаете меньше головной боли.
Т.е. MDM было "круто" лет 25-30 назад, но сейчас - наверно +только+ для изучения "как оно было".
?
21:31
👹 LA
Понял, спасибо! Не умею так смотреть вовнутрь, поэтому наткнулся на её и удивился что снова не слышал достаточно старой базе
27 June 2020
Л(
01:34
Леонид Юрьев (Leonid Yuriev)
libmdbx (ветка devel) собрана и протестирована на платформе E2K (Эльбрус) с использованием компилятора lcc версий 1.23.20 и 1.24.11
24 July 2020
Л(
23:51
Леонид Юрьев (Leonid Yuriev)
Online libmdbx API reference now available!
https://erthink.github.io/libmdbx/
23:54
Feedback & suggestions are welcome.
13 August 2020
Kirill Yukhin invited Kirill Yukhin
Ilya K. invited Ilya K.
Aleksandr Lyapunov invited Aleksandr Lyapunov
Mons Anderson invited Mons Anderson
Alexander Turenko invited Alexander Turenko
Timur / 帖木儿 Safin invited Timur / 帖木儿 Safin
MA
14:30
Mons Anderson
@erthink
Я бы видел mdbx как модуль для тарантула, который можно подключить в app и использовать для persistent local storage
(в принципе я пока вижу этот движок как своего рода berkeleydb ;)
14:31
т.е. сишный слой библиотеки нужно завернуть в lua/ffi биндинги и реализовать удобный Lua API
Sergey Petrenko invited Sergey Petrenko
TS
14:37
Timur / 帖木儿 Safin
In reply to this message
да согласен, что как модуль могло бы быть естественным первым шагом. Но тогда и не совсем станет понятно зачем это как кеш использовать, если есть memtx. Да и не запустить так "рой процессов" если их надо будет встраивать в Tarantool
Л(
14:37
Леонид Юрьев (Leonid Yuriev)
я бы двигался небольшими шагами, так чтобы много не выкидывать и/или не переделывать )

Примерно так:
1) Скоро будет C++ API, который (теоретически) удобнее клеить посредством более-менее продвинутых генераторов.
2) Добавить в libmdbx механизм синхронизации через futex и получение FUTEX_FD.
3) После попробовать подклеить к тарантулу.

При этом следует понимать, что для прода мне нужна (будет реально полезной) связка fpta+тарантул, а не просто mdbx+тарантул. И с этим есть ряд отдельных вопросов.
MA
14:38
Mons Anderson
In reply to this message
Memtx = memory
14:39
В целом мы можем проконсультировать в плане вклейки сишной so'шки в app-рантайм тарантула (без связки с самими данными)
MA
14:41
Mons Anderson
p
puɐɯǝıu 13.08.2020 14:39:08
> - предполагается поддержка только linux и добавление в libmdbx еще одного механизма синхронизации на базе futex с возможностью использования FUTEX_FD (для неблокирующей синхронизации в фиберах тарантула).

если хотите это вставить с мейнлуп тарантула - можете воспользоваться eventfd и coio_wait
Л(
14:47
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Я относительно более-менее в курсе внутреннего устройства тарантула и примерно представляю потенциальные проблемы:
- в libmdbx пишущие транзакции живут отдельно от читающих.
- пишущие строго сериализуются через один mutex в shared memory.
- читатели требуют регистрации (назначения слотов в таблице читателей), эта регистрация еще под одним shared mutex.
- плюс есть еще один mutex внутри каждого процесса для синхронизации тредов при изменении размера БД.

Поэтому мне точно нужно добавлять фьютексы и API для вытаскивания FUTEX_FD, а потом думать о встраивании в eventloop. А вот можно ли это сделать исключительно из lua-модуля я пока не в курсе.
14:56
Отдельно хотелось-бы чтобы со стороны тарантула кто-то глянул на fptu-кортежи (https://github.com/erthink/libfptu) на предмет стыковки с нативными таплами тарантула.
Грубо говоря, мне нужно понять/увидеть наиболее рациональный способ приклейки fptu-таплов в тарантул.
Соответственно, буду благодарен за любые советы и соображения.
Л(
15:13
Леонид Юрьев (Leonid Yuriev)
Л(
Леонид Юрьев (Leonid Yuriev) 13.08.2020 15:12:43
Пардон, я по-привычке использую название FUTEX_FD (хотя стюярдессу давно закопали).
MA
15:14
Mons Anderson
In reply to this message
Доступа к eventloop чисто в lua нет, но если писать Lua модуль на C, то кажется можно добраться
15:15
In reply to this message
Нативный тапл — это msgpack-encoded структура
Л(
15:22
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, я в курсе, и в TODO у fptu есть "конвертация" в/из MsgPack.
Но (мне) надо понять как лучше делать преобразование с учетом всех возможностей и окружения.
Как вариант, не делать "палена из Буранино", а клеить уровнем выше (может быть куда-то ближе к SQL).
Л(
18:58
Леонид Юрьев (Leonid Yuriev)
По теме стыковки с Тарантулом, скоро я добавлю в libmdbx:

1) API для выбора/подклейки функций ввода-вывода.
Это позволит задействовать libeio и другие библиотеки асинхронного I/O, т.е. в любом случае не-на-выброс.

2) API для выбора/подклейки функций синхронизации и блокировки.
Это позволит условно "скрестить" shared mutexes с event-loop в тарантуле, а также логически объединять несколько mdbx-БД для одновременного запуска транзакций.
В любом случае эта фича также не пойдет в корзину:
- позволит в fpta перенести индексы и оперативные данные в tmpfs (@truerps, FYI).
- разнести по разным устройствам хранение мелких данных и больших блоков (Nexenta давно просили).

—-

В результате, с точки зрения взаимодействия с Тарантулом:

READ = Потенциальные треды-читатели будут регистрироваться при открытии БД.
Но даже если оставить как есть, то блокировки будут однократными и крайне мимолетными (считанные микросекунды).

WRITE = С захватом/ожиданием мьютексом при старте пишущей транзакции чуть сложнее:
- непосредственно подружить условный epoll и какой-либо метод синхронизации libmdbx (mutexes, semaphores, SysV IPC) не получится.
- поэтому я думаю запускать пишущие транзакции из отдельного треда в режиме MDBX_NOTLS, пробуждая запросивший транзакцию фибер через EV_ASYNC.
- со стороны Тарантула потребуется чуть-чуть подпилить coio_wait для приёма EV_ASYNC, либо добавить отдельную wait-функцию.
- в перспективе (при необходимости) можно подумать об экономии на переключении контекстов.

@cyanide_burnout, FYI
Леонид Юрьев (Leonid Yuriev) invited puɐɯǝıu
AL
20:54
Aleksandr Lyapunov
Leonid Yuriev added Nobody - забавно
p
20:55
puɐɯǝıu
А шо?)
AL
20:56
Aleksandr Lyapunov
это ж как в deadman
p
20:57
puɐɯǝıu
Никакой связи )
14 August 2020
Peter invited Peter
p
08:53
puɐɯǝıu
Про EV_ASYNC - я бы сильно не полагался на доработки на стороне Тарантула... Если все пилится исключительно под linux, что мешает все же смотреть на eventfd()? Все равно под капотом у libev для EV_ASYNC он используется (вроде, ну а что еще может кроме него использоваться?)
08:55
В своих проектах я для подобного триггеринга между потоками как раз использую evenfd + семафор
Л(
10:44
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Сегодня утром я склоняюсь к простому использованию coio_call() для всех блокирующих операций в отдельном треде.
p
10:53
puɐɯǝıu
Файберы - не треды
10:54
Хотя я может чего и не знаю на эту тему в тарантуле
10:55
Но мой опыт с тарантулом другой. Свои треды можно как угодно, а с мейнлупом тарантула надо аккуратно )
10:56
coio_call тупо создает файбер. В нем нельзя крутить бесконечность, надо йелдить либо йелдой, либо coio_wait-ом
10:59
Пример показать не могу - постить сюда картинки возбраняется
11:00
И я чот не уверен, что coio_call можно из других тредов вызвать безопасно
11:01
+ не стоит забывать об оверхэде на создание файбера и уничтожене
Л(
11:25
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нет, вы путаете.
coio_call() использует пул тредов для асинхронного выполнения функции.
11:27
Накладные расходы там есть, но сделать что-то принципиально лучше без допиливания внутренностей тарантула нельзя (я не вижу как).
p
11:29
puɐɯǝıu
Да, пересмотрел свой код, там fiber_start
11:30
В любом случае, если собираетесь взаимодействовать с луа - вам в мейнлуп
Л(
12:36
Леонид Юрьев (Leonid Yuriev)
In reply to this message
С луа обниматься я не хочу, но (видимо) придется.

Для libmdbx многопоточность и асинхронность не требуется.
Все приседания нужны _только_ чтобы меньше блокировать обслуживающие фиберы треды тарантула.

В libmdbx есть несколько потенциально блокируемых мест, но с учетом специфики тарантула их остаётся три:
- ожидание на мьютексе при старте write-транзакции.
- ожидания fdatasycn/msync при коммите write-транзакции или явном вызове mdbx_env_sync().
- page fault при чтении холодных данных из БД при выполнении CRUD-запросов.

Во всех этих случаях пользователю можно предложить смириться либо с блокированием tx-тредов, либо с накладными расходами на асинхронное выполнение.
В свою очередь асинхронное выполнение логично реализовывать через coio_call(), а не через дополнительные велосипеды.
При этом в coio_call() есть накладные расходы, от которых в принципе можно избавиться (malloc/free).
Но это задача оптимизации C-API тарантула, но никак не приклеивания libmdbx.
p
12:46
puɐɯǝıu
у меня три своих модуля для тарантула: 1) это чек во внешнем фильтре блума через memfd, 2) доставка конкретных данных в обход iproto через memfd 3) некое подобие своего memcached на memfd с триггерингом по eventfd и прямой записью/чтения спейсов или вызова луашных функций в тарантуле в обход iproto
12:47
в последнем - свой C-шный файбер и coio_wait
12:48
все остальное - это C-шные луашные модули, которые, в принципе и без тарантула могут на луа-машине работать
12:49
соответственно, ваши потребности похожи на что-то из вариантов 1 и 2
12:49
можно отвязаться от чисто тарантула и просто сделать луашные модули, которые можно как в тарантул пихать, так и с чем угодно, используюзщее луа использовать
12:50
тогда пофик на coio и прочее, нужно только иметь ввиду, что lua не thread-safe
12:50
и все тарантульные приблуды работают в одном эвент-лупе
Л(
12:56
Леонид Юрьев (Leonid Yuriev)
Мои потребности на самом деле это интеграция libfpta и тарантула, причем желательно включая SQL.
Чтобы можно было использовать тарантул как фронтенд для fpta.
А подклейка libmdbx к тарантулу - это пробный подход к снаряду, который в любом случае нужен для многопроцессного взаимодействия с одной БД.
На всякий напомню: libfpta - это надстройка над libmdbx реализующая таблички с колонками и индексами.
12:57
Lua же для меня вовсе на самоцель, а способ поскриптовать в тарантуле.
p
14:13
puɐɯǝıu
Оба штатных движка тарантула заточены на хранение кортежей в msgpack и все внутренние и внешние апи заточены на это. Если встраивать это дело как один из бэкэндов, явно появится оверхед на сериализацию / десериализацию.
14:13
Кстати, SQL-фронт тарантула - это аккуратно выдранный SQLite
Л(
14:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В курсе. Есть также SQLite натянутый на LMDB и libmdbx, но там ряд проблем...
Л(
14:35
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В курсе.

Увы, MsgPack - imho не лучшее решение:
- с одной стороны, экономиться память, что хорошо для memtx и WAL.
- с другой стороны, народ неизбежно начинает именовать поля (хранить пары строка->значение) что уничтожает всю экономию и только добавляет затрат на (де)десериализацию.

Однако, fptu-кортежи предположительно не создадут проблем с производительностью:
- преобразование fptu-кортежа в msbpack стоит примерно столько-же сколько просто формирование msgpack.
- преобразование msgpack в fptu-кортеж стоит примерно столько-же сколько распаковка msgpack.
- создание, обновление и чтение fptu-кортежей примерно всегда дешевле msgpack (хотя для наглядности не хватает бечмарков).

При этом для моих задач msgpack местами принципиально не подходит - нужно добавлять некий микро-индекс чтобы быстро видеть наличие поля (не-null) и читать значение без чтения всех предыдущих.
UPD: А если такой индекс добавить к msgpack, то fptu-кортежи становятся и рациональнее и быстрее.
AL
15:48
Aleksandr Lyapunov
мы в msgpack имена полей делаем enumами. быстро и дешево
15:49
микроиндекс у нас специально есть в struct tuple
P
16:26
Peter
Hi. I am Peter from Australia. I have had an interest in lmdb and libmdbx for some time. However I haven't been using libmdbx for a while, and it looks like a lot has changed.
For are start it looks like a lot more people involved in developing than just Leo.
I thought I would ask who else is involved with libmdbx and this telegraph group?
I am also interest in find out what you do and what you use libmdbx for?

For myself I am trying to develop a distributed p2p database using Scala and ZIO.dev
I see a modified version of lmdb or libmdbx that works on the jvm (and hopefully also other platforms - android, js etc) as the bottom layer of that stack.
P
16:42
Peter
(I don't speak Russian, but I can always use google translate if you prefer to reply in Russian)
Л(
17:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
А насколько дорого изменения значения поля в кортеже тарантула.
Но именно в контексте одного struct tuble, а не транзакции и/или replay.
Скажем был null, обновили на true, а потом 4242.42
?
MA
17:56
Mons Anderson
In reply to this message
"обновления" как такового нет. это всегда создание нового тапла
AL
17:57
Aleksandr Lyapunov
подтверждаю
Л(
17:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
А ну тогда понятно, а то меня немного укачало в xrow_update...
p
17:59
puɐɯǝıu
А тарантул вроде целиком обновляет кортеж, но я не уверен. Теоретически если тип не меняется, можно резервировать поля под максимальный размер типа
Л(
18:04
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Как уже пояснили реализован COW, что собственно и нужно/логично для MVCC.
А спрашивал чтобы сопоставить/сравнить кортежи тарантула и FPTU.
Л(
18:27
Леонид Юрьев (Leonid Yuriev)
In reply to this message
No one else is involved in active development.
The reason is that the barrier to entry is quite high, due to the original coding style of Howard Chu (i.e. rebus code style).

For several years, the development of libmdbx has been funded by Positive Technologies.
So the library is used in the company's commercial products (see https://www.ptsecurity.com/)

in addition, libmdbx is used in such notable projects/companies as zano.org, miranda-ng.org and mtsgsm.com
Л(
18:55
Леонид Юрьев (Leonid Yuriev)
It is worth saying that in Miranda-NG, a year or two ago, there were enough problems with using libmdbx.
The reasons were both my errors (fixed a long time ago) and incorrect use of the library in Miranda.

Unfortunately, some errors in Miranda-NG remained unsolved and was not fixed for a long time, about two years.
This caused outrage, discontent and distrust among users. Once I even found it necessary to give explanations on this topic.

As far as I know, Miranda is still working with the DB in non-safe/non-durable MDBX_UTTERLY_NOSYNC mode.
Nonetheless, there have been no complaints from Miranda users for more than a year.
Л(
22:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Для (взаимо)понимания сравнение кортежей Тарантула с FPTU (aka «fast positive tuples»).

Кратко:
- Кортежи обоих видов живут в линейных участках памяти.
- в Тарантуле в начале индекс из 32-битных смещений к значениям, затем MessagePack-данные, null-ы хранятся.
- в FPTU в начале индекс из 32-битных дескрипторов (id + тип + смещение к значению), затем данные в сыром машинном виде с 32-битным выравниванием, null-ы НЕ хранятся.
- в FPTU больше явных типов данных, поддерживаются разреженные кортежи и preplaced-поля (структуры C), нет map-ов, вместо массивов есть коллекции (а-ля protobuf repeated).

FPTU-кортежи можно рассматривать как комбинацию фиксированной C-структуры (описывается схемой) и набора пар key{field_id,data_type}->value.

Дизайн FPTU-кортежей исторически рассчитан на «рыхлые» структуры, когда из обширного набора типизированных полей присутствует (имеет значения) относительно небольшая часть. При этом FPTU-кортежи пригодны для представления плоских/одномерных объектов в runtime и интенсивного изменения значений их полей.

---

Чуть подробнее о кортежах Тарантула:
- типы значений кодируются в данных, числовые значения поджимаются, доступ к данным по-байтный.
- поля идентифицируются порядком следования, null-значения требуется хранить.
- при наличии индекса к полю можно быстро обратиться по номеру, иначе требуется парсить данные.
- индекс может быть не персистентным, но его построение требует записи (кортеж без индекса не может быть в read-only памяти).
- в индексе только смещения к данным, для информации о типе нужно читать данные.
- изменения значений полей происходят с копированием кортежа (COW).
- кортежи могут быть очень большими (1Gb).

Чуть подробнее о кортежах FPTU:
- все значения хранятся в нативном машинном виде, с выравниванием на 32 бита.
- у кортежей может быть фиксированная часть (preplaced-поля, которые примерно соответствуют структурам C).
- поля нефиксированной части кортежа являются необязательными и неупорядоченными (looose-поля):
- loose-поля идентифицируются не порядком, а тегами и явно типизированы.
- отсутствующие loose-поля не занимают места, кортежи могут быть разреженными.
- loose-поля могут повторяться образуя коллекции (как repeated в protobuf).
- в индексе вместе со смещениями сразу есть enum-теги loose-полей и типы значений.
- индекс является частью кортежа и хранится вместе с данными, кортежи могут размещаться в readonly-памяти.
- доступ к loose-полю требует сканирования индекса (используется SSE2/AVX/AVX2).
- поддерживаются inplace-обновление значений, дефрагментация не обязательна.
- кортежи НЕ могут быть большими (<256K).
22:21
Задавайте уточняющие вопросы, если что.
Потом я это сравнение перенесу куда-нибудь в доку.
👹 LA removed 👹 LA
17 August 2020
Л(
16:31
Леонид Юрьев (Leonid Yuriev)
TO ALL: Which the C++ interface for key-value do you think is the best/most convenient?
C
16:35
CZ
Мы года два назад делали С++ обертку поверх lmdb/mdbx что бы можно было хранить структуры, может как-то пригодится: https://github.com/hyle-team/zano/blob/master/src/common/db_abstract_accessor.h
16:36
хотя это может быть не совсем то о чем речь
Л(
16:42
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Как-раз примерно то.
У меня почти готова реализация собственного видения, и теперь нужно оценить насколько она похоже на то что на самом деле нужно людям.
AL
16:56
Aleksandr Lyapunov
In reply to this message
STLный. либо я не понял вопроса
16:57
а, речь про key value DB
18 August 2020
Л(
11:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
20 August 2020
Л(
02:09
Леонид Юрьев (Leonid Yuriev)
Please take a look at the preliminary version of the C++ API.
https://github.com/erthink/libmdbx/blob/6eb816642bb355357e0a8194d3b471ca3d4573f0/mdbx.h%2B%2B
02:10
Feedback and suggestions are welcome!
C
15:27
CZ
кстати вопрос, а почему пишется ::std::string ? я если что не в курсе просто, может нам тоже так надо писать
Л(
15:38
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Никакой явной необходимости нет, но в некоторых ситуациях парсер в MSVC сходит сума намного меньше, и еще какая-то дребедень типа intellisence выдает меньше предупреждений.
C
15:42
CZ
понял. я тогда оставлю свой комментарий: так по хедеру сложно сказать, потому что он огромный с кучей перегрузок, наверное будет понятней в нескольких простых примерах в чем приемущество нового интерфейса. Для нас работа сводилась к нескольким элементарным функциям - get, set, enumerate, delete + плюс работа с транзакциями. В этом интерфейсе явно инструментарий шире гораздо, так что я там чуть потерялся.
Л(
16:08
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Тогда я чуть уточню на что хотелось-бы получить feedback:

1) Я постарался привести к здравому смыслу всяческие опции и флаги.
Соответственно получились operate_parameters, create_parameters, geometry, operate_options, reclaiming_options, durability, env::mode.
А также key_mode, value_mode, put_mode, map_handle и cursor::move_operation.
Хотелось-бы оценить насколько это (а) легко понять по названиям, (б) предположительно удобно использовать.

2) slice и buffer - надеюсь понятно что и зачем. Стоит ли добавлять поддержку полиморфных аллокаторов С++17?

3) Насколько понятно разделение на "managed" и "reference" классы: env/env_ref, txn/txn_ref, cursor/cursor_ref?
Может стоит по аналогии переименовать slice в buffer_ref, или как-то еще?

4) Кто готов на практике попробовать использовать новое API, в том числе для генерации байдингов к другим языкам?
Самое время попробовать и что-то допеределать.
C
16:10
CZ
плюс - мне кажется во всей этой истории важно что бы людям еще было просто и понятно переходить с текущего С-интерфейса на новый, возможно какой-то короткий гайденс не помешает.
Станислав Антонов invited Станислав Антонов
Л(
21:32
Леонид Юрьев (Leonid Yuriev)
@antstas, см мой ответ по теме feedback чуть выше
СА
21:33
Станислав Антонов
In reply to this message
ok
Л(
21:34
Леонид Юрьев (Leonid Yuriev)
mdbx::buffer будет переведен на pmr (C++17), а текущий вариант на std::allocator будет переименован в что-нибудь вроде buffer_legacy.

Как-то так:
#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L
using LIBMDBX_API_TYPE buffer =
basic_buffer<::std::pmr::string::allocator_type>;
#endif /* __cpp_lib_memory_resource >= 201603L */

using LIBMDBX_API_TYPE buffer_legacy =
basic_buffer<::std::string::allocator_type>;
A
22:11
Aleksei🐈
А итератор сделать поверх курсора не планируете?
Л(
22:14
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Сделать простейший итератор не сложно, но обычно затем случаются попытки мимикрировать под STL-итераторы с получением ряда проблем.
22:15
In reply to this message
Короче, предложите PR с вашим видением, а там посмотрим.
A
22:18
Aleksei🐈
In reply to this message
Попробую по возможности что-нибудь предложить. Просто итератор над курсором сам собой напрашивается
Л(
22:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
См мой ответ по теме https://habr.com/ru/post/459862/#comment_20414205
A
22:27
Aleksei🐈
In reply to this message
Ну согласен да, специфику надо учитывать. Я пока не смотрел c++ интерфейс, может и курсора достаточно будет
7 September 2020
Л(
00:15
Леонид Юрьев (Leonid Yuriev)
Peter invited A Telegram User
Л(
12:14
Леонид Юрьев (Leonid Yuriev)
Major update of C++ API:
- support for polymorphic allocators;
- base58/base64 encoding and decoding;
- partially documented by doxygen;
- other refined & improvements, but it's still a draft.

Feedback and suggestions are welcome!
https://github.com/erthink/libmdbx/tree/c++
Л(
15:38
Леонид Юрьев (Leonid Yuriev)
There is a problem with building the library using MSVC-2019.
At least MSVC 19.27.29111.0 hangs at AppVeyor during generating code for a release builds (i.e. when optimization enabled).
Seem this is an internal MSVC-2019 bug, but I couldn't reproduce it locally to submit a bug report.
Л(
22:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
https://github.com/erthink/libmdbx/issues/116
This is MSVC-2019 bug (linker hang in a busy loop).
9 September 2020
Л(
09:23
Леонид Юрьев (Leonid Yuriev)
P
Peter 09.09.2020 06:57:40
I am starting a project built on lmdb.
I am considering swapping to libmdbx.
I wanted to get your advice on the state of libmdbx.
Are you the only one working on it? Full time?
Are there others in the libmdbx with experience with libmdbx?
What does the roadmap for libmdbx and Mithraldb look like?
Л(
09:28
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Peter, wonderful!
You should not expect any problems from libmdbx.

Ок.
Am working full time for Positive Technology (known by various Gartner quadrants) which uses libmdbx & libfpta in an one of main products.

Judging by the github traffic, libmdbx now has about 100-150 users, but almost all of them are not members of this group (and apparently do not even know about it).
However, only I know all the details of libmdbx, just as only Howard Chu knows all the details of LMDB.

libmdbx is used in a production environments for now. Therefore, there are no planned development that are not required for Positive Technologies products.
The current roadmap for libmdbx is as follows:
- С++ API
- some improvements for mdbx_chk
- chaining mode to run one transaction for multiple databases, i.e. joining parts placed on HDD, SSD and ramfs/tmpfs to the logically single database.
+ Packages for AltLinux, AstraLinux, MCST Linux, Fedora/RHEL, Debian/Ubuntu.

The development of MithrilDB is associated with the need to solve several technological problems.
Managing large sets of page numbers, including their compact representation and storage, is one of these tasks.
There is no point in publishing any developments until all these problems are solved with all the requirements of Positive Technologies.
However, today/tomorrow I will formulate the objectives of developing MithrilDB on the site.
Л(
14:29
Леонид Юрьев (Leonid Yuriev)
P
Peter 09.09.2020 13:18:20
Hi Leonid.
I thought I would post here, because I don't want to criticize your work in front of others.
I note that not everyone has loved libmdbx.
Consider this harsh post from 2018
I also honestly despise libmdbx at this point, and I wish we could either get the old mmap back (honestly there is nothing good about mdbx), or if you really need something new, migrate to like a verified solution, i.e. sqlite. I understand it'd be slow but right now it's not really fast or at least I can't tell, and the fact the db is 2x bigger, unstable and potentially liable to lose your data with 0 recovery methods is honestly the scariest possible scenario for anyone using an instant messenger aggregator client.


I think you are very clever and have a great vision for this project.
However that does not mean that you can deliver a production ready db sometime soon. Stability, Scala support and other functionality are actually much more important to me than performance.
I am in the process of finalising a contract for a db project that was to rely on lmdb this week. I need to make a decision if I should switch to libmdbx as soon possible. If you are able to talk with me, I would greatly appreciate that.
Thanks
Л(
14:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Hi, Peter.

I don't have very good spoken English, so I don't think I can act as an evangelist for libmdbx.

Nonetheless, I can briefly formulate a few theses, which can then be proved separately:
1. libmdbx has more internal checks than LMDB, i.e. in many cases you will get an error instead of UB (including corruption or data loss) or SIGSEGV.
2. libmdbx has more features compared to LMDB.
3. For now libmdbx is better tested than LMDB.

—-

Using libmdbx in Miranda-NG has become a problem for me.
The library is used incorrectly there, or rather doubly incorrectly.
However, the developers of Miranda are not going to fix the situation.
Moreover, they have certain misconceptions about the internal structure and speed of both SQLite and libmdbx.
Even more, they don't listen to advice (

—-

If we talk about delivery a production-ready db, then I have no illusions.
There are too many usage scenarios and potential error situations to check everything.

So libmdbx is ready for subsets of use cases, especially are similar to PT' (Positive Technology) scenarios, i.e. for a use cases that are already tested in a (pre)production environment.
In other cases, there is a possibility of some bugs that have not yet been discovered.
But this is true for any software.

In general, my position is transparent and has long been unchanged: I am ready to cooperate on an open-source basis, that is, to help with advice and fix errors, if you will report them.
It is worth noting that I can spend quite a lot of time if (suddenly) there are any problems, as this will help to improve the quality and reliability of PT products.

To be honest (based on the amount of tests), I am sure that serious problems in libmdbx are impossible, but there may be manifestations of some minor flaws in rare use cases.
Л(
16:57
Леонид Юрьев (Leonid Yuriev)
Peter, If you find it difficult to make a decision I can only recommend this method:
- Read the "Improvements beyond LMDB" section = https://github.com/erthink/libmdbx#improvements-beyond-lmdb
- If you need one of these features, you should choose libmdbx, otherwise LMDB will be sufficient and good choice.
16:59
I think Howard Chu will tell you something similar.
P
16:59
Peter
Good to hear.
Thanks
14 September 2020
Л(
02:06
Леонид Юрьев (Leonid Yuriev)
In reply to this message
So, sure this is MSVC' optimizer bug.
Optimizer loops infinite (estimates an effect of function inlining) due complex code and /Ob2 option.

It would be possible to say that MS' optimizer is broken again, but can anyone tell did it ever fully worked?
19 September 2020
Л(
14:22
Леонид Юрьев (Leonid Yuriev)
To the mdbx_chk utility has added the ability to check database's MVCC-snapshots available from any of the three meta pages.
This will allows to evaluate the chances of users of Miranda-NG to recover their data lost due to intentionally misuse of libmdbx in this messenger.
See the devel branch at github.

В утилиту mdbx_chk я добавил возможность проверки MVCC-снимка/версии БД по любой из трёх мета-страниц.
Это позволит оценить шансы пользователей Miranda-NG восстановить свои данные из-за намеренно неверного использования libmdbx в этом мессенджере.
Доработки доступны в ветке devel.
Павел Осипов invited Павел Осипов
20 September 2020
Антон Марфин invited Антон Марфин
22 September 2020
Л(
00:46
Леонид Юрьев (Leonid Yuriev)
libmdbx v0.9.1 is scheduled for 2020-09-24
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Added features:

- Preliminary C++ API with support for C++17 polymorphic allocators.
- [Online C++ API reference](https://erthink.github.io/libmdbx/) by Doxygen.
- Quick reference for Insert/Update/Delete operations.
- Explicit MDBX_SYNC_DURABLE to sync modes for API clarity.
- Explicit MDBX_ALLDUPS and MDBX_UPSERT for API clarity.
- Support for read transactions preparation (MDBX_TXN_RDONLY_PREPARE flag).
- Support for cursor preparation/preallocation and reusing (mdbx_cursor_create() and mdbx_cursor_bind() functions).
- Support for checking database using specified meta-page (see mdbx_chk -h).
- Support for explicit reader threads (de)registration.
- The mdbx_txn_break() function to explicitly mark a transaction as broken.
- Improved handling of corrupted databases by mdbx_chk utility and mdbx_walk_tree() function.
- Improved DB corruption detection by checking parent-page-txnid.
- Improved opening large DB (> 4Gb) from 32-bit code.
- Provided pure-function and const-function attributes to C API.

Deprecated functions and flags:

- For clarity and API simplification the MDBX_MAPASYNC flag is deprecated.
Just use MDBX_SAFE_NOSYNC or MDBX_UTTERLY_NOSYNC instead of it.

Fixes:

- Fix mdbx_strerror() for MDBX_BUSY error (no error description is returned).
- Fix update internal meta-geo information in read-only mode (EACCESS or EBADF error).
- Fix mdbx_page_get() null-defer when DB corrupted (crash by SIGSEGV).
- Fix mdbx_env_open() for re-opening after non-fatal errors (mdbx_chk unexpected failures).
- Workaround for MSVC 19.27 static_assert() bug.
- Doxygen descriptions and refinement.
- Update Valgrind's suppressions.
- Fixed a lot of typos.
- Fix MSVC compiler version requirements.
- Workaround to avoid infinite loop of 'nested' testcase on MIPS under QEMU.
- Workarounds for QEMU's bugs to run tests for cross-builded library under QEMU.
25 September 2020
Л(
12:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Возможность проверки по произвольной мета-странице показала свою полезность.

Поэтому был реализован функционал переключения на выбранную мета-страницу при успешной проверки, а также преднамеренного переключения при ошибках проверки (для частичной выгрузки данных).

Соответствующие опции командной строки см mdbx_chk -h и man mdbx_chk.

Пожалуй, это максимум из того, что я могу сделать для пользователей Miranda NG, пострадавших из-за неверного использования libmdbx в этом мессенджере.
Л(
14:51
Леонид Юрьев (Leonid Yuriev)
Камрады, у меня всё-таки большая просьба сделайте, пожалуйста, ревью https://github.com/erthink/libmdbx/blob/devel/mdbx.h%2B%2B
A
15:02
Aleksei🐈
In reply to this message
А что за неверное использование?
Л(
15:12
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Там "ради скорости" используют режим MDBX_UTTERLY_NOSYNC и "для сохранности" данных периодически делают mdbx_env_sync().

Проблема же в том, что вторая транзакция после sync-a снова переводит БД в хрупкое состояние (высокой риск повреждения при выключении питания или системной аварии).

Далее, так как это мессенджер, то в БД почти постоянно что-то льется/меняется и, соответственно, БД слетает при любом системном сбое при работающем мессенджере.
27 September 2020
Л(
23:16
Леонид Юрьев (Leonid Yuriev)
30 September 2020
Л(
00:56
Леонид Юрьев (Leonid Yuriev)
Mikhail Kotov invited Mikhail Kotov
Л(
16:26
Леонид Юрьев (Leonid Yuriev)
Л(
17:41
Леонид Юрьев (Leonid Yuriev)
Mark ☢️ Korenberg invited Mark ☢️ Korenberg
MK
21:27
Mark ☢️ Korenberg
На опеннете сравнение с диаграммой
21:27
Какой идиот ее сделал ? Там нет единиц измерения
21:28
В итоге не понятно, хуже она роксдиби или нет
21:28
Т.е. это тпс или время
Л(
21:29
Леонид Юрьев (Leonid Yuriev)
Этот идиот я, единиц нету ибо безразмерно. См. все диаграммы (и подписи к ним) в README на гитхабе.
MK
21:30
Mark ☢️ Korenberg
Класс. Тогда надо написать хотябы. Чем меньше тем лучше или чем больше...
Л(
21:31
Леонид Юрьев (Leonid Yuriev)
Там разумный минимум информации. При желании на opennet-е можно редактировать новости.
Alexander Potapov invited Alexander Potapov
G invited G
Oleg invited Oleg
1 October 2020
Roman invited Roman
Roman Goncharuk invited Roman Goncharuk
timothy invited timothy
Dmitry Severyanin invited Dmitry Severyanin
Oleg removed Oleg
2 October 2020
Л(
00:17
Леонид Юрьев (Leonid Yuriev)
Компилятор MSVC-19.27.29112.0 из состава Microsoft Visual Studio 2019 16.7.5 по-прежнему зависает (зацикливается) при сборке libmdbx с опцией /Ob2 (включает инлайнинг всех подходящих для этого функций).

Насколько помню, этот баг всплывает у M$ уже в третий раз за последние 6 лет.

Обойти проблему легко: просто не использовать /Ob2.
Например, в CMake вместо 'Release' собирать 'RelWithDebugInfo'.
İgor invited İgor
Л(
15:15
Леонид Юрьев (Leonid Yuriev)
В список рассылки buildroot направлен патч для подключения libmdbx.

Было-бы здорово если кто-то попробует использовать, особенно на экзотических архитектурах, в том числе без MMU.
MK
16:24
Mark ☢️ Korenberg
In reply to this message
запилите пакет в OpenWRT\Lede
Л(
16:43
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Посмотрю в выходные.
6 October 2020
Vladimir Potареv invited Vladimir Potареv
7 October 2020
Л(
16:33
Леонид Юрьев (Leonid Yuriev)
Поступила жалоба/упрек что результаты бенчмарка ioarena не соответствуют заявлению о том что libmdbx немного быстрее LMDB.

Причина была в том что в драйвере libmdbx в ioarena задавался динамический размер БД.
Соответственно, во многих случаях (особенно при большом целевом кол-ве записей), размер файла БД многократно наращивался, на что тратилось время (добавляемое место должно быть перезаписано нулями).

Теперь это поправлено. Т.е. сейчас в драйве ioarena для libmdbx начальный размер БД задается такой-же как в драйвере LMDB.
8 October 2020
Roman invited Roman
9 October 2020
Konstantin invited Konstantin
Леонид Юрьев (Leonid Yuriev) invited Yandex Translate
Леонид Юрьев (Leonid Yuriev) invited Yandex. Translate
Леонид Юрьев (Leonid Yuriev) removed Yandex Translate
Леонид Юрьев (Leonid Yuriev) removed Yandex. Translate
10 October 2020
Л(
01:43
Леонид Юрьев (Leonid Yuriev)
По запросу Clément Renault из MeiliSearch в devel-ветке добавлена функция mdbx_env_delete().
12 October 2020
Deleted invited Deleted Account
Л(
01:06
Леонид Юрьев (Leonid Yuriev)
Testing call for libmdbx v0.9.2
Please clone the devel branch at github and run ./test/long_stochastic.sh.
Rare non-x86 platforms are most interesting.

Regards,
Leonid.
01:10
Oops, just now pushed (commit 112ce742f).
01:23
9-го числа попробовал подключить бота для автоматического перевода (дублирования) каждого сообщения ru<->en.
Эксперимент не удался.
Просьба сообщить если кто-то знает достойное внимания решение.
01:25
В идеале, наверное, каждому пользователю, хотелось-бы видеть кнопку "translate" на его родной язык.
MK
05:42
Mark ☢️ Korenberg
In reply to this message
Дописывалось нулями ?! fallocate() же
Л(
14:58
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, но на это тратилось время и общий показатель производительности "попугаев в секунду" тек вниз.
İgor removed İgor
fuunyK invited fuunyK
Alexey Akhunov invited Alexey Akhunov
AA
16:16
Alexey Akhunov
@erthink Только что прослушал ваш доклад от 2015 года и очень впечатлился. Мы сейчас используем LMDB для нашего клиента для Ethereum: https://github.com/ledgerwatch/turbo-geth. Всё было хорошо, пока мы не начали стирать целые таблицы и пересоздавать из в другом формате. И мы огребли большие проблемы с огромными freelist. Коммиты стали очень медленными. Поковырялись в коде, поняли, что это архитектурная проблема. Я хотел сделать убирание freelist путём перемещения страниц из "хвоста" базы данных в страницы из freelist, но вот сегодня увидел, что вы кажется это уже сделали. Поэтому теперь мы пранируем поэкспериментировать с MDBX, и возможно перейти на него с LMDB, потому что иначе наш проект будет парализован
16:19
English version: I have just watched your presentation from 2015 and was very impressed. We are currently using LMDB for our Ethereum client turbo-geth (link to the repo). Everything was fine, until we started removing the entire tables and recreate them in different format. And we hit serious problems with huge freelist. Commits became very slow. We dag into the code and understood that this is an architctural problem. I wanted to remove the freelist by moving the pages from the "tail" of the database to the pages from the freelist, but then I saw today that you seem to have implemented that already. That's why we are now planning to experiment with MDBX, and perhps switch to it from LMDB, because otherwise our project will be paralysed
Evgenii Danilenko invited Evgenii Danilenko
Renn invited Renn
Alex Sharov invited Alex Sharov
Л(
19:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Приветствую.
Я отвечу по-русски. Если кому-то нужен перевод по маякните или воспользуйтесь Яндексом.

Доклад 2015-го года всё-таки больше об LMDB, хотя и с упоминанием некоторых доработок сделанных в libmdbx.
За 5 лет libmdbx сильно ушла вперед. Грубо говоря, тогда это был fork с небольшими доработками, а теперь это существенно переработанная СУБД.

В libmdbx действительно реализована бесплатная дефрагментация, но без чудес и ровно настолько, насколько это можно сделать без дополнительных накладных расходов.
Поэтому, вполне вероятно, что проблемы с огромными записями во freelist/GC частично сохранятся.
Однако, в libmdbx ситуация в целом будет стремиться к разрешению - к дефрагментации и освобождению места.

Думаю, тут важно дать правильно понимание что и как будет происходить, но я не знаю как это сделать кроме как объяснить как именно это работает:

1) Массивное удаление данных всё равно будет порождать большие списки освобожденных страниц, и эти списки неизбежно будут записаны в freelist/GC.
Однако в libmdbx по-возможности большие записи будут по-шинкованны на более мелкие порции, что снизит в разы накладные расходы в последующих транзакциях.

2) В libmdbx, страницы БД прилегающие к концу используемого пространства, всегда выталкиваются. Это происходит при любых изменениях в БД приводящих к освобождению страниц.
Именно так, по чуть-чуть работает дефрагментация.
Однако, если в использовании останется страница близкая к концу, то это это остановит дефрагментацию.
AA
19:28
Alexey Akhunov
Спасибо за ответ! Да, я понимаю, что там нет никакой магии, потому что я сам хотел было начать это писать, но потом увидел и подумал - зачем, если вы уже написали 🙂 На не страшно, что freelist какое-то время поживёт, нам главное избежать "ловушки", в которую попадает LMDB при появлении большого фри-листа. Пока что мы сделали патч, который запрещает поиск во фрилисте, если нужно выделить более 16-ти страниц по-порядку. Это работает, но скорее всего есть у этого решения какие-то непредвиденные проблемы. Я сказал, что впечатлился выступлением, потому что по нему виден глубокий уровень понимания внутренностей LMDB, и это, в свою очередь добавляет желания попробовать libmdx. Нам было бы тоже очень интересно попробовать MythrillDB, когда там что-то будет. И, кстати, про масшабы - у нас в базе данных сейчас где-то 3 миллиарда записей, и размер - 750 гигабайт
19:32
Мы попробуем libmdbx в ближайшие дни (@AskAlexSharov сделает интеграцию) и расскажем вам, как получилось
19:35
"2) В libmdbx, страницы БД прилегающие к концу используемого пространства, всегда выталкиваются. Это происходит при любых изменениях в БД приводящих к освобождению страниц." - именно это я хотел попробовать сделать - но теперь не буду
Л(
19:36
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В libmdbx точно будет лучше, но насколько лучше - зависит от тонкостей сценария использования и того "как лягут карты".

Логику вашего патча о 16ти страницах я не понял.
Если по любым критериям отказываться от переработки (поиска и использования страниц в freelist/GC), то БД будет пухнуть.
G
19:37
G
а в android можно использовать libmdbx?
Л(
19:37
Леонид Юрьев (Leonid Yuriev)
750 гигабайт - это наверное рекорд, в МегаФоне было 100-120.
19:37
In reply to this message
Да, и в iOS тоже.
G
19:38
G
In reply to this message
стабильно работает без правок в исходниках?
MK
19:39
Mark ☢️ Korenberg
У нас тут массовый эскулайтокопец случилс
19:39
Потому что не стабильно :)
AA
19:40
Alexey Akhunov
логика нашего патча такая - когда нужно выделить 17 последовательных страниц или больше (для переполнения), мы не ищем в списке свободных страниц, а просто выделяем в конце. Конечно, если данные в основном с большими значениями (которые вызывают переполнения), то да, будет всё расти
Л(
19:40
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да.
Последние правки для этого были весной, но не концептуальные, а просто чтобы собиралось.
Тем не менее, в CI сборок для Android и iOS нет (с удовольствием приму PR).
MK
19:44
Mark ☢️ Korenberg
Рпм переходит с беркли диби на эскулайт. Как же вы не углядели
Л(
19:47
Леонид Юрьев (Leonid Yuriev)
In reply to this message
А ну т.е. вы так боретесь с большими списками страниц в памяти.
Такая правка как-то давно обсуждалась для Nexenta, у них схожие проблемы.
Правильная логика немного другая - нужно не отказываться от поиска во freelist, а не подгружать дополнительные записи если нужного кол-ва подряд не найдено и текущий список уже длинный (или подгрузка делает его очень длинным).
19:47
In reply to this message
Углядели.
Там было обсуждение, в том числе предлагали LMDB и libmdbx.
Но не захотели...
MK
19:48
Mark ☢️ Korenberg
In reply to this message
Каковы были аргументы ?
Л(
19:51
Леонид Юрьев (Leonid Yuriev)
In reply to this message
19:55
In reply to this message
Если потребуется, я могу сделать такую доработку в libmdbx.
Проще говоря, не растить список страниц в памяти более N.
20:07
Кто-то спрашивал про rust.

libmdbx переписывать на rust я точно не буду.
Как уже говорил, моя цель - довести проект до готовности, стабилизировать и заморозить, переключившись на MithrilDB.

Реализовывать MithrilDB на rust я пока тоже смысла не вижу:
1) в 50% кода начинается борьба с растом, т.е. от всего memory safe остается только unsafe и получается "rust ради rust".
2) rust примерно не живет без LLVM, в том числе на Эльбрусах.
AA
20:08
Alexey Akhunov
@erthink Большое спасибо за ответы! Будем пробовать
Л(
20:09
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
GK
20:11
Gleb K.
In reply to this message
Есть rust в pure c компилятор, так что можно и на Эльбрусе завести 😬 но это я так, между делом
Л(
20:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ну борьба скорее синтаксическая.
А причина в том, что все основные данные лежат в страницах БД, а не в управляемой памяти.
В результате написать на rust конечно можно, но safe получается не больше чем в C/C++.
GK
20:29
Gleb K.
In reply to this message
Ну научиться играться с лайфтаймами конечно очень интересная задача сама по себе, все таки новая абстракция. Но порой случаются досадные казусы, вроде того что нагородишь темплейты, потратишь на них пол дня, вроде логически работать должно, но не компилится. И ещё спустя пол дня наконец то нагуглишь что вот именно так сделать нельзя, компилятор ещё недостаточно умный, но вот вам многострочный и заумный костыль как обойти и обмануть компилятор.
Л(
20:32
Леонид Юрьев (Leonid Yuriev)
In reply to this message
+1
Л(
23:24
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Попробуйте использовать C++ API. Там может быть что-то сыровано (де-факто мало что протестированно), но код постой и легко поправить (что я и буду делать при необходимости).
AA
23:26
Alexey Akhunov
Нам нужно будет C, потому что мы пока что в Го интегрируемся
23:26
хотя у нас есть и C++ проект
23:26
но он только в самом начале пути
13 October 2020
AS
05:39
Alex Sharov
Привет. Впиливание libmdbx идет хорошо.
Запнулся об `mdbx_dbi_open_ex is deprecated, Please avoid using custom comparators".
У меня есть 1 кейс когда без dcmp сложно: нужно отбросить суффикс в 32 байта, все что осталось cmp_lexical (остатки будут разной длины).
Подскажите почему "avoid using custom comparators" и на что можно перейти.
Л(
06:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
При использовании кастомных компараторов невозможно полностью проверить целостность БД утилитой mdbx_chk.
Это не значит что их нельзя использовать, но просто не желательно.

В вашем случае, если речь именно о dcmp (втором) компараторе, то мне не совсем понятно зачем отбрасывать суффикс при сравнении.
Компаратор dcmp используется для упорядочивания multi-value (aka duplicates), т.е. когда ключу соответствует несколько значений, то они хранятся во вложенном b-tree, для которого и нужен компаратор.

Соответственно, отбрасывание суффикса не изменит порядок, то не позволит добавить значения отличающиеся только суффиксом.
Если вам нужно именно такое поведение, то следует использовать кастомный компаратор игнорируя deprecated.
Но я не уверен, вам нужно именно такое поведение?
AS
06:23
Alex Sharov
Отбрасывание суфикса изменит поряток если остатки будут различной длины. пример:
00{32bytes_of_1}
0000{32bytes_of_1}
Дефолтный компаратор посмотрит на второй байт и скажет что первый ключ больше. Если отбросить 32 байта, то первый ключ станет меньше - потому что он короче.
"00" - это я так нулевой байт обозначаю
Л(
06:27
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Теперь понял о каком отбрасывании вы говорите.
Если требуется сравнение именно как вы описали, то нужно либо использовать кастомный компаратор (и тогда mdbx_chk нужно будет использовать с опцией -i), либо подумать над тем чтобы изменить формат данных.
AS
06:27
Alex Sharov
спасибо
Л(
06:32
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Если хочется заглушить deprecated-предупреждения, то можно так https://github.com/PositiveTechnologies/libfpta/blob/master/fast_positive/tables_internal.h#L113
AS
06:34
Alex Sharov
ok, пока deprecated очень полезны - помогают понять где что отличается от lmdb
Л(
06:35
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Обратите внимание на время жизни курсоров и dbi-хендлов.
AS
06:37
Alex Sharov
спасибо, прочитал.
Л(
11:58
Леонид Юрьев (Leonid Yuriev)
@ledgerwatch, думаю стоит обсудить две доработки.

1) Условное повторение вашего патча для LMDB = не растить в памяти freelist/GC больше некоторого предела.
Оказывать влияние это будет только при поиск места для overflow страниц в больших БД.
В результате, вместо бесконтрольно роста GC-списка в памяти (что возможно при гиганском размере БД), страницы будут выделяться из хвоста с увеличением размера БД.
С системной точки зрения это, конечно, костыль, так как в конечном счете ведет в тупик (чем больше БД, тем больше вероятность её увеличения).
Тем не менее, если overflow-страницы будут выделяться более-менее равномерно, то наступит равновесие.
Доработка относительно простая = будет добавлена функция для установки соответствующего threshold.
Как выбрать этот threshold - отдельная тема, но он не должен зависеть от кол-ва запрашиваемых страниц.

2) Поддержка много-секционных БД.
Снаружи это выглядит как возможность размещать отдельные key-value spaces в b-tree с разным размером страницы и/или размещенные на разных носителях (SSD/HDD).
Соответственно, если у вас есть некие "большие" данные, требующие overflow-страниц, то их лучше будет поместить в b-tree с максимальным размером страницы (64К).
Таким образом, в вашем случае, проблема "большого freelist" решается более системно.
Из минусов - это относительно большая доработка, которая будет включаться отдельным define.
AA
13:25
Alexey Akhunov
По поводу первой доработки - да, мы скорее всего захотим поменять нашу модель данных чтобы минимизировать использование overflow pages, путем уменьшения размера значений. Пока что мы тестируем LMDB с этим костылём пока не проэкспериментируем с переходом на libmbdx
13:26
по поводу второй доработки - да, наши пользователи часто спрашивают о том, можно ли разделить файл базы данных на куски и хранить их на разных дисках. Я пока не знаю как это будет влиять на атомарность транзакций
Л(
13:29
Леонид Юрьев (Leonid Yuriev)
На всякий для понимания:
- первую доработку я сделаю инстантно, просто как только вы подтвердите заинтересованность (лучше сделать некоторые эксперимернты чтобы оценить N).
- вторую доработку неявно оплачивает Positive Technologies (в рамках моего full-time), но вам нужно будет своевременно участвовать (тестировать и высказывать пожелания).
AA
13:30
Alexey Akhunov
Да, мы готовы тестировать вторую доработку. По поводу первой, мы сейчас тестируем с числом 16 🙂
13:31
можно попробовать поиграть с разными числами, но я пока не придумал, как организовать такой эксперимент
13:32
нам сейчас нужно вылезти из "ямы" в которой мы оказались из-за этого сюрприза в LMDB, выпустить более-менее стабильную версию в четверг, чтобы нас пользователи не засыпали проблемами, начать изучать разные числа
Л(
13:34
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Технологически это тоже самое, о чем я писал.
С транзакциями всё хорошо, но будет изменение API и формата БД (мета-страниц).
Самое болезненное, видимо, именно изменение формата БД.
С точки зрения накладных расходов - минимум, будет чтение "чужой" cacheline и дна итераций легкого цикла в <1% случаев.
AA
13:36
Alexey Akhunov
нам пока не страшно изменения формата БД, если можно миграцию сделать за пару часов. Если нет, то мы попросим всех "пересинкать", этот процесс сейчас занимает от двух до пяти дней, в зависимости от дисков, но может быть переход на libmdbx поможет это ускорить
13:37
поэтому если через несколько месяцев мы решим сделать доработку про разделение базы на части, я думаю, мы сможем сделать миграционную утилитку, а для тех у кого нет места на диске, попросим перезакачать
Л(
13:48
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ну смотрите, тут масса блюд вашей внутренней кухни, а мне нужно понятность и прогнозируемость процесса в libmdbx.
Поэтому я (пока) буду действовать как мне удобно (в libfpta для Positive Technologies).
Ваше же влияние на этот процесс = (а) вы участвуете в тестировании и (своевременно) высказываете пожелание, (б) спонсируете и заказываете фичи.
Как реалист я на 99% рассчитываю на (а), но важно чтобы вы вовремя тестировали/оценивали добавляемые фичи.
AS
13:49
Alex Sharov
FYI: я закончил делать go биндинги, впиливать в приложение, и даже тесты прошли. Сейчас данные переливаются, завтра буду что-то осмысленное запускать.
Самое не привычное было - lmdb собирался самим go (там можно всякие CFLAGS указывать и он собирает), а lmdbx cmake-based проект, поэтому сбилдить его средствами go у меня сходу не получилось. Просто после make mdbx прилинковал готовый .a файл. Не думаю что это какая-то проблема, скорее просто непривычно.
Л(
13:59
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Несколько странно.
В libmdbx конечно более навороченный GNUMakefile, но (вроде-бы) никаких проблем нет на не-дремучих системах.
14:02
In reply to this message
Вероятно, вам стоит чуть более активно взаимодействовать со мной.
Это позволит как что-то поправить, так и внести правки в документацию/комментарии.
AS
14:11
Alex Sharov
Предлагаю, перенесни этот вопрос на пятницу или понедельник, когда мы разгребем свой завал и получим больше опыта с mdbx - тогда мы начнем хотеть чего-то конкретного.

Насчет резделенных файлов - наш юзкейс имеет следующую специфику:
1. Часть наших данных имеет свойство - не меняться если они достаточно старые - т.е. если данным пол года, то они иммутабельны. Вот эту иммутабельную часть и хотим унести в отдельные файлы. Т.е. это разбиение одного DBI на 2 (или более), а не разнесение двух DBI по разным файлам. И как следствие - хотим какую-то абстракцию - чтобы по двум частям DBI можно было бы ходить курсором "прозрачно для более высокоуровнего кода приложения".
2. Разделить DBI с большими значениями от DBI с маленьким значениями - это интересно - но мы никогда об этом не думали. У нас есть записи по 128Kb поэтому для них 64Kb странички может будут хорошо работать.
Думю что на эти 2 юзкейса нужно отдельно смотреть.

"Вероятно, вам стоит чуть более активно взаимодействовать со мной" - да, скоро принесу список обо что запинался пока запускал.

Мы в сильно разных верменных зонах - я во Вьетнаме, Алексей в Лондоне, поэтому можем отвечать как попало 🙂

Хотел еще спросить совета:
- У нас есть DBI где мы храним RoaringBitmap индексы. Каждый индекс где-то 1Mb. Мы их сейчас разбиваем на чанки по 2-м причинам - 1. мы их гоняем по сети, и есть возможность передавать на клиента только часть 2. пытаемся чтобы небыло overflow pages, поэтому размер шарда 2Кб.
- Вопрос - какой размер чанка вы бы посоветовали в mdbx? Больше шард - меньше записей в базе (но больше 64Kb думаю нельзя - много по сети гонять).
AS
14:38
Alex Sharov
What I faced during migration from lmdb to mdbx:

⁃ During data migration from LMDB to MDBX faced “MDBX_TXN_FULL: Transaction has too many dirty pages, i.e transaction is too big”
1. I run 2 migrations on MacBook and on Linux Arm PC (64Gb Ram). Migration on Mac finished successfuly, migration on Linux PC finished with “MDBX_TXN_FULL: Transaction has too many dirty pages, i.e transaction is too big”.
2. Migration didn’t do any intermediate .Commit calls
3. Actually we often using LMDB as “db with endless Tx size” - we can drop 200Gb DBI and create new 200Gb one in 1 Tx, or run 8 hour DBI rebuild from scratch also in 1 Tx. Do I need reproduce this issue?

⁃ Custom comparators:
1. We do store tree in 1 DBI. Tree has keys of various length from 1 to 70 bytes, values have fixed size of 32 bytes. First 40 bytes are quite repeatitive - if store it in DupSort bucket, it eats 2Gb - if store it in default bucket, it eats 16Gb. This is “hot” bucket for our application, this is reason why I converted this bucket to DupSort - if key is longer than 40 bytes, then I cut tail of key and join it to value (as prefix). In this case I need custom dup-comparator. Example:
00{32bytes_of_1}
0000{32bytes_of_1}
Default comparator will look into 2nd byte and say that first key is lower. But if drop last 32 bytes, first key will become higher.

⁃ mdbx_env_set_geometry(env, -1, -1, -1 -1, -1, 4096) - returns “MapFull” error. If set size_upper=2Tb then problem gone. Maybe I didn’t read defaults well.
Oleksii Ignachuk invited Oleksii Ignachuk
Ⱄⱅⰵⱇⰰⱀⱏ Ⰺⰾⱐⰺⱍⱐ invited Ⱄⱅⰵⱇⰰⱀⱏ Ⰺⰾⱐⰺⱍⱐ
ⰔⰊ
15:40
Ⱄⱅⰵⱇⰰⱀⱏ Ⰺⰾⱐⰺⱍⱐ
Здравствуйте. Скажите, а въ MithrilDB запланированъ сишный API? Или только C++?
Igor Mandrigin @ Gateway.fm invited Igor Mandrigin @ Gateway.fm
AA
18:18
Alexey Akhunov
@erthink Кстати, проспонсировать разработку мы тоже скорее всего сможем, хотя бы частично
I
18:20
Igor Mandrigin @ Gateway.fm
Всем привет, я тоже работаю с @ledgerwatch! А с кем можно поговорить по поводу модели безопасности, есть какая-нибудь документация на эту тему или человек с кем поговорить?
Л(
21:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В libmdbx максимальный "размер транзакции" по-умолчанию (видимо) меньше чем в LMDB. Этот предел несложно подвинуть (даже есть опция сборки), но дело в другом. Чем больше грязных страниц, тем медленнее операции, и в целом это не целевой сценарий использования. Поэтому этот лимит и был поставлен.
Если вам действительно необходимы транзакции по несколько сотен гигабайт, то это можно реализовать (в ChangeLog в секции TODO есть такой пункт).
21:14
In reply to this message
Ну и размер БД по-умолчанию вам тоже не подходит, т.е. конечно нужно использовать mdbx_env_set_geometry().
21:14
In reply to this message
Да, API для C будет.
AA
22:11
Alexey Akhunov
In reply to this message
По поводу оценки числа N - после размышлений я подумал, что нужно смотреть на типичные данные, а точнее на то, насколько большие бывают значения, и сколько в свою очередь требуется overflow pages. Мы можем прогнать такую оценку через нашу базу данных и посмотреть. Например, число 16 подходит для типичных значений 61kbytes. Для нас это наверное подходит, но мы проверим
22:16
я сейчас как раз тестирую процесс, который у нас в прошлом вызвал проблемы. Это перезапись целого DBI размером в 150 гигабайт и содержащего где-то 11 миллионов записей. Ключи остаются такими же, но значения меняются (перекодируются в другом формате или сжимаются). До этого мы делали перезапись в одной транзакции, и оставались в конце с базой данных на 150 гигабайт больше и огромным фри-листом. Сейчас я пробую по-другому - сначала прочитать всё, преобразовать и выгрузить во временные файлы. Потом удалить всю таблицу и сделать commit. И потом уже во второй транзакции (без всяких читателей в середине) залить новые данные в базу. Посмотрим, поможет ли это уменьшить фри-лист. Но я теперь подумал, что если будет много значений не умещающихся в 16 страниц, то фри-лист всё равно раздуется
14 October 2020
AS
04:46
Alex Sharov
Еще из идей про фрилист: можно добавить в ключ (или в префикс значения) информацию о том - какой самый большой sequence range есть в этой записи. 1. Это позволит не искать enough big sequence там где ее точно нет 2. Обновлять это значение может быть не очень дорого потому что - обновлять его нужно тогда, когда мы уже циклом по значению ходим (просто нужно этот процесс закончить чтобы второй по размеру sequence range вычислить).
04:51
Еще из идей про фрилист: это сортированный список uint. И значит 100% есть более компактный способ сериализации этого списка. Например RoaringBitmap - это сложная фиговина и ее врядли стоит тащить в базу, но, это просто пример того что можно сортированный список uint хранить сильно компактнее и при этом иметь возможность итерироваться по нему.
04:54
Еще из идей про фрилист: когда мы столкнулись с проблемой - самая медленная операция была - найти в большом фрилисте место чтобы записать изменившийся большой фрилист. Возможно имеет смысл решать только эту проблему, а не ее общий случай.
AS
05:55
Alex Sharov
Не связанно с предыдущими сообщениями:
- имеет ли смысл MDBX_TXN_OVERLAPPING если выставлен MDBX_NOTLS?
- отрицательные коды ошибок - это кастомные MDBX коды, а положительные это Syscalls Errno. MDBX часто возвращает EPIPE=0x20 - почему не EPERM? Например сейчас получаю из mdbx_setup_debug.
- в одном процессе - открыл базу, вызвал mdbx_setup_debug, сработало, закрыл базу, открыл заново (создал новый env), вызвал mdbx_setup_debug - получил 0x20.
- Мы используем MDBX_SAFE_NOSYNC (без MDBX_NOMETASYNC) - не по причине производительности, а по причине - хочется точно знать сколько времени занимает коммит и сколько времени занимает fsync - чтобы лучше понимать в случае баг-репортов - это проблемы у базы или у пользователя диск плохой. Мы руками вызываем после каждого коммита mdbx_env_sync(force=true, nonblock=false). Этого достаточно?
Boris invited Boris
ⰔⰊ
12:18
Ⱄⱅⰵⱇⰰⱀⱏ Ⰺⰾⱐⰺⱍⱐ
In reply to this message
Благодарю, это здорово
Л(
15:00
Леонид Юрьев (Leonid Yuriev)
In reply to this message
На всякий, для понимания, примерно в любой MVCC-базе будет такой эффект:
- MVCC предполагает что предыдущая версия данных остается сохранной. как минимум до коммита.
- а при коммите ничего не остается кроме как сначала положить рядом новую версию, а уже после старую отправить в утиль.
- соответственно, в MVCC сценарий "переписать БД в одной транзакции" всегда приводит к удвоению размера БД.

Более того, подобный эффект/проблема будет в любой БД гарантирующей ACID. Например, в условном Oracle потребуется место под логи (и муки отката транзакции при неуспехе).



Поэтому, некую "конвертацию" БД я настоятельно советую делать так:
- создавать новую БД причем в режиме MDBX_EXCLUSIVE, тем самым вы предотвращаете её использование до завершение миграции.
- в старой БД запускать пишущую транзакцию, тем самым предотвращая изменение данных, но позволяя их читать.
- переливаете данные, но не порождая мега-транзакций.
- закрываете новую БД и удаляете старую.

Примерно только так вы получаете ACID-гарантии, в том числе на сохранность данных при системной аварии по ходу миграции, и всё это без лишних движений/затрат.
Дополнительно можно подумать над именованием файлов новой и старой БД, включая транзакционное переименование при завершении и т.п.

+UPDATE: Стоит отметить, что в описанном алгоритме новую БД можно открывать в режиме MDBX_UTTERLY_NOSYNC + MDBX_WRITEMAP, а данные добавлять в порядке возрастания ключей (c опцией MDBX_APPEND). Это может быть существенно быстрее.
15:14
In reply to this message
По поводу потенциальных улучшений freelist:
- есть масса различных идей, включая использование "ревущих" битмапов от Daniel Lemire и т.п.
- но всё это требует изменение бинарного формата БД, поэтому будет в MithrilDB, но не в libmdbx.
AA
15:15
Alexey Akhunov
Мы уже используем ревущие битпамы для индексов
Л(
15:33
Леонид Юрьев (Leonid Yuriev)
In reply to this message
> имеет ли смысл MDBX_TXN_OVERLAPPING если выставлен MDBX_NOTLS?
Да, имеет.
Поскольку довольно странно что один тред одновременно изменяет данные в пишущей транзакции и читает какую-то предыдущую (возможно очень старую) версию данных в транзакции чтения. Есть риск смешать в обработке старые и новые данные.
Т.е. если такое происходит, то явно одна транзакция лишняя, либо какая-то другая проблемы дизайна или runtime.

> MDBX часто возвращает EPIPE=0x20 - почему не EPERM?
В явном виде EPIPE нигде не возвращается в коде libmdbx (см. git grep EPIPE).
А mdbx_setup_debug() возвращает не код ошибки, а предыдущее значение флагов (см. описание).

> Мы используем MDBX_SAFE_NOSYNC (без MDBX_NOMETASYNC) - не по причине производительности, а по причине - хочется точно знать сколько времени занимает коммит и сколько времени занимает fsync - чтобы лучше понимать в случае баг-репортов - это проблемы у базы или у пользователя диск плохой. Мы руками вызываем после каждого коммита mdbx_env_sync(force=true, nonblock=false). Этого достаточно?

Да, но видимо я сделаю ex-вариант коммита, с доп-параметром, который позволит получить время потраченное внутри sync.
15:37
In reply to this message
Для freelist они улучшают ситуацию, но не решают некоторых принципиальных проблем.
Поэтому требуется более сложная комплексная схема управления списками страниц в GC, а не просто схема сжатия id-шников.
AS
15:42
Alex Sharov
Overlaping - да. Mdbx мне уже выявил 2 проблемы дизайна и 1 баг. Огонь.
Л(
15:49
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
15 October 2020
AS
09:24
Alex Sharov
Добрый день. В lmdb и mdbx я ловил следующую штучку. DupSort DBI со следующим циклом: for cursor.First(); ; cursor.Next() { cursor.DeleteCurrent() } приводит к DB_CORRUPTION. Ошибка возвращается из метода cursor.Next()
09:25
lmdb вместо возвращения ошибки падал с assert( PageIsLeaf ) - тоже в методе Next
Л(
14:22
Леонид Юрьев (Leonid Yuriev)
In reply to this message
https://github.com/erthink/libmdbx/issues/121
Постараюсь поправить в ближайшее время.
AS
14:49
Alex Sharov
собрал мысли в кучу и дописал деталей.
Л(
14:53
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Спасибо, я уже воспроизвел проблему.
Там есть пара реально глупых косяков, которые (удивительно) до этого не вылазили.
Но проблема связана не с повреждением БД, а с зависимостью состояние курсора от необязательных аргументов.
AS
14:55
Alex Sharov
Я сегодня переделывал удаление наших DBI чтобы они не в 1 транзакцию удалялись а в несколько (чтобы не создавать 1 большую GC запись).
Сделал как-то так:
for cursor.First(); ; cursor.First() {
cursor.DeleteCurrent()
If deletedAmount > 1_000_000 {
break
}
}
2 раза First.
Л(
14:59
Леонид Юрьев (Leonid Yuriev)
Вот всё-так прошу обратить внимание на то, что я раньше советовал по реализации миграции.
Там принципиально лучшее решение без массы проблем, если же оно не подходит, то нужно точно понимать почему именно.
AS
15:00
Alex Sharov
Да, но нам чаще нужно смигрировать 1 DBI, а не всю базу.
AA
15:01
Alexey Akhunov
мы обратили внимание, спасибо. Так как у нас размер базы сейчас уже почти 750 гигабайт, то для миграции копированием нужно чтобы было еще по крайней мере столько же свободного места. Мы пока не может предполагать, что у всех пользователей оно есть
15:02
потому что некоторые покупают SSD на 1 терабайт
Л(
15:02
Леонид Юрьев (Leonid Yuriev)
В целом поведение курсоров очень тщательно проверяется в тестах libfpta, но там нет некоторых специфический кейсов с нулевыми аргументами mdbx_cursor_get() и mdbx_cursor_del(MDBX_CURRENT).
AA
15:05
Alexey Akhunov
Я еще поясню специфику нашего продукта. Он у нас для "массого" использования, поэтому мы не знаем, сколько людей и как его используют, в основном слышим, когда появляются проблемы
15:06
и нам миграцию поэтому нужно делать идеально "автоматическую"
15:06
то есть обновил версию, перезапустил, база перемигрировалась, и полетели дальше работать
Л(
15:10
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Надо подумать, в том числе посмотреть на поведение при удалении/очистке DBI посредством mdbx_drop(), а не поштучно.
Ибо всё-таки больной freelist не должен являться для libmdbx столь-же большой проблемой как в LMDB.
AA
15:11
Alexey Akhunov
я сейчас как раз изучаю в подробностях нашу проблему с freelist, чтобы точно понять из-за чего она возникает, насколько у нас фрагментированный freelist, и почему
15:12
похоже, что он очень фрагментированный, и это усугубляет проблему
15:12
там даже для 6-10 страниц подряд места не находится
AS
15:12
Alex Sharov
mdbx_drop мне сегодня сказал "transaction too big" - на 150Gb DBI - но вы говорили что есть какой-то флаг который нужно включить.
Л(
15:15
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это специфика b-tree, паттерн использования страниц стремиться к случайному/стохастическому.
Поэтому freelist тоже в среднем содержит случайные номера страниц, т.е. более-менее равномерно распределенные по всему диапазону.
AS
15:17
Alex Sharov
А вообще имеет смысл стремиться к последовательным номерам страниц? OS же можнет принять решения хранить страницы с последовательными номерами в разных местах диска и наоборот?
AA
15:17
Alexey Akhunov
я думаю, что это пережитки времен жестких дисков
AS
15:18
Alex Sharov
я просто не знаю - на сколько абстракция mmap абстрактна.
Л(
15:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Надо смотреть/разбираться, в том числе делать тесткейсы (причем задавая размер страницы в 256 байт).
В libmdbx кейсты подобно вашим (много-гигабайтные) исходно не предусматривались, более того я пару раз специально добавлял ограничения чтобы подобные анти-паттерны выявлялись при разработке, а не у пользователей.
AS
15:20
Alex Sharov
я поэтому и подумал "может и хорошо что mdbx_drop бьет меня по рукам - пойду порежу 1 транзакцию удаления на 100"
Л(
15:27
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это чуть более комплексная проблема.
ОС может принять (и принимает) такое решение, но в целом стремится к линейности.
Причина собственно в том, что чем больше линейности тем меньше объем мета-информации и тем проще работать с большими файлами.

Аналогично и с mmap, хотят внутри ядра ОС многое завязано на фичи процессора связанные со структурой PTE.

Тоже самое повторяет и с GC - чем более он линейный, тем эффективнее можно его хранить и обрабатывать.
Но в LMDB и libmdx нет оптимизаций для хранения и обработки линейных freelist-ов, ибо это в среднем очень редкий кейс.

В mithril всё будет иначе, но эта тема еще требует до-исследования.
AS
15:28
Alex Sharov
интересненько
Л(
15:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
MDBX_HUGE_TRANSACTIONS увеличивает лимит в 4 раза
AS
15:33
Alex Sharov
я думаю что мы впишемся в текущие лимиты. Без тормозов - лучше не ездить.
Л(
15:38
Леонид Юрьев (Leonid Yuriev)
Для понимания, проблемы с гиганскими транзакциями примерно такие:

1) Требуется другие реализации операций со списками страниц, заточенные не под эффективность для "средних по больнице" сценариев (мелкие транзакции), а под стабильность поведения.

2) Их сложно тестировать, т.е нужно много (~128-256) гигов ОЗУ чтобы тесты были более-менее быстрыми.

3) Мега-большие транзакции очень-очень мало кому нужны.
AA
15:40
Alexey Akhunov
Да, мы сегодня с @AskAlexSharov это обсуждали, и я уверен, что у нас тоже скоро отпадёт в них необходимость, когда модель данных стабилизируется
15:40
поэтому инвестировать слишком много в это я бы не стал
15:40
если работают текущие миграции без больших потерь - замечательно
15:41
мы просто сейчас в такой фазе очень "рискованного танца" - с одной стороны мы хотим продолжать улучшать модель данных, с другой - у нас всё больше пользователей
Л(
15:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это примерно стандартная проблема со стандартным решением - заранее требовать от пользователей двойной резерв свободного места на диске.
Если вы будите "заигрывать" с 1-терабайтными дисками, то рано или поздно, загоните себя в угол.
AA
15:57
Alexey Akhunov
понимаю
I
16:41
Igor Mandrigin @ Gateway.fm
если двойное место — то просто создавать новую БД при миграции? makes sense
AS
Л(
16:43
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, это стандартный путь (гарантирующий отсутствие проблем), который используется повсеместно, включая PostgreSQL, MySQL, Oracle и т.п.
I
16:44
Igor Mandrigin @ Gateway.fm
ну да, такое для нас неплохо с одной стороны, потому что фрагментация минимальная
16:45
кстати, у меня такой вопрос, может уже задавали
16:45
например у меня есть база в стостоянии S, и я ее выложил в инет, как снапшот
16:45
а потом я туда еще напихал данных и получил S’, ничего не удалял
16:46
есть ли шансы сделать какой-то дифф-снапшот чтобы вторую не целиком выкладывать?
B
16:46
Boris
Ты что подразусеваешь под выкладывать?
I
16:47
Igor Mandrigin @ Gateway.fm
ну если у нас chaindata на блоке 10.000.000 и мы его выложим off-chain
16:47
а потом мы хотим выложить для 11.000.000
16:47
было бы не оч круто 2 базы по 700 гб выкладывать
B
16:47
Boris
а про пописать кусок памяти в конец.
I
16:48
Igor Mandrigin @ Gateway.fm
ну как-то так… наивный способ — просто открыть 2 бд и руками их слить
16:48
но может что-то красивее есть
Л(
16:48
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Эта feature обычно называется "incremental backup".
Сделать возможно в виде некой отдельной утилиты, но сейчас не реализовано.
I
16:49
Igor Mandrigin @ Gateway.fm
ну да, я что-то очень много слов написал для такого простого концепта 🙂
16:49
именно это я и имел в виду
Л(
16:52
Леонид Юрьев (Leonid Yuriev)
Технологически реализуется как постраничный diff для b-tree, с дальнейшей оптимизацией diff-объема путем поиска страниц с ближайшим содержимым и сжатием с использованием предыдущего содержания БД как словаря для back-reference.
I
16:53
Igor Mandrigin @ Gateway.fm
ну я не думаю, что мы сами сейчас будем это реализовывать, просто хотел узнать, нет ли стандартных инструментов
Л(
16:58
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нет, готового ничего нет.
Базовая реализация относительно проста:
- открываете старую и новую БД, т.е. оба "снапшота".
- начинает обход b-tree посредством mdbx_env_pgwalk().
- делаете hash-cross-join для страниц...
- в итоге получаете diff в виде набора страниц и как-то его записываете, а потом реализуется apply для этого diff-а.
Л(
20:44
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Если коротко:
- проблему/ошибку я локализовал и (думаю) сегодня поправлю;
- специфика вашего кода в том, что на самом деле он удаляет записи не подряд, а через одну (так как после DeleteCurrent() курсор переходит к следующей);
- в LMDB (и унаследованно в libmdbx) есть баг в состоянии курсора, после удаления последней записи во вложенном b-tree для multi-values, когда там остается одна leaf-страница.
16 October 2020
AS
03:32
Alex Sharov
т.е. удалять много записей нужно таким циклом?
auto cursor = tx.OpenCursor(DBI)
for cursor.DeleteCurrent(); ; cursor.DeleteCurrent() {
}

а каково ожидаемое поведение cursor.DeleteCurrent на курсоре сразу после его создания (если его никуда другими методами не двигали)?
Л(
03:43
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Запутанное поведение...

В LMDB у Говарда Чу после удаления курсор переходил к следующей записи и взводился флажок C_DEL, если запись была последней то и C_EOF.
Но если после удаления курсор двигался на следующую запись, то первое перемещение игнорировалось и сбрасывало C_EOF.

Далее к этому добавлялась обработка частных случаев и "подпорок" для всяких исключений.
Например, переход к следующему дубликату после удаления возвращал NOTFOUND и т.д.
В результате, поведение НИКОГДА не было единообразным...
03:44
Это "место" я правил уже раз 10, но де-факто нужно еще раз допеределать (и добавить тесты).
AS
03:44
Alex Sharov
ок, значит я оставлю для совместимости с LMDB: First, Del, First, Del, ...
Л(
03:53
Леонид Юрьев (Leonid Yuriev)
Сейчас у меня готов черновой вариант, отрабатывающий без ошибок в соответствии с изначально задуманным в LMDB поведением.
Т.е. после удаления курсор переходит к следующей записи, но следующее перемещение еще на одну запись вперед однократно игнорируется.

Однако, мне очень не нравится такая непрозрачность, масса связанных с этим дополнительных проверок и ветвлений в коде.
Надо подумать и (вероятно) выпилить, с явным отражением в документации.
AS
04:03
Alex Sharov
да, не очень понятно на какую логику приложения рассчитано такое поведение.
AS
05:45
Alex Sharov
Какие еще негативные последствия могут быть от увеличения размера страницы? (кроме увеличения latency of random read и увеличения размера базы)
AS
07:45
Alex Sharov
Есть еще следующий кейс:
- мы старались чтобы большинство DBI были db-friendly - чтобы апдейты происходили только в конце DBI, чтобы чтения были последовательные...
- но не везде это получилось. И у нас есть DBI где ключи достаточно рандомны и обновления/чтения тоже достаточно рандомны и делают только upsert/get по одному ключу.
- поэтому для производительности мы накапливаем такие изменения в std::map - 1. он быстрее mdbx 2. многие ключи обновляются часто - до базы доходит только последняя версия.
- Но, из-за того что ключи достаточно рандомны - даже не очень большая std::map - может накопить столько изменений что придется обновить огромное количество страниц - и получить MDBX_TXN_FULL
- Вот думаю что с этим делать - уменьшать размер std::map - означает уменьшать наш throughput.
- Эта часть приложения - однопоточная.

И у меня такое ощущение что после того как я получил много раз MDBX_TXN_FULL (после попытки больших обновлений) - то сейчас запуская приложение на тойже базе я получаю MDBX_TXN_FULL даже на транзакции из 1 записи.
Л(
07:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Эта палка всегда о двух концах, получая что-то в плюс, вы получаете что-то в минус.
А общий баланс плюсов и минусов зависит от массы факторов.

Чем больше страница, чем меньше их количество, и меньше высота дерева.
Чем больше страница, тем более линейны обращения к диску, но больше RAF/WAF.
Чем больше страница, чем больше накладных расходов CPU по изменению данных с короткими ключами, но (в среднем) лучше для длинных ключей.
Если страница БД больше системной, то её отсутствие в ОЗУ породит не один, а несколько page fault.
и т.д.
AS
08:00
Alex Sharov
Спасибо.
Л(
08:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
- hdd-friendly (линейная структура) получается только при первоначальном заполнении с опциями MDBX_APPEND/MDBX_APPENDDUP. В остальных случаях итоговый паттерн доступа очень быстро выражается в случайный.

- накапливать изменения в std::map может быть и стоит. Например, это точно стоит делать если серия изменений приводит к исходным значениям, или какое-то большое подмножество ключей обновляется много раз. В остальных случаях выигрыш может быть меньше чем потери из-за роста RSS и суммарного трафика по памяти.
Тут я бы предложил посмотреть в сторону LRU, с вытеснением самых давно обновленных записей из std::map в БД.

- MDBX_TXN_FULL может возникать по двум причинам: либо много измененных (dirty) страниц, либо очень много retired страниц для помещения во freelist.
Первую причину можно отследить через mdbx_txn_info() и сделать коммит до того как лимит будет достигнут.
Вторая причина, к сожалений, пока не попадает в инфу от транзакции и не видна снаружи, но фактически большой freelist получает только при множественном удалении данных.

> И у меня такое ощущение что после того как я получил много раз MDBX_TXN_FULL (после попытки больших обновлений) - то сейчас запуская приложение на тойже базе я получаю MDBX_TXN_FULL даже на транзакции из 1 записи.

У вас действительно очень специфический сценарий, под который оптимизаций не делалось (не считая проверки работы на больших транзакциях).
Поэтому я не исключаю что могут быть какие-то недочеты.
Так или иначе нужно разбираться что происходит, в том числе пытаться воспроизвести проблему искусственно в тестах с минимальным размером страниц (чтобы помещалось в /dev/shm).
AS
08:32
Alex Sharov
Ок, Это про dirty страницы. Добавлю txinfo в сообщении об ошибке и буду смотреть. Вложенные транзакции проблему с количеством dirty страниц не решают(а наоборот ухудшают), да?
Л(
08:33
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да
AS
08:36
Alex Sharov
Многие DBI получается наливать через append. А mdbx_copy -compact улучшает ситуацию с фрагментацией?
Л(
08:37
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, копирование с компактификацией дефрагментирует и "выпрямляет" БД.
Л(
20:53
Леонид Юрьев (Leonid Yuriev)
Для желающих спонсировать теперь есть официальный способ: https://sobe.ru/na/libmdbx
PayPal и другие варианты (пока) не предполагаются.

Ближайшие задачи:
1) исправление унаследованной ошибки перемещения/состояния курсора после удаления текущей записи (issue #121).
2) замер длительности отдельных стадий коммита.
3) ускорение обработки больших списков грязных страниц (актуально для больших транзакций).
4) дополнительные эвристики и доработки для связанные с большими списками страниц (актуально для транзакций с удалением или изменением большого кол-ва данных).
5) релиз 0.9.2 и обновление пакета для buildroot
6) поддержка простейшего варианта многосекционных БД.
7) финализация C++ API.
8) подготовка пакетов для различных дистрибутивов.
9) релиз 1.0
AA
22:31
Alexey Akhunov
In reply to this message
Попробуем зарегистрироваться в Яндекс-деньги, посмотрим - я никогда раньше не использовал
Л(
22:32
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Там не нужна регистрация и вообще сильно не заморачивайтесь.
17 October 2020
Л(
02:12
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Чтобы не затягивать с простыми доработками, я вытащил пару вещей из stash и черновых веток.
В частности, теперь есть mdbx_txn_commit_ex() со сбором commit stages latency в опциональный аргумент.
Doxygen-описания пока нет, но там (вроде-бы) всё очевидно.

Предлагаю пробовать эту функцию вместо костылей в виде ослабления durability и замера длительности mdbx_env_sync().

+ В ветке devel на github = https://github.com/erthink/libmdbx/commit/2e31b2cc5ae90a565a0605f0838bac7873979c65
AS
08:06
Alex Sharov
SafeNoSync ( but no flag NoMetaSync):
preparation=0s gc="9.347µs" write=0s fsync=0s whole="163.162µs"

MDBX_SYNC_DURABLE:
preparation=0s gc="52.022µs" write=0s fsync="33.858µs" whole="62.404µs"
AS
09:23
Alex Sharov
Один раз получилось что Whole меньше суммы слагаемых:
preparation=0s gc="43.636µs" write=0s fsync="6.718µs" whole="42.943µs"
19 October 2020
AS
05:49
Alex Sharov
Вспомнил еще штучку:
- Месяца 2 назад мы нашли что если открыть базу в ReadOnly, то DBI можяно открыть только в Read-транзакции которую нужно закоммитить.
- Когда еще нужно коммитить Read транзакции?
AS
07:38
Alex Sharov
@ledgerwatch хочешь пообщаться про https://t.me/libmdbx/441 ?
Л(
10:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Что-то явно не так с арифметикой, то ли у меня при операциях с monotime, то ли у вас с конвертацией из 16dot16.
Надо будет разобраться.
AS
10:58
Alex Sharov
я списал конвертацию:
const ratio = 1000000000
func toNano(seconds16dot16 C.uint32_t) uint64 {
return (
ratio*seconds16dot16 + 32768) >> 16
}
Л(
10:59
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это в LMDB так.
В MDBX открытые DBI сохраняются, если только они не были созданы непосредственно в прерванной пишущей транзакции.
11:00
In reply to this message
А на какой платформе вы отлаживаетесь?
AA
11:01
Alexey Akhunov
In reply to this message
Я пока не готов. Мне хочется дописать парсер файлов LMDB, чтобы полностью разобраться в формате. И я всё-таки решил попробовать проверить, насколько быстро можно удалять freelist путём переноса страниц. После этого, думаю, у меня будет достаточно знаний, чтобы начать смотреть код MDBX
AS
11:03
Alex Sharov
In reply to this message
цифры которые я давал: с linux amd64. дать config.h?
Л(
15:40
Леонид Юрьев (Leonid Yuriev)
In reply to this message
У ratio тип должен быть uint64_t, иначе будет переполнение
AS
16:02
Alex Sharov
действительно. спасибо. тогда так:
SafeNoSync: preparation=0s gc=29.632568ms write=0s fsync=0s whole=365.463257ms
Durable: preparation=0s gc=20.675659ms write=0s fsync=494.659424ms whole=892.730713ms
AS
16:26
Alex Sharov
и с macbook: preparation=0s gc=10.284424ms write=0s fsync=1.487411499s whole=3.873718262s
Л(
16:27
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Что-то whole сильно больше слагаемых.
Надо будет мне перепроверить код.
AS
16:28
Alex Sharov
но whole равен тому что я снаружи померял.
Л(
16:29
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да так должно быть, но получается что раскладка по слагаемым сильно искаженная.
AS
16:31
Alex Sharov
зато поднимает вопрос - что на маке в коммите происходило оставшиеся 2 секунды
Л(
16:33
Леонид Юрьев (Leonid Yuriev)
In reply to this message
На всех платформах разница существенна.
Видимо я что-то упустил, вечером посмотрю код.
Л(
18:22
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Пока не увидел каких-либо изъянов, и код достаточно прост.

Видимо нужно смотреть на ситуацию в целом:
1) Если есть конкуренция писателей, то освобождения мьютекса будет вызывать немедленное переключение на другой тред.
2) После sycn-а внутри mdbx_txn_end() выполняется освобождение всяческих списков, и если транзакции большие (и не в WRITEMAP-режиме), то это может быть достаточно затратный процесс (с выталкиванием больших регионов в ОС, компрессией/декомпрессией/подкачкой страниц).
AS
18:25
Alex Sharov
1. нет. это пример из однопоточного кода.
2. если честно я так и не осознал достаточно глубоко что такое writemap (поэтому мы его не используем пока).
18:28
раньше код был запутанным и включать writemap было опасным, сейчас уже наверное более безопасно - но пока не дошли руки нормальный эксперимент запустить. "This may be slightly faster for DBs that fit entirely in RAM, but is slower for DBs larger than RAM" - плюс мы далеко за RAM.
Л(
18:43
Леонид Юрьев (Leonid Yuriev)
In reply to this message
MDBX_WRITEMAP - это когда файл БД отображается в память на чтение-запись, а не только-чтение.
В результате данные меняются непосредственно в памяти, не требуются теневые/временные dirty-страницы и файловый I/O.

Соответственно, меньше накладных расходов и нужно намного меньше памяти для больших пишущих транзакций.
Однако, есть риск убить БД сделав запись по плохому указателю.

Что касается упомянутого примечания, то очень многое зависит от того как работает ядро ОС, т.е. какие там тактики/стратегии.
Без WRITEMAP всё упирается в LRU для Unified Page Cache - это сейчас работает более-менее одинаково хорошо во всех ОС (даже в Windows), кроме OpenBSD где нет Unified Page Cache.
C WRITEMAP теоретически LRU должен работать только также, но бывают странности из-за того что тут для LRU возникает две метки последнее чтение и последняя запись.
Плюс с WRITEMAP иногда возникает отдельная боль в системах с компрессией грязных страниц - может получаться что ядро ОС начинает их лишний раз сжимать/разжимать, хотя стоило-бы просто записать на диск.

В вашем случае я бы рекомендовал (как и писал ранее) WRITEMAP при необходимости больших транзакций, т.е. при миграции/конвертировании БД и именно для нового экземпляра.
AS
18:46
Alex Sharov
"В результате данные меняются непосредственно в памяти" - но copy-on-write же совсем не выключается? Иначе как rollback работать будет...
Л(
18:51
Леонид Юрьев (Leonid Yuriev)
In reply to this message
CoW всегда остается, но без WRITEMAP все копии страниц, измененные страницы и новые, сначала накапливаются в памяти, а при коммите пишутся в файл.
Причем, пока они не записаны, приходиться просматривать этот dirty-кеш в памяти при чтении каждой страницы.
AS
18:53
Alex Sharov
а, вот теперь понятно. Алексей, смотри, я нашел LSM в LMDB ^
18:53
🙂
21 October 2020
Л(
02:38
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Вероятно через пару часов (как пройдут тесты Coverity и CI) я пропушу итоговую версию фикса в devel.

Подумав и попробовав я решил не менять поведение унаследованное от LMDB:
- это меняет API и ранее отлаженный код начинает подглючивать.
- полностью выпилить нежелательные состояние/флажки не получается из-за перемещений NEXTDUP/PREVDUP.
- в результате получается еще запутаннее...

Исправление как-бы финальное, но патч затрагивает массу условий по коду.
Поэтому есть вероятность что придется править что-то еще.
AS
06:15
Alex Sharov
Пару вопросов:
- есть ли у вас какой-то опыт использования libmdbx на какой-нибудь файловой системе с включенной компрессией? Можете ли что-то подсказать - что точно будет работать плохо, а что может быть ок? Для случая: read-only база.
- "Please don't forget submit a PT with your Go' binding (if it is seem reasonable)." - имеете ввиду: 1. куда-нибудь в отдельную репу как сделано для lmdb https://github.com/ledgerwatch/lmdb-go/ ? 2. или в https://github.com/erthink/libmdbx ? 3. или что-то другое имеется ввиду?
AS
08:12
Alex Sharov
Обновил devel:
Mac: preparation=0s gc=2.532959ms audit=0s write=0s fsync=2.033721924s ending="30.518µs" whole=7.402679443s
тесты на разную возню с курсорами прошли
AS
09:40
Alex Sharov
И еще:
- shrink_threshold - нужно дописать немножко документации - как его выбирать. И например если установить 1Gb growth step, то не будут ли эти 2 параметра мешать друг другу (один наращивает, второй уменьшает). И я правильно ли понимаю - за динамическую геометрию мы платим появлением какого-то мьютекса? Какие операции через него проходят? Хочу сделать какой-то тест на это - посмотреть как просядет график латенси параллельных чтений при росте базы.
Л(
10:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Какого-то конкретного опыта нет, не было необходимости.
Но всё будет достаточно печально: ядро Ос должно будет разжать данные при первом чтении и хранить пока есть память.
А при нехватке памяти выбрасывать закешированные страницы, а при обращении к ним (page faults) снова разжимать соответствующие блоки файла.
Так как данные жмутся обычно порядка 16-32-64К, то логично установить именно такой-же размер страницы.

Про bindings - я намерен начать собирать их внутри репы libmdbx, имо если отдельно, то не тестируются и они протухают.
Как именно это делать, в том числе в случае в golang, пока полного понимания нет, есть только намерения:
- максимально нативным для каждого языка способом, чтобы пользователям было удобно.
- с подключением CI-тестов.
10:55
In reply to this message
Пока не понятно почему теперь сумма слагаемых не совпадает с whole.
10:59
In reply to this message
Шаг приращения и увеличения не должны быть слишком маленькими, чтобы не дребезжать по-понапрасну,
Логично также не ставить шаг уменьшения меньше шага приращения, ибо иначе сразу после увеличения БД есть повод её уменьшить.
Вроде-бы это где-то написано в доке, но возможно ошибаюсь.
AS
11:23
Alex Sharov
я выложил текущую версию go биндингов: https://github.com/torquem-ch/mdbx-go
можете взять если хотите.
там же есть пример CI на винде: https://github.com/torquem-ch/mdbx-go/blob/master/.github/workflows/test.yml#L19
22 October 2020
AS
09:14
Alex Sharov
"Логично также не ставить шаг уменьшения меньше шага приращения, ибо иначе сразу после увеличения БД есть повод её уменьшить." - имели ввиду шаг уменьшения больше шага приращения? А если дефолт оставить grow_step=1Gb, shrink_threshold=-1 ?
AS
09:36
Alex Sharov
У нас есть место - где мы std::map сортируем и заливаем в DBI. Можно ли получить какую-то пользу из того что данные уже отсортированы?
AS
12:10
Alex Sharov
На devel сейчас получил: mdbx_cursor_put: MDBX_CORRUPTED: Database is corrupted
При наливании 35Gb данных в пустой DBI через AppendDup
(сейчас второй раз наливается, посмотрим)
Л(
13:45
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Сегодня посмотрю
13:56
In reply to this message
По умолчанию, т.е. если параметр shrink_threshold=-1, то он будет установлен в два раза больше grow_step, т.е. так чтобы не было проблем.
AS
14:04
Alex Sharov
Л(
14:08
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В Append режимах заполненные страницы не будут разделяться пополам, вместо этого будет добавляться новая страница.
Таким образом, при добавлении данных в порядке возрастания, в append режимах страницы будут полностью заполненными, а без них только наполовину.

Если затем не предполагается добавление данных (либо обновление с удлинением значений), то append-режимы позволяют получить более плотное заполнение БД за меньшее кол-вот тактов CPU.
Но добавление данных после append-режимов, почти в каждом случае, будет приводить к разделению уже полностью заполненной страницы - вся ранее полученная экономия будет скомпенсирована.
AS
14:09
Alex Sharov
да, мы для себя это назвали "slackness effect" 🙂 и не боремся с ним
14:12
я имел ввиду случай когда DBI уже полный, и уже принял много обычных апдейтов. И потом мы приходим с еще одно отсортированной пачкой - и вопрос - можно ли какую-то пользу получить от того что они уже отсортированы или то что это "увеличивает вероятность попадания в кэш" уже достаточно и остальное не важно?
Л(
14:13
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Вполне вероятно что это последствия последних доработок.
Если упало один раз, то упадет и еще.
Надо формировать/изолировать минимальный сценарий изолированный.
AS
14:14
Alex Sharov
второй раз упало в том же месте завтра добавлю логов.
Л(
14:24
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это увеличит эффективность LRU для всех кешей (как в CPU, так и page cache внутри ядра ОС), но величина эффекта сильно зависит от общего размера данных.
Непосредственно для БД от этого хуже точно не будет.
Однако, затраты на std::map, в том числе место в ОЗУ, могут быть больше экономии.
Т.е. только ради упорядочивания std::map терпеть не стоит.

Кроме этого, стоит ответить, что переход на MDBX_WRITEMAP должен в дать в разы больше эффекта.
14:25
In reply to this message
Лучше постарайтесь описать сценарий, включая паттерн размера ключей и данных.
AS
14:53
Alex Sharov
DupSort. 2 вида ключей: 32 и 40 байт (из них первые 32 байта это крипто-хэш). У ключей 32 байта не бывает дубликатов. У ключей 40 байтов много дубликатов. Значения ключей по 32 байта - от 1 до 30 байт, у ключей в 40 байт значения длиной от 33 до 100 байт(из них первые 32 байта это крипто-хэш).
14:54
Дефолтные компараторы
Timur / 帖木儿 Safin removed Timur / 帖木儿 Safin
Л(
16:46
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не понял, вам же требовались кастомные компараторы?
AS
17:42
Alex Sharov
Да, но эта ошибка случилась не с тем DBI. Здесь дефолтные.
17:49
У нас 50 DBI из них 5 DupSort из них 1 с кастомным dcmp. AppendDup сегодня ругнулся на DupSort без компаратора.
Л(
18:21
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Я попробую добавить тесткейс, чтобы воспроизвести проблему, но не факт что получится.
Поэтому вы можете помочь показав stack trace.
Т.е. приложить патчь https://gist.github.com/erthink/933c62a7718421aec4be7100d0570065, воспроизвести проблему (с оптимизацией -Og или -O0), получить core и показать стек вызовов из gdb (или в скриншот из MSVC).
23 October 2020
Л(
05:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Пробовал воспроизвести посредством игры с параметрами существующего теста, пока не получилось.
Поэтому stack trace от вас был-бы кстати.
И на всякий уточните - вы добавляете данные посредством mdbx_put() или через mdbx_cursor_put()?
AS
06:49
Alex Sharov
mdbx_cursor_put(MDBX_APPENDDUP)

stack trace - да, где-то через час закончу текучку и возьмусь за mdbx.
Л(
10:09
Леонид Юрьев (Leonid Yuriev)
Буду пробовать вечером, но и stack trace тоже жду.

На всякий флажки MDBX_APPEND и MDBX_APPENDDUP работают по-отдельности.
Первый - для ключей (требует упорядоченности ключей).
Второй - для значений при равенстве ключей (требует упорядоченности значений и даёт эффект при заполнении страниц вложенных b-tree).
AS
10:16
Alex Sharov
похоже я забыл sudo для gdb 🙁
(../sysdeps/unix/sysv/linux/raise.c: No such file or directory.)


APPENDDUP для DupSort DBI я использую без APPEND.
Л(
10:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Хм, raise.c не найдется и с sudo.
AS
10:19
Alex Sharov
libc6-dbg и libc6-dev стоит.
Л(
10:25
Леонид Юрьев (Leonid Yuriev)
Всё верно, gdb видит символы и может отработать bt. Но исходников glibc в системе нет, и они не нужны.
AS
10:37
Alex Sharov
Л(
10:38
Леонид Юрьев (Leonid Yuriev)
Спасибо, буду смотреть через ~час
26 October 2020
Л(
04:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Доработал тесты и в результате нашел пару недочетов, но не относящихся к проблеме.
Тесты более-менее постоянно крутятся на десятке машин, но проблему воспроизвести пока не удалось.
Ваши гига-логи качаются, смотреть буду завтра во второй половине дня по MSK.
27 October 2020
Л(
16:08
Леонид Юрьев (Leonid Yuriev)
В сухом остатке:
- устранена еще одна, унаследованная от LMDB, ошибка (Говард Чу по подсказке поправил в LMDB, плюс еще одну багу ранее устраненную в libmdbx).
- были доработаны тесты и устранено несколько недочетов, не связанных с обозначенными проблемами.
- однако, я не смог воспроизвести проблему с APPEND, в том числе с вашими данными и на различных версиях (старых, промежуточных, текущей).

Тесты продолжают работать. Если не будет новой информации, то завтра я закрою issue на github, а к выходным будет релиз 0.9.2
AS
16:12
Alex Sharov
Ок, я сегодня попробую туже базу использовать из мастера. Если так же сломается, то будем считать что побилось каким-то незаредиженым кодом.
16:12
Спасибо
AA
16:19
Alexey Akhunov
А я планирую закончить начальное ревью интеграции и первичные тесты, и замержить интеграцию сегодня или завтра (скорее всего завтра). И она будет доступка как экспериментальная опция в нашем релизе в четверг
Л(
16:50
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Не заметил ваш ответ на github, когда писал предыдущее сообщение.
Как там ответил, мне нужен способ воспроизведения проблемы.

Маловероятно, но все же возможно, что воспроизводимость проблемы зависит от текущего содержимого БД, даже если конкретная multi-map пуста или отсутствует.
Поэтому, если проблема воспроизводится на конкретной БД, то она мне нужна целиком, а не просто её дамп.

Разместите сжатый файл БД где вам удобно, но с sha-дайджестом в имени файла и отправьте URL в личном сообщении в телеграм.
16:54
Кроме этого, если проблема воспроизводиться (только) в вашем ПО (на go-lang, etc), то я готов по-отлаживать.
Но мне нужны максимально короткие инструкции как это сделать.
AS
17:51
Alex Sharov
На мастер версии mdbx - тоже в том же месте MDBX_CORRUPTED. Ok, попробую загрузить этот файл базы.
18:03
я воспроизведу с mdbx_load чтобы исключить go-lang
Л(
18:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, желательно. Чтобы точнее понимать где проблема и меньше пересылать данных.
28 October 2020
pavel invited pavel
Л(
17:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
У вас получилось воспроизвести проблему без go-lang?
Л(
19:16
Леонид Юрьев (Leonid Yuriev)
Также меня интересует feedback по https://github.com/erthink/libmdbx/issues/123#issuecomment-714574885
29 October 2020
AS
07:07
Alex Sharov
Добрый день.
- "У вас получилось воспроизвести проблему без go-lang?" - еще в процессе.
- https://github.com/erthink/libmdbx/issues/123#issuecomment-714574885 - я не очень понимаю какой нужен фидбек - нужно протестировать в devel появляется ли MDBX_TXN_FULL на LifoReclaim? Или что?
AA
15:11
Alexey Akhunov
В сегодняшнем релизе мы включили экспериментальный саппорт
15:11
MDBX
Л(
15:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Там вылечена описанная проблема, но не отключением поиска больших multi-page, а прекращением подгрузки записей GC при длинном списке.
Желательно чтобы вы это попробовали, но и подумали о желаемом лимите.

На днях я реализую API для установки этого и других лимитов, и нужно будет задавать какие-то значения.
Универсальных решений тут нет, а ваш сценарий использования достаточно экстремальный.
15:18
In reply to this message
👍
p
15:46
pavel
Вопрос знатокам mmap()-технологий. А можете сказать, где должно бомбануть, если на 64-гиговой машине 8 процессов запамят в память каждый по 16 файлов по 1 гиг каждый и начнут их рандомно читать. Иногда встаю в ядре, которое что-то перебирает в списках свободных страниц.
Л(
15:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Буквально "бомбануть" нигде не должно, но если данных больше чем ОЗУ и паттерн обращения случайный, то система будет вязнуть в LRU-вытеснении и подкачке данных.
Единственный выход - не делать так.
p
15:55
pavel
Вот не очень понятно насчёт LRU-вытеснений. Одно LRU-вытеснение - это операция за единицу. Казалось бы, цена промаха мимо кеша должна быть равна одному походу на диск. Но иногда я получаю 300 мсек в ядре внезапно на что-то внутри page_fault.
Л(
16:20
Леонид Юрьев (Leonid Yuriev)
При честной реализации LRU достаточно дорог.
Поэтому примерно повсеместно он реализуется через комбинацию различных эвристик и подпорок.
Всё это ориентируется на работу в оптимистических сценариях, когда "горячие" данные помещаются в память, ибо прочие сценарии оптимизировать бесполезно.

Линукс более-менее справляется пока данные помещаются в память.
Если же данных больше, то многие эвристики и оптимизации начинают работать против.
Т.е. вы начинаете попадать на какие-то пенальти, в том числе на синхронное выполнение подзадач/процедур управления памятью.

В разных версиях ядер это проявляется по-разному. Периодически что-то то улучшают, то ломают.
16:22
Но в целом - нужно либо "не есть с ножа", либо тюнить ядро (включая кастомные сборки и собственные правки).
16:25
Однако, максимум что вы получите - уменьшение выбросов latency при существенном (кратном) увеличении суммарных расходов CPU на обслуживание LRU.
AS
17:08
Alex Sharov
In reply to this message
Ок, завтра погоняю новый devel с lifo.
17:11
Вопрос: если shrink_threshold большой - может ли это стать причиной замедления (сильного) mdbx_env_close? И лечить это нужно уменьшением shrink_threshold?
Л(
17:28
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нет, shrink_threshold не может влиять на длительность закрытия.
mdbx_env_close() явно сбрасывает данные на диск и освобождает ресурсы.
p
17:45
pavel
In reply to this message
Я думал LRU это просто список. Достать из конца и пихнуть в начало - это просто..
Л(
17:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Но для начала надо дешево отследить страницы к которым было обращение...
Короче, советую покурить https://www.kernel.org/doc/gorman/html/understand/understand013.html
p
18:01
pavel
In reply to this message
каждая страница при обращении просто выдергивается из своей позиции в списке и пушится в голову списка. Этотсупердешево
18:05
Ладно я покурю всё посоветованное
30 October 2020
AS
07:34
Alex Sharov
Хорошие новости: у меня получилось воспроизвести Corruption без большой базы - наливая дамп того DBI в пустую базу (на текущем master коммите).

Для этого нужно:
⁃ добавлять данные только через APPENDDUP (без APPEND)
⁃ не делать промежуточных коммитов (только 1 коммит в конце, но до него дело не дойдет).
⁃ А это кореектно - наливать данные в DupSort бакет только через MDBX_APPENDDUP (без MDBX_APPEND)?
- Значит ли это что рекомендованный способ заливания больших данных - это много маленьких коммитов? Как-то это неконсистентно.

mdbx_load - делает промежуточные коммиты - думаю поэтому не воспроизводится (когда я из скрипта делаю промежуточные коммиты - не воспроизводится).

Еще я вижу такой код в mdbx_load (зачем занулять компараторы?):
mdbx_dbi_open_ex(txn, subname, dbi_flags | MDBX_CREATE, &dbi,
(putflags & MDBX_APPEND) ? equal_or_greater : nullptr,
(putflags & MDBX_APPEND) ? equal_or_greater : nullptr);
Л(
15:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Спасибо за информацию, сейчас займусь этим.

Про MDBX_APPENDDUP без MDBX_APPEND:
- Да, это корректно в libmdbx (в LMDB не уверен). Соответственно, при этом append-логика заполнения страниц будет работать только для дубликатов (aka multi-values), но не для ключей.
- Однако, в mdbx_load для этого нужно внести правки, как минимум выбирать data-компаратор по флагу MDBX_APPENDUP, а не MDBX_APPEND.

Про компараторы в mdbx_load:
- Компараторы не "зануляются", а выбираются по-умолчанию (если БЕЗ опции -a), либо подставляются псевдо-компараторы для опции -a.
Если данные отличаются эти псевдо-компараторы всегда возвращают результат "больше", тем самым реализуется сохранение порядка следования данных (со всеми проверками), вне зависимости от используемых пользователем компараторов.
AS
15:25
Alex Sharov
А, прикольно
Л(
16:38
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Я воспроизвел проблему, сегодня будет исправление.
AS
16:51
Alex Sharov
🔥
3 November 2020
AS
11:53
Alex Sharov
-DNDEBUG=1 - нужен по умолчанию?
Л(
14:13
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Так отключаются assert-ы на стадии компиляции, см. https://ru.wikipedia.org/wiki/Assert.h
AS
19:11
Alex Sharov
FYI: Сегодня у нас парень опять поймал проблему с фрилистом в LMDB (после нашего фикса) - у него фрилист после COPY_COMPACT вырос до 7М страниц и скатился в "худший случай" - когда ищешь последовательности и не можешь найти. В результате mdb_freelist_save внутри крутит цикл 10 минут. Будем копать.
Л(
19:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, это понятно/ожидаемо.
Как ранее писал в MDBX это пофикшено, но еще требуется выбор адекватного порога для отказа от поиска.

Кроме этого, всё это коррелирует с серией доработок "для больших транзакций", поддержка которых была частично выпилена из MDBX, ибо работала во вред в основных сценариях использования.
Для понимания, планируются такие доработки:
- ликвидация лимита для размера GC-списка, т.е. чтобы MDBX_TXN_FULL не возникала при mdbx_drop() даже при огромных размерах.
- переработка реализации списка грязных страниц, чтобы исключить скатывание в worst cases при больших размерах.
- поддержка установки различных порогов и лимитов в runtime.
4 November 2020
Л(
03:47
Леонид Юрьев (Leonid Yuriev)
В двух словах о v0.9.2: намеченный релиз откладывается, ибо:
- вероятно есть регресс/баг в изменениях после v0.9.1;
- формально текущий master не прошел тесты, хотя повторить сбой (пока) не получилось с 10-кратным повторением тестов;
- так или иначе, есть сообщение о проблемах от https://github.com/ledgerwatch, которое (единожды) получилось воспроизвести.
p
04:51
pavel
А напомните, в LMDB в единицу времени 1 writer, которого ждут все readers?
Л(
04:52
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, и в MDBX аналогично.
04:52
Только readerds ничего не ждут, примерно совсем.
04:53
RTFM.
p
05:39
pavel
Сорян да они не ждут.Перепутал с другими writers
AS
05:40
Alex Sharov
begin нового writer ждет когда закончится commit предыдущего writer - все остальное неблокируемо.
6 November 2020
AS
07:37
Alex Sharov
мде... в lmdb совсем нет возможности получить размер DupSort DBI... только врубив audit. в mdbx вроде есть.
AS
11:38
Alex Sharov
Экономит ли MDBX_IntegerKey место на диске? Или это только оптимизация скорости компаратора и все?
Л(
11:50
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В lmdb это не работает, т.е. для DUPSORT в принципе не считается кол-во используемых страниц, а аудит сломан.
11:53
In reply to this message
Экономит, но без чудес. Для ключей и значений фиксированного/одинакового размера этот размер не хранится.
AS
11:55
Alex Sharov
Для значений - тот же эффект получится от DupFixed.
Понятно.
Не очевидно - почему тогда нет ключа KeysFixed или НеХраниРазмерыКлючейЯТутВСвоемКомпаратореЗахардкожу.
Л(
12:32
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Основная причина, пожалуй, в том что это требует отдельного типа страниц.
Точнее говоря, комбинаторного удвоения кол-ва этих типов и способов заполнения.

Это всё можно сделать и это даст какую-то экономию места, но усложнит код и API, неизбежно привнесет баги.
В текущей "архитектуре" кода это не рационально - количество if-ов удвоится, а тестирование усложнится в 4 раза.
Но экономия места может быть не заметной, ибо внутри b-tree страницы могут быть заполнены на 25-100%, а более равномерное заполнение приведет к падению производительности.

Возможно я сделаю это в MithrilDB, ибо там С++ с шаблонами.
AS
15:23
Alex Sharov
Понятненько. Я просто пытаюсь для данных которые лежат в DupSort DBI - придумать версионирование (хранить старые версии данных с номерами версий), вот и копаю всякое.
9 November 2020
Dev Ryoma invited Dev Ryoma
12 November 2020
AS
10:29
Alex Sharov
FYI:
В итоге Алексей докурил как работает freelist в lmdb и пришел к следующему https://github.com/ledgerwatch/lmdb-go/pull/13/files

- Большие куски (записи во фрилисте которые не влазят на 1 страницу) разбиваются на мелкие (без overflow), и записываются во фрилист отдельными записями - ключами этих записей служат номера транзакций меньшие чем те что сейчас разбиваем (там FIFO). Однако если у нас транзакция с маленьким ID - то места для записи маленьких кусочков нет. Фикс: стартовать базу сразу с txid=1_000_000
- Фрилист не может быть использован если он не случился хотябы 2 транзакции назад (я лично не понимаю что мешает фрилисту быть использованным в следующей же транзакции - но Алексей обещал нарисовать).
- И еще: comparison "oldest < latest" instead of "oldest <= latest" - is to enable quicker recycling of pages in the freelist

И наш предыдущий фикс (ограничивающий размер value который может попытаться найти последовательные страницы) мы удалим.
AA
10:31
Alexey Akhunov
Я уже начал рисовать, но еще не закончил - сегодня продолжу: https://github.com/ledgerwatch/turbo-geth/wiki/LMDB-freelist-illustrated-guide
AA
20:47
Alexey Akhunov
Я закончил описание логики фрилиста и там в конце я также описываю два фикса, которые я сделал и почему: https://github.com/ledgerwatch/turbo-geth/wiki/LMDB-freelist-illustrated-guide
20:48
Можно, кстати, сделать подобную генерацию картинок для формата MDBX
20:48
просто надо парсер страниц немного подкрутить
Л(
20:49
Леонид Юрьев (Leonid Yuriev)
Немного приболел. Поэтому отвечаю вяло.
AA
20:49
Alexey Akhunov
Ничего страшного, выздоравливай
Л(
20:52
Леонид Юрьев (Leonid Yuriev)
Да, неплохо-бы прикрутить.
Даже были мысли сделать что-то на JS.
При этом в libmdbx есть walk-функция, т.е. буквально парсить уже не надо.
Достаточно вызвать функцию и интерпретировать данные в коллбеке.
13 November 2020
AS
13:27
Alex Sharov
Говард сказал что в 1.0 фрилист будет dupfixed
Л(
14:05
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Я в курсе, но я бы не назвал это продуманным решением.
Технически это решает только одну проблему - хранение больших freelist без overflow страниц, с сохранением всех остальных проблем.
Т.е. это действительно имеет смысл, но если только в БД совсем не будет overflow pages и (соответственно) необходимости искать смежные страницы в GC.
14:12
В Mithril вместо overflow страниц будут blobы со streamable интерфейсом и быстрыми rope-итераторами для чтения.
14:16
Что касается LMDB 1.0 то у меня сомнения в надёжности этого кода:
- фичей больше, а код всё также непрозрачен.
- нет полноценных тестов.
- за последние 3-4 года я не помню бага, который в LMDB был-бы исправен раньше чем в libmdbx.
AA
14:16
Alexey Akhunov
Да, я согласен
14:17
Мы сейчас пытаемся вычистить нашу модель данных, чтобы она не использовала overflow pages, чтобы у нас производительность стабилировалась, и могли спокойно тестировать переход на MBDX
Л(
14:17
Леонид Юрьев (Leonid Yuriev)
Короче, Говарду можно верить, но (увы) если только не включать в розетку (не использовать в production).
15 November 2020
Л(
08:12
Леонид Юрьев (Leonid Yuriev)
Nim binding for libmdbx https://github.com/snej/nimdbx
18 November 2020
Л(
15:27
Леонид Юрьев (Leonid Yuriev)
AS
16:32
Alex Sharov
Ouch, my birthday
Л(
21:07
Леонид Юрьев (Leonid Yuriev)
In reply to this message
21:09
mini anniversary: libmdbx got 555 starts on the github.
😁
19 November 2020
Pp invited Pp
P
12:51
Pp
Hello, through the nimdbx I got to the libmdbx repo and found it very interesting. I have written wrapper of the LevelDB for the Janet programming language, but LevelDB has many ugly sides (Google is of them for sure 😊), so I was searching for replacement and I think I have just found it. So please take this as my introduction, and maybe I would be asking some stupid questions along the way here, so please bear with me, as my C-fu is not very hight rank. Thanks
Л(
15:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
23 November 2020
AS
08:53
Alex Sharov
lmdb доки говорят что нельзя использовать баз на networking FS's - потому что там ломаются локи. А в mdbx доках я видел что вродебы это можно. Какая файловая система тогда подходит для MDBX? NFS или что-то другое?
Л(
08:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
MDBX умеет эксклюзивный режим (ограничение на один работающий с БД процесс).
Поэтому может работать с БД на сетевых носителях в этом эксклюзивном режиме.
При этом требуется чтобы корректно работали POSIX-блокировки, а какая именно будет "файловая система" не важно.
AS
08:58
Alex Sharov
эксклюзив наверное нам не интересно здесь. ок. спс.
kobyakov aa invited kobyakov aa
27 November 2020
Л(
10:25
Леонид Юрьев (Leonid Yuriev)
Released libmdbx v0.9.2
https://github.com/erthink/libmdbx/releases/tag/v0.9.2

44 files changed, 3538 insertions(+), 1261 deletions(-)
P
11:48
Pp
I just found the note on MithrillDB in the README. Do you think it is better to wait for its release?
Л(
14:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
No.
- MithrilDB is still at the research / experiment stage.
- I try not to make any promises about deadlines, so that I don't have any obligations until the first release.
- an assumed order of the releases: LMDB v1.0, libmdbx v1.0, MithrilDB 0.1.
P
14:56
Pp
Great 👍🏿. Thank you very much
AS
17:25
Alex Sharov
in tool similar to mdbx_load - to understand when use Append and when AppendDup - only way is keep previous key and compare it with current key? Just wounder if I missing some more performant implementation.
Л(
17:47
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Both MDBX_APPEND and MDBX_APPENDDUP mainly do two important things:
- enforce the restrictions of the order for adding key/data values;
- when a page is full, hints to putting elements to the new empty page, instead of splitting of full one.

The MDBX_APPEND works for b+tree of keys, and the MDBX_APPENDDUP works for nested b+tree of multi-values (aka duplicates).
And nothing else.
AS
17:49
Alex Sharov
yes, and when I filling empty dupsort DBI by sorted data - only way to undrstand - can I add Append flag or not is - compare each key with previous key and if it is different add Append flag.
Л(
18:02
Леонид Юрьев (Leonid Yuriev)
In reply to this message
To be able use`MDBX_APPEND` the new key must be not less the largest existing one key of an dupsort-DBI.

Otherwise, an error may be returned or you may not get the desired effect (i.e. none of speedup or more dense page filling).
AS
18:20
Alex Sharov
Tnx
29 November 2020
󠃲 invited 󠃲
?
21:27
󠃲
привет
нашлась интересная ветка у sqlite:

https://www2.sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md

https://www2.sqlite.org/src/doc/wal2/doc/wal2.md

https://www2.sqlite.org/src/timeline?r=begin-concurrent-pnu-wal2

позволяет конкурент врайтеры
при условии:
- разных таблиц
- разных индексов не попадающих в одну и ту же страницу

насколько реалистично такое было бы в lmdb(x)? может через суб-бд? без wal наверное такое никак, учитывая что лмбд менеджит сама себя через тот же btree что внутри одного файла, и спейс реклейм завязан друг на друга?
21:28
так бы выкинуть скулайт можно было бы подальше лесочком
30 November 2020
Л(
14:23
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В libmdbx это не возможно - нужно всё переделать и вы верно увидели основные проблемы.

Ну и в sqlite выглядит странным.
Да, поддерживая N WAL можно выполнять N транзакций параллельно, если они не пересекаются по данным.
Однако возникает три "но":
1) Надо отслеживать изоляцию, т.е. чтобы одна транзакция не читала данные изменяемые в другой. Это приводит к адовым затратам на проверках и блокировках, а иногда требует рестарта транзакций и т.д.
2) Если WAL-ы размещены в одной ФС или на одном диске, то всё равно будет серилизация.
3) Все WAL-ы придется потом сливать в основный файлы БД.
?
14:30
󠃲
1) я думаю можно подтюнить гранулярность проверок чтобы не было адских затрат. одновременно это и снижает конкурентность, конечно. без рестартов никак, да
2) это лучше чем каждый раз велосипедить в каждом приложении и городить свои буферы, или разбивать на несколько бд-файлов
3) разумеется
14:32
> Да, поддерживая N WAL можно выполнять N транзакций параллельно, если они не пересекаются по данным.

не так. это не N tx per N wals
а M x N
покамест они не конфликтят
1 December 2020
Л(
15:10
Леонид Юрьев (Leonid Yuriev)
libmdbx package is available now for FreeBSD by Mahlon E. Smith.
5 December 2020
?
18:42
󠃲
In reply to this message
сделал синтетический тест

сколько удачных ТПС, сколько busy
комбинации wal1/wal2 + default/concurrent + 1..8 тредов
в итоге вообще никакой разницы, флуктуации на уровне рандома
лесом :)

у них вот тоже ещё одна ссылка нашлась:

https://sqlite.org/src/file?name=README-server-edition.html&ci=server-process-edition

см. таблицу внизу

всё от лукавого
Л(
18:45
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Спасибо за информацию.

Таблицу гляну позже, но в целом я примерно такой результат ожидал (без чудес).
?
19:06
󠃲
In reply to this message
_единственное_ где я могут представить преимущество, если операции будут не как у меня и у них -- один простой инсерт -- а если это какая-то тяжёлая операция, которая может конкурентно работать в нескольких тредах и сидеть в локе до своей очереди на запись
а не так как сейчас: все сидят в локе и только один тред делает непосредственную работу
т.е. мог бы быть оффлоад number crunching'а
может быть, а может нет
Deleted invited Deleted Account
8 December 2020
Дмитрий Михин invited Дмитрий Михин
12 December 2020
G
00:41
G
почему у libmdbx лицензия OpenLDAP?
00:43
можно ли libmdbx собрать в виде статической либы, чтобы вместе с исполняемым файлом собрать?
MK
05:51
Mikhail Kotov
In reply to this message
Унаследовано от LMDB, насколько я помню. А тот, в свою очередь является компонентом OpenLDAP.
Л(
07:12
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Конечно, штатно так собирается.
G
11:43
G
при сборке ещё собирается so-либа; а so-либа нормально будет работать?
11:43
что предпочтительнее: static-либа или shared-либа?
G
22:41
G
?это единственный пример: libmdbx/example/example-mdbx.c
22:41
может есть ещё примеры использования?
или хотя бы комменты добавить в пример существующий?
22:42
почему в этом примере example-mdbx.c используется goto?
13 December 2020
Л(
12:41
Леонид Юрьев (Leonid Yuriev)
In reply to this message
1. Примерами могут служить mdbx-утилиты и тесты, а также любые проекты использующие libmdbx.
Например, libfpta где реализовано представление табличных данных с различными индексами.

2. libmdbx расширяет API LMDB. Поэтому любые примеры, статьи и руководства по LMDB, применимы в контексте libmdbx с минимальными изменениями.
Причем, в основном, эти изменения сводятся к изменению префиксов имен (MDB->MDBX, mdb->mdbx), а остальное достаточно подробно описано в документации.

3. libmdbx, как и LMDB, предлагает достаточно ожидаемый для key-value хранилищ набор возможностей, и API похожее на BerkeleyDB с его >30-летней историей.
Поэтому разработчику знакомому с key-value достаточно легко "оседлать" libmdbx после однократного прочтения введения и описания API, с дальнейшим использованием справочника.
https://erthink.github.io/libmdbx/

4. libmdbx не является обучающим проектом и у меня нет ресурсов на подготовку обучающих материалов, в том числе за это никто не платит.
Тем не менее, я с радостью приму PR с дополнительными примерами (в том числе без goto), обучающими материалами и т.д.
Более того, готов оказывать консультации, если кто-то решит написать книгу или хотя-бы статью.
14 December 2020
Bat Man invited Bat Man
AS
12:28
Alex Sharov
добрый день
mc->mc_signature == MDBX_MC_READY4CLOSE
это значит что приложение закрыло курсор? или есть другие случаи? (мы не используем renew курсоров)
Л(
12:58
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Это значит что завершена транзакция, в которой был открыт курсор.
Такой курсор уже никак не связан с транзакцией, может быть переиспользован (renew), либо должен быть явно закрыт (close) во избежание утечек памяти.
AS
12:58
Alex Sharov
понял
MK
15:22
Mark ☢️ Korenberg
Всем привет. Вопросы:
1. 100М записей норм потянет ?
2. Как атомарно столько ключей вставить ?

В роксдб нарм.
15:22
Тут не пробовал даже
15:25
Ключи короткие
15:25
Валуе еще короче
15:25
16 байт ключи
Л(
15:36
Леонид Юрьев (Leonid Yuriev)
In reply to this message
1. Да, легко.
Было в Мегафоне и сейчас подобные масштабы в ledgerwatch/turbo-geth (подробности у @AskAlexSharov).

2. Атомарная вставка/изменение/удаление означает что всё происходит в одной транзакции.
При этом конечно есть определенные ограничения на размер транзакций (кол-во "грязных"/изменяемых страниц).
Плюс пока есть определенное падение производительности в очень больших транзакциях в режимах без MDBX_WRITEMAP.
Подробности см. https://github.com/erthink/libmdbx/issues/132 и https://github.com/erthink/libmdbx/issues/123.
По этим и другим issue запланирована (см TODO в ChangeLog) и ведется работа (см. ветку devel).
Тем не менее, неделю назад я делал некоторые испытания = БД объемом до 28 Гб заполнялась и затем опустошалась в рамках одной транзакции.
MK
15:39
Mark ☢️ Korenberg
In reply to this message
Нармулик. А жор памяти на вставке 1М ключей ?
G
15:40
G
а как бэкапы делать?
Л(
15:48
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В основном память расходуется на теневые копии измененных страниц БД.
Остальные затраты относительно незаметны.

Однако, есть существенная разница в зависимости от режиме MDBX_WRITEMAP:
- с MDBX_WRITEMAP изменения вносятся непосредственно в отображенный в память файл, и при необходимости ядро ОС само выталкивает их на диск (OOM-killer не приходит).
- БЕЗ MDBX_WRITEMAP теневые копии страниц накапливаются в памяти и явно пишутся в файл при коммите, а после остаются в preallocated-списке (может прийти OOM-killer).
MK
15:49
Mark ☢️ Korenberg
Спасибо, прояснилось.
15:49
мне после вставки ещё надо будет компакшен сделать (или аналог)
15:49
производительность записи в моей задачи не имеет особого значения. А вот чтения — ещё как
Л(
15:49
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Два варианта:
1. Утилита mdbx_copy, см man-страницу.
2. Утилиты mdbx_dump и mdbx_load с возможностью обмена данными с BerkeleyDB и LMDB.
AS
15:50
Alex Sharov
In reply to this message
Если вставлять в сортированном порядке - методом Append - то компакшен не нужен будет.
MK
15:50
Mark ☢️ Korenberg
окей, но вставка к сожалению будет рандомная
15:51
с частичным перетиранием других ключей и удалением ненужных
Л(
15:55
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В таком случае, примерно для всех баз на основе b-tree, лучше:
- сначала заполнить БД.
- затем сделать дамп (посредством mdbx_dump), а после загрузить его в новую БД в append-режиме (посредством mdbx_load с опцией -a).

Так вы получите примерно вдвое более плотное заполнение страниц b-tree.
Соответственно, размер используемой части БД будет примерно вдвое меньше.
MK
15:56
Mark ☢️ Korenberg
о_О
15:56
а с роксдб разницы нет если после вставки сделать полный компакшен
15:56
или я не прав ?
Л(
15:57
Леонид Юрьев (Leonid Yuriev)
Однако, последующие вставки данных (или изменение размера ключей/значений) заполнение страниц b-tree будет стремиться к 50% (т.е. будет компенсация полученной экономии).
MK
15:57
Mark ☢️ Korenberg
прикол в том, что параллельно с этов ставкой есть несколько процессов которые БД читают. и вот нельзя их прерывать. Реализовывать механизмы быстрого переключения на другую базу тоже не хочется
Л(
15:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
А причем тут RocksDB?
MK
15:58
Mark ☢️ Korenberg
In reply to this message
ну я новое потенциально более лучшее решение сравниваю с ней
Л(
16:00
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Тут вопрос в том насколько важна для вас экономия.

Например, если у вас какой-то редко-изменяемый мега-справочник (больше размера ОЗУ), то его уменьшение вдвое как минимум удвоит производительность чтения (уменьшит RSS и кол-во page faults).
MK
16:00
Mark ☢️ Korenberg
да, редко изменяемый. один раз в день.
16:01
ну... не больше размера ОЗУ, но оператива нужна не только ему :)
16:01
ИТОГО. есть ли в mdbx полный компакшен ? планируется использоваться после одной атомарной вставки изменений.
16:02
размер БД около 1 ГБ
Л(
16:02
Леонид Юрьев (Leonid Yuriev)
Если изменения происходят постоянно и конкурентно с чтением, то "компактификацию" никак не сделать.
А иначе есть смысл подумать о "компактификации" при старте, после вливания изменений или периодически.
MK
16:03
Mark ☢️ Korenberg
хм. печально. "при старте" нельзя. ну тоесть можно, но нужно танцы танцевать. сервис который использует справочник вобще говоря должен работать безостановочно
Л(
16:03
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нет, такого нет и не будет.
Так как при необходимости такое можно сделать в обвязке.
MK
16:03
Mark ☢️ Korenberg
ну вот.. а в роксе есть
Л(
16:04
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, но в обмен LSM может подарить вам latency в пару минут )
MK
16:04
Mark ☢️ Korenberg
интересно почему
16:05
ну только изза IO
16:05
вангую
AS
16:05
Alex Sharov
In reply to this message
- открываете транзакцию на чтение для читателей
- делаете все что угодно, включая компакшен
- читатели до сих пор видят старые данные и читают их без проблем
- закрываете старые читающие транзакции, открываете новые - читатели видят новые данные
- done?
Л(
16:05
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Потому-что LSM с поиском в глубину, на фоне конкурирующих слияний и другой нагрузки на диск...
MK
16:06
Mark ☢️ Korenberg
In reply to this message
тогда надо делать нотификацию приложений что надо переоткрыть транзакцию
16:07
и наверно ещё ожидание пока все отцепятся чтобы старое удалить
Л(
16:07
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Так тоже можно, но...
1. потребуется двойной размер БД и будет использован двойной объем ОЗУ.
2. после "компактификации" страницы будут всегда перемешаны по-порядку.
MK
16:08
Mark ☢️ Korenberg
ну это всё классно. но как сделать "правильно" чтобы не кодить овердофига
Л(
16:08
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Пока вы не перезапустите транзакцию чтения вы не увидите новых данных, ибо MVCC.
MK
16:08
Mark ☢️ Korenberg
In reply to this message
а вот в роксе....
16:09
впрочем, если открыте транзакции очень дешевое то можно при каждом лукапе
Л(
16:09
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, нет транзакций и ACID )
MK
16:09
Mark ☢️ Korenberg
In reply to this message
угу.
16:09
ну не совсем. сэлментами...
16:10
окей, открытие транзакции насколько дорогое ? в какомнибудь sqlite это мрак
Л(
16:10
Леонид Юрьев (Leonid Yuriev)
Давайте начнем "от печки".

Как часто будут вливаться изменения в БД?
Сколько раз в секунду или в сутки?
MK
16:11
Mark ☢️ Korenberg
In reply to this message
один раз в сутки
Л(
16:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
микросекунды, если правильно использовать API (обойтись без malloc/free и т.п.)
MK
16:12
Mark ☢️ Korenberg
In reply to this message
хорошо, тогда можно рассмотреть открытие транзакции на каждый лукап
Л(
16:16
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Тогда вам действительно можно в одной транзакции все перелопатить/обновить и записать.
Снаружи это будет выглядеть примерно так:
- при вливании данных у процессе реализующего вливание RSS увеличивается вдвое.
- по завершении вливания этот RSS быстро перетекает на все процессы читающие БД (но это разделяемый RSS).
- постепенно ядро видит что к страницам со старыми данными нет обращений и выбрасывает их из page cache и памяти.

Т.е. будет некий пик RSS.
MK
16:16
Mark ☢️ Korenberg
окей. а размер этого пика как примерно прибросить?
16:17
я правильно понял что библиотека просто memory-map делает на всё ?
Л(
16:17
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, так можно.
Но лучше оперировать "сессиями", т.е. если вы будете каждый раз запускать новую транзакцию, то для одного ключа можно читать разные (новые) данные.
16:18
In reply to this message
Не понял вопроса.
MK
16:18
Mark ☢️ Korenberg
In reply to this message
я потом сообразил. не важно.
16:18
In reply to this message
вот теперь я не понял
Л(
16:18
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Да, примерно как "нарисовать сову" ;)
MK
16:19
Mark ☢️ Korenberg
я вот только не понял - мне нужно будет изобретать механизм нотификации приложени ?
16:19
если не открывать каждый раз новую транзакцию
16:19
видимо да
Л(
16:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Каждая читающая транзакция всегда видит целостный MVCC-снимок БД, причем самый новый, который был доступен при её старте.
16:21
И параллельно с читающими транзакциями, любой другой процесс/утилита может изменить данные.
MK
16:21
Mark ☢️ Korenberg
да это понятно. я прост не понял что такое сессия
Л(
16:23
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Пардон.
Пусть это будет некоторый отрезок времени, кусок кода или этап отработки логики приложения, в рамках которых вы хотите работать с одним MVCC-снимком данных.
MK
16:23
Mark ☢️ Korenberg
а, это не требуется. каждый запрос совершенно автономен
Л(
16:24
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Нужно смотреть на ваш сценарий использования в целом.
Но как вариант, можно смотреть на отставание текучей читающей транзакции от последней доступной в БД версии.
16:25
In reply to this message
Тогда можно перезапускать каждый раз, или делать какой-то минимальный естественный батчинг (например, если запросы можно вычитывать пачками).
MK
16:25
Mark ☢️ Korenberg
ну хотелось бы чтобы после внедрения изменений в данные увидеть новые в последующих запросах как можно скорее
16:26
ладно, попробую с открытием транзакции каждый раз на каждый запрос
Л(
16:28
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В API есть дешевые функции для проверки и перезапуска читающий транзакций.
Собственно запускать транзакции очень дешево, но иногда возникает потребность экономить на спичках.
MK
16:29
Mark ☢️ Korenberg
хм, интересно. я апи ещё не смотрел, честно
Л(
16:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Просмотрите описание API хотя-бы один раз.
Там есть функции выделения читающих транзакций и последующей их остановки и перезапуска.
MK
16:30
Mark ☢️ Korenberg
ладно-ладно. :)
17 December 2020
AS
14:24
Alex Sharov
У нас есть случай - когда dupsort экономит место, но при этом есть много ключей у которых 2 (мало) значений, а страница выделена. Ну, т.е. если клиенты большие - то их мало и они очень большие, а если маленькие - то их очень много и они очень маленькие. Можно ли что-то с этим сделать? Или проще забить?
Л(
15:06
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Для мелких dupsort-кустов выделяются не отдельные страницы, а создаются вложенные.
Поэтому проблемы вообще никакой не должно быть.
AS
15:14
Alex Sharov
это в mdbx или в lmdb тоже?
Л(
15:16
Леонид Юрьев (Leonid Yuriev)
В LMDB тоже
AS
15:17
Alex Sharov
а mdbx_stat такие "вложенные" страницы включает в LeafPages?
Л(
15:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Хм, честно говоря не помню.
Теоретически они НЕ должны учитываться, ибо сумма всех страниц + GC = размер БД.

И на всякий - в LMDB для dupsort статистика в принципе неверная, многое считается, но не везде и в целом цифры не достоверные.
AS
15:22
Alex Sharov
да, поэтому я mdbx использую чтобы понять размер DBI 🙂
18 December 2020
Noel Kuntze invited Noel Kuntze
NK
03:56
Noel Kuntze
Hi, in the latest release 0.9.2, make check doesn't work because there's no check target in the Makefile
03:57
Linux and other platforms with GNU Make
To build the library it is enough to execute make all in the directory of source code, and make check to execute the basic tests.
25 December 2020
b h invited b h
Л(
16:48
Леонид Юрьев (Leonid Yuriev)
In reply to this message
I apologize for the wait. I had the flu.
Now I have checked your issue.

Both the Makefile and the GNUmakefile have the check target.
https://github.com/erthink/libmdbx/blob/master/Makefile#L3
https://github.com/erthink/libmdbx/blob/master/GNUmakefile#L171

So`make check` just work fine, but only within full source code (i.e. within a clone of the libmdbx' git repository).
Otherwise, if you use the amalgamated source code, then there are no any tests and (accordingly) there is no really the check target in the makefiles.
NK
16:51
Noel Kuntze
I see. I am building libmdbx from the tagged release, which contains the amalgated version. Is it possible to get the part that runs the checks and integrate it somehow so the checks run? I am packaging libmdbx for Alpine as preparation to rewrite some applications using bsddb.
Л(
17:05
Леонид Юрьев (Leonid Yuriev)
When used libmdbx on new or exotic platforms, it is highly desirable to use tests. In particular, if possible, it is desirable to run the script test/long_stochastic.sh (you may need to modify it) and let it work for at least a few hours.
To do this, of course, you should use the full version of the source code.

After successful tests, you must decide for yourself which version (full or amalgamated) is more convenient for you to use.
But the tests are only available in the full version and there is no reason to include ones in the amalgamated version of the source code.
NK
17:08
Noel Kuntze
Alpine Linux is not a, umh, new or exotic platform (except for the fact that it uses musl instead of GNU libc). I am asking for the tests because it is customary to run any tests available at build time.
Can we have a tagged release of the full version then, please?
Л(
17:11
Леонид Юрьев (Leonid Yuriev)
> Can we have a tagged release of the full version then, please?
Sure, github provides tarball downloads for all tags by default.

i.e. https://github.com/erthink/libmdbx/archive/v0.9.2.tar.gz
NK
17:14
Noel Kuntze
Yeah, that's where I point the build tool at. I am asking for manually uploaded tar.gz and zip archives under the tagged release. Sometimes the hashes of the automatically built archives change and then the checksums need updating.
17:14
It's a hassle to do.
Л(
17:31
Леонид Юрьев (Leonid Yuriev)
The release's commits and tags I sign and do not change after publication.
And github made some effort to ensure that the archives (created on the fly on request) did not change when updating software on github's servers.
At least I don't remember such problems for quite a long time.
So you can rely on the consistency of hash sums, otherwise it will be someone's mistake.
26 December 2020
NK
09:27
Noel Kuntze
Thank you for your response. I had trouble with the archives in the past, which is why I asked for manually uploaded ones.

I just tried building from the automatically created archive, but it fails and tells me to use the amalgated version or use a git submodule. Well, I can't use the amalgated version because I need the checks, and I don't want to use it as a git submodule because that'd be another dependency at build time. Is it okay if I just patch that out somehow and make it work, or is there a particular, critical reason for preventing the easy use of it, without a submodule?
Л(
14:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
From the my point of view, there is a clear logic in this and I would not like to change it.

The full source code (with tests) is intended for development and/or adaptation of the library on new platforms.
In this case, it should be possible to both get the latest fixes from upstream and send patches back.
So a git submodule is useful and preferred, and the makefiles are designed to get version information from a git tags.

After the library itself is finalized/adapted and tested on the new platform, there is no need to test the library itself.
In this case, may be more convenient to use amalgamated (i.e. frozen) source code, although you can still use git submodule.

Nonetheless, in both cases above, a good development process involves having integration and smoke tests at the application level.
If you want to use the full source code, but not in the form of a git submodule, then you just need to apply a patch to GNUmakefile and/or CMakefiles.txt with assignment of explicit values to variables with version information, instead of calling git to get ones.
Л(
14:27
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Perhaps it is worth explaining that I prefer only these two options to always have accurate information about the libmdbx version, in all cases of questions, problems and bug reports, etc.
29 December 2020
Kenta invited Kenta
K
08:50
Kenta
Hello 👋 libmdbx caught my interest - might consider writing bindings for it in https://ziglang.org
08:54
Just out of curiosity, for a workload where periodically:
1. A database is opened,
2. A batch amount of random writes is performed,
3. The database is committed - if the commit fails, worst-case, the database should be left in its original state in Step 1.

(a small number of concurrent reads might happen in between step 1 to 3, to which the data read should be a snapshot of the database before batch writes in Step 2 occurs)

How would libmdbx compare to, say, a LSM database such as SQLite3's LSM1 extension / RocksDB / LevelDB?
08:55
Also would love to know any suggestions for modes / APIs to use of libmdbx to best support this sort of workload 😄
AS
09:55
Alex Sharov
What is critical in your workload? Write speed, read speed or both or none?
K
10:36
Kenta
In reply to this message
Write speed primarily
10:38
Just in case, the workload I described could omit Step 1 (the database could be kept open and reused after it is committed to in Step 3) + there are no intervening writers throughout all steps
10:38
It is fine for writes to fail, in amidst Step 2 or Step 3, though it shouldn't corrupt the database and should keep the database in it's former state in Step 1
AS
12:11
Alex Sharov
LSM may over-perform in write speed. But, in everything else libmdbx is better - lock-free reads, no background compactions, transactions - as you expecting - it’s safe to kill process or kill machine, can point to memory in db until finish of transaction - means don’t need to copy/allocate anything to use data within transaction. Random-writes is only not great thing - but it’s not random-disk-writes - in fact you can perform tons of random writes into db and do 1 write to disk in the end of transaction (before this moment any random writes into db will only read data or write in memory. Unless OS will not decide that RAM is needed in another place or disk is idle - then OS can start writing something to disk before end of transaction).
12:13
In case of machine kill - only 1 thing may happen - 1 last transaction (which not fully written to disk) may disappear
K
12:17
Kenta
In reply to this message
Gotcha - so in my workload where I really only need to do a single write to disk at the end of a batch number of random writes, it would be better?
AS
12:21
Alex Sharov
In reply to this message
You can do write to disk manually by method mdbx_sync, but i think default configuration will work well enough. By default commit of write-transaction does call mdbx_sync under the hood.
12:22
How big are your data (compare to available ram)? And how big are updates?
K
12:24
Kenta
For the workload I described, at most 4GB of data would be written immediately in Step 2
12:25
One thing I forgot to mention is that in Step 2, batches of writes are performed conditionally on batches of reads (so a CRUD-like workload, though it all happens in one single transaction)
AS
12:28
Alex Sharov
For 4Gb update - If you will see “transaction is too big error” - compile libmdbx with flag: MDBX_HUGE_TRANSACTIONS 1
K
12:28
Kenta
So the workload is akin to - say I have a log of bank transactions, and my database is a ledger of accounts.

I want to process new bank transactions periodically every 24 hours after they are batched up over the ledger of accounts, and then commit the changes as a single large write batch in one database transaction.

If in amidst processing the bank transactions I notice that some bank transactions may have been tampered with, I would throw away the transaction and commit none of the changes.

Once the entire batch of writes is prepared and ready to be committed, and the commit fails, I'll retry committing another time (it's fine for fsync to fail).
Л(
12:30
Леонид Юрьев (Leonid Yuriev)
In reply to this message
There will be an update coming soon that will introduce a runtime option instead of this build time option.
K
12:32
Kenta
In reply to this message
I see 👍 Having the build option for now is fine - I'll start tinkering around creating a simulation of the workload a little later today
Л(
12:32
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Please read the https://erthink.github.io/libmdbx/.
There are answers to all your questions.
AS
12:36
Alex Sharov
In reply to this message
If you do not crypto-hash account keys, then it’s real-world data - and it’s not enough random to make noticeable problems.
Л(
12:37
Леонид Юрьев (Leonid Yuriev)
On the topic of ensuring database integrity in case of write errors and / or system crashes, I advise you to look at Howard Chu's presentations on LMDB.
Links from the LMDB wiki page, articles on LMDB and BoltDB can also be useful.
K
12:38
Kenta
In reply to this message
👍 I'll go through a deeper dive into the API and usage guidelines
12:38
In reply to this message
Hmm, account ID's in this case are hashed
AS
12:52
Alex Sharov
In reply to this message
Then you doing blockchain and speed of writes is your last problem :-)
K
12:53
Kenta
If I were to set mode MDBX_UTTERLY_NOSYNC, and my system crashes in amidst creating a database transaction (before committing), would it corrupt the database?
12:54
Also, should the system crash during calling mdbx_env_sync(), would it corrupt the database or would the last transaction just not be committed?
K
12:55
Kenta
When exactly do system buffers get written to though?
Л(
12:56
Леонид Юрьев (Leonid Yuriev)
In reply to this message
This depends on the selected sync-mode of the DB.
K
12:58
Kenta
i.e. if while constructing a transaction, none of the transaction's data gets written to the system buffers, then system crashes won't corrupt the database right?
12:59
Ah okay I see - it looks like the ideal option for me would be MDBX_NOMETASYNC (losing the last transaction on system crash is ok)
AS
13:00
Alex Sharov
In reply to this message
I advise you to go with MDBX_DURABLE mode - then you will not get corrupted in any case - and if you will see that commit/sync is bottleneck for you - then try another modes.
K
13:01
Kenta
Okay, will do - thank you 😄 Got everything I need now, I'll start writing a binding in Zig.
AS
13:06
Alex Sharov
In reply to this message
because optimizations by define do not give enough performance over runtime options? or just to make it more user-friendly?
Л(
13:06
Леонид Юрьев (Leonid Yuriev)
In reply to this message
👍
13:17
In reply to this message
Because I'm redoing parts of the code related to dirty page lists and spilling. In turn, this allows me to replace some buildtime options with options that can be changeable at runtime. This is a prerequisite for providing a system-wide shared library (i.e. a linux package).
K
15:15
Kenta
Are there any particular C defines needed for libmdbx? Tried the ones from the amalgamation C source archive and mdbx_env_open yields 'Illegal instruction'
15:16
This is the build error: https://pasteboard.co/JHacPEX.png
Л(
15:25
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Please use GCC/CLANG-compatible compiler and glibc/musl compatible libc.
15:28
I'm not sure zig compiler could be used. Do it support atomics and gcc's builtins?
K
15:30
Kenta
Yep - it also links in glibc/musl
Л(
15:32
Леонид Юрьев (Leonid Yuriev)
Please submit an issue at github if you could reproduce such build error with gcc/clang for your target platform (i.e. ARM, MIPS, x86, etc).
K
16:45
Kenta
I'll check it out on Zig's end first
16:46
In reply to this message
Also have a question, what is the LIBMDBX_BUILD_CONFIG variable for?
16:46
Just curious as it complicates including/linking in the amalgamated source code a bit
AS
16:47
Alex Sharov
In reply to this message
Look into GNUMake file of libmdbx repo - it creating config.h file with some info about current environment.
16:48
ah, no - i talking about MDBX_CONFIG_H, not about LIBMDBX_BUILD_CONFIG. Don't know what LIBMDBX_BUILD_CONFIG is.
K
16:49
Kenta
Hm, what is the info in config.h used for though? Trying to use a different build system for libmdbx right now, and noticed that removing any references to it still allows mdbx.c / mdbx.h to compile
AS
16:51
Alex Sharov
build it by make and you will see what is inside config.h - it kind of collecting info about compiler/linker/arc/etc... and compile this info inside binary.
yes, because of config.h - i also can't compile libmdbx by golang toolchain.
16:51
so, i just build it by make, then link to .so file from golang
Л(
16:54
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Yes, since this information can be very useful when analyzing various problems.
17:00
The corresponding defines/macros can be defined via the compiler's command-line options, or via the config.h.
And both of these methods can be used simultaneously in any proportion, as is convenient in a particular assembly system.

For instance, when using CMake, it is more convenient to generate config.h from config.h.in.
17:03
So the MDBX_CONFIG_H macro allow use (or don't use) any include file in the manner of config.h, which could be generated from config.h.in or by a build system with any usable method.
K
17:06
Kenta
Ok gotcha 😄 Thanks - Zig's compiler already provides the information config.h provides on compile time, so it's convenient to just pass them in vs. producing a config.h
31 December 2020
Л(
17:15
Леонид Юрьев (Leonid Yuriev)
2 January 2021
K
11:02
Kenta
Finally found the problem I was having compiling libmdbx with Zig - it seems LLVM's UBsan (undefined behavior detector) is marking some of libmdbx's code.
Л(
13:03
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Historically, libmdbx has inherited code from LMDB with some UB:
- signed int arithmetic overflow.
- half-word aligned (i.e. unaligned) access to words.

For now all such known issues are fixed in the master branch, and libmdbx' code was checked by CLANG & GCC (upto 10.x versions) with -fsanitize=undefined option (see test-ubsan target in the makefile).

Please submit an issue at github if you find another such bug.
4 January 2021
K
08:12
Kenta
In reply to this message
Okay, I'll make sure to 😄
10 January 2021
AS
09:50
Alex Sharov
@kiwasaki have you succeed to complie mdbx by zig's toolchain? can you show if yes?
K
09:59
Kenta
In reply to this message
Yep I have - not on my computer now, but it's a matter of passing the flag -fno-sanitize=undefined to disable LLVM's UBsan
09:59
Happy to provide a github gist later also when I'm on my computer
10:00
In reply to this message
Apologies for the late response - I'll file an issue later today 🙏
AS
10:04
Alex Sharov
Yep, no rush. I asking for golang bindings.
I mean - have you succeed to pass all that OS/Compiler/Linker-specific flags as GNUMakefile has:
LIBS ?= $(shell uname | grep -qi SunOS && echo "-lkstat") $(shell uname | grep -qi -e Darwin -e OpenBSD || echo "-lrt") $(shell uname | grep -qi Windows && echo "-lntdll")

LDFLAGS ?= $(shell $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1')$(shell $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip')
K
10:09
Kenta
I only needed to disable LLVMs UBsan and provide the BUILD_FLAGS define which is usually stored on config.h
AS
10:11
Alex Sharov
i see
K
10:12
Kenta
Any errors you're getting with compiling in Go?
AS
10:16
Alex Sharov
just can't create config.h file by go's tollchain befor compiling.
K
10:32
Kenta
Oh, that isn't necessary
11 January 2021
NK
14:19
Noel Kuntze
Hi, when using mdbx_test, is there an obvious flag for disabling the massive output?
Л(
14:26
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Currently no.
mdbx_test is mostly internal tool and for now loglevel is hardcoded to depend of NDEBUG macro.
I.e. non-debug build will provide much less output.

Please submit an issue at github if you need such command-line option for mdbx_test.
NK
14:38
Noel Kuntze
Thank you for your response. Could I simply discard stdout?
14:38
I'm interested in if the tests fail, and if they do, with what Error
14:38
(e.g. Error 141 or something else)
Л(
14:47
Леонид Юрьев (Leonid Yuriev)
Usually, it is enough to use the NDEBUG-build of the mdbx_test with discarding output, and use the debug build only for digging in case someone failed.
NK
15:28
Noel Kuntze
I need to test the exact sources that are packaged
Л(
15:38
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ok, you can use the NDEBUG-build and heed only the test(s) result, ignoring all logs.
18 January 2021
K
12:23
Kenta
Submitted an issue for ubsan: https://github.com/erthink/libmdbx/issues/153
Л(
14:20
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Will be fixed soon.
K
14:22
Kenta
In reply to this message
Appreciate it 😄 Thank you
14:22
In case anymore pop out after that one, I'll let you know
AA
14:55
Alexey Akhunov
We are planning to transition from LMDB to MDBX as part of our Beta: https://github.com/ledgerwatch/turbo-geth/wiki/Criteria-for-transitioning-from-Alpha-to-Beta
Л(
14:58
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Please wait until (this week) I will complete the improvements related to page spilling, extra large transactions and other options.
AA
15:01
Alexey Akhunov
Don't worry, the beta will be in at least couple of months, but thanks for the warning
15:02
We would also like to support you more formally after this transition
K
15:05
Kenta
In reply to this message
Oh interesting - was working on a Merkle trie impl with libmdbx 😄
AS
15:08
Alex Sharov
In reply to this message
Me too. With many different formats. Will send you message to get some experience.
P
17:15
Pp
In reply to this message
👍
20 January 2021
AS
07:41
Alex Sharov
Good day. Wanna rise question one more time: (after implementing “spill”) what will happen after big bucket drop. Will freelist contain 1 big record? (Lifo=false).
Л(
08:06
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Yes. This cannot be changed in MDBX, as it requires changing the binary format of the database.

A new format of GC/freelist will be in MithrilDB (like "roaring" bitmaps over b+tree) and LMDB 1.x (dupsort-based as Howard Chu says).
AS
08:45
Alex Sharov
what about - that trick which does LMDB 0.*:
- it splitting big freelist record to 4kb records (or wathaver it needs to fit in 1 page) with keys < lastActiveTransactionID
- and we did patch - where DB starts from big txID, not from 1. Then always enough space in freelist to insert. (probably you can change it, but we can maintain our own patch here).
AS
09:03
Alex Sharov
slow part there is: to update multi-page record of freelist need find countinuous-sequence of pages in freelist.
Л(
09:16
Леонид Юрьев (Leonid Yuriev)
You are confusing the two stages of putting records to a GC/freelist.

1.
During committing a transaction, we have a list of retired pages that can be reused after no reader uses the MVCC-snapshot that we are currently committing on.
This list can't be split to chunks with key less than current transaction id (but can be split to chunk with the same key in case of dupsort).

2.
Later when we taken some pages from GC/freelist we need update corresponding record(s).
This list can be split and now MDBX does it better (but more complex) than LMDB.
AS
09:18
Alex Sharov
oh, i see. then it's great. and to confirm - "now MDBX does it better" is only works when LIFO=false, right?
Л(
09:30
Леонид Юрьев (Leonid Yuriev)
MDBX does it with any combination of MDBX_LIFO and MDBX_COALESCE.
And by "better" I mean less overhead and stable behavior even in extreme cases.

On the other hand, this is one of the algorithmically most complex and obscure places in MDBX (take a look at the mdbx_update_gc() code).
AS
09:32
Alex Sharov
nice. i will take a look.
21 January 2021
K
01:26
Kenta
Out of curiosity, after seeking with a cursor, is it possible to count the number of KV pairs the cursor seek went over?
01:27
@erthink testing out the devel branch right now
AS
04:58
Alex Sharov
No, because cursor doesn’t “seek over”. Seek is “go by B+Tree down from root”, not go “from current position forward over other keys”.
05:00
But i remember there was some api to estimate distance between 2 keys.
05:01
Check in mdbx.h
26 January 2021
Artem Vorotnikov invited Artem Vorotnikov
AV
18:48
Artem Vorotnikov
Почему mdbx_put принимает мутируемый аргумент data, но при этом немутируемый key? И почему в LMDB key тоже мутируемый?
18:50
(я переписываю растовые привязки lmdb для mdbx, нарвался на ворох предупреждений линтера о ненужном использовании мутирующего указателя)
Л(
18:51
Леонид Юрьев (Leonid Yuriev)
In reply to this message
18:57
In reply to this message
1. Привязка для rust уже есть, включая унификацию MDBX и LMDB (хотя местами это сомнительно).
2. Для чего-то нового рекомендую смотреть на новое C++ API, в том числа давать обратную связь.
AV
19:06
Artem Vorotnikov
In reply to this message
1. Существующие привязки к mdbx - это всего лишь unsafe-автоген (крейт mdbx-sys), которым нежелательно пользоваться напрямую. Для LMDB есть два крейта в одном репозитории - как автоген lmdb-sys, так и lmdb, предоставляющий идиоматический и безопасный API для работы. Его я и портирую.
2. Мне в любом случае нужны растовые привязки - я прямо сейчас портирую код @AskAlexSharov на Rust.
19:14
@erthink прошу прощения, не увидел https://github.com/Kerollmops/heed
19:15
возможно имеет смысл добавить ссылку в документацию libmdbx? там только ссылка на автоген
Л(
19:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Упс, добавлял, но видимо потерял коммит. Сегодня поправлю.
19:25
Тем не менее, мне хотелось-бы видеть максимально унифицированный интерфейс (Rust, C++, Go), но не повторение сишного API с его неоднозначностями, и не зоопарк сильно разнящихся API для каждого языка.

Если такой общий/узнаваемый диалект API удастся сформировать, то он станет основой для API MithrilDB, и таким образом обеспечит переносимость (с минимальным изменениями, или даже полную).
27 January 2021
AV
05:13
Artem Vorotnikov
я правильно понимаю, что даже при использовании флага NO_TLS я не могу двигать транзакцию на запись между потоками? даже если у меня гарантия последовательности обращений к объекту транзакции?
05:17
для справки: прибитие к потокам очень затрудняет написание приложений на базе многопоточных асинхронных work-stealing экзекьюторов (напр. Tokio)
AS
05:19
Alex Sharov
расскажи это людям из go - у нас впринципе есть всего 1 метод - "дорогой гошный рантайм, не уноси мою горутину с текущего треда, пока я не скажу что можно" 🙂
AV
05:21
Artem Vorotnikov
ха, ну у вас тут всё императивно - можно наколхозить чтобы работало

в расте прибитие к потокам выражается через систему типов
AS
05:21
Alex Sharov
Раз вы API обсуждаете, покажу что мы сделали для того чтобы унифицировать LMDB, MDBX, и RemoteDB (это наш сетевой read-only api - который позволяет открыть курсор по сети, но транзакции менеджит сервер - если сервер захочет переоткрывать read транзакцию для клиетна каждые 10 секунд, то клиет будет жить с тем что ему дают). Но это уже более application-specific api - написаный поверх биндингов: https://github.com/ledgerwatch/turbo-geth/blob/master/ethdb/kv_abstract.go
AV
05:21
Artem Vorotnikov
пока не придумаешь элегантное решение программа вообще не соберётся -_-
05:22
In reply to this message
я бы вообще забил на LMDB, тем более что у нас он пойдёт под нож с окончательным переездом на MDBX 🌝 🌚
AS
05:26
Alex Sharov
из хороших штук - mdbx сделал чтобы commit возвращал тайминги - что сколько времени заняло во время коммита. это оказалось не только удобным, но баго-устойчивым. у нас случилась 1 жирная транзакция, sync вызывался после коммита (а значит вне его лока пишущих транзакций) - в результате - sync жирной транзакции занимал Х времени, сразу же случалось 10 мелких транзакций по Х/10 времени и они тоже вызывали sync - от этого sync начинало плохеть и он занимал пару минут вместо миллисекунд. поэтому вот этот api change считаю полезным.
05:31
In reply to this message
и да, и нет. FYI: есть пару блокеров - https://github.com/erthink/libmdbx/issues/132 и частое получение TXN_FULL ошибки. думаю в обозримом будущем все победим.
AV
05:32
Artem Vorotnikov
In reply to this message
Я сразу решил писать только вариант KV на MDBX
05:33
Всё равно до прода как до луны, к тому моменту все косяки почините 😉
Л(
07:26
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Во-первых, какую транзакцию (читающую или пишущую)?

Режим NO_TLS позволяет "двигать" читающие транзакции, но не пишущие.
Пишущие можно "двигать" если собрать библиотеку с MDBX_TXN_CHECKOWNER=0, при понимании внутренних механизмов и соблюдении ряда ограничений.
Но в целом - это плохой путь.
07:28
В частности, читающие транзакции очень дешевы.
Поэтому они не должны жить дольше чем требует логика приложения (с точки зрения изоляции транзакций), и по-хорошему нет смысла таскать их между потоками.
NK
07:50
Noel Kuntze
Hey Leonid, libmdbx 0.9.2 fails a test on the ppc64le architecture:
  ./mdbx_chk -vvn /tmp/mdbx-test.db-copy >/dev/null
>............................................................
............................................................
..............>[ 00867 child_1.1 erro ] mdbx: fatal failure: mdbx_sync_locked, 11959
[ 00867 child_1.1 fail ] mdbx_sync_locked: assert: prev_discarded_bytes > discard_edge_bytes
.make: *** [GNUmakefile:90: test] Error 1
07:52
Stdout is silenced for that test because it's just too much stuff to capture with gitlab
Л(
07:53
Леонид Юрьев (Leonid Yuriev)
In reply to this message
На всякий - если вы используете non-durable режимы и для "сохранности" данных периодически вызываете, то ОГРОМНАЯ просьба пересчитать доку и/или переспросить, чтобы не получилось как в Miranda-NG (мессенджер под винду).
Там (до недавнего времени) движок использовался не корректно, из-за многие пользователи потеряли данные (многие до сих пор считают что виновата libmdbx).
08:05
In reply to this message
Anyway, please:
1. Use the current master branch.
2. Redirect output to a file (maybe through gzip, etc) and provide it.
3. File an issue at github
NK
08:06
Noel Kuntze
Regarding 2: Are you aware that gzip produces corrupted output if the program providing the input pipe fails?
Л(
08:29
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Nope.
From gzip's point of view this is regular case when an input fd (i.e. not output) closed on the producer's side.
NK
08:30
Noel Kuntze
I tested it and it does. Or at least the version that Alpine has does.
08:30
If you try to decompress the produced gzip file, it fails
08:32
You can recover the file by redirecting to stdout and writing that to a file instead of using gzip -d
08:32
gzip -d creates a file with the name of the original archive (except the .gz ending) and writes to it, but deletes it when it encounters the error
08:33
It's something to consider when I send you the debug output
Л(
08:34
Леонид Юрьев (Leonid Yuriev)
In reply to this message
This maybe a gitlab issue - killing a group immediately when build failed.
If so do this manually from command line or find another way.
NK
08:34
Noel Kuntze
I did it directly from cmdline
08:35
I'll get back to you once I got the debug output and got master working on gitlab
Л(
08:35
Леонид Юрьев (Leonid Yuriev)
Ok, just redirect to a file, then gzip it and attachment to the issue.
08:38
@thermi, as a fast-and-dirty hack/workaround try to disable C11 while build libmdbx.
This could help on architectures with relaxed memory model, and will help me to fix.
08:44
In reply to this message
MDBX_TXN_FULL больше быть не должно, а #132 сейчас в работе.
Л(
10:33
Леонид Юрьев (Leonid Yuriev)
In reply to this message
I looked at the build log and found a few oddities there:
- two versions of the source code are mixed (used simultaneously): amalgamated (without tests) and full (with tests).
- a lot of file was patched by 0001-Add-test-suite-silence-tests.patch, so I have a suspicion that this is the reason for the problems.

In general you should:

1. Make sure that the library works correctly on your platform => Build libmdbx with test suite for your platform and check it.
- use the full source code (i.e. non amalgamated with test suite);
- build library and test suite optionally without -DNDEBUG and with -DMDBX_FORCE_ASSERTIONS=1 for your platform;
- run make check for fast/smoke tests.
- run the test/long_stochastic.sh script and let it at least for a few days to ensure libmdbx has no defects on your platform.

2. Build libmdbx for normal use => without test suite, but with -DNDEBUG.
- preferably use the amalgamated source code, with minimal patching and preferably submit ones to me.
NK
10:33
Noel Kuntze
1) The parts are from the same release, 0.9.2
10:34
2) The tests are required for Alpine Linux to get it into the distribution
NK
13:13
Noel Kuntze
Any shorthand to bypass the generation of version.c (implies fetching the whole git repo)?
A I invited A I
NK
15:54
Noel Kuntze
I got the logs and test db. https://github.com/erthink/libmdbx/issues/157
AV
16:01
Artem Vorotnikov
In reply to this message
если у меня пишущая транзакция завёрнута в мьютекс (или просто есть гарантия, что одновременно будет доступ только из одного потока) - этого достаточно чтобы безопасно обращаться из разных потоков? или нужно соблюдать ещё какие-то условия?
16:05
мой кейс:

async {
...
let txn = ...;
txn.put(...);
drop(txn);
...
}


очень важно чтобы всё содержимое async-блока можно было перемещать между потоками - тогда весь async-блок можно запустить на многопоточном экзекьюторе. При это есть гарантия, что к txn обращения только из данной конкретной корутины
Л(
16:31
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Thank you, I'll deal with it later.
Preliminary, in the current understanding, the problem is a consequence of aggressive GCC optimization on architectures with the relaxed memory model.
So first I'll issue a dirty version with a lot of explicit memory barriers.
If the problem disappears, then I will replace the explicit barriers with functions in accordance with the memory model.

If possible, it would be nice for you to try CLANG and other optimization options (including -Og and -O0).
NK
16:32
Noel Kuntze
I can't do that, because I personally have no pcc64le box
16:32
I only have indirect access via that gitlab instance of the Alpine Linux team
16:32
I could kindly ask for some kind of access though
16:32
Let me get back to you
16:32
(btw, that failure is with -Os) (sorry, not -Og)
16:33
(But gcc, of course)
Л(
16:36
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Этого достаточно, при условиях:
- libmdbx будет собрана с опцией MDBX_TXN_CHECKOWNER=0;
- поток запустивший транзакцию (и удерживающий shared mutex) не будет завершен;
- реализация shard mutex (в конкретной версии libc на конкретной платформе) позволяет освобождать чужой мьютекс (захваченый другим потоком), либо транзакцию будет гарантированно коммитить/абортить тот-же поток что её запустил.
AS
16:37
Alex Sharov
In reply to this message
Это похоже на go. Все выполняется где попало, но можно в .Begin() попросить не двигать тебя между тредами, и в Drop сказать что теперь можно двигать. Даже с CHECK_owners=1 работает.
16:41
А! там еще есть проверка что в треде где сейчас запущена write tx не будет запущена read tx - это работает в go - потому что когда просишь тебя не двигать - рантайм так же никого не пускает в твой тред. Поэтому check_owners=1 работает.
Л(
16:42
Леонид Юрьев (Leonid Yuriev)
In reply to this message
I have a similar situation.

libmdbx has been tested on various platforms, but not PowerPC.
More precisely, libmdbx for PowerPC was tested in qemu, which does not allow you to check the correctness of the operation, taking into account the implementation of the memory model of the target hardware platform.
16:43
In reply to this message
Это лучшее решение, если оно не приводит к существенному overhead в Go.
NK
16:44
Noel Kuntze
ppc64le, gcc and -O0, -O2 or -Og fail
16:44
I'll see to testing it with clang
NK
17:10
Noel Kuntze
Л(
17:11
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Thx for testing
NK
17:11
Noel Kuntze
yw, ty for your time
AV
17:14
Artem Vorotnikov
In reply to this message
если у меня полноценный многопоточный мьютекс, я могу делать rollback/commit из другого потока?
17:16
я позабочусь о синхронизации доступа, но мне нужно полностью расцепить конкретные потоки и транзакции )
17:17
растовые синхронные и асинхронные мьютексы позволяют обращаться к ним из любого потока
Л(
17:19
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Для самой библиотеки в этом нет проблем, если собрать с указанной выше опцией.
Но проблемы могут быть в зависимости от используемого метода синхронизации (вида блокировок). Что зависит от платформы.
17:27
In reply to this message
Rust тут не причем. Libmdbx обеспечивает взаимодействие роя локальных процессов, и на разных платформах используются разные системные примитивы синхронизации (файловые блокировки, разделяемые мьютексы, SysV семафоры и т.п.).
Поэтому, в целом, завершение транзакции из другого протока = UB.
29 January 2021
Л(
08:33
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Please check the devel branch.
AV
09:03
Artem Vorotnikov
In reply to this message
Ааа, вижу что в конце транзакции разлочивается мутекс... интересно

А если добавить флажок, который бы отключал встроенный мутекс и отдавал это на откуп биндингам? У нас в расте есть async-friendly мутекс, гвард которого можно двигать между потоками
NK
09:16
Noel Kuntze
In reply to this message
Ty, noted. Will test next week.
Л(
09:35
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Ну а как это будет работать из другого процесса?
Например, из утилит mdbx_chk или mdbx_copy?
09:49
In reply to this message
Есть примерно три варианта, которые IMHO стоит обсуждать:
- Выяснить, есть ли в Rust какой-нибудь "пиннинг" executors/actors к нативным тредам.
- Явно запускать в Rust отдельный тред, которому делегировать старт и завершение пишущих транзакций.
- Запускать такой тред "внутри" libmdbx и уведомлять клиентский код через обратные вызовы, без какой-либо специфической привязки к Rust.
Л(
10:16
Леонид Юрьев (Leonid Yuriev)
For the awareness of the failure in the ppc64le architecture (issue #157 on github):

- The cause of the problem was not a weak PowerPC memory model, but a trivial bug that have affected only if the system memory page size was greater than 32K. This is fixed for now in the devel branch.

- However, later today there will be another fix for very large system page sizes.

- Improvements I made to better support architectures with a weak memory model will also be merged, but after the fixes mentioned above.
AV
16:22
Artem Vorotnikov
In reply to this message
1) Можно, но тогда все корутины, которые касаются mdbx надо прибивать к потоку. У @AskAlexSharov так и сделано, но в расте это будет сделать ещё сложнее потому что тредобезопасность - часть системы типов, а прибить корутину к треду изнутри корутины нельзя.
2) Ну это такое - надо писать новые биндинги, которые будут дублировать API, пересылая команды в тред с mdbx
3) Ну это по факту сделать 2) на стороне libmdbx - не фанат ещё и потому что это гарантированно +1 тред вместо переиспользования тредов tokio (растовый асинк рантайм)
16:25
In reply to this message
как я понял, камень преткновения в нашем случае - pthread-овый мутекс - как именно другие процессы касаются этот мутекс?
16:30
К.м.к. если есть возможность вынести синхронизацию в инварианты в доках API, то биндинги смогут обернуть libmdbx в родные мутексы, решая как минимум эту проблему
Л(
16:31
Леонид Юрьев (Leonid Yuriev)
In reply to this message
Если рассматривать только Linux, то это shared robust pthread mutex, который физически находится в разделяемой памяти (в отображенном в память lck-файле) и используется совместно всеми процессами работающими с экземпляром БД.
Л(
16:53
Леонид Юрьев (Leonid Yuriev)
In reply to this message
На всякий, чтобы исключить недопонимание:
- обсуждаемое касается только read-write транзакций, которые в libmdbx принципиально отличаются от read-only транзакций.
- минимально требуется обеспечить выполнение mdbx_txn_commit() и mdbx_txn_abort() в том-же нативном треде где был вызван mdbx_txn_begin().

На мой взгляд растаскивание write-транзакций по нескольким тредам - очень сомнительное решение.
Логичнее готовить все данные для набора операций и затем выполнять их в рамках одной транзакции целиком в одном треде.
Использование разных тредов потенциально приводит к переключениями между ядрами CPU и перетаскиванию массы информации между кешами, т.е. это со 100% гарантией точно не быстрее.
AV
16:54
Artem Vorotnikov
In reply to this message
так нет задачи сделать быстрее, цель - вкрутить в приложение, использующее work-stealing рантайм )
16:54
это не про производительность вызовов к mdbx, а про эргономику использования 🙂
16:56
и здесь проблема в том, что у меня логические, а не системные треды
Л(
16:57
Леонид Юрьев (Leonid Yuriev)
In reply to this message
В "песочнице" хорошо, пока из неё не нужно выходить...