Move MapBlock (de)serializing code out of Database class
authorsfan5 <sfan5@live.de>
Tue, 8 Jul 2014 18:04:37 +0000 (20:04 +0200)
committersfan5 <sfan5@live.de>
Sat, 12 Jul 2014 15:38:17 +0000 (17:38 +0200)
12 files changed:
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.h
src/main.cpp
src/map.cpp
src/map.h

index 7f715dd19bef81b0929fb2bacd248c44363cceb2..df1057274f4fc335209fa675b46f978055ba3d76 100644 (file)
@@ -45,112 +45,18 @@ int Database_Dummy::Initialized(void)
 void Database_Dummy::beginSave() {}
 void Database_Dummy::endSave() {}
 
-bool Database_Dummy::saveBlock(MapBlock *block)
+bool Database_Dummy::saveBlock(v3s16 blockpos, std::string &data)
 {
-       DSTACK(__FUNCTION_NAME);
-       /*
-               Dummy blocks are not written
-       */
-       if(block->isDummy())
-       {
-               v3s16 p = block->getPos();
-               infostream<<"Database_Dummy::saveBlock(): WARNING: Not writing dummy block "
-                               <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
-               return true;
-       }
-
-       // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST_WRITE;
-       // Get destination
-       v3s16 p3d = block->getPos();
-
-       /*
-               [0] u8 serialization version
-               [1] data
-       */
-
-       std::ostringstream o(std::ios_base::binary);
-       o.write((char*)&version, 1);
-       // Write basic data
-       block->serialize(o, version, true);
-       // Write block to database
-       std::string tmp = o.str();
-
-       m_database[getBlockAsInteger(p3d)] = tmp;
-       // We just wrote it to the disk so clear modified flag
-       block->resetModified();
+       m_database[getBlockAsInteger(blockpos)] = data;
        return true;
 }
 
-MapBlock* Database_Dummy::loadBlock(v3s16 blockpos)
+std::string Database_Dummy::loadBlock(v3s16 blockpos)
 {
-       v2s16 p2d(blockpos.X, blockpos.Z);
-
-        if(m_database.count(getBlockAsInteger(blockpos))) {
-                /*
-                        Make sure sector is loaded
-                */
-                MapSector *sector = srvmap->createSector(p2d);
-                /*
-                        Load block
-                */
-                std::string datastr = m_database[getBlockAsInteger(blockpos)];
-//                srvmap->loadBlock(&datastr, blockpos, sector, false);
-
-               try {
-                       std::istringstream is(datastr, std::ios_base::binary);
-                       u8 version = SER_FMT_VER_INVALID;
-                       is.read((char*)&version, 1);
-
-                       if(is.fail())
-                               throw SerializationError("ServerMap::loadBlock(): Failed"
-                                                    " to read MapBlock version");
-
-                       MapBlock *block = NULL;
-                       bool created_new = false;
-                       block = sector->getBlockNoCreateNoEx(blockpos.Y);
-                       if(block == NULL)
-                       {
-                               block = sector->createBlankBlockNoInsert(blockpos.Y);
-                               created_new = true;
-                       }
-                       // Read basic data
-                       block->deSerialize(is, version, true);
-                       // If it's a new block, insert it to the map
-                       if(created_new)
-                               sector->insertBlock(block);
-                       /*
-                               Save blocks loaded in old format in new format
-                       */
-
-                       //if(version < SER_FMT_VER_HIGHEST || save_after_load)
-                       // Only save if asked to; no need to update version
-                       //if(save_after_load)
-                        //             saveBlock(block);
-                       // We just loaded it from, so it's up-to-date.
-                       block->resetModified();
-
-               }
-               catch(SerializationError &e)
-               {
-                       errorstream<<"Invalid block data in database"
-                                     <<" ("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<")"
-                                     <<" (SerializationError): "<<e.what()<<std::endl;
-                     // TODO: Block should be marked as invalid in memory so that it is
-                     // not touched but the game can run
-
-                       if(g_settings->getBool("ignore_world_load_errors")){
-                             errorstream<<"Ignoring block load error. Duck and cover! "
-                                             <<"(ignore_world_load_errors)"<<std::endl;
-                       } else {
-                             throw SerializationError("Invalid block data in database");
-                             //assert(0);
-                       }
-               }
-
-                return srvmap->getBlockNoCreateNoEx(blockpos);  // should not be using this here
-        }
-       return(NULL);
+       if (m_database.count(getBlockAsInteger(blockpos)))
+               return m_database[getBlockAsInteger(blockpos)];
+       else
+               return "";
 }
 
 void Database_Dummy::listAllLoadableBlocks(std::list<v3s16> &dst)
