Significantly optimize LevelDB database backend

This commit is contained in:
ShadowNinja 2014-03-28 16:47:19 -04:00
parent 6e565e93d1
commit 5905c34ec0
6 changed files with 61 additions and 49 deletions

@ -17,6 +17,7 @@
#include <stdexcept> #include <stdexcept>
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#include <vector>
#include "config.h" #include "config.h"
#include "PlayerAttributes.h" #include "PlayerAttributes.h"
#include "TileGenerator.h" #include "TileGenerator.h"
@ -308,17 +309,17 @@ void TileGenerator::openDb(const std::string &input)
void TileGenerator::loadBlocks() void TileGenerator::loadBlocks()
{ {
std::vector<int64_t> vec = m_db->getBlockPos(); std::vector<int64_t> vec = m_db->getBlockPos();
for(unsigned int i = 0; i < vec.size(); i++) { for(std::vector<int64_t>::iterator it = vec.begin(); it != vec.end(); ++it) {
BlockPos pos = decodeBlockPos(vec[i]); BlockPos pos = decodeBlockPos(*it);
// Check that it's in geometry (from --geometry option)
if (pos.x < m_geomX || pos.x > m_geomX2 || pos.z < m_geomY || pos.z > m_geomY2) { if (pos.x < m_geomX || pos.x > m_geomX2 || pos.z < m_geomY || pos.z > m_geomY2) {
continue; continue;
} }
if (pos.y < m_yMin * 16) { // Check that it's between --miny and --maxy
continue; if (pos.y < m_yMin * 16 || pos.y > m_yMax * 16) {
}
if (pos.y > m_yMax * 16) {
continue; continue;
} }
// Adjust minimum and maximum positions to the nearest block
if (pos.x < m_xMin) { if (pos.x < m_xMin) {
m_xMin = pos.x; m_xMin = pos.x;
} }

@ -17,46 +17,56 @@ inline std::string i64tos(int64_t i) {
DBLevelDB::DBLevelDB(const std::string &mapdir) { DBLevelDB::DBLevelDB(const std::string &mapdir) {
leveldb::Options options; leveldb::Options options;
posCacheLoaded = false;
options.create_if_missing = false; options.create_if_missing = false;
leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &m_db); leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &db);
if(!status.ok()) if(!status.ok())
throw std::runtime_error("Failed to open Database"); throw std::runtime_error("Failed to open Database");
} }
DBLevelDB::~DBLevelDB() { DBLevelDB::~DBLevelDB() {
delete m_db; delete db;
} }
std::vector<int64_t> DBLevelDB::getBlockPos() { std::vector<int64_t> DBLevelDB::getBlockPos() {
std::vector<int64_t> vec; loadPosCache();
std::set<int64_t> s; return posCache;
leveldb::Iterator* it = m_db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
vec.push_back(stoi64(it->key().ToString()));
s.insert(stoi64(it->key().ToString()));
}
delete it;
m_bpcache = s;
return vec;
} }
DBBlockList DBLevelDB::getBlocksOnZ(int zPos) void DBLevelDB::loadPosCache() {
{ if (posCacheLoaded) {
return;
}
leveldb::Iterator * it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
posCache.push_back(stoi64(it->key().ToString()));
}
delete it;
posCacheLoaded = true;
}
DBBlockList DBLevelDB::getBlocksOnZ(int zPos) {
DBBlockList blocks; DBBlockList blocks;
std::string datastr; std::string datastr;
leveldb::Status status; leveldb::Status status;
int64_t psMin; int64_t psMin = (zPos * 16777216L) - 0x800000;
int64_t psMax; int64_t psMax = (zPos * 16777216L) + 0x7fffff;
psMin = (zPos * 16777216l) - 0x800000;
psMax = (zPos * 16777216l) + 0x7fffff;
for(int64_t i = psMin; i <= psMax; i++) { // FIXME: This is still very very inefficent (even with m_bpcache) for (std::vector<int64_t>::iterator it = posCache.begin(); it != posCache.end(); ++it) {
if(m_bpcache.find(i) == m_bpcache.end()) int64_t i = *it;
if (i < psMin || i > psMax) {
continue; continue;
status = m_db->Get(leveldb::ReadOptions(), i64tos(i), &datastr); }
if(status.ok()) status = db->Get(leveldb::ReadOptions(), i64tos(i), &datastr);
blocks.push_back( DBBlock( i, std::basic_string<unsigned char>( (const unsigned char*) datastr.c_str(), datastr.size() ) ) ); if (status.ok()) {
blocks.push_back(
DBBlock(i,
std::basic_string<unsigned char>((const unsigned char*) datastr.data(), datastr.size())
)
);
}
} }
return blocks; return blocks;

@ -3,7 +3,6 @@
#include "db.h" #include "db.h"
#include <leveldb/db.h> #include <leveldb/db.h>
#include <set>
class DBLevelDB : public DB { class DBLevelDB : public DB {
public: public:
@ -12,8 +11,12 @@ public:
virtual DBBlockList getBlocksOnZ(int zPos); virtual DBBlockList getBlocksOnZ(int zPos);
~DBLevelDB(); ~DBLevelDB();
private: private:
leveldb::DB *m_db; void loadPosCache();
std::set<int64_t> m_bpcache;
leveldb::DB *db;
bool posCacheLoaded;
std::vector<int64_t> posCache;
}; };
#endif // _DB_LEVELDB_H #endif // _DB_LEVELDB_H

@ -5,7 +5,7 @@
#define SQLRES(f, good) \ #define SQLRES(f, good) \
result = (sqlite3_##f);\ result = (sqlite3_##f);\
if (result != good) {\ if (result != good) {\
throw std::runtime_error(sqlite3_errmsg(m_db));\ throw std::runtime_error(sqlite3_errmsg(db));\
} }
#define SQLOK(f) SQLRES(f, SQLITE_OK) #define SQLOK(f) SQLRES(f, SQLITE_OK)
@ -13,13 +13,13 @@ DBSQLite3::DBSQLite3(const std::string &mapdir) {
int result; int result;
std::string db_name = mapdir + "map.sqlite"; std::string db_name = mapdir + "map.sqlite";
SQLOK(open_v2(db_name.c_str(), &m_db, SQLITE_OPEN_READONLY | SQLITE_OPEN_PRIVATECACHE, 0)) SQLOK(open_v2(db_name.c_str(), &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_PRIVATECACHE, 0))
SQLOK(prepare_v2(m_db, SQLOK(prepare_v2(db,
"SELECT pos, data FROM blocks WHERE (pos >= ? AND pos <= ?)", "SELECT pos, data FROM blocks WHERE (pos >= ? AND pos <= ?)",
-1, &stmt_get_blocks, NULL)) -1, &stmt_get_blocks, NULL))
SQLOK(prepare_v2(m_db, SQLOK(prepare_v2(db,
"SELECT pos FROM blocks", "SELECT pos FROM blocks",
-1, &stmt_get_block_pos, NULL)) -1, &stmt_get_block_pos, NULL))
} }
@ -29,12 +29,12 @@ DBSQLite3::~DBSQLite3() {
SQLOK(finalize(stmt_get_blocks)); SQLOK(finalize(stmt_get_blocks));
SQLOK(finalize(stmt_get_block_pos)); SQLOK(finalize(stmt_get_block_pos));
SQLOK(close(m_db)); SQLOK(close(db));
} }
std::vector<int64_t> DBSQLite3::getBlockPos() { std::vector<int64_t> DBSQLite3::getBlockPos() {
std::vector<int64_t> vec; std::vector<int64_t> vec;
int result = 0; int result;
while ((result = sqlite3_step(stmt_get_block_pos)) != SQLITE_DONE) { while ((result = sqlite3_step(stmt_get_block_pos)) != SQLITE_DONE) {
if (result == SQLITE_ROW) { if (result == SQLITE_ROW) {
int64_t blockpos = sqlite3_column_int64(stmt_get_block_pos, 0); int64_t blockpos = sqlite3_column_int64(stmt_get_block_pos, 0);
@ -42,9 +42,10 @@ std::vector<int64_t> DBSQLite3::getBlockPos() {
} else if (result == SQLITE_BUSY) { // Wait some time and try again } else if (result == SQLITE_BUSY) { // Wait some time and try again
usleep(10000); usleep(10000);
} else { } else {
throw std::runtime_error(sqlite3_errmsg(m_db)); throw std::runtime_error(sqlite3_errmsg(db));
} }
} }
SQLOK(reset(stmt_get_block_pos));
return vec; return vec;
} }
@ -52,15 +53,13 @@ DBBlockList DBSQLite3::getBlocksOnZ(int zPos)
{ {
DBBlockList blocks; DBBlockList blocks;
sqlite3_int64 psMin; int64_t psMin = (static_cast<sqlite3_int64>(zPos) * 16777216L) - 0x800000;
sqlite3_int64 psMax; int64_t psMax = (static_cast<sqlite3_int64>(zPos) * 16777216L) + 0x7fffff;
psMin = (static_cast<sqlite3_int64>(zPos) * 16777216L) - 0x800000;
psMax = (static_cast<sqlite3_int64>(zPos) * 16777216L) + 0x7fffff;
sqlite3_bind_int64(stmt_get_blocks, 1, psMin); sqlite3_bind_int64(stmt_get_blocks, 1, psMin);
sqlite3_bind_int64(stmt_get_blocks, 2, psMax); sqlite3_bind_int64(stmt_get_blocks, 2, psMax);
int result = 0; int result;
while ((result = sqlite3_step(stmt_get_blocks)) != SQLITE_DONE) { while ((result = sqlite3_step(stmt_get_blocks)) != SQLITE_DONE) {
if (result == SQLITE_ROW) { if (result == SQLITE_ROW) {
int64_t blocknum = sqlite3_column_int64(stmt_get_blocks, 0); int64_t blocknum = sqlite3_column_int64(stmt_get_blocks, 0);
@ -70,7 +69,7 @@ DBBlockList DBSQLite3::getBlocksOnZ(int zPos)
} else if (result == SQLITE_BUSY) { // Wait some time and try again } else if (result == SQLITE_BUSY) { // Wait some time and try again
usleep(10000); usleep(10000);
} else { } else {
throw std::runtime_error(sqlite3_errmsg(m_db)); throw std::runtime_error(sqlite3_errmsg(db));
} }
} }
SQLOK(reset(stmt_get_blocks)); SQLOK(reset(stmt_get_blocks));

@ -11,7 +11,7 @@ public:
virtual DBBlockList getBlocksOnZ(int zPos); virtual DBBlockList getBlocksOnZ(int zPos);
~DBSQLite3(); ~DBSQLite3();
private: private:
sqlite3 *m_db; sqlite3 *db;
sqlite3_stmt *stmt_get_block_pos; sqlite3_stmt *stmt_get_block_pos;
sqlite3_stmt *stmt_get_blocks; sqlite3_stmt *stmt_get_blocks;

5
db.h

@ -7,14 +7,13 @@
#include <string> #include <string>
#include <utility> #include <utility>
// we cannot use ... char>> here because mingw-gcc is f**king retarded (caring about whitespace and shit)
typedef std::pair<int64_t, std::basic_string<unsigned char> > DBBlock; typedef std::pair<int64_t, std::basic_string<unsigned char> > DBBlock;
typedef std::list<DBBlock> DBBlockList; typedef std::list<DBBlock> DBBlockList;
class DB { class DB {
public: public:
virtual std::vector<int64_t> getBlockPos()=0; virtual std::vector<int64_t> getBlockPos() = 0;
virtual DBBlockList getBlocksOnZ(int zPos)=0; virtual DBBlockList getBlocksOnZ(int zPos) = 0;
}; };
#endif // _DB_H #endif // _DB_H