From 58841ef12f6cba1bb622353c1fcaa0e3c6fb46c9 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Tue, 23 Oct 2012 01:18:44 +0400 Subject: Add dummy and LevelDB database backends --- src/database-sqlite3.cpp | 319 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 src/database-sqlite3.cpp (limited to 'src/database-sqlite3.cpp') diff --git a/src/database-sqlite3.cpp b/src/database-sqlite3.cpp new file mode 100644 index 000000000..e15aa0c1c --- /dev/null +++ b/src/database-sqlite3.cpp @@ -0,0 +1,319 @@ +/* + 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 +*/ + +#include "map.h" +#include "mapsector.h" +#include "mapblock.h" +#include "main.h" +#include "filesys.h" +#include "voxel.h" +#include "porting.h" +#include "mapgen.h" +#include "nodemetadata.h" +#include "settings.h" +#include "log.h" +#include "profiler.h" +#include "nodedef.h" +#include "gamedef.h" +#include "util/directiontables.h" +#include "rollback_interface.h" + +#include "database-sqlite3.h" + +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_savedir = savedir; + srvmap = map; +} + +int Database_SQLite3::Initialized(void) +{ + return m_database ? 1 : 0; +} + +void Database_SQLite3::beginSave() { + verifyDatabase(); + if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK) + infostream<<"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."; +} + +void Database_SQLite3::createDirs(std::string path) +{ + if(fs::CreateAllDirs(path) == false) + { + infostream<isDummy()) + { + /*v3s16 p = block->getPos(); + infostream<<"Database_SQLite3::saveBlock(): WARNING: Not writing dummy 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(); + + if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) + infostream<<"WARNING: Block position failed to bind: "<resetModified(); +} + +MapBlock* 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: " + <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); + +// 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 + } + sqlite3_reset(m_database_read); + return(NULL); +} + +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_ABORT) + throw FileNotGoodException("Could not create sqlite3 database structure"); + else + infostream<<"ServerMap: SQLite3 database structure was created"; + +} + +void Database_SQLite3::listAllLoadableBlocks(core::list &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="<