index d179d422603cba86cf97f08d601a8d2dbae9d47b..e1c7b5b2d1884f9a901071e225ed887021f07795 100644 (file)
@@ -33,10 +33,10 @@ public:
        Database_Dummy(ServerMap *map);
        virtual void beginSave();
        virtual void endSave();
-        virtual bool saveBlock(MapBlock *block);
-        virtual MapBlock *loadBlock(v3s16 blockpos);
-        virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
-        virtual int Initialized(void);
+       virtual bool saveBlock(v3s16 blockpos, std::string &data);
+       virtual std::string loadBlock(v3s16 blockpos);
+       virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
+       virtual int Initialized(void);
        ~Database_Dummy();
 private:
        ServerMap *srvmap;
index 0cf685740fd70f9d69b9ca768fe26fc179590343..d57462be948b73f60f4cd0b6c2de33341cf6a9db 100644 (file)
@@ -58,129 +58,29 @@ int Database_LevelDB::Initialized(void)
 void Database_LevelDB::beginSave() {}
 void Database_LevelDB::endSave() {}
 
-bool Database_LevelDB::saveBlock(MapBlock *block)
+bool Database_LevelDB::saveBlock(v3s16 blockpos, std::string &data)
 {
-       DSTACK(__FUNCTION_NAME);
-
-       v3s16 p3d = block->getPos();
-
-       /*
-               Dummy blocks are not written
-       */
-       if(block->isDummy())
-       {
-               errorstream << "WARNING: saveBlock: Not writing dummy block "
-                               << PP(p3d) << std::endl;
-               return true;
-       }
-
-       // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST_WRITE;
-
-       /*
-               [0] u8 serialization version
-               [1] data
-       */
-       std::ostringstream o(std::ios_base::binary);
-       o.write((char*)&version, 1);
-       // Write basic data
-       block->serialize(o, version, true);
-       // Write block to database
-       std::string tmp = o.str();
-
        leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
-                       i64tos(getBlockAsInteger(p3d)), tmp);
+                       i64tos(getBlockAsInteger(blockpos)), data);
        if (!status.ok()) {
                errorstream << "WARNING: saveBlock: LevelDB error saving block "
-                       << PP(p3d) << ": " << status.ToString() << std::endl;
+                       << PP(blockpos) << ": " << status.ToString() << std::endl;
                return false;
        }
 
-       // We just wrote it to the disk so clear modified flag
-       block->resetModified();
        return true;
 }
 
