mirror of
https://github.com/minetest/minetestmapper.git
synced 2024-11-21 23:13:53 +01:00
Add redis database backend
This commit is contained in:
parent
22d3e401f8
commit
2553e44e8d
@ -60,6 +60,26 @@ if(ENABLE_LEVELDB)
|
|||||||
endif(LEVELDB_LIBRARY AND LEVELDB_INCLUDE_DIR)
|
endif(LEVELDB_LIBRARY AND LEVELDB_INCLUDE_DIR)
|
||||||
endif(ENABLE_LEVELDB)
|
endif(ENABLE_LEVELDB)
|
||||||
|
|
||||||
|
# Find redis
|
||||||
|
set(USE_REDIS 0)
|
||||||
|
|
||||||
|
OPTION(ENABLE_REDIS "Enable redis backend")
|
||||||
|
|
||||||
|
if(ENABLE_REDIS)
|
||||||
|
find_library(REDIS_LIBRARY hiredis)
|
||||||
|
find_path(REDIS_INCLUDE_DIR hiredis.h PATH_SUFFIXES hiredis)
|
||||||
|
message (STATUS "redis library: ${REDIS_LIBRARY}")
|
||||||
|
message (STATUS "redis headers: ${REDIS_INCLUDE_DIR}")
|
||||||
|
if(REDIS_LIBRARY AND REDIS_INCLUDE_DIR)
|
||||||
|
set(USE_REDIS 1)
|
||||||
|
message(STATUS "redis backend enabled")
|
||||||
|
include_directories(${REDIS_INCLUDE_DIR})
|
||||||
|
else(REDIS_LIBRARY AND REDIS_INCLUDE_DIR)
|
||||||
|
set(USE_REDIS 0)
|
||||||
|
message(STATUS "redis not found!")
|
||||||
|
endif(REDIS_LIBRARY AND REDIS_INCLUDE_DIR)
|
||||||
|
endif(ENABLE_REDIS)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"${PROJECT_BINARY_DIR}"
|
"${PROJECT_BINARY_DIR}"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
@ -88,6 +108,10 @@ if(USE_LEVELDB)
|
|||||||
set(mapper_SRCS ${mapper_SRCS} db-leveldb.cpp)
|
set(mapper_SRCS ${mapper_SRCS} db-leveldb.cpp)
|
||||||
endif(USE_LEVELDB)
|
endif(USE_LEVELDB)
|
||||||
|
|
||||||
|
if(USE_REDIS)
|
||||||
|
set(mapper_SRCS ${mapper_SRCS} db-redis.cpp)
|
||||||
|
endif(USE_REDIS)
|
||||||
|
|
||||||
add_executable(minetestmapper
|
add_executable(minetestmapper
|
||||||
${mapper_SRCS}
|
${mapper_SRCS}
|
||||||
)
|
)
|
||||||
@ -96,6 +120,7 @@ target_link_libraries(
|
|||||||
minetestmapper
|
minetestmapper
|
||||||
${SQLITE3_LIBRARY}
|
${SQLITE3_LIBRARY}
|
||||||
${LEVELDB_LIBRARY}
|
${LEVELDB_LIBRARY}
|
||||||
|
${REDIS_LIBRARY}
|
||||||
${LIBGD_LIBRARY}
|
${LIBGD_LIBRARY}
|
||||||
${ZLIB_LIBRARY}
|
${ZLIB_LIBRARY}
|
||||||
)
|
)
|
||||||
|
@ -9,6 +9,7 @@ Requirements
|
|||||||
* libgd
|
* libgd
|
||||||
* sqlite3
|
* sqlite3
|
||||||
* leveldb (optional, set ENABLE_LEVELDB=1 in CMake to enable leveldb support)
|
* leveldb (optional, set ENABLE_LEVELDB=1 in CMake to enable leveldb support)
|
||||||
|
* hiredis (optional, set ENABLE_REDIS=1 in CMake to enable redis support)
|
||||||
|
|
||||||
Compilation
|
Compilation
|
||||||
-----------
|
-----------
|
||||||
@ -66,7 +67,7 @@ max-y:
|
|||||||
Don't draw nodes above this y value, `--max-y 75`
|
Don't draw nodes above this y value, `--max-y 75`
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
Use specific map backend, supported: sqlite3, leveldb, `--backend leveldb`
|
Use specific map backend, supported: sqlite3, leveldb, redis, `--backend leveldb`
|
||||||
|
|
||||||
geometry:
|
geometry:
|
||||||
Limit area to specific geometry, `--geometry -800:-800+1600+1600`
|
Limit area to specific geometry, `--geometry -800:-800+1600+1600`
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#if USE_LEVELDB
|
#if USE_LEVELDB
|
||||||
#include "db-leveldb.h"
|
#include "db-leveldb.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if USE_REDIS
|
||||||
|
#include "db-redis.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -298,6 +301,10 @@ void TileGenerator::openDb(const std::string &input)
|
|||||||
#if USE_LEVELDB
|
#if USE_LEVELDB
|
||||||
else if(m_backend == "leveldb")
|
else if(m_backend == "leveldb")
|
||||||
m_db = new DBLevelDB(input);
|
m_db = new DBLevelDB(input);
|
||||||
|
#endif
|
||||||
|
#if USE_REDIS
|
||||||
|
else if(m_backend == "redis")
|
||||||
|
m_db = new DBRedis(input);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
throw std::runtime_error(((std::string) "Unknown map backend: ") + m_backend);
|
throw std::runtime_error(((std::string) "Unknown map backend: ") + m_backend);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#define CMAKE_CONFIG_H
|
#define CMAKE_CONFIG_H
|
||||||
|
|
||||||
#define USE_LEVELDB @USE_LEVELDB@
|
#define USE_LEVELDB @USE_LEVELDB@
|
||||||
|
#define USE_REDIS @USE_REDIS@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
165
db-redis.cpp
Normal file
165
db-redis.cpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include "db-redis.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
static inline int64_t stoi64(const std::string &s)
|
||||||
|
{
|
||||||
|
std::stringstream tmp(s);
|
||||||
|
int64_t t;
|
||||||
|
tmp >> t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline std::string i64tos(int64_t i)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << i;
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string trim(const std::string &s)
|
||||||
|
{
|
||||||
|
size_t front = 0;
|
||||||
|
while(s[front] == ' ' ||
|
||||||
|
s[front] == '\t' ||
|
||||||
|
s[front] == '\r' ||
|
||||||
|
s[front] == '\n'
|
||||||
|
)
|
||||||
|
++front;
|
||||||
|
|
||||||
|
size_t back = s.size();
|
||||||
|
while(back > front &&
|
||||||
|
(s[back-1] == ' ' ||
|
||||||
|
s[back-1] == '\t' ||
|
||||||
|
s[back-1] == '\r' ||
|
||||||
|
s[back-1] == '\n'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
--back;
|
||||||
|
|
||||||
|
return s.substr(front, back - front);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EOFCHECK() \
|
||||||
|
if(is.eof()) \
|
||||||
|
throw std::runtime_error("setting not found");
|
||||||
|
|
||||||
|
std::string get_setting(std::string name, std::istream &is)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
char s[256];
|
||||||
|
std::string nm, value;
|
||||||
|
|
||||||
|
next:
|
||||||
|
while((c = is.get()) == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||||
|
;
|
||||||
|
EOFCHECK();
|
||||||
|
if(c == '#') // Ignore comments
|
||||||
|
is.ignore(0xffff, '\n');
|
||||||
|
EOFCHECK();
|
||||||
|
s[0] = c; // The current char belongs to the name too
|
||||||
|
is.get(&s[1], 255, '=');
|
||||||
|
is.ignore(1); // Jump over the =
|
||||||
|
EOFCHECK();
|
||||||
|
nm = trim(std::string(s));
|
||||||
|
is.get(s, 256, '\n');
|
||||||
|
value = trim(std::string(s));
|
||||||
|
if(name == nm)
|
||||||
|
return value;
|
||||||
|
else
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef EOFCHECK
|
||||||
|
|
||||||
|
std::string get_setting_default(std::string name, std::istream &is, const std::string def)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return get_setting(name, is);
|
||||||
|
} catch(std::runtime_error e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBRedis::DBRedis(const std::string &mapdir)
|
||||||
|
{
|
||||||
|
std::ifstream ifs((mapdir + "/world.mt").c_str());
|
||||||
|
if(!ifs.good())
|
||||||
|
throw std::runtime_error("Failed to read world.mt");
|
||||||
|
std::string tmp;
|
||||||
|
try {
|
||||||
|
tmp = get_setting("redis_address", ifs);
|
||||||
|
ifs.seekg(0);
|
||||||
|
hash = get_setting("redis_hash", ifs);
|
||||||
|
ifs.seekg(0);
|
||||||
|
} catch(std::runtime_error e) {
|
||||||
|
throw std::runtime_error("Set redis_address and redis_hash in world.mt to use the redis backend");
|
||||||
|
}
|
||||||
|
const char *addr = tmp.c_str();
|
||||||
|
int port = stoi64(get_setting_default("redis_port", ifs, "6379"));
|
||||||
|
ctx = redisConnect(addr, port);
|
||||||
|
if(!ctx)
|
||||||
|
throw std::runtime_error("Cannot allocate redis context");
|
||||||
|
else if(ctx->err) {
|
||||||
|
std::string err = std::string("Connection error: ") + ctx->errstr;
|
||||||
|
redisFree(ctx);
|
||||||
|
throw std::runtime_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadPosCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DBRedis::~DBRedis()
|
||||||
|
{
|
||||||
|
redisFree(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<BlockPos> DBRedis::getBlockPos()
|
||||||
|
{
|
||||||
|
return posCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DBRedis::loadPosCache()
|
||||||
|
{
|
||||||
|
redisReply *reply;
|
||||||
|
reply = (redisReply*) redisCommand(ctx, "HKEYS %s", hash.c_str());
|
||||||
|
if(!reply)
|
||||||
|
throw std::runtime_error(std::string("redis command 'HKEYS %s' failed: ") + ctx->errstr);
|
||||||
|
if(reply->type != REDIS_REPLY_ARRAY)
|
||||||
|
throw std::runtime_error("Failed to get keys from database");
|
||||||
|
for(size_t i = 0; i < reply->elements; i++) {
|
||||||
|
if(!reply->element[i]->type == REDIS_REPLY_STRING)
|
||||||
|
throw std::runtime_error("Got errornous response to 'HKEYS %s' command");
|
||||||
|
posCache.push_back(decodeBlockPos(stoi64(reply->element[i]->str)));
|
||||||
|
}
|
||||||
|
freeReplyObject(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DBRedis::getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos)
|
||||||
|
{
|
||||||
|
redisReply *reply;
|
||||||
|
std::string tmp;
|
||||||
|
|
||||||
|
for (std::vector<BlockPos>::iterator it = posCache.begin(); it != posCache.end(); ++it) {
|
||||||
|
if (it->z != zPos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tmp = i64tos(encodeBlockPos(*it));
|
||||||
|
reply = (redisReply*) redisCommand(ctx, "HGET %s %s", hash.c_str(), tmp.c_str());
|
||||||
|
if(!reply)
|
||||||
|
throw std::runtime_error(std::string("redis command 'HGET %s %s' failed: ") + ctx->errstr);
|
||||||
|
if (reply->type == REDIS_REPLY_STRING && reply->len != 0) {
|
||||||
|
Block b(*it, ustring((const unsigned char *) reply->str, reply->len));
|
||||||
|
blocks[b.first.x].push_back(b);
|
||||||
|
}
|
||||||
|
freeReplyObject(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
db-redis.h
Normal file
22
db-redis.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef DB_REDIS_HEADER
|
||||||
|
#define DB_REDIS_HEADER
|
||||||
|
|
||||||
|
#include "db.h"
|
||||||
|
#include <hiredis.h>
|
||||||
|
|
||||||
|
class DBRedis : public DB {
|
||||||
|
public:
|
||||||
|
DBRedis(const std::string &mapdir);
|
||||||
|
virtual std::vector<BlockPos> getBlockPos();
|
||||||
|
virtual void getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos);
|
||||||
|
~DBRedis();
|
||||||
|
private:
|
||||||
|
void loadPosCache();
|
||||||
|
|
||||||
|
std::vector<BlockPos> posCache;
|
||||||
|
|
||||||
|
redisContext *ctx;
|
||||||
|
std::string hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DB_REDIS_HEADER
|
@ -34,7 +34,7 @@ void usage()
|
|||||||
" --noshading\n"
|
" --noshading\n"
|
||||||
" --min-y <y>\n"
|
" --min-y <y>\n"
|
||||||
" --max-y <y>\n"
|
" --max-y <y>\n"
|
||||||
" --backend <sqlite3/leveldb>\n"
|
" --backend <sqlite3/leveldb/redis>\n"
|
||||||
" --geometry x:y+w+h\n"
|
" --geometry x:y+w+h\n"
|
||||||
"Color format: '#000000'\n";
|
"Color format: '#000000'\n";
|
||||||
std::cout << usage_text;
|
std::cout << usage_text;
|
||||||
|
Loading…
Reference in New Issue
Block a user