Clean up database API and save the local map on an interval
authorShadowNinja <shadowninja@minetest.net>
Sun, 16 Nov 2014 20:31:57 +0000 (15:31 -0500)
committerShadowNinja <shadowninja@minetest.net>
Fri, 6 Mar 2015 05:20:45 +0000 (00:20 -0500)
16 files changed:
src/client.cpp
src/client.h
src/database-dummy.cpp
src/database-dummy.h
src/database-leveldb.cpp
src/database-leveldb.h
src/database-redis.cpp
src/database-redis.h
src/database-sqlite3.cpp
src/database-sqlite3.h
src/database.cpp
src/database.h
src/main.cpp
src/map.cpp
src/map.h
src/network/packethandlers/client.cpp

index a1ae1e6abd6c9402de20c642d84c992a045e4ffd..00b79e92ef181093dc0c52b383d478c31f703e9d 100644 (file)
@@ -47,10 +47,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "config.h"
 #include "version.h"
 #include "drawscene.h"
-#include "subgame.h"
-#include "server.h"
-#include "database.h"
 #include "database-sqlite3.h"
+#include "serialization.h"
 
 extern gui::IGUIEnvironment* guienv;
 
@@ -266,16 +264,13 @@ Client::Client(
        m_time_of_day_update_timer(0),
        m_recommended_send_interval(0.1),
        m_removed_sounds_check_timer(0),
-       m_state(LC_Created)
+       m_state(LC_Created),
+       m_localdb(NULL)
 {
-       /*
-               Add local player
-       */
-       {
-               Player *player = new LocalPlayer(this, playername);
+       // Add local player
+       m_env.addPlayer(new LocalPlayer(this, playername));
 
-               m_env.addPlayer(player);
-       }
+       m_cache_save_interval = g_settings->getU16("server_map_save_interval");
 
        m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
        m_cache_enable_shaders  = g_settings->getBool("enable_shaders");
@@ -285,10 +280,10 @@ void Client::Stop()
 {
        //request all client managed threads to stop
        m_mesh_update_thread.Stop();
-       if (localdb != NULL) {
-               actionstream << "Local map saving ended" << std::endl;
-               localdb->endSave();
-               delete localserver;
+       // Save local server map
+       if (m_localdb) {
+               infostream << "Local map saving ended." << std::endl;
+               m_localdb->endSave();
        }
 }
 
@@ -679,6 +674,13 @@ void Client::step(float dtime)
                        Send(pkt);
                }
        }
+
+       // Write server map
+       if (m_localdb && m_localdb_save_interval.step(dtime,
+                       m_cache_save_interval)) {
+               m_localdb->endSave();
+               m_localdb->beginSave();
+       }
 }
 
 bool Client::loadMedia(const std::string &data, const std::string &filename)
@@ -813,34 +815,19 @@ void Client::initLocalMapSaving(const Address &address,
                const std::string &hostname,
                bool is_local_server)
 {
-       localdb = NULL;
-
-       if (!g_settings->getBool("enable_local_map_saving") || is_local_server)
+       if (!g_settings->getBool("enable_local_map_saving") || is_local_server) {
                return;
+       }
 
        const std::string world_path = porting::path_user
                + DIR_DELIM + "worlds"
                + DIR_DELIM + "server_"
                + hostname + "_" + to_string(address.getPort());
 
-       SubgameSpec gamespec;
-
-       if (!getWorldExists(world_path)) {
-               gamespec = findSubgame(g_settings->get("default_game"));
-               if (!gamespec.isValid())
-                       gamespec = findSubgame("minimal");
-       } else {
-               gamespec = findWorldSubgame(world_path);
-       }
-
-       if (!gamespec.isValid()) {
-               errorstream << "Couldn't find subgame for local map saving." << std::endl;
-               return;
-       }
+       fs::CreateAllDirs(world_path);
 
-       localserver = new Server(world_path, gamespec, false, false);
-       localdb = new Database_SQLite3(&(ServerMap&)localserver->getMap(), world_path);
-       localdb->beginSave();
+       m_localdb = new Database_SQLite3(world_path);
+       m_localdb->beginSave();
        actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
 }
 