-MapBlock* Database_LevelDB::loadBlock(v3s16 blockpos)
+std::string Database_LevelDB::loadBlock(v3s16 blockpos)
 {
-       v2s16 p2d(blockpos.X, blockpos.Z);
-
        std::string datastr;
        leveldb::Status status = m_database->Get(leveldb::ReadOptions(),
                i64tos(getBlockAsInteger(blockpos)), &datastr);
-       if (datastr.length() == 0 && status.ok()) {
-               errorstream << "Blank block data in database (datastr.length() == 0) ("
-                       << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")" << std::endl;
-
-               if (g_settings->getBool("ignore_world_load_errors")) {
-                       errorstream << "Ignoring block load error. Duck and cover! "
-                               << "(ignore_world_load_errors)" << std::endl;
-               } else {
-                       throw SerializationError("Blank block data in database");
-               }
-               return NULL;
-       } 
-       if (status.ok()) {
-               /*
-                       Make sure sector is loaded
-               */
-               MapSector *sector = srvmap->createSector(p2d);
-
-               try {
-                       std::istringstream is(datastr, std::ios_base::binary);
-                       u8 version = SER_FMT_VER_INVALID;
-                       is.read((char *)&version, 1);
-
-                       if (is.fail())
-                               throw SerializationError("ServerMap::loadBlock(): Failed"
-                                       " to read MapBlock version");
-
-                       MapBlock *block = NULL;
-                       bool created_new = false;
-                       block = sector->getBlockNoCreateNoEx(blockpos.Y);
-                       if (block == NULL)
-                       {
-                               block = sector->createBlankBlockNoInsert(blockpos.Y);
-                               created_new = true;
-                       }
-
-                       // Read basic data
-                       block->deSerialize(is, version, true);
-
-                       // If it's a new block, insert it to the map
-                       if (created_new)
-                               sector->insertBlock(block);
-
-                       /*
-                               Save blocks loaded in old format in new format
-                       */
-                       //if(version < SER_FMT_VER_HIGHEST || save_after_load)
-                       // Only save if asked to; no need to update version
-                       //if(save_after_load)
-                       //      saveBlock(block);
-                       // We just loaded it from, so it's up-to-date.
-                       block->resetModified();
-               }
-               catch (SerializationError &e)
-               {
-                       errorstream << "Invalid block data in database"
-                               << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z
-                               << ") (SerializationError): " << e.what() << std::endl;
-                       // TODO: Block should be marked as invalid in memory so that it is
-                       // not touched but the game can run
-
-                       if (g_settings->getBool("ignore_world_load_errors")) {
-                               errorstream << "Ignoring block load error. Duck and cover! "
-                                       << "(ignore_world_load_errors)" << std::endl;
-                       } else {
-                               throw SerializationError("Invalid block data in database");
-                               //assert(0);
-                       }
-               }
-
-               return srvmap->getBlockNoCreateNoEx(blockpos);  // should not be using this here
-       }
-       return NULL;
+
+       if(status.ok())
+               return datastr;
+       else
+               return "";
 }
 
 void Database_LevelDB::listAllLoadableBlocks(std::list<v3s16> &dst)
index 0c20aeaefb28d849543c5064f7eded2da50b23f5..ad165fcf2e8018e84ad8d2136ee235430a946e8d 100644 (file)
@@ -36,10 +36,10 @@ public:
        Database_LevelDB(ServerMap *map, std::string savedir);
        virtual void beginSave();
        virtual void endSave();
-        virtual bool saveBlock(MapBlock *block);
-        virtual MapBlock *loadBlock(v3s16 blockpos);
-        virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
-        virtual int Initialized(void);
+       virtual bool saveBlock(v3s16 blockpos, std::string &data);
+       virtual std::string loadBlock(v3s16 blockpos);
+       virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
+       virtual int Initialized(void);
        ~Database_LevelDB();
 private:
        ServerMap *srvmap;
index 595fb20ecc18b7c9ac28fc942533fe2f25f53355..b9e75ededd957d8452a946cab59fddfc7530aaac 100644 (file)
@@ -81,138 +81,44 @@ void Database_Redis::endSave() {
        freeReplyObject(reply);
 }
 
