2014-03-05 21:41:27 +01:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <sstream>
|
2014-04-19 08:13:34 +02:00
|
|
|
#include "db-leveldb.h"
|
|
|
|
#include "types.h"
|
2014-03-05 21:41:27 +01:00
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
static inline int64_t stoi64(const std::string &s)
|
|
|
|
{
|
2014-03-05 21:41:27 +01:00
|
|
|
std::stringstream tmp(s);
|
2014-04-19 08:13:34 +02:00
|
|
|
int64_t t;
|
2014-03-05 21:41:27 +01:00
|
|
|
tmp >> t;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
static inline std::string i64tos(int64_t i)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << i;
|
|
|
|
return os.str();
|
2014-03-05 21:41:27 +01:00
|
|
|
}
|
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
DBLevelDB::DBLevelDB(const std::string &mapdir)
|
|
|
|
{
|
2014-03-05 21:41:27 +01:00
|
|
|
leveldb::Options options;
|
|
|
|
options.create_if_missing = false;
|
2014-03-28 21:47:19 +01:00
|
|
|
leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &db);
|
2014-04-19 08:13:34 +02:00
|
|
|
if (!status.ok()) {
|
2014-05-13 14:15:44 +02:00
|
|
|
throw std::runtime_error(std::string("Failed to open Database: ") + status.ToString());
|
2014-04-19 08:13:34 +02:00
|
|
|
}
|
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
2014-04-19 08:13:34 +02:00
|
|
|
loadPosCache();
|
2014-03-05 21:41:27 +01:00
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
|
|
|
|
DBLevelDB::~DBLevelDB()
|
|
|
|
{
|
2014-03-28 21:47:19 +01:00
|
|
|
delete db;
|
2014-03-05 21:41:27 +01:00
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
std::vector<BlockPos> DBLevelDB::getBlockPos(BlockPos min, BlockPos max)
|
2014-04-19 08:13:34 +02:00
|
|
|
{
|
2020-03-27 16:12:26 +01:00
|
|
|
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;
|
2014-03-28 21:47:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
void DBLevelDB::loadPosCache()
|
|
|
|
{
|
2014-03-28 21:47:19 +01:00
|
|
|
leveldb::Iterator * it = db->NewIterator(leveldb::ReadOptions());
|
2014-03-05 21:41:27 +01:00
|
|
|
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
2014-04-19 08:13:34 +02:00
|
|
|
int64_t posHash = stoi64(it->key().ToString());
|
2020-03-27 16:12:26 +01:00
|
|
|
BlockPos pos = decodeBlockPos(posHash);
|
|
|
|
|
|
|
|
posCache[pos.z].emplace_back(pos.x, pos.y);
|
2014-03-05 21:41:27 +01:00
|
|
|
}
|
|
|
|
delete it;
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
void DBLevelDB::getBlocksOnXZ(BlockList &blocks, int16_t x, int16_t z,
|
|
|
|
int16_t min_y, int16_t max_y)
|
2014-04-19 08:13:34 +02:00
|
|
|
{
|
2014-03-05 21:41:27 +01:00
|
|
|
std::string datastr;
|
|
|
|
leveldb::Status status;
|
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
auto it = posCache.find(z);
|
|
|
|
if (it == posCache.cend())
|
|
|
|
return;
|
|
|
|
for (auto pos2 : it->second) {
|
|
|
|
if (pos2.first != x)
|
2014-03-05 21:41:27 +01:00
|
|
|
continue;
|
2020-03-27 16:12:26 +01:00
|
|
|
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);
|
2014-03-28 21:47:19 +01:00
|
|
|
if (status.ok()) {
|
2020-03-27 16:12:26 +01:00
|
|
|
blocks.emplace_back(
|
|
|
|
pos, ustring((unsigned char *) datastr.data(), datastr.size())
|
|
|
|
);
|
2014-03-28 21:47:19 +01:00
|
|
|
}
|
2014-03-05 21:41:27 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 21:10:00 +01:00
|
|
|
|
|
|
|
void DBLevelDB::getBlocksByPos(BlockList &blocks,
|
|
|
|
const std::vector<BlockPos> &positions)
|
|
|
|
{
|
|
|
|
std::string datastr;
|
|
|
|
leveldb::Status status;
|
|
|
|
|
|
|
|
for (auto pos : positions) {
|
|
|
|
status = db->Get(leveldb::ReadOptions(), i64tos(encodeBlockPos(pos)), &datastr);
|
|
|
|
if (status.ok()) {
|
|
|
|
blocks.emplace_back(
|
|
|
|
pos, ustring((unsigned char *) datastr.data(), datastr.size())
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|