minetest-mapper-cpp/db-leveldb.cpp
Rogier 9a9b83e638 Detect libstdc++ ABI incompatibility to allow compiling using clang again.
Currently, this is only relevant when using LevelDB, and a newer version
of libstdc++, which uses a different C++ ABI which clang does not yet support.

A symptom of the problem are unexpected linking failures, caused by undefined
symbols, while other symbols from the same library do not cause errors.

The solution is a workaround, that avoids using the offending symbols, at the
cost of reduced functionality. As this currently only affects the text of an
error message, the impact is minor.
2016-06-28 11:44:09 +02:00

117 lines
3.0 KiB
C++

#include "db-leveldb.h"
#include <stdexcept>
#include <sstream>
#include "build_config.h"
#include "types.h"
inline int64_t stoi64(const std::string &s) {
std::stringstream tmp(s);
long long t;
tmp >> t;
return t;
}
inline std::string i64tos(int64_t i) {
std::ostringstream o;
o<<i;
return o.str();
}
DBLevelDB::DBLevelDB(const std::string &mapdir) :
m_blocksReadCount(0),
m_blocksQueriedCount(0),
m_keyFormatI64Usage(0),
m_keyFormatAXYZUsage(0)
{
leveldb::Options options;
options.create_if_missing = false;
leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &m_db);
if(!status.ok())
#if CPP_ABI_STDSTRING_OK
throw std::runtime_error(std::string("Failed to open Database: ") + status.ToString());
#else
throw std::runtime_error(std::string("Failed to open Database: ") +
( status.ok() ? "Ok (??? how is this possible ???"")" // "" is needed to prevent interpretation as trigraph -shudder-
: status.IsNotFound() ? "NotFound"
: status.IsCorruption() ? "Corruption"
: status.IsIOError() ? "IOError"
: "Cannot determine error type - could be NotSupported or InvalidArgument or something else"));
#endif
}
DBLevelDB::~DBLevelDB() {
delete m_db;
}
int DBLevelDB::getBlocksReadCount(void)
{
return m_blocksReadCount;
}
int DBLevelDB::getBlocksQueriedCount(void)
{
return m_blocksQueriedCount;
}
const DB::BlockPosList &DBLevelDB::getBlockPosList() {
m_blockPosList.clear();
leveldb::Iterator* it = m_db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
m_blockPosList.push_back(BlockPos(it->key().ToString()));
}
delete it;
return m_blockPosList;
}
DB::Block DBLevelDB::getBlockOnPos(const BlockPos &pos)
{
std::string datastr;
leveldb::Status status;
// If block format is not known, try both alternatives, but prefer
// the version that has worked best in recent history
if (pos.databaseFormat() == BlockPos::Unknown) {
BlockPos::StrFormat format[2];
if (m_keyFormatI64Usage > m_keyFormatAXYZUsage) {
format[0] = BlockPos::I64;
format[1] = BlockPos::AXYZ;
}
else {
format[0] = BlockPos::AXYZ;
format[1] = BlockPos::I64;
}
int i;
for (i = 0; i < 2; i++) {
m_blocksQueriedCount++;
status = m_db->Get(leveldb::ReadOptions(), pos.databasePosStrFmt(format[i]), &datastr);
if (status.ok())
break;
}
if (i < 2) {
if (format[i] == BlockPos::I64) {
m_keyFormatI64Usage = (m_keyFormatI64Usage << 1) | 0x01;
m_keyFormatAXYZUsage = (m_keyFormatAXYZUsage >> 1);
}
else {
m_keyFormatAXYZUsage = (m_keyFormatAXYZUsage << 1) | 0x01;
m_keyFormatI64Usage = (m_keyFormatI64Usage >> 1);
}
}
}
else {
m_blocksQueriedCount++;
status = m_db->Get(leveldb::ReadOptions(), pos.databasePosStr(), &datastr);
}
if(status.ok()) {
m_blocksReadCount++;
return Block(pos, ustring(reinterpret_cast<const unsigned char *>(datastr.c_str()), datastr.size()));
}
else {
return Block(pos, ustring(reinterpret_cast<const unsigned char *>("")));
}
}