@@ -1663,7 +1650,8 @@ void Client::makeScreenshot(IrrlichtDevice *device)
                if (image) {
                        raw_image->copyTo(image);
                        irr::c8 filename[256];
-                       snprintf(filename, sizeof(filename), "%s" DIR_DELIM "screenshot_%u.png",
+                       snprintf(filename, sizeof(filename),
+                               (std::string("%s") + DIR_DELIM + "screenshot_%u.png").c_str(),
                                 g_settings->get("screenshot_path").c_str(),
                                 device->getTimer()->getRealTime());
                        std::ostringstream sstr;
index c0146911de8ea7556967c1b5ba3990a1ae599db3..a0add689a8ae443b7311c4efd469e0475524b18c 100644 (file)
@@ -48,7 +48,6 @@ struct MapDrawControl;
 class MtEventManager;
 struct PointedThing;
 class Database;
-class Server;
 
 struct QueuedMeshUpdate
 {
@@ -620,8 +619,9 @@ private:
        LocalClientState m_state;
 
        // Used for saving server map to disk client-side
-       Database *localdb;
-       Server *localserver;
+       Database *m_localdb;
+       IntervalLimiter m_localdb_save_interval;
+       u16 m_cache_save_interval;
 
        // TODO: Add callback to update these when g_settings changes
        bool m_cache_smooth_lighting;
index 5b1a1434121bff436612777dfd3f66652a50ec4d..71f60d81c898188048d8ff5baa0fc935b7ae94e2 100644 (file)
@@ -18,64 +18,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 /*
-Dummy "database" class
+Dummy database class
 */
 
-
 #include "database-dummy.h"
 
-#include "map.h"
-#include "mapsector.h"
-#include "mapblock.h"
-#include "serialization.h"
-#include "main.h"
-#include "settings.h"
-#include "log.h"
-
-Database_Dummy::Database_Dummy(ServerMap *map)
-{
-       srvmap = map;
-}
-
-int Database_Dummy::Initialized(void)
-{
-       return 1;
-}
-
-void Database_Dummy::beginSave() {}
-void Database_Dummy::endSave() {}
 
-bool Database_Dummy::saveBlock(v3s16 blockpos, std::string &data)
+bool Database_Dummy::saveBlock(const v3s16 &pos, const std::string &data)
 {
-       m_database[getBlockAsInteger(blockpos)] = data;
+       m_database[getBlockAsInteger(pos)] = data;
        return true;
 }
 
-std::string Database_Dummy::loadBlock(v3s16 blockpos)
+std::string Database_Dummy::loadBlock(const v3s16 &pos)
 {
-       if (m_database.count(getBlockAsInteger(blockpos)))
-               return m_database[getBlockAsInteger(blockpos)];
+       s64 i = getBlockAsInteger(pos);
+       if (m_database.count(i))
+               return m_database[i];
        else
                return "";
 }
 
-bool Database_Dummy::deleteBlock(v3s16 blockpos)
+bool Database_Dummy::deleteBlock(const v3s16 &pos)
 {
-       m_database.erase(getBlockAsInteger(blockpos));
+       m_database.erase(getBlockAsInteger(pos));
        return true;
 }
 
 void Database_Dummy::listAllLoadableBlocks(std::vector<v3s16> &dst)
 {
-       for(std::map<u64, std::string>::iterator x = m_database.begin(); x != m_database.end(); ++x)
-       {
-               v3s16 p = getIntegerAsBlock(x->first);
-               //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
-               dst.push_back(p);
+       for (std::map<s64, std::string>::const_iterator x = m_database.begin();
+                       x != m_database.end(); ++x) {
+               dst.push_back(getIntegerAsBlock(x->first));
        }
 }
 
-Database_Dummy::~Database_Dummy()
-{
-       m_database.clear();
-}
index 732a206f8274904c6373ea4e12beee9be3007b93..0cf56928e08d314f2ad11edf5fcc172b106cbc0f 100644 (file)
@@ -25,22 +25,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "database.h"
 #include "irrlichttypes.h"
 
-class ServerMap;
-
 class Database_Dummy : public Database
 {
 public:
-       Database_Dummy(ServerMap *map);
-       virtual void beginSave();
-       virtual void endSave();
-       virtual bool saveBlock(v3s16 blockpos, std::string &data);
-       virtual std::string loadBlock(v3s16 blockpos);
-       virtual bool deleteBlock(v3s16 blockpos);
+       virtual bool saveBlock(const v3s16 &pos, const std::string &data);
+       virtual std::string loadBlock(const v3s16 &pos);
+       virtual bool deleteBlock(const v3s16 &pos);
        virtual void listAllLoadableBlocks(std::vector<v3s16> &dst);
-       virtual int Initialized(void);
-       ~Database_Dummy();
+
 private:
-       ServerMap *srvmap;
-       std::map<u64, std::string> m_database;
+       std::map<s64, std::string> m_database;
 };
+
 #endif
+
index b35e612b6be8b4929fd2a2fed01cca95b7cfb896..e895354a4cac2432617ad2e242982872f1819e12 100644 (file)
@@ -22,57 +22,54 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #if USE_LEVELDB
 
 #include "database-leveldb.h"
-#include "leveldb/db.h"
 
-#include "map.h"
-#include "mapsector.h"
-#include "mapblock.h"
-#include "serialization.h"
-#include "main.h"
-#include "settings.h"
 #include "log.h"
 #include "filesys.h"
+#include "exceptions.h"
+#include "util/string.h"
+
+#include "leveldb/db.h"
+
 
 #define ENSURE_STATUS_OK(s) \
        if (!(s).ok()) { \
-               throw FileNotGoodException(std::string("LevelDB error: ") + (s).ToString()); \
+               throw FileNotGoodException(std::string("LevelDB error: ") + \
+                               (s).ToString()); \
        }
 
-Database_LevelDB::Database_LevelDB(ServerMap *map, std::string savedir)
+
+Database_LevelDB::Database_LevelDB(const std::string &savedir)
 {
        leveldb::Options options;
        options.create_if_missing = true;
-       leveldb::Status status = leveldb::DB::Open(options, savedir + DIR_DELIM + "map.db", &m_database);
+       leveldb::Status status = leveldb::DB::Open(options,
+               savedir + DIR_DELIM + "map.db", &m_database);
        ENSURE_STATUS_OK(status);
-       srvmap = map;
 }
 
-int Database_LevelDB::Initialized(void)
+Database_LevelDB::~Database_LevelDB()
 {
-       return 1;
+       delete m_database;
 }
 
-void Database_LevelDB::beginSave() {}
-void Database_LevelDB::endSave() {}
-
-bool Database_LevelDB::saveBlock(v3s16 blockpos, std::string &data)
+bool Database_LevelDB::saveBlock(const v3s16 &pos, const std::string &data)
 {
        leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
-                       i64tos(getBlockAsInteger(blockpos)), data);
+                       i64tos(getBlockAsInteger(pos)), data);
        if (!status.ok()) {
                errorstream << "WARNING: saveBlock: LevelDB error saving block "
-                       << PP(blockpos) << ": " << status.ToString() << std::endl;
+                       << PP(pos) << ": " << status.ToString() << std::endl;
                return false;
        }
 
        return true;
 }
 
-std::string Database_LevelDB::loadBlock(v3s16 blockpos)
+std::string Database_LevelDB::loadBlock(const v3s16 &pos)
 {
        std::string datastr;
        leveldb::Status status = m_database->Get(leveldb::ReadOptions(),
-               i64tos(getBlockAsInteger(blockpos)), &datastr);
+               i64tos(getBlockAsInteger(pos)), &datastr);
 
        if(status.ok())
                return datastr;
@@ -80,13 +77,13 @@ std::string Database_LevelDB::loadBlock(v3s16 blockpos)
                return "";
 }
 
-bool Database_LevelDB::deleteBlock(v3s16 blockpos)
+bool Database_LevelDB::deleteBlock(const v3s16 &pos)
 {
        leveldb::Status status = m_database->Delete(leveldb::WriteOptions(),
-                       i64tos(getBlockAsInteger(blockpos)));
+                       i64tos(getBlockAsInteger(pos)));
        if (!status.ok()) {
                errorstream << "WARNING: deleteBlock: LevelDB error deleting block "
-                       << PP(blockpos) << ": " << status.ToString() << std::endl;
+                       << PP(pos) << ": " << status.ToString() << std::endl;
                return false;
        }
 
@@ -103,8 +100,5 @@ void Database_LevelDB::listAllLoadableBlocks(std::vector<v3s16> &dst)
        delete it;
 }
 
-Database_LevelDB::~Database_LevelDB()
-{
-       delete m_database;
-}
-#endif
+#endif // USE_LEVELDB
+
index 5d44ba3e7a2ed8e2b679dbf20f82b60946f14fd0..4afe2fdc727bc3261803a2b971a788c63b18bcc5 100644 (file)
@@ -28,23 +28,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "leveldb/db.h"
 #include <string>
 