-bool Database_Redis::saveBlock(MapBlock *block)
+bool Database_Redis::saveBlock(v3s16 blockpos, std::string &data)
 {
-       DSTACK(__FUNCTION_NAME);
-
-       v3s16 p3d = block->getPos();
-
-       /*
-               Dummy blocks are not written
-       */
-       if(block->isDummy())
-       {
-               errorstream << "WARNING: saveBlock: Not writing dummy block "
-                               << PP(p3d) << std::endl;
-               return true;
-       }
-
-       // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST_WRITE;
-
-       /*
-               [0] u8 serialization version
-               [1] data
-       */
-
-       std::ostringstream o(std::ios_base::binary);
-       o.write((char*)&version, 1);
-       // Write basic data
-       block->serialize(o, version, true);
-       // Write block to database
-       std::string tmp1 = o.str();
-       std::string tmp2 = i64tos(getBlockAsInteger(p3d));
+       std::string tmp = i64tos(getBlockAsInteger(blockpos));
 
        redisReply *reply = (redisReply *)redisCommand(ctx, "HSET %s %s %b",
-                       hash.c_str(), tmp2.c_str(), tmp1.c_str(), tmp1.size());
+                       hash.c_str(), tmp.c_str(), data.c_str(), data.size());
        if (!reply) {
                errorstream << "WARNING: saveBlock: redis command 'HSET' failed on "
-                       "block " << PP(p3d) << ": " << ctx->errstr << std::endl;
+                       "block " << PP(blockpos) << ": " << ctx->errstr << std::endl;
                freeReplyObject(reply);
                return false;
        }
 
        if (reply->type == REDIS_REPLY_ERROR) {
-               errorstream << "WARNING: saveBlock: save block " << PP(p3d)
+               errorstream << "WARNING: saveBlock: saving block " << PP(blockpos)
                        << "failed" << std::endl;
                freeReplyObject(reply);
                return false;
        }
 
-       // We just wrote it to the disk so clear modified flag
-       block->resetModified();
        freeReplyObject(reply);
        return true;
 }
 
-MapBlock* Database_Redis::loadBlock(v3s16 blockpos)
+std::string Database_Redis::loadBlock(v3s16 blockpos)
 {
-       v2s16 p2d(blockpos.X, blockpos.Z);
-
        std::string tmp = i64tos(getBlockAsInteger(blockpos));
        redisReply *reply;
        reply = (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)
+               return "";
 
-       if (reply->type == REDIS_REPLY_STRING && reply->len == 0) {
-               freeReplyObject(reply);
-               errorstream << "Blank block data in database (reply->len == 0) ("
-                       << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")" << std::endl;
-
-               if (g_settings->getBool("ignore_world_load_errors")) {
-                       errorstream << "Ignoring block load error. Duck and cover! "
-                               << "(ignore_world_load_errors)" << std::endl;
-               } else {
-                       throw SerializationError("Blank block data in database");
-               }
-               return NULL;
-       }
-
-       if (reply->type == REDIS_REPLY_STRING) {
-               /*
-                       Make sure sector is loaded
-               */
-               MapSector *sector = srvmap->createSector(p2d);
-
-               try {
-                       std::istringstream is(std::string(reply->str, reply->len), std::ios_base::binary);
-                       freeReplyObject(reply); // std::string copies the memory so we can already do this here
-                       u8 version = SER_FMT_VER_INVALID;
-                       is.read((char *)&version, 1);
-
-                       if (is.fail())
-                               throw SerializationError("ServerMap::loadBlock(): Failed"
-                                       " to read MapBlock version");
-
-                       MapBlock *block = NULL;
-                       bool created_new = false;
-                       block = sector->getBlockNoCreateNoEx(blockpos.Y);
-                       if (block == NULL)
-                       {
-                               block = sector->createBlankBlockNoInsert(blockpos.Y);
-                               created_new = true;
-                       }
-
-                       // Read basic data
-                       block->deSerialize(is, version, true);
-
-                       // If it's a new block, insert it to the map
-                       if (created_new)
-                               sector->insertBlock(block);
-
-                       // We just loaded it from, so it's up-to-date.
-                       block->resetModified();
-               }
-               catch (SerializationError &e)
-               {
-                       errorstream << "Invalid block data in database"
-                               << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z
-                               << ") (SerializationError): " << e.what() << std::endl;
-                       // TODO: Block should be marked as invalid in memory so that it is
-                       // not touched but the game can run
-
-                       if (g_settings->getBool("ignore_world_load_errors")) {
-                               errorstream << "Ignoring block load error. Duck and cover! "
-                                       << "(ignore_world_load_errors)" << std::endl;
-                       } else {
-                               throw SerializationError("Invalid block data in database");
-                       }
-               }
-
-               return srvmap->getBlockNoCreateNoEx(blockpos);  // should not be using this here
-       }
-       return NULL;
+       std::string str(reply->str, reply->len);
+       freeReplyObject(reply); // std::string copies the memory so this won't cause any problems
+       return str;
 }
 
 void Database_Redis::listAllLoadableBlocks(std::list<v3s16> &dst)
