From ea3279e8f03f0e1377b681f1ad6f0088bb98f6d8 Mon Sep 17 00:00:00 2001 From: Test_User Date: Fri, 28 Jun 2024 10:29:08 -0400 Subject: Initial LMDB support --- src/CMakeLists.txt | 2 + src/database/CMakeLists.txt | 1 + src/database/database-lmdb.cpp | 226 +++++++++++++++++++++++++++++++++++++++++ src/database/database-lmdb.h | 64 ++++++++++++ src/map.cpp | 3 + 5 files changed, 296 insertions(+) create mode 100644 src/database/database-lmdb.cpp create mode 100644 src/database/database-lmdb.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c068be575..d051fad68 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -531,6 +531,7 @@ if(BUILD_CLIENT) ${LUA_BIT_LIBRARY} ${FREETYPE_LIBRARY} ${PLATFORM_LIBS} + /usr/lib/x86_64-linux-gnu/liblmdb.a ) if(NOT USE_LUAJIT) set_target_properties(${PROJECT_NAME} PROPERTIES @@ -600,6 +601,7 @@ if(BUILD_SERVER) ${LUA_BIT_LIBRARY} ${GMP_LIBRARY} ${PLATFORM_LIBS} + /usr/lib/x86_64-linux-gnu/liblmdb.a ) set_target_properties(${PROJECT_NAME}server PROPERTIES COMPILE_DEFINITIONS "SERVER") diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt index e9d157c29..991d0c565 100644 --- a/src/database/CMakeLists.txt +++ b/src/database/CMakeLists.txt @@ -6,5 +6,6 @@ set(database_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/database-postgresql.cpp ${CMAKE_CURRENT_SOURCE_DIR}/database-redis.cpp ${CMAKE_CURRENT_SOURCE_DIR}/database-sqlite3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/database-lmdb.cpp PARENT_SCOPE ) diff --git a/src/database/database-lmdb.cpp b/src/database/database-lmdb.cpp new file mode 100644 index 000000000..f36eecb57 --- /dev/null +++ b/src/database/database-lmdb.cpp @@ -0,0 +1,226 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* +LMDB database class +*/ + +#include "database-lmdb.h" +#include "remoteplayer.h" + +#include +//#include + +//static uint64_t microtime(void) { +// struct timeval tv; +// struct timezone tz = {0}; +// +// gettimeofday(&tv, &tz); +// return (tv.tv_sec * 1000000) + tv.tv_usec; +//} + +Database_LMDB::Database_LMDB(const std::string &savedir) +{ + mdb_env_create(&env); + mdb_env_set_mapsize(env, 0x10000000000); + mdb_strerror(mdb_env_open(env, (savedir+"/map.mdb").c_str(), MDB_NOSUBDIR | MDB_NORDAHEAD | MDB_NOMETASYNC, S_IRUSR | S_IWUSR)); + mdb_txn_begin(env, NULL, MDB_RDONLY, &rdtxn); + mdb_txn_begin(env, NULL, 0, &wrtxn); + mdb_dbi_open(wrtxn, NULL, MDB_INTEGERKEY, &dbi); + mdb_txn_commit(wrtxn); +} + +Database_LMDB::~Database_LMDB() +{ + mdb_txn_abort(rdtxn); + mdb_dbi_close(env, dbi); + mdb_env_close(env); +} + +bool Database_LMDB::saveBlock(const v3s16 &pos, const std::string &data) +{ + struct MDB_val key, val; + s64 k = getBlockAsInteger(pos); + key.mv_size = sizeof(k); + key.mv_data = &k; + val.mv_size = data.size(); + val.mv_data = (void*)data.c_str(); + + int retval = mdb_cursor_put(wrcursor, &key, &val, 0); + if (retval != 0) + return false; + + return true; +} + +void Database_LMDB::loadBlock(const v3s16 &pos, std::string *block) +{ +// uint64_t start_time = microtime(); + s64 k = getBlockAsInteger(pos); + + MDB_val key, val; + key.mv_size = sizeof(k); + key.mv_data = &k; + + int notfound = mdb_get(rdtxn, dbi, &key, &val); +// printf("loadBlock: took %luus\n", microtime() - start_time); + + if (notfound) + *block = ""; + else + *block = std::string((const char *)val.mv_data, val.mv_size); + + return; +} + +bool Database_LMDB::deleteBlock(const v3s16 &pos) +{ + mdb_txn_reset(rdtxn); + int retval = mdb_txn_begin(env, NULL, 0, &wrtxn); + if (retval != 0) + return false; +// printf("txn_begin: %s\n", mdb_strerror(retval)); + + s64 k = getBlockAsInteger(pos); + MDB_val key; + key.mv_size = sizeof(k); + key.mv_data = &k; + mdb_del(wrtxn, dbi, &key, NULL); + + retval = mdb_txn_commit(wrtxn); + if (retval != 0) + return false; +// printf("txn_commit: %s\n", mdb_strerror(retval)); + mdb_txn_renew(rdtxn); + + return true; +} + +void Database_LMDB::listAllLoadableBlocks(std::vector &dst) +{ +// dst.reserve(m_database.size()); +// for (std::map::const_iterator x = m_database.begin(); +// x != m_database.end(); ++x) { +// dst.push_back(getIntegerAsBlock(x->first)); +// } + + mdb_txn_reset(rdtxn); + MDB_txn *txn; + mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + MDB_cursor *cursor; + + mdb_cursor_open(txn, dbi, &cursor); + MDB_val key, val; + if (mdb_cursor_get(cursor, &key, &val, MDB_FIRST) != 0) + return; + + dst.push_back(getIntegerAsBlock((s64)key.mv_data)); + + while (mdb_cursor_get(cursor, &key, &val, MDB_NEXT) == 0) + dst.push_back(getIntegerAsBlock(*((s64*)key.mv_data))); + + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + mdb_txn_renew(rdtxn); +} + +//static uint64_t start_time; + +void Database_LMDB::beginSave() +{ +// start_time = microtime(); + mdb_txn_reset(rdtxn); + mdb_txn_begin(env, NULL, 0, &wrtxn); +// if (retval != 0) +// printf("txn_begin: %s\n", mdb_strerror(retval)); + + mdb_cursor_open(wrtxn, dbi, &wrcursor); +// if (retval != 0) +// printf("cursor_open: %s\n", mdb_strerror(retval)); +} + +void Database_LMDB::endSave() +{ + mdb_txn_commit(wrtxn); +// if (retval != 0) +// printf("txn_commit: %s\n", mdb_strerror(retval)); + mdb_txn_renew(rdtxn); +// printf("Write complete, time: %luus\n", microtime() - start_time); +} + +//void Database_LMDB::savePlayer(RemotePlayer *player) +//{ +// m_player_database.insert(player->getName()); +//} +// +//bool Database_LMDB::loadPlayer(RemotePlayer *player, PlayerSAO *sao) +//{ +// return m_player_database.find(player->getName()) != m_player_database.end(); +//} +// +//bool Database_LMDB::removePlayer(const std::string &name) +//{ +// m_player_database.erase(name); +// return true; +//} +// +//void Database_LMDB::listPlayers(std::vector &res) +//{ +// for (const auto &player : m_player_database) { +// res.emplace_back(player); +// } +//} +// +//bool Database_LMDB::getModEntries(const std::string &modname, StringMap *storage) +//{ +// const auto mod_pair = m_mod_meta_database.find(modname); +// if (mod_pair != m_mod_meta_database.cend()) { +// for (const auto &pair : mod_pair->second) { +// (*storage)[pair.first] = pair.second; +// } +// } +// return true; +//} +// +//bool Database_LMDB::setModEntry(const std::string &modname, +// const std::string &key, const std::string &value) +//{ +// auto mod_pair = m_mod_meta_database.find(modname); +// if (mod_pair == m_mod_meta_database.end()) { +// m_mod_meta_database[modname] = StringMap({{key, value}}); +// } else { +// mod_pair->second[key] = value; +// } +// return true; +//} +// +//bool Database_LMDB::removeModEntry(const std::string &modname, const std::string &key) +//{ +// auto mod_pair = m_mod_meta_database.find(modname); +// if (mod_pair != m_mod_meta_database.end()) +// return mod_pair->second.erase(key) > 0; +// return false; +//} +// +//void Database_LMDB::listMods(std::vector *res) +//{ +// for (const auto &pair : m_mod_meta_database) { +// res->push_back(pair.first); +// } +//} diff --git a/src/database/database-lmdb.h b/src/database/database-lmdb.h new file mode 100644 index 000000000..12efc651c --- /dev/null +++ b/src/database/database-lmdb.h @@ -0,0 +1,64 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include + +#include +#include +#include "database.h" +#include "irrlichttypes.h" + +class Database_LMDB : public MapDatabase//, public PlayerDatabase, public ModMetadataDatabase +{ +public: + Database_LMDB(const std::string &savedir); + ~Database_LMDB(); + + bool saveBlock(const v3s16 &pos, const std::string &data); + void loadBlock(const v3s16 &pos, std::string *block); + bool deleteBlock(const v3s16 &pos); + void listAllLoadableBlocks(std::vector &dst); + +// void savePlayer(RemotePlayer *player); +// bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); +// bool removePlayer(const std::string &name); +// void listPlayers(std::vector &res); +// +// bool getModEntries(const std::string &modname, StringMap *storage); +// bool setModEntry(const std::string &modname, +// const std::string &key, const std::string &value); +// bool removeModEntry(const std::string &modname, const std::string &key); +// void listMods(std::vector *res); +// + void beginSave(); + void endSave(); + +//private: +// std::map m_database; +// std::set m_player_database; +// std::unordered_map m_mod_meta_database; + + MDB_env *env; + MDB_txn *rdtxn; + MDB_txn *wrtxn; + MDB_dbi dbi; + MDB_cursor *wrcursor; +}; diff --git a/src/map.cpp b/src/map.cpp index 58443a000..d5a4fccdc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database/database.h" #include "database/database-dummy.h" #include "database/database-sqlite3.h" +#include "database/database-lmdb.h" #include "script/scripting_server.h" #include #include @@ -1699,6 +1700,8 @@ MapDatabase *ServerMap::createDatabase( return new MapDatabaseSQLite3(savedir); if (name == "dummy") return new Database_Dummy(); + if (name == "lmdb") + return new Database_LMDB(savedir); #if USE_LEVELDB if (name == "leveldb") return new Database_LevelDB(savedir); -- cgit v1.2.3