LINUX.ORG.RU

Как правильно работать с lmdb?

 ,


1

2

Разбираю lmdb.

Если выполняю mdb_txn_commit после каждого mdb_put, то получаю жутко медленную скорость, всего десятки записей в секунду.

А если не закрывать, то в какой то момент получаю сообщение об ошибке «MDB_MAP_FULL: Environment mapsize limit reached», каждый раз на разном кол-ве произведенных записей.

Делаю примерно как описано в примере: https://github.com/rvagg/lmdb/blob/master/deps/liblmdb-20130601/sample-mdb.c

Как правильно производить запись в эту базу?

Установите изначально лимит, достаточный для того, чтобы хранить всё, что вам нужно. mdb_env_set_mapsize(). Если вы будете по одной записи коммитить, то всё равно упрётесь в этот лимит.

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

Если же вас это не устраивает, т.е. вам нужен бесконечный лимит, то вам придётся быть готовым к повторной записи тех данных, что не были успешно записаны. Вам надо будет абортнуть все транзакции в процессе, а затем увеличить лимит. mdb_env_info() + mdb_env_set_mapsize(), а также добавить поддержку кода возврата MDB_MAP_RESIZED из функции mdb_txn_begin(), если вы работаете с БД из других процессов. Можно увеличивать лимит, например, каждый раз в 2 раза, так вы быстро дойдёте до удовлетворяющего вас значения.

Sorcerer ★★★★★
()
Последнее исправление: Sorcerer (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Последовательность примерно такая:

//Инициализация:
mdb_env_create
mdb_env_open
mdb_txn_begin
mdb_open (получаю dbi)
mdb_txn_commit

Запись/чтение:
mdb_txn_begin
// либо каждую оборачиваю - медлено
// либо сразу пачками, но с ошибками
mdb_put/mdb_get
mdb_txn_commit

Закрытие:
mdb_close
mdb_env_close
Согласно бенчмарку: http://www.lmdb.tech/bench/microbench/, который так и не удосужился сам откомпилить (наверняка там будут куча проблем с этим), должно быть 240тыс записей в секунду, если делать коммиты после каждой записи. А получатется около пары десятков штук. Примерно такая же картина в SQLite если не оборачивать все в транзакцию, но в SQLite об этом прямо говорится, что если так, то будет медленно. А для lmdb говорят что и без этого все будет замечательно.

anonymous
()
Ответ на: комментарий от anonymous

Кажется, до меня дошло. Я всегда флаг MDB_NOSYNC передаю. Без него данные сбрасываются на диск после каждой транзакции, что и даёт эти несколько десятков в секунду.

Посмотри ещё в сторону флагов MDB_MAPASYNC и MDB_WRITEMAP.

i-rinat ★★★★★
()

Как указал Sorcerer, действительно эту ошибку исправляет периодический вызов mdb_env_set_mapsize. lmdb резервирует место на диске под данные, и когда оно заканчивается, то происходит указанная ошибка. Сама база динамически перевыделять это место не хочет. Нужно вызывать mdb_env_set_mapsize для расширения размера базы, можно не закрывая базы. Перевыделить, и повторить операцию записи на которой произошла ошибка. Как заранее проверять, сколько еще свободного места не понятно.

В остальном, если кому интересно, по результатам теста, на моей программе где вставки занимают порядка 80%, пока записей менее 10млн, то эта база быстрее чем leveldb примерно на 20%. А после 10млн начинает падать скорость, и уже от 15млн записей lmdb становится существенно хуже чем leveldb.

Тестировалось для lmdb при MDB_NOSYNC|MDB_WRITEMAP. Для leveldb устанавливал kNoCompression, а в остальном все типовое.

victor79
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.