-class ServerMap;
-
 class Database_LevelDB : public Database
 {
 public:
-       Database_LevelDB(ServerMap *map, std::string savedir);
-       virtual void beginSave();
-       virtual void endSave();
-       virtual bool saveBlock(v3s16 blockpos, std::string &data);
-       virtual std::string loadBlock(v3s16 blockpos);
-       virtual bool deleteBlock(v3s16 blockpos);
-       virtual void listAllLoadableBlocks(std::vector<v3s16> &dst);
-       virtual int Initialized(void);
+       Database_LevelDB(const std::string &savedir);
        ~Database_LevelDB();
+
+       virtual bool saveBlock(const v3s16 &pos, const std::string &data);
+       virtual std::string loadBlock(const v3s16 &pos);
+       virtual bool deleteBlock(const v3s16 &pos);
+       virtual void listAllLoadableBlocks(std::vector<v3s16> &dst);
+
 private:
-       ServerMap *srvmap;
-       leveldb::DB* m_database;
+       leveldb::DB *m_database;
 };
+
+#endif // USE_LEVELDB
+
 #endif
-#endif
+
index 0962e97baa23553ad78de88da3c63673171fc433..7b42274b97394c9ee038194f65582ae7e88f36ca 100644 (file)
@@ -20,84 +20,78 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "config.h"
 
 #if USE_REDIS
-/*
-       Redis databases
-*/
-
 
 #include "database-redis.h"
-#include <hiredis.h>
 
-#include "map.h"
-#include "mapsector.h"
-#include "mapblock.h"
-#include "serialization.h"
-#include "main.h"
 #include "settings.h"
 #include "log.h"
-#include "filesys.h"
+#include "exceptions.h"
+#include "util/string.h"
+
+#include <hiredis.h>
+#include <cassert>
 
 
-Database_Redis::Database_Redis(ServerMap *map, std::string savedir)
+Database_Redis::Database_Redis(Settings &conf)
 {
-       Settings conf;
-       conf.readConfigFile((std::string(savedir) + DIR_DELIM + "world.mt").c_str());
        std::string tmp;
        try {
-       tmp = conf.get("redis_address");
-       hash = conf.get("redis_hash");
-       } catch(SettingNotFoundException e) {
-               throw SettingNotFoundException("Set redis_address and redis_hash in world.mt to use the redis backend");
+               tmp = conf.get("redis_address");
+               hash = conf.get("redis_hash");
+       } catch (SettingNotFoundException) {
+               throw SettingNotFoundException("Set redis_address and "
+                       "redis_hash in world.mt to use the redis backend");
        }
        const char *addr = tmp.c_str();
        int port = conf.exists("redis_port") ? conf.getU16("redis_port") : 6379;
        ctx = redisConnect(addr, port);
-       if(!ctx)
+       if (!ctx) {
                throw FileNotGoodException("Cannot allocate redis context");
-       else if(ctx->err) {
+       else if(ctx->err) {
                std::string err = std::string("Connection error: ") + ctx->errstr;
                redisFree(ctx);
                throw FileNotGoodException(err);
        }
-       srvmap = map;
 }
 
-int Database_Redis::Initialized(void)
+Database_Redis::~Database_Redis()
 {
-       return 1;
+       redisFree(ctx);
 }
 
 void Database_Redis::beginSave() {
-       redisReply *reply;
-       reply = (redisReply*) redisCommand(ctx, "MULTI");
-       if(!reply)
-               throw FileNotGoodException(std::string("redis command 'MULTI' failed: ") + ctx->errstr);
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "MULTI"));
+       if (!reply) {
+               throw FileNotGoodException(std::string(
+                       "Redis command 'MULTI' failed: ") + ctx->errstr);
+       }
        freeReplyObject(reply);
 }
 
 void Database_Redis::endSave() {
-       redisReply *reply;
-       reply = (redisReply*) redisCommand(ctx, "EXEC");
-       if(!reply)
-               throw FileNotGoodException(std::string("redis command 'EXEC' failed: ") + ctx->errstr);
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "EXEC"));
+       if (!reply) {
+               throw FileNotGoodException(std::string(
+                       "Redis command 'EXEC' failed: ") + ctx->errstr);
+       }
        freeReplyObject(reply);
 }
 
-bool Database_Redis::saveBlock(v3s16 blockpos, std::string &data)
+bool Database_Redis::saveBlock(const v3s16 &pos, const std::string &data)
 {
-       std::string tmp = i64tos(getBlockAsInteger(blockpos));
+       std::string tmp = i64tos(getBlockAsInteger(pos));
 
-       redisReply *reply = (redisReply *)redisCommand(ctx, "HSET %s %s %b",
-                       hash.c_str(), tmp.c_str(), data.c_str(), data.size());
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "HSET %s %s %b",
+                       hash.c_str(), tmp.c_str(), data.c_str(), data.size()));
        if (!reply) {
                errorstream << "WARNING: saveBlock: redis command 'HSET' failed on "
-                       "block " << PP(blockpos) << ": " << ctx->errstr << std::endl;
+                       "block " << PP(pos) << ": " << ctx->errstr << std::endl;
                freeReplyObject(reply);
                return false;
        }
 
        if (reply->type == REDIS_REPLY_ERROR) {
-               errorstream << "WARNING: saveBlock: saving block " << PP(blockpos)
+               errorstream << "WARNING: saveBlock: saving block " << PP(pos)
                        << "failed" << std::endl;
                freeReplyObject(reply);
                return false;
@@ -107,38 +101,36 @@ bool Database_Redis::saveBlock(v3s16 blockpos, std::string &data)
        return true;
 }
 
-std::string Database_Redis::loadBlock(v3s16 blockpos)
+std::string Database_Redis::loadBlock(const v3s16 &pos)
 {
-       std::string tmp = i64tos(getBlockAsInteger(blockpos));
-       redisReply *reply;
-       reply = (redisReply*) redisCommand(ctx, "HGET %s %s", hash.c_str(), tmp.c_str());
+       std::string tmp = i64tos(getBlockAsInteger(pos));
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx,
+                       "HGET %s %s", hash.c_str(), tmp.c_str()));
 
-       if(!reply)
-               throw FileNotGoodException(std::string("redis command 'HGET %s %s' failed: ") + ctx->errstr);
-       if(reply->type != REDIS_REPLY_STRING)
+       if (!reply) {
+               throw FileNotGoodException(std::string(
+                       "Redis command 'HGET %s %s' failed: ") + ctx->errstr);
+       } else if (reply->type != REDIS_REPLY_STRING) {
                return "";
+       }
 
        std::string str(reply->str, reply->len);
        freeReplyObject(reply); // std::string copies the memory so this won't cause any problems
        return str;
 }
 
