LMDB创建与读取
创建
可以创建带目录和不带目录的,都会产生主题数据文件和锁(lock)文件。锁文件可以删除,因为下次打开的时候会自动创建。
创建 env 之后,要先设置 mapsize 再创建打开文件;mapsize 可以设置很大,如果设置的太小,会导致加数据或提交时出现 MDB_MAP_FULL 错误。不同担心 mapsize 设置很大时,没开始写数据内存就爆,或写出去的数据文件会特别大,不会的,内存和文件只和你喂给它数据多少有关。
inline void check(int code) { if (code != MDB_SUCCESS) { auto msg = mdb_strerror(code); throw std::runtime_error(msg); } } void create(const fs::path& lmdbFilename, bool subdir) { MDB_env *env = nullptr; check(mdb_env_create(&env)); check(mdb_env_set_mapsize(env, 1099511627776ul)); // 1 TB check(mdb_env_open(env, lmdbFilename.u8string().c_str(), subdir ? 0 : MDB_NOSUBDIR, 0664)); MDB_txn *txn = nullptr; check(mdb_txn_begin(env, nullptr, 0, &txn)); MDB_dbi dbi = 0; check(mdb_dbi_open(txn, nullptr, 0, &dbi)); std::string str(u8"test"); std::vector<uint8_t> data(128, 0); MDB_val key{0}; key.mv_data = (void*)str.data(); key.mv_size = str.size(); MDB_val val{0}; val.mv_data = (void*)data.data(); val.mv_size = data.size(); check(mdb_put(txn, dbi, &key, &val, 0)); check(mdb_txn_commit(txn)); mdb_dbi_close(env, dbi); mdb_env_close(env); }
读取
打开文件时建议加上 MDB_FIXEDMAP,加上读取时要相对快很多。
void read(const fs::path& lmdbFilename, bool subdir) { MDB_env *env = nullptr; check(mdb_env_create(&env)); check(mdb_env_set_mapsize(env, 1099511627776ul)); // 1 TB int flags = MDB_FIXEDMAP | MDB_RDONLY | (subdir ? 0 : MDB_NOSUBDIR); check(mdb_env_open(env, lmdbFilename.u8string().c_str(), flags, 0664)); MDB_txn *txn = nullptr; check(mdb_txn_begin(env, nullptr, flags, &txn)); MDB_dbi dbi = 0; check(mdb_dbi_open(txn, nullptr, 0, &dbi)); MDB_cursor *cursor = nullptr; check(mdb_cursor_open(txn, dbi, &cursor)); MDB_val key{0}; MDB_val val{0}; int ret = MDB_SUCCESS; while ((ret = mdb_cursor_get(cursor, &key, &val, MDB_NEXT)) != MDB_NOTFOUND) { check(ret); std::string str((const char*)key.mv_data, (const char*)key.mv_data + key.mv_size); std::vector<uint8_t> data((const uint8_t*)val.mv_data, (const uint8_t*)val.mv_data + val.mv_size); cout << str << endl; } mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); }