index 92983ee7bfb2ed0e891d085ce88a92ca497c4777..cc33db7d4835eac55d296669f6c8b1ebbe38a500 100644 (file)
@@ -36,8 +36,8 @@ public:
        Database_Redis(ServerMap *map, std::string savedir);
        virtual void beginSave();
        virtual void endSave();
-       virtual bool saveBlock(MapBlock *block);
-       virtual MapBlock *loadBlock(v3s16 blockpos);
+       virtual bool saveBlock(v3s16 blockpos, std::string &data);
+       virtual std::string loadBlock(v3s16 blockpos);
        virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
        virtual int Initialized(void);
        ~Database_Redis();
index fb76d8eae6d672d909c8e61e1b8c7ee4921a2ee7..7e1767a8fb0b7bee2d3a6765b41964a7450a06c0 100644 (file)
@@ -63,13 +63,13 @@ int Database_SQLite3::Initialized(void)
 void Database_SQLite3::beginSave() {
        verifyDatabase();
        if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
-               infostream<<"WARNING: beginSave() failed, saving might be slow.";
+               errorstream<<"WARNING: beginSave() failed, saving might be slow.";
 }
 
 void Database_SQLite3::endSave() {
        verifyDatabase();
        if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
-               infostream<<"WARNING: endSave() failed, map might not have saved.";
+               errorstream<<"WARNING: endSave() failed, map might not have saved.";
 }
 
 void Database_SQLite3::createDirs(std::string path)