-bool Database_Redis::deleteBlock(v3s16 blockpos)
+bool Database_Redis::deleteBlock(const v3s16 &pos)
 {
-       std::string tmp = i64tos(getBlockAsInteger(blockpos));
+       std::string tmp = i64tos(getBlockAsInteger(pos));
 
-       redisReply *reply = (redisReply *)redisCommand(ctx, "HDEL %s %s",
-               hash.c_str(), tmp.c_str());
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx,
+               "HDEL %s %s", hash.c_str(), tmp.c_str()));
        if (!reply) {
-               errorstream << "WARNING: deleteBlock: redis command 'HDEL' failed on "
-                       "block " << PP(blockpos) << ": " << ctx->errstr << std::endl;
-               freeReplyObject(reply);
-               return false;
-       }
-
-       if (reply->type == REDIS_REPLY_ERROR) {
-               errorstream << "WARNING: deleteBlock: deleting block " << PP(blockpos)
-                       << "failed" << std::endl;
+               throw FileNotGoodException(std::string(
+                       "Redis command 'HDEL %s %s' failed: ") + ctx->errstr);
+       } else if (reply->type == REDIS_REPLY_ERROR) {
+               errorstream << "WARNING: deleteBlock: deleting block " << PP(pos)
+                       << " failed" << std::endl;
                freeReplyObject(reply);
                return false;
        }
@@ -149,21 +141,19 @@ bool Database_Redis::deleteBlock(v3s16 blockpos)
 
 void Database_Redis::listAllLoadableBlocks(std::vector<v3s16> &dst)
 {
-       redisReply *reply;
-       reply = (redisReply*) redisCommand(ctx, "HKEYS %s", hash.c_str());
-       if(!reply)
-               throw FileNotGoodException(std::string("redis command 'HKEYS %s' failed: ") + ctx->errstr);
-       if(reply->type != REDIS_REPLY_ARRAY)
+       redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "HKEYS %s", hash.c_str()));
+       if (!reply) {
+               throw FileNotGoodException(std::string(
+                       "Redis command 'HKEYS %s' failed: ") + ctx->errstr);
+       } else if (reply->type != REDIS_REPLY_ARRAY) {
                throw FileNotGoodException("Failed to get keys from database");
-       for(size_t i = 0; i < reply->elements; i++) {
+       }
+       for (size_t i = 0; i < reply->elements; i++) {
                assert(reply->element[i]->type == REDIS_REPLY_STRING);
                dst.push_back(getIntegerAsBlock(stoi64(reply->element[i]->str)));
        }
        freeReplyObject(reply);
 }
 
-Database_Redis::~Database_Redis()
-{
-       redisFree(ctx);
-}
-#endif
+#endif // USE_REDIS
+
index 3c4e2b6d81507add04bacd6c769317961817d37e..45e702c83463a29c9e0a0e3e84247137ff84f2ae 100644 (file)
@@ -28,24 +28,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <hiredis.h>
 #include <string>
 
-class ServerMap;
+class Settings;
 
 class Database_Redis : public Database
 {
 public:
-       Database_Redis(ServerMap *map, std::string savedir);
+       Database_Redis(Settings &conf);
+       ~Database_Redis();
+
        virtual void beginSave();
        virtual void endSave();
-       virtual bool saveBlock(v3s16 blockpos, std::string &data);
-       virtual std::string loadBlock(v3s16 blockpos);
-       virtual bool deleteBlock(v3s16 blockpos);
+
+       virtual bool saveBlock(const v3s16 &pos, const std::string &data);
+       virtual std::string loadBlock(const v3s16 &pos);
+       virtual bool deleteBlock(const v3s16 &pos);
        virtual void listAllLoadableBlocks(std::vector<v3s16> &dst);
-       virtual int Initialized(void);
-       ~Database_Redis();
+
 private:
-       ServerMap *srvmap;
        redisContext *ctx;
        std::string hash;
 };
+
+#endif // USE_REDIS
+
 #endif
-#endif
+
index 2edae8be2e08216592e160b1c553631bc18bc830..3480894c941790f0ab48723c7495eab200fffd6c 100644 (file)
@@ -18,259 +18,205 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 /*
-       SQLite format specification:
-       - Initially only replaces sectors/ and sectors2/
-
-       If map.sqlite does not exist in the save dir
-       or the block was not found in the database
-       the map will try to load from sectors folder.
-       In either case, map.sqlite will be created
-       and all future saves will save there.
-
-       Structure of map.sqlite:
-       Tables:
-               blocks
-                       (PK) INT pos
-                       BLOB data
+SQLite format specification:
+       blocks:
+               (PK) INT id
+               BLOB data
 */
 
 
 #include "database-sqlite3.h"
 
-#include "map.h"
-#include "mapsector.h"
-#include "mapblock.h"
-#include "serialization.h"
-#include "main.h"
-#include "settings.h"
 #include "log.h"
 #include "filesys.h"
