diff options
Diffstat (limited to 'src/map.cpp')
-rw-r--r-- | src/map.cpp | 263 |
1 files changed, 39 insertions, 224 deletions
diff --git a/src/map.cpp b/src/map.cpp index 457db14da..e2191f9e1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -38,6 +38,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "emerge.h" #include "mapgen_v6.h" #include "biome.h" +#include "database.h" +#include "database-dummy.h" +#include "database-sqlite3.h" +#if USE_LEVELDB +#include "database-leveldb.h" +#endif #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -2401,10 +2407,7 @@ s16 Map::getHumidity(v3s16 p) ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge): Map(dout_server, gamedef), m_seed(0), - m_map_metadata_changed(true), - m_database(NULL), - m_database_read(NULL), - m_database_write(NULL) + m_map_metadata_changed(true) { verbosestream<<__FUNCTION_NAME<<std::endl; @@ -2435,6 +2438,28 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer Try to load map; if not found, create a new one. */ + // Determine which database backend to use + std::string conf_path = savedir + DIR_DELIM + "world.mt"; + Settings conf; + 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 + else + throw BaseException("Unknown map backend"); + } + m_savedir = savedir; m_map_saving_enabled = false; @@ -2526,12 +2551,7 @@ ServerMap::~ServerMap() /* Close database if it was opened */ - if(m_database_read) - sqlite3_finalize(m_database_read); - if(m_database_write) - sqlite3_finalize(m_database_write); - if(m_database) - sqlite3_close(m_database); + delete(dbase); #if 0 /* @@ -3167,81 +3187,12 @@ plan_b: //return (s16)level; } -void ServerMap::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_ABORT) - throw FileNotGoodException("Could not create database structure"); - else - infostream<<"ServerMap: Database structure was created"; -} - -void ServerMap::verifyDatabase() { - if(m_database) - return; - - { - std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; - bool needs_create = false; - int d; - - /* - Open the database connection - */ - - createDirs(m_savedir); - - if(!fs::PathExists(dbp)) - needs_create = true; - - d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); - if(d != SQLITE_OK) { - infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl; - throw FileNotGoodException("Cannot open database file"); - } - - if(needs_create) - createDatabase(); - - d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL); - if(d != SQLITE_OK) { - infostream<<"WARNING: Database 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: Database 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: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl; - throw FileNotGoodException("Cannot prepare read statement"); - } - - infostream<<"ServerMap: Database opened"<<std::endl; - } -} - bool ServerMap::loadFromFolders() { - if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) + if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ? return true; return false; } -sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) { - return (sqlite3_int64)pos.Z*16777216 + - (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X; -} - void ServerMap::createDirs(std::string path) { if(fs::CreateAllDirs(path) == false) @@ -3414,50 +3365,13 @@ void ServerMap::save(ModifiedState save_level) } } -static s32 unsignedToSigned(s32 i, s32 max_positive) -{ - if(i < max_positive) - return i; - else - return i - 2*max_positive; -} - -// modulo of a negative number does not work consistently in C -static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod) -{ - if(i >= 0) - return i % mod; - return mod - ((-i) % mod); -} - -v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i) -{ - s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - x) / 4096; - s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - y) / 4096; - s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048); - return v3s16(x,y,z); -} - void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst) { if(loadFromFolders()){ errorstream<<"Map::listAllLoadableBlocks(): Result will be missing " <<"all blocks that are stored in flat files"<<std::endl; } - - { - 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); - } - } + dbase->listAllLoadableBlocks(dst); } void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst) @@ -3743,88 +3657,16 @@ bool ServerMap::loadSectorFull(v2s16 p2d) #endif void ServerMap::beginSave() { - verifyDatabase(); - if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK) - infostream<<"WARNING: beginSave() failed, saving might be slow."; + dbase->beginSave(); } void ServerMap::endSave() { - verifyDatabase(); - if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK) - infostream<<"WARNING: endSave() failed, map might not have saved."; + dbase->endSave(); } void ServerMap::saveBlock(MapBlock *block) { - DSTACK(__FUNCTION_NAME); - /* - Dummy blocks are not written - */ - if(block->isDummy()) - { - /*v3s16 p = block->getPos(); - infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block " - <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ - return; - } - - // Format used for writing - u8 version = SER_FMT_VER_HIGHEST_WRITE; - // Get destination - v3s16 p3d = block->getPos(); - - -#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(); - const char *bytes = tmp.c_str(); - - bool success = true; - if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) { - infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl; - success = false; - } - if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length - infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl; - success = false; - } - int written = sqlite3_step(m_database_write); - if(written != SQLITE_DONE) { - errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") " - <<sqlite3_errmsg(m_database)<<std::endl; - success = false; - } - // Make ready for later reuse - sqlite3_reset(m_database_write); - - // We just wrote it to the disk so clear modified flag - if (success) - block->resetModified(); + dbase->saveBlock(block); } void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load) @@ -3978,38 +3820,11 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos) v2s16 p2d(blockpos.X, blockpos.Z); - if(!loadFromFolders()) { - verifyDatabase(); - - if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) - infostream<<"WARNING: 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 = createSector(p2d); - - /* - Load block - */ - const char * data = (const char *)sqlite3_column_blob(m_database_read, 0); - size_t len = sqlite3_column_bytes(m_database_read, 0); - - std::string datastr(data, len); + MapBlock *ret; - loadBlock(&datastr, blockpos, sector, false); - - sqlite3_step(m_database_read); - // We should never get more than 1 row, so ok to reset - sqlite3_reset(m_database_read); - - return getBlockNoCreateNoEx(blockpos); - } - sqlite3_reset(m_database_read); - - // Not found in database, try the files - } + ret = dbase->loadBlock(blockpos); + if (ret) return (ret); + // Not found in database, try the files // The directory layout we're going to load from. // 1 - original sectors/xxxxzzzz/ |