@@ -99,7 +99,7 @@ void Database_SQLite3::verifyDatabase() {
 
        d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
        if(d != SQLITE_OK) {
-               infostream<<"WARNING: SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
+               errorstream<<"SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
                throw FileNotGoodException("Cannot open database file");
        }
 
@@ -110,208 +110,87 @@ void Database_SQLite3::verifyDatabase() {
                         + itos(g_settings->getU16("sqlite_synchronous"));
        d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
        if(d != SQLITE_OK) {
-               infostream<<"WARNING: Database pragma set failed: "
+               errorstream<<"Database pragma set failed: "
                                <<sqlite3_errmsg(m_database)<<std::endl;
                throw FileNotGoodException("Cannot set pragma");
        }
 
        d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
        if(d != SQLITE_OK) {
-               infostream<<"WARNING: SQLite3 database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
+               errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
                throw FileNotGoodException("Cannot prepare read statement");
        }
 
        d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
        if(d != SQLITE_OK) {
-               infostream<<"WARNING: SQLite3 database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
+               errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
                throw FileNotGoodException("Cannot prepare write statement");
        }
 
        d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
        if(d != SQLITE_OK) {
-               infostream<<"WARNING: SQLite3 database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
+               infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
                throw FileNotGoodException("Cannot prepare read statement");
        }
 
        infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
 }
 
-bool Database_SQLite3::saveBlock(MapBlock *block)
+bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
 {
-       DSTACK(__FUNCTION_NAME);
-
-       v3s16 p3d = block->getPos();
-
-       /*
-               Dummy blocks are not written, but is not a save failure
-       */
-       if(block->isDummy())
-       {
-               errorstream << "WARNING: saveBlock: Not writing dummy block "
-                               << PP(p3d) << std::endl;
-               return true;
-       }
-
-       // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST_WRITE;
-
-#if 0
-       v2s16 p2d(p3d.X, p3d.Z);
-       std::string sectordir = getSectorDir(p2d);
-
-       createDirs(sectordir);
-
-       std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
-       std::ofstream o(fullpath.c_str(), std::ios_base::binary);
-       if(o.good() == false)
-               throw FileNotGoodException("Cannot open block data");
-#endif
-       /*
-               [0] u8 serialization version
-               [1] data
-       */
-
        verifyDatabase();
 
-       std::ostringstream o(std::ios_base::binary);
-
-       o.write((char *)&version, 1);
-
-       // Write basic data
-       block->serialize(o, version, true);
-
-       // Write block to database
-       std::string tmp = o.str();
-
-       if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
+       if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
                errorstream << "WARNING: saveBlock: Block position failed to bind: "
-                       << PP(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
+                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
                sqlite3_reset(m_database_write);
                return false;
        }
 
-       if (sqlite3_bind_blob(m_database_write, 2, (void *)tmp.c_str(), tmp.size(), NULL) != SQLITE_OK) {
+       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(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
+                       << 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(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
+                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
                sqlite3_reset(m_database_write);
                return false;
        }
 
-       // We just wrote it to the disk so clear modified flag
-       block->resetModified();
        sqlite3_reset(m_database_write);
        return true;
 }
 
-MapBlock* Database_SQLite3::loadBlock(v3s16 blockpos)
+std::string Database_SQLite3::loadBlock(v3s16 blockpos)
 {
-       v2s16 p2d(blockpos.X, blockpos.Z);
        verifyDatabase();
 
        if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
-               infostream << "WARNING: Could not bind block position for load: "
+               errorstream << "Could not bind block position for load: "
                        << sqlite3_errmsg(m_database)<<std::endl;
        }
 
        if (sqlite3_step(m_database_read) == SQLITE_ROW) {
-               /*
-                       Make sure sector is loaded
-               */
-               MapSector *sector = srvmap->createSector(p2d);
-
-               /*
-                       Load block
-               */
-               const char *data = (const char *)sqlite3_column_blob(m_database_read, 0);
+               const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
                size_t len = sqlite3_column_bytes(m_database_read, 0);
-               if (data == NULL || len == 0) {
-                       errorstream << "Blank block data in database (data == NULL || len"
-                               " == 0) (" << blockpos.X << "," << blockpos.Y << ","
-                               << blockpos.Z << ")" << std::endl;
-
-                       if (g_settings->getBool("ignore_world_load_errors")) {
-                               errorstream << "Ignoring block load error. Duck and cover! "
-                                       << "(ignore_world_load_errors)" << std::endl;
-                       } else {
-                               throw SerializationError("Blank block data in database");
-                       }
-                       return NULL;
-               }
-
-               std::string datastr(data, len);
-
-               //srvmap->loadBlock(&datastr, blockpos, sector, false);
-
-               try {
-                       std::istringstream is(datastr, std::ios_base::binary);
-
-                       u8 version = SER_FMT_VER_INVALID;
-                       is.read((char *)&version, 1);
-
-                       if (is.fail())
-                               throw SerializationError("ServerMap::loadBlock(): Failed"
-                                        " to read MapBlock version");
-
-                       MapBlock *block = NULL;
-                       bool created_new = false;
-                       block = sector->getBlockNoCreateNoEx(blockpos.Y);
-                       if (block == NULL)
-                       {
-                               block = sector->createBlankBlockNoInsert(blockpos.Y);
-                               created_new = true;
-                       }
-
-                       // Read basic data
-                       block->deSerialize(is, version, true);
-
-                       // If it's a new block, insert it to the map
-                       if (created_new)
-                               sector->insertBlock(block);
-
-                       /*
-                               Save blocks loaded in old format in new format
-                       */
-                       //if(version < SER_FMT_VER_HIGHEST || save_after_load)
-                       // Only save if asked to; no need to update version
-                       //if(save_after_load)
-                       //      saveBlock(block);
-
-                       // We just loaded it from, so it's up-to-date.
-                       block->resetModified();
-               }
-               catch (SerializationError &e)
-               {
-                       errorstream << "Invalid block data in database"
-                               << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")"
-                               << " (SerializationError): " << e.what() << std::endl;
-
-                       // TODO: Block should be marked as invalid in memory so that it is
-                       // not touched but the game can run
-
-                       if (g_settings->getBool("ignore_world_load_errors")) {
-                               errorstream << "Ignoring block load error. Duck and cover! "
-                                       << "(ignore_world_load_errors)" << std::endl;
-                       } else {
-                               throw SerializationError("Invalid block data in database");
-                               //assert(0);
-                       }
-               }
+
+               std::string s = "";
+               if(data)
+                       s = std::string(data, len);
 
                sqlite3_step(m_database_read);
                // We should never get more than 1 row, so ok to reset
                sqlite3_reset(m_database_read);
 
-               return srvmap->getBlockNoCreateNoEx(blockpos);  // should not be using this here
+               return s;
        }
+
        sqlite3_reset(m_database_read);
-       return NULL;
+       return "";
 }
 
 void Database_SQLite3::createDatabase()
@@ -368,4 +247,3 @@ Database_SQLite3::~Database_SQLite3()
                                << "Failed to close database: rc=" << rc << std::endl;
        }
 }