+#include "exceptions.h"
+#include "main.h"
+#include "settings.h"
+#include "util/string.h"
+
+#include <cassert>
+
+
+#define SQLRES(s, r) \
+       if ((s) != (r)) { \
+               throw FileNotGoodException(std::string(\
+                                       "SQLite3 database error (" \
+                                       __FILE__ ":" TOSTRING(__LINE__) \
+                                       "): ") +\
+                               sqlite3_errmsg(m_database)); \
+       }
+#define SQLOK(s) SQLRES(s, SQLITE_OK)
+
+#define PREPARE_STATEMENT(name, query) \
+       SQLOK(sqlite3_prepare_v2(m_database, query, -1, &m_stmt_##name, NULL))
+
+#define FINALIZE_STATEMENT(statement) \
+       if (sqlite3_finalize(statement) != SQLITE_OK) { \
+               throw FileNotGoodException(std::string( \
+                       "SQLite3: Failed to finalize " #statement ": ") + \
+                        sqlite3_errmsg(m_database)); \
+       }
 
-Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
-{
-       m_database = NULL;
-       m_database_read = NULL;
-       m_database_write = NULL;
-       m_database_list = NULL;
-       m_database_delete = NULL;
-       m_savedir = savedir;
-       srvmap = map;
-}
 
-int Database_SQLite3::Initialized(void)
+Database_SQLite3::Database_SQLite3(const std::string &savedir) :
+       m_initialized(false),
+       m_savedir(savedir),
+       m_database(NULL),
+       m_stmt_read(NULL),
+       m_stmt_write(NULL),
+       m_stmt_list(NULL),
+       m_stmt_delete(NULL)
 {
-       return m_database ? 1 : 0;
 }
 
 void Database_SQLite3::beginSave() {
        verifyDatabase();
-       if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
-               errorstream<<"WARNING: beginSave() failed, saving might be slow.";
+       SQLRES(sqlite3_step(m_stmt_begin), SQLITE_DONE);
+       sqlite3_reset(m_stmt_begin);
 }
 
 void Database_SQLite3::endSave() {
        verifyDatabase();
-       if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
-               errorstream<<"WARNING: endSave() failed, map might not have saved.";
+       SQLRES(sqlite3_step(m_stmt_end), SQLITE_DONE);
+       sqlite3_reset(m_stmt_end);
 }
 
-void Database_SQLite3::createDirs(std::string path)
+void Database_SQLite3::openDatabase()
 {
-       if(fs::CreateAllDirs(path) == false)
-       {
-               infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
-                               <<"\""<<path<<"\""<<std::endl;
-               throw BaseException("Database_SQLite3 failed to create directory");
-       }
-}
+       if (m_database) return;
 
-void Database_SQLite3::verifyDatabase() {
-       if(m_database)
-               return;
-
-       std::string dbp = m_savedir + DIR_DELIM "map.sqlite";
-       bool needs_create = false;
-       int d;
+       std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
 
        // Open the database connection
 
-       createDirs(m_savedir); // ?
+       if (!fs::CreateAllDirs(m_savedir)) {
+               infostream << "Database_SQLite3: Failed to create directory \""
+                       << m_savedir << "\"" << std::endl;
+               throw FileNotGoodException("Failed to create database "
+                               "save directory");
+       }
 
-       if(!fs::PathExists(dbp))
-               needs_create = true;
+       bool needs_create = !fs::PathExists(dbp);
 
-       d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
-       if(d != SQLITE_OK) {
-               errorstream<<"SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
+       if (sqlite3_open_v2(dbp.c_str(), &m_database,
+                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+                       NULL) != SQLITE_OK) {
+               errorstream << "SQLite3 database failed to open: "
+                       << sqlite3_errmsg(m_database) << std::endl;
                throw FileNotGoodException("Cannot open database file");
        }
 
-       if(needs_create)
+       if (needs_create) {
                createDatabase();
+       }
 
-       std::string querystr = std::string("PRAGMA synchronous = ")
+       std::string query_str = std::string("PRAGMA synchronous = ")
                         + itos(g_settings->getU16("sqlite_synchronous"));
-       d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
-       if(d != SQLITE_OK) {
-               errorstream<<"Database pragma set failed: "
-                               <<sqlite3_errmsg(m_database)<<std::endl;
-               throw FileNotGoodException("Cannot set pragma");
-       }
+       SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL));
+}
 
-       d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
-       if(d != SQLITE_OK) {
-               errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-               throw FileNotGoodException("Cannot prepare read statement");
-       }
+void Database_SQLite3::verifyDatabase()
+{
+       if (m_initialized) return;
+
+       openDatabase();
+
+       PREPARE_STATEMENT(begin, "BEGIN");
+       PREPARE_STATEMENT(end, "COMMIT");
+       PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `pos` = ? LIMIT 1");
 #ifdef __ANDROID__
-       d = sqlite3_prepare(m_database, "INSERT INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
+       PREPARE_STATEMENT(write,  "INSERT INTO `blocks` (`pos`, `data`) VALUES (?, ?)");
 #else
-       d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
+       PREPARE_STATEMENT(write, "REPLACE INTO `blocks` (`pos`, `data`) VALUES (?, ?)");
 #endif
-       if(d != SQLITE_OK) {
-               errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-               throw FileNotGoodException("Cannot prepare write statement");
-       }
+       PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `pos` = ?");
+       PREPARE_STATEMENT(list, "SELECT `pos` FROM `blocks`");
 
-       d = sqlite3_prepare(m_database, "DELETE FROM `blocks` WHERE `pos`=?;", -1, &m_database_delete, NULL);
-       if(d != SQLITE_OK) {
-               infostream<<"WARNING: SQLite3 database delete statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-               throw FileNotGoodException("Cannot prepare delete statement");
-       }
+       m_initialized = true;
 
-       d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
-       if(d != SQLITE_OK) {
-               infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-               throw FileNotGoodException("Cannot prepare read statement");
-       }
+       verbosestream << "ServerMap: SQLite3 database opened." << std::endl;
+}
 
-       infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
+inline void Database_SQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index)
+{
+       SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos)));
 }
 
-bool Database_SQLite3::deleteBlock(v3s16 blockpos)
+bool Database_SQLite3::deleteBlock(const v3s16 &pos)
 {
        verifyDatabase();
 
-       if (sqlite3_bind_int64(m_database_delete, 1,
-                       getBlockAsInteger(blockpos)) != SQLITE_OK) {
-               errorstream << "WARNING: Could not bind block position for delete: "
-                       << sqlite3_errmsg(m_database) << std::endl;
-       }
+       bindPos(m_stmt_delete, pos);
+
+       bool good = sqlite3_step(m_stmt_delete) == SQLITE_DONE;
+       sqlite3_reset(m_stmt_delete);
 
-       if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
+       if (!good) {
                errorstream << "WARNING: deleteBlock: Block failed to delete "
-                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
-               sqlite3_reset(m_database_delete);
-               return false;
+                       << PP(pos) << ": " << sqlite3_errmsg(m_database) << std::endl;
        }
-
-       sqlite3_reset(m_database_delete);
-       return true;
+       return good;
 }
 
-bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
+bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data)
 {
        verifyDatabase();
 
-       s64 bkey = getBlockAsInteger(blockpos);
-
 #ifdef __ANDROID__
        /**
-        * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
-        * deleting them and inserting first works.
+        * Note: For some unknown reason SQLite3 fails to REPLACE blocks on Android,
+        * deleting them and then inserting works.
         */
-       if (sqlite3_bind_int64(m_database_read, 1, bkey) != SQLITE_OK) {
-               infostream << "WARNING: Could not bind block position for load: "
-                       << sqlite3_errmsg(m_database)<<std::endl;
-       }
+       bindPos(m_stmt_read, pos);
 
-       int step_result = sqlite3_step(m_database_read);
-       sqlite3_reset(m_database_read);
-
-       if (step_result == SQLITE_ROW) {
-               if (sqlite3_bind_int64(m_database_delete, 1, bkey) != SQLITE_OK) {
-                       infostream << "WARNING: Could not bind block position for delete: "
-                               << sqlite3_errmsg(m_database)<<std::endl;
-               }
-
-               if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
-                       errorstream << "WARNING: saveBlock: Block failed to delete "
-                               << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
-                       return false;
-               }
-               sqlite3_reset(m_database_delete);
+       if (sqlite3_step(m_stmt_read) == SQLITE_ROW) {
+               deleteBlock(pos);
        }
+       sqlite3_reset(m_stmt_read);
 #endif
 
-       if (sqlite3_bind_int64(m_database_write, 1, bkey) != SQLITE_OK) {
-               errorstream << "WARNING: saveBlock: Block position failed to bind: "
-                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
-               sqlite3_reset(m_database_write);
-               return false;
-       }
-
-       if (sqlite3_bind_blob(m_database_write, 2, (void *)data.c_str(),
-                       data.size(), NULL) != SQLITE_OK) {
-               errorstream << "WARNING: saveBlock: Block data failed to bind: "
-                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
-               sqlite3_reset(m_database_write);
-               return false;
-       }
-
-       if (sqlite3_step(m_database_write) != SQLITE_DONE) {
-               errorstream << "WARNING: saveBlock: Block failed to save "
-                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
-               sqlite3_reset(m_database_write);
-               return false;
-       }
+       bindPos(m_stmt_write, pos);
+       SQLOK(sqlite3_bind_blob(m_stmt_write, 2, data.data(), data.size(), NULL));
 
-       sqlite3_reset(m_database_write);
+       SQLRES(sqlite3_step(m_stmt_write), SQLITE_DONE)
+       sqlite3_reset(m_stmt_write);
 
        return true;
 }
 
-std::string Database_SQLite3::loadBlock(v3s16 blockpos)
+std::string Database_SQLite3::loadBlock(const v3s16 &pos)
 {
        verifyDatabase();
 
-       if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
-               errorstream << "Could not bind block position for load: "
-                       << sqlite3_errmsg(m_database)<<std::endl;
-       }
+       bindPos(m_stmt_read, pos);
 
-       if (sqlite3_step(m_database_read) == SQLITE_ROW) {
-               const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
-               size_t len = sqlite3_column_bytes(m_database_read, 0);
-
-               std::string s = "";
-               if(data)
-                       s = std::string(data, len);
+       if (sqlite3_step(m_stmt_read) != SQLITE_ROW) {
+               sqlite3_reset(m_stmt_read);
+               return "";
+       }
+       const char *data = (const char *) sqlite3_column_blob(m_stmt_read, 0);
+       size_t len = sqlite3_column_bytes(m_stmt_read, 0);
 
-               sqlite3_step(m_database_read);
-               // We should never get more than 1 row, so ok to reset
-               sqlite3_reset(m_database_read);
+       std::string s;
+       if (data)
+               s = std::string(data, len);
 
-               return s;
-       }
+       sqlite3_step(m_stmt_read);
+       // We should never get more than 1 row, so ok to reset
+       sqlite3_reset(m_stmt_read);
 
-       sqlite3_reset(m_database_read);
-       return "";
+       return s;
 }
 
 void Database_SQLite3::createDatabase()
 {
-       int e;
        assert(m_database);
-       e = sqlite3_exec(m_database,
-               "CREATE TABLE IF NOT EXISTS `blocks` ("
-                       "`pos` INT NOT NULL PRIMARY KEY,"
-                       "`data` BLOB"
-               ");"
-       , NULL, NULL, NULL);
-       if(e != SQLITE_OK)
-               throw FileNotGoodException("Could not create sqlite3 database structure");
-       else
-               infostream<<"ServerMap: SQLite3 database structure was created";
+       SQLOK(sqlite3_exec(m_database,
+               "CREATE TABLE IF NOT EXISTS `blocks` (\n"
+               "       `pos` INT PRIMARY KEY,\n"
+               "       `data` BLOB\n"
+               ");\n",
+               NULL, NULL, NULL));
 
 }
 
@@ -278,36 +224,25 @@ void Database_SQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
 {
        verifyDatabase();
 
-       while(sqlite3_step(m_database_list) == SQLITE_ROW) {
-               sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
-               v3s16 p = getIntegerAsBlock(block_i);
-               //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
-               dst.push_back(p);
+       while (sqlite3_step(m_stmt_list) == SQLITE_ROW) {
+               dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0)));
        }
+       sqlite3_reset(m_stmt_list);
 }
 
-
-#define FINALIZE_STATEMENT(statement)                                          \
-       if ( statement )                                                           \
-               rc = sqlite3_finalize(statement);                                      \
-       if ( rc != SQLITE_OK )                                                     \
-               errorstream << "Database_SQLite3::~Database_SQLite3():"                \
-                       << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
-
 Database_SQLite3::~Database_SQLite3()
 {
-       int rc = SQLITE_OK;
-
-       FINALIZE_STATEMENT(m_database_read)
-       FINALIZE_STATEMENT(m_database_write)
-       FINALIZE_STATEMENT(m_database_list)
-       FINALIZE_STATEMENT(m_database_delete)
-
-       if(m_database)
-               rc = sqlite3_close(m_database);
-
-       if (rc != SQLITE_OK) {
+       FINALIZE_STATEMENT(m_stmt_read)
+       FINALIZE_STATEMENT(m_stmt_write)
+       FINALIZE_STATEMENT(m_stmt_list)
+       FINALIZE_STATEMENT(m_stmt_begin)
+       FINALIZE_STATEMENT(m_stmt_end)
+       FINALIZE_STATEMENT(m_stmt_delete)
+
+       if (sqlite3_close(m_database) != SQLITE_OK) {
                errorstream << "Database_SQLite3::~Database_SQLite3(): "
-                               << "Failed to close database: rc=" << rc << std::endl;
+                               << "Failed to close database: "
+                               << sqlite3_errmsg(m_database) << std::endl;
        }
 }
+
index 270e4e3be549fa47a2c81ac940feb9aef98a91e4..a775742be83ba1ef241b3575147a4858e61b7c9d 100644 (file)
@@ -27,35 +27,43 @@ extern "C" {
        #include "sqlite3.h"
 }
 
-class ServerMap;
-
 class Database_SQLite3 : public Database
 {
 public:
-       Database_SQLite3(ServerMap *map, std::string savedir);
+       Database_SQLite3(const std::string &savedir);
+
        virtual void beginSave();
        virtual void endSave();
 
-       virtual bool saveBlock(v3s16 blockpos, std::string &data);
-       virtual std::string loadBlock(v3s16 blockpos);
-       virtual bool deleteBlock(v3s16 blockpos);
+       virtual bool saveBlock(const v3s16 &pos, const std::string &data);
+       virtual std::string loadBlock(const v3s16 &pos);
+       virtual bool deleteBlock(const v3s16 &pos);
        virtual void listAllLoadableBlocks(std::vector<v3s16> &dst);
-       virtual int Initialized(void);
+       virtual bool initialized() const { return m_initialized; }
        ~Database_SQLite3();
-private:
-       ServerMap *srvmap;
-       std::string m_savedir;
-       sqlite3 *m_database;
-       sqlite3_stmt *m_database_read;
-       sqlite3_stmt *m_database_write;
-       sqlite3_stmt *m_database_delete;
-       sqlite3_stmt *m_database_list;
 
+private:
+       // Open the database
+       void openDatabase();
        // Create the database structure
        void createDatabase();
-       // Verify we can read/write to the database
+       // Open and initialize the database if needed
        void verifyDatabase();
-       void createDirs(std::string path);
+
+       void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index=1);
+
+       bool m_initialized;
+
+       std::string m_savedir;
+
+       sqlite3 *m_database;
+       sqlite3_stmt *m_stmt_read;
+       sqlite3_stmt *m_stmt_write;
+       sqlite3_stmt *m_stmt_list;
+       sqlite3_stmt *m_stmt_delete;
+       sqlite3_stmt *m_stmt_begin;
+       sqlite3_stmt *m_stmt_end;
 };
 
 #endif
