1
0
mirror of https://github.com/luanti-org/minetestmapper.git synced 2025-10-05 21:35:22 +02:00

Rewrite DB class to allow backends to fully optimize block fetches

This commit is contained in:
sfan5
2020-03-27 16:12:26 +01:00
parent ecc2b31f78
commit 5b264fd443
11 changed files with 325 additions and 154 deletions

View File

@@ -11,7 +11,6 @@ static inline int64_t stoi64(const std::string &s)
return t;
}
static inline std::string i64tos(int64_t i)
{
std::ostringstream os;
@@ -19,6 +18,7 @@ static inline std::string i64tos(int64_t i)
return os.str();
}
DBLevelDB::DBLevelDB(const std::string &mapdir)
{
leveldb::Options options;
@@ -28,6 +28,9 @@ DBLevelDB::DBLevelDB(const std::string &mapdir)
throw std::runtime_error(std::string("Failed to open Database: ") + status.ToString());
}
/* LevelDB is a dumb key-value store, so the only optimization we can do
* is to cache the block positions that exist in the db.
*/
loadPosCache();
}
@@ -38,9 +41,21 @@ DBLevelDB::~DBLevelDB()
}
std::vector<BlockPos> DBLevelDB::getBlockPos()
std::vector<BlockPos> DBLevelDB::getBlockPos(BlockPos min, BlockPos max)
{
return posCache;
std::vector<BlockPos> res;
for (const auto &it : posCache) {
if (it.first < min.z || it.first >= max.z)
continue;
for (auto pos2 : it.second) {
if (pos2.first < min.x || pos2.first >= max.x)
continue;
if (pos2.second < min.y || pos2.second >= max.y)
continue;
res.emplace_back(pos2.first, pos2.second, it.first);
}
}
return res;
}
@@ -49,26 +64,35 @@ void DBLevelDB::loadPosCache()
leveldb::Iterator * it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
int64_t posHash = stoi64(it->key().ToString());
posCache.push_back(decodeBlockPos(posHash));
BlockPos pos = decodeBlockPos(posHash);
posCache[pos.z].emplace_back(pos.x, pos.y);
}
delete it;
}
void DBLevelDB::getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos)
void DBLevelDB::getBlocksOnXZ(BlockList &blocks, int16_t x, int16_t z,
int16_t min_y, int16_t max_y)
{
std::string datastr;
leveldb::Status status;
for (const auto &it : posCache) {
if (it.z != zPos) {
auto it = posCache.find(z);
if (it == posCache.cend())
return;
for (auto pos2 : it->second) {
if (pos2.first != x)
continue;
}
status = db->Get(leveldb::ReadOptions(), i64tos(encodeBlockPos(it)), &datastr);
if (pos2.second < min_y || pos2.second >= max_y)
continue;
BlockPos pos(x, pos2.second, z);
status = db->Get(leveldb::ReadOptions(), i64tos(encodeBlockPos(pos)), &datastr);
if (status.ok()) {
Block b(it, ustring((const unsigned char *) datastr.data(), datastr.size()));
blocks[b.first.x].push_back(b);
blocks.emplace_back(
pos, ustring((unsigned char *) datastr.data(), datastr.size())
);
}
}
}