-
index 1753072e863013715d6ebafc5fbeb8bbe323ceff..81f7d459dd11b33b9145dbfb9fe9cc04cdbc44cc 100644 (file)
@@ -33,13 +33,13 @@ class Database_SQLite3 : public Database
 {
 public:
        Database_SQLite3(ServerMap *map, std::string savedir);
-        virtual void beginSave();
-        virtual void endSave();
+       virtual void beginSave();
+       virtual void endSave();
 
-        virtual bool saveBlock(MapBlock *block);
-        virtual MapBlock *loadBlock(v3s16 blockpos);
-        virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
-        virtual int Initialized(void);
+       virtual bool saveBlock(v3s16 blockpos, std::string &data);
+       virtual std::string loadBlock(v3s16 blockpos);
+       virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
+       virtual int Initialized(void);
        ~Database_SQLite3();
 private:
        ServerMap *srvmap;
@@ -51,9 +51,9 @@ private:
 
        // Create the database structure
        void createDatabase();
-        // Verify we can read/write to the database
-        void verifyDatabase();
-        void createDirs(std::string path);
+       // Verify we can read/write to the database
+       void verifyDatabase();
+       void createDirs(std::string path);
 };
 
 #endif
index d8669dd9b8a3834fc0f6206815968ace644ad1d9..ffec7c977b56eaeec4c0fbabeef7146f649f8099 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define DATABASE_HEADER
 
 #include <list>
+#include <string>
 #include "irr_v3d.h"
 #include "irrlichttypes.h"
 
@@ -28,16 +29,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 #endif
 
