From: sfan5 Date: Tue, 8 Jul 2014 18:04:37 +0000 (+0200) Subject: Move MapBlock (de)serializing code out of Database class X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=eec456be63f6fee8604f7a9c40aa41a1af3f1fac;p=zefram%2Fminetest%2Fminetest_engine.git Move MapBlock (de)serializing code out of Database class --- diff --git a/src/database-dummy.cpp b/src/database-dummy.cpp index 7f715dd1..df105727 100644 --- a/src/database-dummy.cpp +++ b/src/database-dummy.cpp @@ -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 " - <<"("<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" - <<" ("<getBool("ignore_world_load_errors")){ - errorstream<<"Ignoring block load error. Duck and cover! " - <<"(ignore_world_load_errors)"<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 &dst) diff --git a/src/database-dummy.h b/src/database-dummy.h index d179d422..e1c7b5b2 100644 --- a/src/database-dummy.h +++ b/src/database-dummy.h @@ -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 &dst); - virtual int Initialized(void); + virtual bool saveBlock(v3s16 blockpos, std::string &data); + virtual std::string loadBlock(v3s16 blockpos); + virtual void listAllLoadableBlocks(std::list &dst); + virtual int Initialized(void); ~Database_Dummy(); private: ServerMap *srvmap; diff --git a/src/database-leveldb.cpp b/src/database-leveldb.cpp index 0cf68574..d57462be 100644 --- a/src/database-leveldb.cpp +++ b/src/database-leveldb.cpp @@ -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 &dst) diff --git a/src/database-leveldb.h b/src/database-leveldb.h index 0c20aeae..ad165fcf 100644 --- a/src/database-leveldb.h +++ b/src/database-leveldb.h @@ -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 &dst); - virtual int Initialized(void); + virtual bool saveBlock(v3s16 blockpos, std::string &data); + virtual std::string loadBlock(v3s16 blockpos); + virtual void listAllLoadableBlocks(std::list &dst); + virtual int Initialized(void); ~Database_LevelDB(); private: ServerMap *srvmap; diff --git a/src/database-redis.cpp b/src/database-redis.cpp index 595fb20e..b9e75ede 100644 --- a/src/database-redis.cpp +++ b/src/database-redis.cpp @@ -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 &dst) diff --git a/src/database-redis.h b/src/database-redis.h index 92983ee7..cc33db7d 100644 --- a/src/database-redis.h +++ b/src/database-redis.h @@ -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 &dst); virtual int Initialized(void); ~Database_Redis(); diff --git a/src/database-sqlite3.cpp b/src/database-sqlite3.cpp index fb76d8ea..7e1767a8 100644 --- a/src/database-sqlite3.cpp +++ b/src/database-sqlite3.cpp @@ -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: "<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: " <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)<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; } } - diff --git a/src/database-sqlite3.h b/src/database-sqlite3.h index 1753072e..81f7d459 100644 --- a/src/database-sqlite3.h +++ b/src/database-sqlite3.h @@ -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 &dst); - virtual int Initialized(void); + virtual bool saveBlock(v3s16 blockpos, std::string &data); + virtual std::string loadBlock(v3s16 blockpos); + virtual void listAllLoadableBlocks(std::list &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 diff --git a/src/database.h b/src/database.h index d8669dd9..ffec7c97 100644 --- a/src/database.h +++ b/src/database.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define DATABASE_HEADER #include +#include #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 &dst) = 0; diff --git a/src/main.cpp b/src/main.cpp index 8a9d14d0..bb2ac5fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1296,9 +1296,13 @@ int main(int argc, char *argv[]) new_db->beginSave(); for (std::list::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 - diff --git a/src/map.cpp b/src/map.cpp index 29bbbc0d..fda4d461 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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. diff --git a/src/map.h b/src/map.h index f4c7bb2f..9b505d8e 100644 --- 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 -