+
index 26f6992fcb47e7e84b5fad70707857fcaa1cd857..262d475ec5554b25c5c4f2a6b8331dfedf3e2ef8 100644 (file)
@@ -48,7 +48,7 @@ static inline s64 pythonmodulo(s64 i, s16 mod)
 }
 
 
-s64 Database::getBlockAsInteger(const v3s16 pos) const
+s64 Database::getBlockAsInteger(const v3s16 &pos)
 {
        return (u64) pos.Z * 0x1000000 +
                (u64) pos.Y * 0x1000 +
@@ -56,7 +56,7 @@ s64 Database::getBlockAsInteger(const v3s16 pos) const
 }
 
 
-v3s16 Database::getIntegerAsBlock(s64 i) const
+v3s16 Database::getIntegerAsBlock(s64 i)
 {
        v3s16 pos;
        pos.X = unsigned_to_signed(pythonmodulo(i, 4096), 2048);
index f4a2a4e8c85774bec999dfc75feec1b422393daf..cee7b6fd96d5589869ee2a5a9aa322193521923b 100644 (file)
@@ -32,16 +32,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 class Database
 {
 public:
-       virtual void beginSave() = 0;
-       virtual void endSave() = 0;
-
-       virtual bool saveBlock(v3s16 blockpos, std::string &data) = 0;
-       virtual std::string loadBlock(v3s16 blockpos) = 0;
-       virtual bool deleteBlock(v3s16 blockpos) = 0;
-       s64 getBlockAsInteger(const v3s16 pos) const;
-       v3s16 getIntegerAsBlock(s64 i) const;
+       virtual ~Database() {}
+
+       virtual void beginSave() {}
+       virtual void endSave() {}
+
+       virtual bool saveBlock(const v3s16 &pos, const std::string &data) = 0;
+       virtual std::string loadBlock(const v3s16 &pos) = 0;
+       virtual bool deleteBlock(const v3s16 &pos) = 0;
+
+       static s64 getBlockAsInteger(const v3s16 &pos);
+       static v3s16 getIntegerAsBlock(s64 i);
+
        virtual void listAllLoadableBlocks(std::vector<v3s16> &dst) = 0;
-       virtual int Initialized(void)=0;
-       virtual ~Database() {};
+
+       virtual bool initialized() const { return true; }
 };
+
 #endif
+
index 922effb1f38af57b2a87dc3e80553c275723d6b8..4e5bf51fd2b690676992e51a8eaf2393eaac3e98 100644 (file)
@@ -914,52 +914,46 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
 static bool migrate_database(const GameParams &game_params, const Settings &cmd_args,
                Server *server)
 {
+       std::string migrate_to = cmd_args.get("migrate");
        Settings world_mt;
-       bool success = world_mt.readConfigFile((game_params.world_path
-                       + DIR_DELIM + "world.mt").c_str());
+       std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
+       bool success = world_mt.readConfigFile(world_mt_path.c_str());
        if (!success) {
                errorstream << "Cannot read world.mt" << std::endl;
-               return false;
+               return 1;
        }
-
        if (!world_mt.exists("backend")) {
-               errorstream << "Please specify your current backend in world.mt file:"
-                           << std::endl << "   backend = {sqlite3|leveldb|redis|dummy}"
-                           << std::endl;
-               return false;
+               errorstream << "Please specify your current backend in world.mt:"
+                       << std::endl;
+               errorstream << "        backend = {sqlite3|leveldb|redis|dummy}"
+                       << std::endl;
+               return 1;
        }
-
        std::string backend = world_mt.get("backend");
        Database *new_db;
-       std::string migrate_to = cmd_args.get("migrate");
-
        if (backend == migrate_to) {
-               errorstream << "Cannot migrate: new backend is same as the old one"
-                           << std::endl;
-               return false;
+               errorstream << "Cannot migrate: new backend is same"
+                       <<" as the old one" << std::endl;
+               return 1;
        }
-
        if (migrate_to == "sqlite3")
-               new_db = new Database_SQLite3(&(ServerMap&)server->getMap(),
-                               game_params.world_path);
-#if USE_LEVELDB
+               new_db = new Database_SQLite3(game_params.world_path);
+       #if USE_LEVELDB
        else if (migrate_to == "leveldb")
-               new_db = new Database_LevelDB(&(ServerMap&)server->getMap(),
-                               game_params.world_path);
-#endif
-#if USE_REDIS
+               new_db = new Database_LevelDB(game_params.world_path);
+       #endif
+       #if USE_REDIS
        else if (migrate_to == "redis")
-               new_db = new Database_Redis(&(ServerMap&)server->getMap(),
-                               game_params.world_path);
-#endif
+               new_db = new Database_Redis(world_mt);
+       #endif
        else {
-               errorstream << "Migration to " << migrate_to << " is not supported"
-                           << std::endl;
-               return false;
+               errorstream << "Migration to " << migrate_to
+                       << " is not supported" << std::endl;
+               return 1;
        }
 
        std::vector<v3s16> blocks;
-       ServerMap &old_map = ((ServerMap&)server->getMap());
+       ServerMap &old_map = (ServerMap &) server->getMap();
        old_map.listAllLoadableBlocks(blocks);
        int count = 0;
        new_db->beginSave();
@@ -975,16 +969,15 @@ static bool migrate_database(const GameParams &game_params, const Settings &cmd_
                }
                ++count;
                if (count % 500 == 0)
-                  actionstream << "Migrated " << count << " blocks "
-                          << (100.0 * count / blocks.size()) << "% completed" << std::endl;
+                       actionstream << "Migrated " << count << " blocks "
+                               << (100.0 * count / blocks.size()) << "% completed" << std::endl;
        }
        new_db->endSave();
        delete new_db;
 
        actionstream << "Successfully migrated " << count << " blocks" << std::endl;
        world_mt.set("backend", migrate_to);
-       if (!world_mt.updateConfigFile(
-                               (game_params.world_path+ DIR_DELIM + "world.mt").c_str()))
+       if (!world_mt.updateConfigFile(world_mt_path.c_str()))
                errorstream << "Failed to update world.mt!" << std::endl;
        else
                actionstream << "world.mt updated" << std::endl;
index 2c70280095b47f4c5cdfd31097d05a8eb85ed199..e58ae2cfe3a0a9c59bcf47e6be03d7778cd4a832 100644 (file)
@@ -53,22 +53,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
-/*
-       SQLite format specification:
-       - Initially only replaces sectors/ and sectors2/
-
-       If map.sqlite does not exist in the save dir
-       or the block was not found in the database
-       the map will try to load from sectors folder.
-       In either case, map.sqlite will be created
-       and all future saves will save there.
-
-       Structure of map.sqlite:
-       Tables:
-               blocks
-                       (PK) INT pos
-                       BLOB data
-*/
 
 /*
        Map
@@ -2031,25 +2015,26 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
        bool succeeded = conf.readConfigFile(conf_path.c_str());
        if (!succeeded || !conf.exists("backend")) {
                // fall back to sqlite3
-               dbase = new Database_SQLite3(this, savedir);
                conf.set("backend", "sqlite3");
-       } else {
-               std::string backend = conf.get("backend");
-               if (backend == "dummy")
-                       dbase = new Database_Dummy(this);
-               else if (backend == "sqlite3")
-                       dbase = new Database_SQLite3(this, savedir);
-               #if USE_LEVELDB
-               else if (backend == "leveldb")
-                       dbase = new Database_LevelDB(this, savedir);
-               #endif
-               #if USE_REDIS
-               else if (backend == "redis")
-                       dbase = new Database_Redis(this, savedir);
-               #endif
-               else
-                       throw BaseException("Unknown map backend");
        }
+       std::string backend = conf.get("backend");
+       if (backend == "dummy")
+               dbase = new Database_Dummy();
+       else if (backend == "sqlite3")
+               dbase = new Database_SQLite3(savedir);
+       #if USE_LEVELDB
+       else if (backend == "leveldb")
+               dbase = new Database_LevelDB(savedir);
+       #endif
+       #if USE_REDIS
+       else if (backend == "redis")
+               dbase = new Database_Redis(conf);
+       #endif
+       else
+               throw BaseException("Unknown map backend");
+
+       if (!conf.updateConfigFile(conf_path.c_str()))
+               errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
 
        m_savedir = savedir;
        m_map_saving_enabled = false;
@@ -2828,7 +2813,8 @@ plan_b:
 }
 
 bool ServerMap::loadFromFolders() {
-       if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
+       if(!dbase->initialized() &&
+                       !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
                return true;
        return false;
 }
@@ -2850,14 +2836,14 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout)
        {
                case 1:
                        snprintf(cc, 9, "%.4x%.4x",
-                               (unsigned int)pos.X&0xffff,
-                               (unsigned int)pos.Y&0xffff);
+                               (unsigned int) pos.X & 0xffff,
+                               (unsigned int) pos.Y & 0xffff);
 
                        return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
                case 2:
-                       snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
-                               (unsigned int)pos.X&0xfff,
-                               (unsigned int)pos.Y&0xfff);
+                       snprintf(cc, 9, (std::string("%.3x") + DIR_DELIM + "%.3x").c_str(),
+                               (unsigned int) pos.X & 0xfff,
+                               (unsigned int) pos.Y & 0xfff);
 
                        return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
                default:
@@ -2881,10 +2867,10 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
        {
                // New layout
                fs::RemoveLastPathComponent(dirname, &component, 2);
-               r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
+               r = sscanf(component.c_str(), (std::string("%3x") + DIR_DELIM + "%3x").c_str(), &x, &y);
                // Sign-extend the 12 bit values up to 16 bits...
-               if(x&0x800) x|=0xF000;
-               if(y&0x800) y|=0xF000;
+               if(x & 0x800) x |= 0xF000;
+               if(y & 0x800) y |= 0xF000;
        }
        else
        {
@@ -3299,7 +3285,7 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db)
 
        std::string data = o.str();
        bool ret = db->saveBlock(p3d, data);
-       if(ret) {
+       if (ret) {
                // We just wrote it to the disk so clear modified flag
                block->resetModified();
        }
@@ -3311,7 +3297,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
 {
        DSTACK(__FUNCTION_NAME);
 
-       std::string fullpath = sectordir+DIR_DELIM+blockfile;
+       std::string fullpath = sectordir + DIR_DELIM + blockfile;
        try {
 
                std::ifstream is(fullpath.c_str(), std::ios_base::binary);
@@ -3513,7 +3499,7 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
        */
 
        std::string blockfilename = getBlockFilename(blockpos);
-       if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
+       if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
                return NULL;
 
        /*
index ab5f45ab96443920652dfca62f62e18174d2674b..073f9314dba3abeeb96c9c6bf20fb3b5b9c382c4 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -481,8 +481,8 @@ public:
        // Returns true if sector now resides in memory
        //bool deFlushSector(v2s16 p2d);
 
-       bool saveBlock(MapBlock *block, Database *db);
        bool saveBlock(MapBlock *block);
+       static bool saveBlock(MapBlock *block, Database *db);
        // This will generate a sector with getSector if not found.
        void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
        MapBlock* loadBlock(v3s16 p);
index e1e57b3a656d94c011b2aa14eb9c4cc7b84c2204..82f8b61b7244fb5f476bba443b0054c64c8c0cad 100644 (file)
@@ -168,8 +168,8 @@ void Client::handleCommand_BlockData(NetworkPacket* pkt)
                sector->insertBlock(block);
        }
 
-       if (localdb != NULL) {
-               ((ServerMap&) localserver->getMap()).saveBlock(block, localdb);
+       if (m_localdb) {
+               ServerMap::saveBlock(block, m_localdb);
        }
 
        /*