-class MapBlock;
-
 class Database
 {
 public:
        virtual void beginSave() = 0;
        virtual void endSave() = 0;
 
-       virtual bool saveBlock(MapBlock *block) = 0;
-       virtual MapBlock *loadBlock(v3s16 blockpos) = 0;
+       virtual bool saveBlock(v3s16 blockpos, std::string &data) = 0;
+       virtual std::string loadBlock(v3s16 blockpos) = 0;
        s64 getBlockAsInteger(const v3s16 pos) const;
        v3s16 getIntegerAsBlock(s64 i) const;
        virtual void listAllLoadableBlocks(std::list<v3s16> &dst) = 0;
index 8a9d14d0aff6296953223bc3a481dbe5c37594f6..bb2ac5faf47fe2cb57feccd7f3551ac8e80f45fd 100644 (file)
@@ -1296,9 +1296,13 @@ int main(int argc, char *argv[])
                        new_db->beginSave();
                        for (std::list<v3s16>::iterator i = blocks.begin(); i != blocks.end(); i++) {
                                MapBlock *block = old_map.loadBlock(*i);
-                               new_db->saveBlock(block);
-                               MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
-                               sector->deleteBlock(block);
+                               if (!block) {
+                                       errorstream << "Failed to load block " << PP(*i) << ", skipping it.";
+                               } else {
+                                       old_map.saveBlock(block, new_db);
+                                       MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
+                                       sector->deleteBlock(block);
+                               }
                                ++count;
                                if (count % 500 == 0)
                                        actionstream << "Migrated " << count << " blocks "
@@ -1947,4 +1951,3 @@ int main(int argc, char *argv[])
 }
 
 //END
-
index 29bbbc0d9388960f3e2ff0f4a4ad133567774b2f..fda4d461dbe43480e674970849ba555b86ef39dc 100644 (file)
@@ -3265,7 +3265,38 @@ void ServerMap::endSave()
 
 bool ServerMap::saveBlock(MapBlock *block)
 {
-       return dbase->saveBlock(block);
+       return saveBlock(block, dbase);
+}
+
+bool ServerMap::saveBlock(MapBlock *block, Database *db)
+{
+       v3s16 p3d = block->getPos();
+
+       // Dummy blocks are not written
+       if (block->isDummy()) {
+               errorstream << "WARNING: saveBlock: Not writing dummy block "
+                       << PP(p3d) << std::endl;
+               return true;
+       }
+
+       // Format used for writing
+       u8 version = SER_FMT_VER_HIGHEST_WRITE;
+
+       /*
+               [0] u8 serialization version
+               [1] data
+       */
+       std::ostringstream o(std::ios_base::binary);
+       o.write((char*) &version, 1);
+       block->serialize(o, version, true);
+
+       std::string data = o.str();
+       bool ret = db->saveBlock(p3d, data);
+       if(ret) {
+               // We just wrote it to the disk so clear modified flag
+               block->resetModified();
+       }
+       return ret;
 }
 
 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
@@ -3274,7 +3305,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
        DSTACK(__FUNCTION_NAME);
 
        std::string fullpath = sectordir+DIR_DELIM+blockfile;
-       try{
+       try {
 
                std::ifstream is(fullpath.c_str(), std::ios_base::binary);
                if(is.good() == false)
@@ -3420,10 +3451,13 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
 
        v2s16 p2d(blockpos.X, blockpos.Z);
 
-       MapBlock *ret;
+       std::string ret;
 
        ret = dbase->loadBlock(blockpos);
-       if (ret) return (ret);
+       if (ret != "") {
+               loadBlock(&ret, blockpos, createSector(p2d), false);
+               return getBlockNoCreateNoEx(blockpos);
+       }
        // Not found in database, try the files
 
        // The directory layout we're going to load from.
index f4c7bb2fceb799026ac998bbe8ce6a2ac871b60e..9b505d8e66984807d19d305910f00126062dfc1f 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -270,7 +270,7 @@ public:
 
        // Server implements this.
        // Client leaves it as no-op.
-       virtual bool saveBlock(MapBlock *block){ return false; };
+       virtual bool saveBlock(MapBlock *block) { return false; };
 
        /*
                Updates usage timers and unloads unused blocks and sectors.
@@ -485,6 +485,7 @@ public:
        // Returns true if sector now resides in memory
        //bool deFlushSector(v2s16 p2d);
 
+       bool saveBlock(MapBlock *block, Database *db);
        bool saveBlock(MapBlock *block);
        // 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);
@@ -560,4 +561,3 @@ protected:
 };
 
 #endif
-